3.2 双向链表

1.简介

前面3.1的单链表在操作过程中有一个缺点,就是后面的节点无法直接找到前面的节点,这使很多操作都得从头到尾去搜寻节点,算法效率变得非常低,解决这个问题的方法就是重新定义链表的节点使每个节点有两个指针,一个指向前驱一个指向后驱,这就是双向链表。

节点定义

  1. template<class T>
  2. class DLLNode {
  3. public:
  4. DLLNode() {
  5. next = prev = 0;
  6. }
  7. DLLNode(const T& el, DLLNode<T> *n = 0, DLLNode<T> *p = 0) {
  8. info = el; next = n; prev = p;
  9. }
  10. T info;
  11. DLLNode<T> *next, *prev;
  12. };

3.1节中所定义方法的局限性是链表只能存储整数. 如果希望链表存储浮点数点数或者数组.就必须重新写一套类似的代码。然而,更好的做法是只对这样的类声明一次,并且不提前确定其中存储什么数据类型,在 C++中,用模板就能很方便地做到这一点 。 为了说明模板在链表处理中的用法, 从本节开始使用模版来定义链表,但链表操作的示例仍然采用存储整数的链表。

2.双向链表的操作

DoublyLinkedList类定义了双向链表的操作

  1. template<class T>
  2. class DoublyLinkedList {
  3. public:
  4. DoublyLinkedList() {
  5. head = tail = 0;
  6. }
  7. void addToDLLTail(const T&);//插入节点到双向链表结尾
  8. T deleteFromDLLTail();//删除末尾的节点并返回其值
  9. ~DoublyLinkedList() {
  10. clear();
  11. }
  12. bool isEmpty() const {
  13. return head == 0;
  14. }
  15. void clear();
  16. void setToNull() {
  17. head = tail = 0;
  18. }
  19. void addToDLLHead(const T&);
  20. T deleteFromDLLHead();
  21. T& firstEl();
  22. T* find(const T&) const;
  23. protected:
  24. DLLNode<T> *head, *tail;
  25. friend ostream& operator<<(ostream& out, const DoublyLinkedList<T>& dll) {
  26. for (DLLNode<T> *tmp = dll.head; tmp != 0; tmp = tmp->next)
  27. out << tmp->info << ‘ ‘;
  28. return out;
  29. }
  30. };

这里只讨论两种操作方法:插入节点到双向链表结尾和删除末尾的节点,其余操作方法读者可以自行参考代码。

(1)插入节点到双向链表结尾

具体分为下面几个步骤:

  • 创建一个新的节点并初始化三个数据成员(info初始化为el,next初始化为null)
  • 将prev的值设置为tail
  • 将tail指向新加入的节点
  • 前驱节点的next指向新加入的节点
  1. template<class T>
  2. void DoublyLinkedList<T>::addToDLLTail(const T& el) {
  3. if (tail != 0) {
  4. tail = new DLLNode<T>(el,0,tail);
  5. tail->prev->next = tail;
  6. }
  7. else head = tail = new DLLNode<T>(el);
  8. }

(2)删除末尾的节点

双向链表删除一个末尾节点比较简单,因为不需要通过循环来查找待删除节点的前驱节点,将tail指向待删除节点的前驱,

然后将待删除节点的next设置为null。但是如果待操作的链表是空链表可能会引起程序崩溃,因此使用者在删除末尾节点之前要先检查链表是否为空,检查链表是否为空,代码中也提供了。

  1. if (!list.isEmpty())
  2. n = list.deleteFromDLLTail();
  3. else do not delete;

另一种特殊情况是链表只有一个节点,要将head和tail设置为空。

因为可以直接访问最后一个节点,因此这两个方法执行的时间复杂度为O(1)。

完整代码见:http://www.oschina.net/code/snippet_588162_48663

来自为知笔记(Wiz)

附件列表

时间: 2024-12-29 23:29:11

3.2 双向链表的相关文章

数据结构第四篇——线性表的链式存储之双向链表

?注:未经博主同意,不得转载. 前面讨论的单链表,每个结点中只有一个指针域,用来存放指向后继结点的指针,因此,从某个结点出发只能顺时针往后查找其他结点.若要查找某个结点的直接前驱,则需要从头指针开始沿链表探寻,处理起来十分不方便.为克服单链表的这一缺点,可引入双向链表. 双向链表中每一个结点含有两个指针域,一个指针指向其直接前驱结点,另一个指针指向直接后继结点.和单链表类似,双向链表一般也只有头指针唯一确定:同样也可设头结点,使得双向链表的某些操作简便一些. 双向链表结构定义如下:  双向链表是

