文章目录

  • 双链表的定义
  • 双链表上的操作
    • 初始化
    • 插入操作
    • 建立双链表
      • 头插法建立双链表
      • 尾插法建立双链表
    • 遍历操作
    • 求双链表的长度
    • 查找操作
      • 按值查找
      • 按位查找
    • 删除操作
    • 判空操作
  • 完整代码及实例
  • 总结

双链表的定义

 为什么引入双链表?

 单链表的结点中只有一个指向其后继的指针,使得单链表要访问某个结点的前驱结点时,只能从头开始遍历,访问后驱结点的复杂度为O(1),访问前驱结点的复杂度为O(n)。为了克服上述缺点,引入了双链表。

 双链表的结点中有两个指针prior和next,分别指向前驱结点和后继结点。

 双链表中结点类型的描述:

typedef struct DNode{int data;  //数据域struct DNode *prior,*next;  //前驱和后继指针
}DNode, *DLinkList;

双链表上的操作

初始化

 双链表与单链表一样,为了操作方便也可以加入头结点,那么初始化双链表其实就是定义一个头结点,然后将指针域置空。

//初始化
void InitList(DLinkList &L){L = (DNode *)malloc(sizeof(DLinkList));L->prior = NULL;L->next = NULL;
}

插入操作

  在双链表中p所指的结点之后插入结点*s,其指针的变化过程如下图所示:

 实现代码:

//将x插入到双链表L中*p结点的下一个结点
void Insert(DLinkList &L, DNode *p, int x){DNode *s = (DNode *)malloc(sizeof(DNode));s->data = x;s->next = p->next;  //1p->next->prior = s; //2s->prior = p;  //3p->next = s; //4
}

 当然,插入操作的语句并不只有这一种顺序,但必须保证1和2两步必须在4步之前,否则*p的后继结点的指针就会丢掉,导致插入失败。


建立双链表

头插法建立双链表

 每次在头结点的后面插入新结点。

 实现代码:

//头插法建立双链表
DLinkList HeadInsert(DLinkList &L){InitList(L); //初始化int x;cin>>x;while(x!=9999){DNode *s = (DNode *)malloc(sizeof(DNode));s->data = x;if(L->next == NULL){s->next = NULL;s->prior = L;L->next = s;}else{s->next = L->next;L->next->prior = s;s->prior = L;L->next = s;}cin>>x;}return L;
}

尾插法建立双链表

 每次在双链表的尾部插入新结点,为此,应该声明一个尾指针r并始终指向尾结点。

 实现代码:

//尾插法建立双链表
DLinkList TailInsert(DLinkList &L){InitList(L);DNode *s,*r=L;int x;cin>>x;while(x!=9999){s = (DNode *)malloc(sizeof(DNode));s->data = x;s->next = NULL;s->prior = r;r->next = s;r = s;cin>>x;}return L;
}

遍历操作

 从单链表的第一个结点开始,依次遍历输出结点的数据直到最后一个结点。

 实现代码:

//遍历操作
void PrintList(DLinkList L){DNode *p = L->next;while(p){cout<<p->data<<" ";p = p->next;}cout<<endl;
}

求双链表的长度

 从双链表的第一个结点开始,依次遍历每个结点,并计数,直到最后一个结点为止。

 实现代码:

//求双链表的长度
int Length(DLinkList L){DNode *p = L->next;int len = 0;while(p){len++;p = p->next;}return len;
}

查找操作

按值查找

 查找值x在L中的位置。与单链表的按值查找是一样的,不会用到前驱结点指针prior。

 实现代码:

//按值查找:查找x在L中的位置
DNode *LocateElem(DLinkList L, int x){DNode *p = L->next;while(p && p->data != x){p = p->next;}return p;
}

按位查找

 查找在双链表L中第 i 个位置的结点。与单链表的按位查找是一样的,不会用到前驱结点指针prior。

 实现代码:

//按位查找:查找在双链表L中第i个位置的结点
DNode *GetElem(DLinkList L, int i){int j=1;DNode *p = L->next;if(i==0)return L;if(i<1)return NULL;while(p && j<i){p = p->next;j++;}return p; //如果i大于表长,p=NULL,直接返回p即可
}

删除操作


 将双链表中的第 i 个结点删除。

 实现代码:

//删除操作:将双链表中的第i个结点删除
void Delete(DLinkList &L, int i){if(i<1 || i>Length(L)){cout<<"delete failed: index is wrong."<<endl;return;}DNode *p = GetElem(L,i-1);DNode *q = p->next;p->next = q->next; //1q->next->prior = p; //2free(q);
}

判空操作

 判断双链表是否为空。

 实现代码:

//判空操作
bool Empty(DLinkList L){if(L->next == NULL){cout<<"L is null"<<endl;return true;}else{cout<<"L is not null"<<endl;return false;}
}

完整代码及实例

 完整代码:

#include<bits/stdc++.h>
using namespace std;typedef struct DNode{int data;struct DNode *prior,*next;
}DNode, *DLinkList;//初始化
void InitList(DLinkList &L){L = (DNode *)malloc(sizeof(DLinkList));L->prior = NULL;L->next = NULL;
}//遍历操作
void PrintList(DLinkList L){DNode *p = L->next;while(p){cout<<p->data<<" ";p = p->next;}cout<<endl;
}//求双链表的长度
int Length(DLinkList L){DNode *p = L->next;int len = 0;while(p){len++;p = p->next;}return len;
}//头插法建立双链表
DLinkList HeadInsert(DLinkList &L){InitList(L); //初始化int x;cin>>x;while(x!=9999){DNode *s = (DNode *)malloc(sizeof(DNode));s->data = x;if(L->next == NULL){s->next = NULL;s->prior = L;L->next = s;}else{s->next = L->next;L->next->prior = s;s->prior = L;L->next = s;}cin>>x;}return L;
}//尾插法建立双链表
DLinkList TailInsert(DLinkList &L){InitList(L);DNode *s,*r=L;int x;cin>>x;while(x!=9999){s = (DNode *)malloc(sizeof(DNode));s->data = x;s->next = NULL;s->prior = r;r->next = s;r = s;cin>>x;}return L;
}//按值查找:查找x在L中的位置
DNode *LocateElem(DLinkList L, int x){DNode *p = L->next;while(p && p->data != x){p = p->next;}return p;
}//按位查找:查找在双链表L中第i个位置的结点
DNode *GetElem(DLinkList L, int i){int j=1;DNode *p = L->next;if(i==0)return L;if(i<1)return NULL;while(p && j<i){p = p->next;j++;}return p; //如果i大于表长,p=NULL,直接返回p即可
}//将x插入到双链表L中*p结点的下一个结点
void Insert(DLinkList &L, DNode *p, int x){DNode *s = (DNode *)malloc(sizeof(DNode));s->data = x;s->next = p->next;p->next->prior = s;s->prior = p;p->next = s;
}//删除操作:将双链表中的第i个结点删除
void Delete(DLinkList &L, int i){if(i<1 || i>Length(L)){cout<<"delete failed: index is wrong."<<endl;return;}DNode *p = GetElem(L,i-1);DNode *q = p->next;p->next = q->next;q->next->prior = p;free(q);
}//判空操作
bool Empty(DLinkList L){if(L->next == NULL){cout<<"L is null"<<endl;return true;}else{cout<<"L is not null"<<endl;return false;}
}int main(){//尾插法建立双链表,并遍历单链表DLinkList L = TailInsert(L);cout<<"L: ";PrintList(L);DNode *p;//按值查找p = LocateElem(L,2);cout<<"值为2的结点的下一个结点值是:"<<p->next->data<<endl;cout<<"值为2的结点的上一个结点值是:"<<p->prior->data<<endl;//按位查找p = GetElem(L,3);cout<<"第三个结点值是:"<<p->data<<endl;//插入操作Insert(L,p,7);cout<<"在第三个结点后面插入值为7的结点后L: ";PrintList(L);//删除操作Delete(L, 5);cout<<"删除第五个结点后L: ";PrintList(L);//求表长cout<<"表长为:"<<Length(L)<<endl;;//判空Empty(L);return 0;
}

 运行结果:


总结

 双链表与单链表在某些操作上几乎是相同的,比如按位查找,按值查找,求表长,打印链表等等,但由于双链表有指向前驱结点的指针,故双链表在初始化,建立双链表,插入操作,删除操作等函数内需要对前驱结点的指针进行修改。本文中插入和删除操作都是对结点*q的后面进行插入和删除,由于双链表有指向前驱结点的指针,故这些操作也可以转换为在某个结点前的插入删除操作等等。

