面试题5:C#链表(上)

  前言:写随笔主要是加深自己对C#的理解,如果有错误的地方请指正,感激不尽。

剑指offer的面试题5:要求可以逆向实现打印链表,原文中给出的C++代码,我自己用C#代码实现。自己写代码总要比读代码认识到的东西要多一些,在实现的过程中主要遇到的知识点有

  1,如何使自己的链表具有实现foreach功能

  2,实现中选择继承IList接口,里面有一个copyTo函数,学到了使用ICLone接口

  3,实现Contains函数时需要比较,于是查了C#中==,equal,Reference的相同处和不同出?

  4,最后要测试,学习了白盒测试的几种覆盖

  5, 关于比较接口的不同。

首先请看代码。

public interface IPrint
    {
        void print();
    }

  Iprint的接口,是我自己写的一个接口,分别有链表链表元素继承,实现打印自己功能。

  下面是链表元素的代码:

 1     public class LKNode : IPrint, IComparable<LKNode>, ICloneable
 2     {
 3         public int _value;
 4         public LKNode _next;
 5         public LKNode() 
 6         {
 7             _value = int.MinValue;
 8             _next = null;
 9         }
10         public void print()
11         {
12             Console.WriteLine("{0}",_value);
13         }
14         public int CompareTo(LKNode other)
15         {
16             if (_value > other._value)
17                 return 1;
18             else if (_value < other._value)
19                 return -1;
20             else
21                 return 0;
22         }
23         public override string ToString()
24         {
25             return _value.ToString();
26         }
27         public object Clone()
28         {
29             LKNode p = new LKNode();
30             p._value = _value;
31             p._next = _next;
32             return p;
33         }
34     }

  LKNode节点不但实现了Iprint接口,还实现了一个比较接口,和一个IClone接口。实现比较接口,当初构想可以实现链表的排序功能。