双向链表(一)

参考: http://blog.sina.com.cn/s/blog_7d44748b01013fsf.html    (写的太好啦) http://blog.163.com/haibianfeng_yr/blog/static/34572620201453061036702/ 双(向)链表中有两条方向不同的链,即每个结点中除next域存放后继结点地址外,还增加一个指向其直接前趋的指针域prior.双向链表在查找时更方便 特别是大量数据的遍历 注意:    ①双链表由头指针head惟一确定的. 

c语言双向链表

typedef int ElemType; typedef struct _Node { ElemType value; struct _Node* pnext; struct _Node* prev; }node, *pNode; //创建双向链表 pNode Create_Double_List(int count) { pNode pn = NULL; pNode pb = NULL; pNode phead = (pNode)malloc(sizeof(node)); printf("请

C++__双向链表(练习)

双向链表 link.h #ifndef LINK_H_ #define LINK_H_ #define HEADER 0 #define TAIL -1 typedef int data_type; enum LINK_OP { LINK_ERR = -1, LINK_OK }; class LINK { private: data_type data; LINK *next; LINK *last; public: LINK(); LINK(data_type data); virtual ~

剑指offer:二叉搜索树与双向链表

1.题目描述: 输入一棵二叉搜索树,将该二叉搜索树转换成一个排序的双向链表.要求不能创建任何新的结点,只能调整树中结点指针的指向. 2.解题思路: (1)将左子树构造成双向链表,并返回链表头节点: (2)定位左子树双链表的尾节点: (3)如果左子树链表不为空,将当前root连缀其链尾: (4)将右子树构造出双向链表,并返回链表头节点: (5)如果右子树链表不为空,将当前root连缀其表头: (6)根据左子树链表是否为空,确定返回的节点. 3.JavaScript实现: function Conv

Uva 12657 Boxes in a Line 双向链表

操作4比较特殊,为了避免一次性修改所有元素的指针,由于题目只要求输出奇数盒子的编号,所以我们可以灵活的根据是否进行过操作4对操作1 操作2 进行改动 操作3不受操作4影响 上代码.... #include<cstdio> #include<algorithm> const int maxn=100000+5; int right[maxn],left[maxn]; void link (int L,int R){ right[L]=R;left[R]=L; } //在双向链表这样复

双向链表 Boxes in a Line UVA - 12657

首先记录一下对链表的理解,最初看链表是在教材上看的,上面是用结构体, 理解起来还不是很困难,我也以为自己懂了,然而看到紫书上链表用的是数组(UVA11988),真的是..到最后把他的代码背下来了都还是有点晕(/(ㄒoㄒ)/~~),那个时候做题有点匆忙,也就没深究,不过后面那道(也就是这道)也就没再写了,差不多隔了一个月吧,有那么一点点感觉就是这次没看代码自己写过一遍后. 单向每一个结构体有两个元素(或者更多),其中一个是下一个元素的地址,其他的是他本身有的东西,在这道题中,1 2 3 4 5,

Shuffling Machine和双向链表

1. 双向链表 https://github.com/BodhiXing/Data_Structure 2. Shuffling Machine https://pta.patest.cn/pta/test/17/exam/4/question/264 思路: 代码: 1 #include <iostream> 2 using namespace std; 3 4 #define MAXCARD 54 5 6 string int2str(int x) 7 { 8 char ch[4]; 9

二叉搜索树与双向链表

void convertNode(BSTreeNode *root, BSTreeNode ** pLastNodeInList) { if(!root) return ; if(root->left) { convertNode(root->left, pLastNodeInList); } root->left = *pLastNodeInList; if(*pLastNodeInList != NULL) (*pLastNodeInList)->right = root; *

数据结构 线性双向链表

//线性双向链表 #ifndef _MY_DLINKLIST_H_ #define _MY_DLINKLIST_H_ typedef void DLinkList; typedef struct _tag_DLinkListNode { struct _tag_DLinkListNode* next; struct _tag_DLinkListNode * pre; }DLinkListNode; //创建双向链表 DLinkList* DLinkList_Create(); //销毁双向链表