双链表——双链表的定义及其基本操作(初始化、头插法尾插法建表、插入、查找、删除、判空等)相关推荐

  1. 单链表——单链表的定义及基本操作(初始化、头插法尾插法建表、查找、插入、删除、判空等)

    文章目录 单链表的定义 单链表上的操作 初始化 建立单链表 头插法建立单链表 尾插法建立单链表 遍历单链表 求单链表的长度 查找操作 按值查找 按位查找 插入操作 删除操作 判空操作 完整代码及实例 ...

  2. 二、单链表的头插法建表和尾插法建表

    链式存储结构: 用一组不一定连续的存储单元存储逻辑上相邻的元素,元素间的逻辑关系是由附加的指针域表示的,由此得到的存储结构称为链式存储结构. 单链表(线性链表) 使用链式存储结构表示每个数据元素 ai ...

  3. 单链表的头插法尾插法及删除节点操作

    带头节点的单链表的头插法尾插法及删除节点操作 链表的操作对于初学者来说理解非常有难度,初学的同学们应该在学习链表的过程中多再练习本上画图,写一行代码就画出代码执行后链表各节点图的变化,方便理解.我也是 ...

  4. 翻转链表II[翻转链表3种方式+dummyHead/头插法/尾插法]

    翻转链表 前言 一.翻转链表中间部分 二.dummyHead&头插法&尾插法 1.一次扫描 + 翻转链表(另一次扫描) 2.一次扫描&头插法&尾插法(进阶) 总结 参考 ...

  5. C语言的单链表创建:头插法/尾插法

    文章目录 前言 链表头插法 链表尾插法 源码实现 前言 接下来一段时间,将对数据结构进行复习,总的来说数据结构自大学之后忘记得有点吓人,为了防止脑容量本就小得脑袋更小,必须得持续性得温故了. 链表数据 ...

  6. C语言头插法尾插法创建单链表

    前言 链表 [Linked List]:链表是由一组不必相连[不必相连:可以连续也可以不连续]的内存结构 [节点],按特定的顺序链接在一起的抽象数据类型. 下面介绍单链表的创建: 创建节点 链表是由一 ...

  7. c语言 链表建立头插法尾插法,单链表的创建(头插法和尾插法)

    单链表的创建分为头插法和尾插法,头插法是不断地向头结点插入新的结点.这样会使你所插入的结点值呈现逆序,所以头插法也可以实现单链表的逆置.尾插法是不断地向插入的新元素之后再插入新的元素.需要注意的是头插 ...

  8. 王道代码版单链表头插法,不带头的头插法,尾插法,不带头的尾插法的总结

    在编译器上面编译发现很容易控制台打印不出来,这可能就是细节所在,但是网上也没有很全的全代码输出的案例.我做题的感觉写的是对的其实并不对,你只是第六感感觉是对的仅此而已!!!要注意引以为戒,下面总结一下 ...

  9. 单链表的基本操作----------头插法/尾插法建立链表

    头插法 步骤: 1.在内存中找开辟一个空间,作为链表的头节点,将头结点滞空. 具体代码: L = (LinkList)malloc(sizeof(ND)); L -> next = NULL; ...

最新文章

  1. lazada开店入驻最新流程,开店只需三步
  2. Boost:bimap双图的突变关系的测试程序
  3. 大大提高你的工作效率的Linux 技巧
  4. 信息发布webpart——网页编辑器应用攻略
  5. kaggle颅内出血比赛分析
  6. spring-boot的spring-cache中的扩展redis缓存的ttl和key名
  7. Nutshell中的Java 8语言功能-第1部分
  8. 装mysql最后一步没响应_解决MySQL安装到最后一步未响应的三种方法
  9. redis笔记1---基础
  10. 《Entity Framework 6 Recipes》中文翻译系列 (11) -----第三章 查询之异步查询 (转)...
  11. 熄风的止颤的汤治疗帕金森的优势
  12. 简单几步解决 svchost 占用资源过高的问题
  13. Jupyter更改默认浏览器
  14. Python win32gui.ShowWindow() 窗口没弹出来解决方法
  15. 大数据影响下的专题地图编制
  16. 论马云在中国的影响力!
  17. IE编程1(.net)——读取IE窗口信息
  18. HDU 4125 Moles 二叉排序树 树状数组 kmp
  19. VS2015官方下载地址(个人免费版)
  20. C语言实现三子棋游戏(规范化)

热门文章

  1. :-1: error: cannot open C:\Users\???\AppData\Local\Temp\main.obj.5136.0.jom for write
  2. Pytorch_Geometric(PyG)使用DataLoader报错RuntimeError: Sizes of tensors must match except in dimension 0.
  3. IBinder转换为BpBinder
  4. 运维前线:一线运维专家的运维方法、技巧与实践3.4 小结
  5. 树莓派无源蜂鸣器c语言,[Python]使用树莓派+无源蜂鸣器播放
  6. 很文艺,很小资 —— 初级华语音乐装逼指南【转载自豆瓣九点】
  7. 如何清理虚拟机缓存文件
  8. 计算机英语短文,计算机英语短文
  9. matlab在通信中的应用实验指导书 课后答案,《MATLAB及Simulink应用》实验指导书+答案...
  10. 一个产品需求的研发流程是怎样的?