一、关于比较接口。

  C#比较接口主要有两类:IComparableIComparer(详细内容参考 http://www.readme8.com/ReadIng/read_net/7107.html

  两者的区别为:

  IComparable在要比较的对象的类中实现,可以比较该对象和另一个对象;

  IComparer在一个单独的类中实现,可以比较任意两个对象

  .net Framework在类Comparer上提供了IComparer接口的默认实现方式,类Comparer位于System.Collections命名空间中,可以对简单类型以及支持IComparable接口的认识类型进行特定文化的比较。结合(http://blog.csdn.net/wmqdn/article/details/7537651)另一篇文章的内容,对于int,string类型的数组,.net 已经实现了IComparer接口,系统利用该接口可以实现排序功能,但是当排序对象是自定义类型时,需要实现一个或者两个接口,帮助系统完成对对象接口的排序功能。马上要写排序的相关代码,要亲自实现一下

      MSND 对于 IComparer 的CompareTo函数,给出如果自身大于要比较的对象返回大于零的整数,小于则返回小于零的整数,等于返回0.

二、关于克隆IClone接口

  C#,对于值类型可以直接复制的,对于对象类型复制代表自己的一个引用,在链表实现中有一个CopyTo函数,把链表的元素放到链表元素的数组上,如果直接复制,就是对链表元素的一个引用,改变数组的元素也会改变链表中的元素。因此实现一个IClone接口,有一点需要强调的是当自定义的类的成员有引用类型时,此时的克隆(拷贝),就有深拷贝和浅拷贝之分。如何实现见(http://www.cnblogs.com/vagerent/archive/2009/06/29/1513339.html

  链表元素还重载了object的ToString()函数,下面介绍链表的数据接口,代码太长,隐藏了,链表LKList类实现了IList<LKNode>,实现了该接口的所有函数其中就有GetEnumerator()返回一个IEnumerator接口--ListNode集合,可是实现对集合的简单迭代,可以通过foreach访问List元素。

链表的实现代码
    public class LKList : IList<LKNode>,IPrint
    {
        /// <summary>
        /// 头结点不用来存储链表的数据
        /// </summary>
        private LKNode HeadNode;
        private int _count; 
        public LKList() 
        {
            HeadNode = new LKNode(); 
            _count = 0;
        }
        public int IndexOf(LKNode item)
        {
            if (HeadNode._next == null||item==null)
            {
                return -1;
            }
            else 
            {
                LKNode p = HeadNode._next;
                int index=0;
                bool bingGo = false;
                while(index<_count)
                {
                    if (p.Equals(item))
                    {
                        bingGo = true;
                        break;
                    }
                    else 
                    {
                        p = p._next;
                        index++;
                    }                     
                }
                if (bingGo)
                    return index;
                else
                    return -1;
            }
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="index"> index not out Range</param>
        /// <param name="item">not null</param>
        public void Insert(int index, LKNode item)
        {
            //1,2,3,4
            if (index<0||index >= _count||item==null)
                return;
            //5
            if (Contains(item))
                return;
            LKNode p = HeadNode;
            int i = 0;
            //6
            while (i < index) 
            {
                //7
                p = p._next;
                i++;
            }
            item._next=p._next;
            p._next = item;
            _count++;
        }
        public void RemoveAt(int index)
        {
            if (index < 0 || index >= _count)
                return;
            LKNode p = HeadNode;
            int i = 0;
            while (i < index) 
            {
                p = p._next;
                i++;
            }
            p._next = p._next._next;
            _count--;
        }
        public LKNode this[int index]
        {
            get
            {
                if (index < 0 || index >= _count)
                    return null;
                int i = 0;
                LKNode p = HeadNode._next;
                while(i<index)
                {
                    i++;
                    p = p._next;
                }
                return p;
            }
            set
            {
                if (index < 0 || index >= _count)
                    throw new IndexOutOfRangeException();
                int i = 0;
                LKNode p = HeadNode;
                while (i < index)
                {
                    i++;
                    p = p._next;
                }
                value._next=p._next._next;
                p._next = value;
            }
        }
        public void Add(LKNode item)
        {
            //1
            if (item == null)
                return;
            //2
            if (Contains(item))
                return;
            else
            {//3
                item._next = HeadNode._next;
                HeadNode._next = item;
                _count++;
            }
             //4   
        }
        public void Clear()
        {
            HeadNode._next = null;
            _count = 0;
        }
        public bool Contains(LKNode item)
        {
            if (item == null)
                return false;
            int i = 0;
            LKNode p = HeadNode._next;
            bool bingGo = false;
            while (i < _count) 
            {
                if (p.Equals(item))
                {
                    bingGo = true;
                    break;
                }
                i++;
            }
            return bingGo;
        }
        public void CopyTo(LKNode[] array, int arrayIndex)
        {
           if(array==null)
           {   
               return;
               throw new NullReferenceException();
           }
           if (arrayIndex<0||arrayIndex+_count>array.Length)
            {
                return;
                throw new IndexOutOfRangeException();
            }
           int i = 0;
           while (i < _count) 
           {
               array[arrayIndex] = this[i].Clone() as LKNode;
               i++;
               arrayIndex++;
           }
        }
        public int Count
        {
            get { return _count; }
        }
        public bool IsReadOnly
        {
            get { return false; }
        }
        public bool Remove(LKNode item)
        {
            if (item == null)
                return false;           
            LKNode p = HeadNode;
            int i = 0; 
            bool bingGo = false;
            while (i < _count)
            {
                if(p._next.Equals(item))
                {
                    bingGo = true;
                    break;
                }
                p = p._next;
                i++;
            }
            if(bingGo)
            {
                p._next = p._next._next;
                _count--;
            }
            return bingGo;
        }
        public IEnumerator<LKNode> GetEnumerator()
        {
            return new LKListIEnumerator(this);
        }
        System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
        {
            return new LKListIEnumerator(this);
        }
        public class LKListIEnumerator : IEnumerator<LKNode> 
        {
            private LKNode p;
            private LKList _list;
            public LKListIEnumerator(LKList lkl) 
            {
                _list = lkl;
                p = lkl.HeadNode;
            }

            public LKNode Current
            {
                get 
                {
                    p = p._next;
                    return p;
                }
            }

            public void Dispose()
            {
                _list = null;
            }

            object IEnumerator.Current
            {
                get { return Current; }
            }

            public bool MoveNext()
            {
                if (p == null || p._next == null)
                {
                    return false;
                }
                else 
                {
                    return true;
                }
            }

            public void Reset()
            {
                p = _list.HeadNode;
            }
        }
        public void ReversingPrint() 
        {
            Stack<LKNode> stkLKN = new Stack<LKNode>();
            foreach(LKNode lkn in this)
            {
                stkLKN.Push(lkn);
            }
            while(stkLKN.Count>0)
            {
                stkLKN.Pop().print();
            }
        }
        public void print()
        {
            if (_count <= 0)
            {
                Console.WriteLine("List is null");
            }
            else 
            {
                Console.WriteLine("List has {0} element",_count);
                foreach (LKNode lk in this)
                {
                    lk.print();
                }
            }

        }
    }

三、IEnumerator接口和IEnumerable接口

  实现GetEnumerator()函数时,只发现了要返回一个GetEnumerator接口,顺便查到了IEnumerable接口的,IEnumerable接口是声明式接口,而IEnumerator接口是实现式接口,(详见http://www.cnblogs.com/shaosks/archive/2011/09/27/2193270.html),因此IList<LKNode>应该继承了IEnumerable接口了。

  实现IEnumerator接口通过一个内部类,详见代码。  

        public class LKListIEnumerator : IEnumerator<LKNode> 
        {
            private LKNode p;
            private LKList _list;
            public LKListIEnumerator(LKList lkl) 
            {
                _list = lkl;
                p = lkl.HeadNode;
            }

            public LKNode Current
            {
                get 
                {
                    p = p._next;
                    return p;
                }
            }

            public void Dispose()
            {
                _list = null;
            }

            object IEnumerator.Current
            {
                get { return Current; }
            }

            public bool MoveNext()
            {
                if (p == null || p._next == null)
                {
                    return false;
                }
                else 
                {
                    return true;
                }
            }

            public void Reset()
            {
                p = _list.HeadNode;
            }
        }

    关于equal和测试,下篇文章再写,胃有点难受,大家好好保重身体。

                                                  菜包子

                                               2013年4月10日17:06:09 商房大厦

  

  

 

原文地址:https://www.cnblogs.com/CaiBaoZi/p/3012712.html