织梦CMS - 轻松建站从此开始!

罗索

又一个 C++ 双向链表类

jackyhwei 发布于 2010-07-27 10:16 点击:次 
原书这部分内容很多,至少相对于循环链表是很多。相信当你把单链表的指针域搞清楚后,这部分应该难不倒你。现在我的问题是,能不能从单链表派生出双向链表?
TAG:

原书这部分内容很多,至少相对于循环链表是很多。相信当你把单链表的指针域搞清楚后,这部分应该难不倒你。现在我的问题是,能不能从单链表派生出双向链表?
你可以有几种做法:
一种就是先定义一个双链节点——但是,它的名字必须叫Node,这是没办法的事;不然你就只好拷贝一份单链表的实现文件,把其中的Node全都替换成你的双链节点名字,但是这就不叫继承了。
另一种做法就是先定义一种结构例如这样的:

 

  1. template <class Type> class newtype 
  2. public
  3. Type data; 
  4. Node<newtype> *link; 
当你派生双向链表时,这样写template <calss Type> class DblList : public List<newtype<Type> >,注意连续的两个“>”之间要有空格。或者根本不定义这样的结构,直接拿Node类型来做,例如我下面给出的。但是,请注意要完成“==” 的重载,否则,你又要重写Find函数,并且其他的某些操作也不方便。
在开始完成你的从单链表派生出来的双向链表之前,要在单链表这个基类中添加修改当前指针和当前前驱指针的接口,如下所示:

 

  1. protected
  2. void Put(Node<Type> *p)//尽量不用,双向链表将使用这个完成向前移动 
  3. current = p; 
  4.   
  5. void PutPrior(Node<Type> *p)//尽量不用,原因同上 
  6. prior = p; 
因为这个接口很危险,而且几乎用不到,所以我在前面并没有给出,但要完成双向链表最“杰出”的优点——向前移动当前指针,必须要使用。另外说的是,我从前也从来没计划从单链表派生双链表,下面你将看到,这个过程很让人烦人,甚至不如重写一个来的省事,执行效率也不是很好,这种费力不讨好的事做它有什么意思呢?的确,我也觉得我在钻牛角尖。(别拿鸡蛋丢我)

定义和实现

 

  1. #ifndef DblList_H 
  2. #define DblList_H 
  3.   
  4. #include "List.h" 
  5.   
  6. template <class Type> class DblList : public List< Node<Type> > 
  7. public
  8. Type *Get() 
  9. if (pGet() != NULL) return &pGet()->data.data; 
  10. else return NULL; 
  11.   
  12. Type *Next() 
  13. pNext(); 
  14. return Get(); 
  15.   
  16. Type *Prior() 
  17. if (pGetPrior != NULL) 
  18. Put(pGetPrior()); 
  19. PutPrior( (Node< Node<Type> >*)pGet()->data.link); 
  20. return Get(); 
  21. return NULL; 
  22.   
  23. void Insert(const Type &value) 
  24. Node<Type> newdata(value, (Node<Type>*)pGet()); 
  25. List< Node<Type> >::Insert(newdata); 
  26. if (pGetNext()->link != NULL) 
  27. pGetNext()->link->data.link = (Node<Type>*)pGetNext(); 
  28.   
  29. BOOL Remove() 
  30. if (List< Node<Type> >::Remove()) 
  31. pGet()->data.link = (Node<Type>*)pGetPrior(); 
  32. return TURE; 
  33. return FALSE; 
  34.   
  35. }; 
  36.   
  37. #endif 
【说明】只完成了最重要的Insert和 Remove函数和最具特点的Prior()函数,其他的没有重新实现。所以,你在这里使用单链表的其他方法,我不保证一定正确。并且,这里的指针类型转换依赖于编译器实现,我也不能肯定其他的编译器编译出来也能正确。对于让不让Prior返回头节点的data,我考虑再三,反正用First();Get ();这样的组合也能返回,所以就不在乎他了,所以要是用Prior遍历直到返回NULL,就会将头节点的data输出来了。
【补充】至于双向循环链表,也可以从这个双向链表派生(仿照派生循环链表的方法);或者从循环链表派生(仿照派生双向链表的方法),就不一一举例了(再这样下去,我就真闹心的要吐血了)。至此,可以得出一个结论,链表的各种结构都是能从单链表派生出来的。换句话说,单链表是根本所在,如果研究透了单链表,各种链式结构都不难。

一小段测试程序

 

  1. void DblListTest_int() 
  2. DblList<int> a; 
  3. for (int i = 10; i > 1; i--) a.Insert(i); 
  4. for (i = 10; i > 1; i--) cout << *a.Next() << " "
  5. a.First(); 
  6. cout << endl; 
  7. cout << *a.Next() << endl; 
  8. cout << *a.Next() << endl; 
  9. cout << *a.Next() << endl; 
  10. cout << *a.Next() << endl; 
  11. a.Remove(); 
  12. cout << *a.Get() << endl; 
  13. cout << *a.Prior() << endl; 
  14. cout << *a.Prior() << endl; 
  15. cout << *a.Prior() << endl; 
【后记】从我对双向链表不负责任的实现来看,我并不想这么来实现双向链表,我只是尝试怎样最大限度的利用已有的类来实现这种类型。实践证明,不如重写一个。别人看起来也好看一些,自己写起来也不用这样闹心。不过,这个过程让我对函数的调用和返回的理解又更深了一步。如果你能第一次就写对这里的Insert函数,相信你一定对C++有一定的感触了。我也觉得,只有做一些创新,才能最已经很成熟的东西更深入的了解。比如,这些数据结构,在C++的标准库(STL)中都可以直接拿来用,我们为什么还辛辛苦苦的写,结果还不如人家原来的好。为了学习,这就是理由,这也是一切看起来很笨的事发生的理由。
(Dreamcode)
本站文章除注明转载外,均为本站原创或编译欢迎任何形式的转载,但请务必注明出处,尊重他人劳动,同学习共成长。转载请注明:文章转载自:罗索实验室 [http://www.rosoo.net/a/201007/9885.html]
本文出处:CSDN博客 作者:Dreamcode
顶一下
(0)
0%
踩一下
(0)
0%
------分隔线----------------------------
发表评论
请自觉遵守互联网相关的政策法规,严禁发布色情、暴力、反动的言论。
评价:
表情:
用户名: 验证码:点击我更换图片
栏目列表
将本文分享到微信
织梦二维码生成器
推荐内容