数据结构学习(C++)之双向链表

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

template <class Type> class newtype
{
public:
Type data;
Node<newtype> *link;
}

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

protected:
void Put(Node<Type> *p)//尽量不用,双向链表将使用这个完成向前移动
{
current = p;
}
void PutPrior(Node<Type> *p)//尽量不用,原因同上
{
prior = p;
}

  因为这个接口很危险,而且几乎用不到,所以我在前面并没有给出,但要完成双向链表最"杰出"的优点--向前移动当前指针,必须要使用。另外说的是,我从前也从来没计划从单链表派生双链表,下面你将看到,这个过程很让人烦人,甚至不如重写一个来的省事,执行效率也不是很好,这种费力不讨好的事做它有什么意思呢?的确,我也觉得我在钻牛角尖。
  定义和实现

#ifndef DblList_H
#define DblList_H
#include "List.h"
template <class Type> class DblList : public List< Node<Type> >
{
public:
Type *Get()
{
if (pGet() != NULL) return &pGet()->data.data;
else return NULL;
}
Type *Next()
{
pNext();
return Get();
}
Type *Prior()
{
if (pGetPrior != NULL)
{
Put(pGetPrior());
PutPrior( (Node< Node<Type> >*)pGet()->data.link);
return Get();
}
return NULL;
}
void Insert(const Type &value)
{
Node<Type> newdata(value, (Node<Type>*)pGet());
List< Node<Type> >::Insert(newdata);
if (pGetNext()->link != NULL)
pGetNext()->link->data.link = (Node<Type>*)pGetNext();
}
BOOL Remove()
{
if (List< Node<Type> >::Remove())
{
pGet()->data.link = (Node<Type>*)pGetPrior();
return TURE;
}
return FALSE;
}
};
#endif

  【说明】只完成了最重要的Insert和Remove函数和最具特点的Prior()函数,其他的没有重新实现。所以,你在这里使用单链表的其他方法,我不保证一定正确。并且,这里的指针类型转换依赖于编译器实现,我也不能肯定其他的编译器编译出来也能正确。对于让不让Prior返回头节点的data,我考虑再三,反正用First();Get();这样的组合也能返回,所以就不在乎他了,所以要是用Prior遍历直到返回NULL,就会将头节点的data输出来了。
  【补充】至于双向循环链表,也可以从这个双向链表派生(仿照派生循环链表的方法);或者从循环链表派生(仿照派生双向链表的方法),就不一一举例了(再这样下去,我就真闹心的要吐血了)。至此,可以得出一个结论,链表的各种结构都是能从单链表派生出来的。换句话说,单链表是根本所在,如果研究透了单链表,各种链式结构都不难。
  一小段测试程序

void DblListTest_int()
{
DblList<int> a;
for (int i = 10; i > 1; i--) a.Insert(i);
for (i = 10; i > 1; i--) cout << *a.Next() << " ";
a.First();
cout << endl;
cout << *a.Next() << endl;
cout << *a.Next() << endl;
cout << *a.Next() << endl;
cout << *a.Next() << endl;
a.Remove();
cout << *a.Get() << endl;
cout << *a.Prior() << endl;
cout << *a.Prior() << endl;
cout << *a.Prior() << endl;
}

  【后记】从我对双向链表不负责任的实现来看,我并不想这么来实现双向链表,我只是尝试怎样最大限度的利用已有的类来实现这种类型。实践证明,不如重写一个。别人看起来也好看一些,自己写起来也不用这样闹心。不过,这个过程让我对函数的调用和返回的理解又更深了一步。如果你能第一次就写对这里的Insert函数,相信你一定对C++有一定的感触了。我也觉得,只有做一些创新,才能最已经很成熟的东西更深入的了解。比如,这些数据结构,在C++的标准库(STL)中都可以直接拿来用,我们为什么还辛辛苦苦的写,结果还不如人家原来的好。为了学习,这就是理由,这也是一切看起来很笨的事发生的理由。

时间: 2024-08-31 09:20:54

数据结构学习(C++)之双向链表的相关文章

数据结构学习笔记

在网上有较多的数据结构视频课,我通过学习邓俊辉的网课免费视频来学习的.他的视频讲得还很详细,比较适合刚入门的与那些即将毕业,找工作但是数据结构比较薄弱的同学来学习. 向量 有很多接口方法. 可扩充向量:总容量capacity,size当前的实际规模.当size不及capacity一半是,会下溢(装填因子=size/capacity). 动态空间管理:当即将上溢时,就会适当的扩容.

数据结构学习笔记--队列

