前言:写随笔主要是加深自己对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#比较接口主要有两类:IComparable和IComparer(详细内容参考 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 商房大厦