• 面试题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 商房大厦

      

      

     

  • 相关阅读:
    smarty基础
    phpcms 内容模块PC标签调用
    phpcms v9中的$CATEGORYS栏目数组
    PHP如何实现验证码
    PHP生成一个不重复随机数组的封装方法
    简单实现php文件管理
    PHP-----作业:查询数据,在页面上显示
    PHP-----设计模式六大原则
    PHP-----静态
    PHP-----面向对象的设计模式:工厂模式例题
  • 原文地址:https://www.cnblogs.com/CaiBaoZi/p/3012712.html
Copyright © 2020-2023  润新知