引子:只有学习才是激情的生命,才是燃烧的岁月,才是完美的人生 声明:本笔记由<嵌入式系统软件设计中的数据结构>产生,旨在提升自己的软件设计水平,绝无侵权行为,望转载者备注说明 一 队列逻辑结构 1 是一种只允许在表的一端-"队尾"进行插入,而在另一端-"队头"进行删除的线性表.实则为线性表的一种特例.也称为先进先出表 2 当队列中没有结点时称为空队列.队列的修改是依照先进先出的原则进行的 二 队列的基本运算 置空队 SetNull(Q):将队列 Q 置成

答读者问(24):一个大二学生有关数据结构学习的疑问及答复

       最近,在V众投上有一个标题为"最近学习数据结构陷入了死循环大脑一片空白"的问题(http://www.vzhongtou.com/question/744),具体内容如下:         大一下学期学历c语言 学了半吊子 大二一开学就开始讲数据结构 没学过汇编啥的 我知道c语言的指针很重要就复习了指针现在对指针有所了解 老师讲课是一星期讲两节大课 一大章一节讲课一节上机 只讲伪算法 现在讲到树了感觉太抽象了完全搞不懂 本人数学基础比较薄弱 另外感觉自己的逻辑和抽象思维有

Python高级数据结构学习教程

本文虽然不是很深入,不过实例比较多,学习Python高级数据结构的好基础教程. 数据结构的概念 数据结构的概念很好理解,就是用来将数据组织在一起的结构.换句话说,数据结构是用来存储一系列关联数据的东西.在Python中有四种内建的数据结构,分别是List.Tuple.Dictionary以及Set.大部分的应用程序不需要其他类型的数据结构,但若是真需要也有很多高级数据结构可供选择,例如Collection.Array.Heapq.Bisect.Weakref.Copy以及Pprint.本文将介绍

通过改写算法获得数据结构学习的更佳效果

[事件] 某名数据结构基础网络学员在"单链表的基本算法"部分连问两个问题: 老师,我while语句里面j<i-1改为j<i,else里面直接q=p可以么? 老师,你这样万一刚好q->next==NULL呢,这样没影响吧? 我的"即时"回答,也已经是10个小时之后了,我不知道他看到解答后,状态还在不在.另外,这种问题,并非是可以.不行就简单回答的,背后很细致的考量,用有限的文字根本说不清楚. 这名认真学习.主动思考的学员,此时需要的是在学习方法上的改

数据结构学习(C++)之图

图的应用恐怕是所有数据结构中最宽泛的了,但这也注定了在讲"数据结构的图"的时候没什么好讲的--关于图的最重要的是算法,而且相当的一部分都是很专业的,一般的人几乎不会接触到:相对而言,结构就显得分量很轻.你可以看到关于图中元素的操作很少,远没有单链表那里列出的一大堆"接口".--一个结构如果复杂,那么能确切定义的操作就很有限. 基本储存方法 不管怎么说,还是先得把图存起来.不要看书上列出了好多方法,根本只有一个--邻接矩阵.如果矩阵是稀疏的,那就可以用十字链表来储存矩

数据结构学习(C++)之二叉树

树 因为现实世界中存在这"树"这种结构--族谱.等级制度.目录分类等等,而为了研究这类问题,必须能够将树储存,而如何储存将取决于所需要的操作.这里有个问题,是否允许存在空树.有些书认为树都是非空的,因为树表示的是一种现实结构,而0不是自然数:我用过的教科书都是说可以有空树,当然是为了和二叉树统一.这个没有什么原则上的差别,反正就是一种习惯. 二叉树 二叉树可以说是人们假想的一个模型,因此,允许有空的二叉树是无争议的.二叉树是有序的,左边有一个孩子和右边有一个的二叉树是不同的两棵树.做这

数据结构学习(C++)之栈和队列

栈和队列是操作受限的线性表,好像每本讲数据结构的数都是这么说的.有些书按照这个思路给出了定义和实现:但是很遗憾,本文没有这样做,所以,有些书中的做法是重复建设,这或许可以用不是一个人写的这样的理由来开脱. 顺序表示的栈和队列,必须预先分配空间,并且空间大小受限,使用起来限制比较多.而且,由于限定存取位置,顺序表示的随机存取的优点就没有了,所以,链式结构应该是首选. 栈的定义和实现 #ifndef Stack_H #define Stack_H #include "List.h" tem

数据结构学习(C++)之稀疏矩阵

先说说什么叫稀疏矩阵.你说,这个问题很简单吗,那你一定不知道中国学术界的嘴皮子仗,对一个字眼的"抠"将会导致两种相反的结论.这是清华2000年的一道考研题:"表示一个有1000个顶点,1000条边的有向图的邻接矩阵有多少个矩阵元素?是否稀疏矩阵?"如果你是个喜欢研究出题者心理活动的人,你可以看出这里有两个陷阱,就是让明明会的人答错,我不想说出是什么,留给读者思考.姑且不论清华给的标准答案是什么,那年的参考书是严蔚敏的<数据结构(C语言版)>,书上对于稀疏