作者名:Demo不是emo 

主页面链接:主页传送门
创作初心:对于计算机的学习者来说,初期的学习无疑是最迷茫和难以坚持的,中后期主要是经验和能力的提高,我也刚接触计算机1年,也在不断的探索,在CSDN写博客主要是为了分享自己的学习历程,学习方法,总结的经验等等,希望能帮助到大家
座右铭:不要让时代的悲哀成为你的悲哀
专研方向:网络安全,数据结构

每日emo:想念的心很浓,想说的话很多

目录

双链表的理解

双链表数据节点和头结点的定义

双链表的创建

双链表数据节点的插入

双链表数据节点的删除


双链表的理解

·一般学习双链表都是在学习单链表之后(本文需要一定单链表基础),但单链表有一个缺点,就是无法访问前驱节点,需要查找某个已知节点的前一个节点时能再次从头遍历,就比较麻烦,那么,在节点中再加一个指针指向前驱节点的链表就称为双链表,再综合单链表的节点写法,那么双链表的写法就很简单了。数据节点包含一个数据域,两个指针(一个指向前驱节点,一个指向后驱节点)。大致图解如下:

而因为多了一个前指针,所以数据节点的插入,删除等操作相对于单链表来说更难一点,但理解透了其实差不多,这里都不给出具体图解了,我们直接进入正文。

双链表数据节点和头结点的定义

双链表的数据节点定义只需要在定义单链表数据节点的基础上加一个前驱指针,这里我们还是定义一个头结点结构体来保存双链表的信息,另一个结构体充当数据节点

typedef struct header//头结点保存双链表信息
{int length;//记录双链表当前大小struct node* next;//指向第一个数据节点
}head;
typedef struct node//数据节点
{int val;//数据域struct node* pre;//指向前一个数据节点(与单链表最大的区别)struct node* next;//指向下一个数据节点}node;

如上,一个最基础的双链表头结点和数据节点就定义好了,下面就可以对双链表进行操作啦。

双链表的创建

和单链表的创建一样,双链表的创建同样只需要创建好头结点就可以了,链表每储存一个元素就分配一个内存单元构建数据节点 ,所以双链表的创建也相对简单,具体代码如下:

head* listcreat()//创建双链表
{head* p;p=(head*)malloc(sizeof(head));//给头结点分配空间p->length=0;//初始化双链表p->next=NULL;//双链表的最后指向NULL即可return p;//返回创建好的头结点地址
}

双链表数据节点的插入

学习双链表在我看来比较难的便是双链表数据节点的插入,主要是不好想, 所以建议大家可以在本子上画一下,具体代码如下(本文都是用封装函数的形式写的,文章末尾有完整代码):

void listinsert(head* p,int pos,int x)//头结点地址,要插入的位置,要插入的元素
{node* temp;//temp即我们要插入的数据节点temp=(node*)malloc(sizeof(node));//为其分配空间temp->val=x;//填充数据域if(p==NULL||pos<0||pos>p->length)//判断插入失败的情况{printf("listinsert():error\n");return;}if(p->length==0)//判断双链表为空的情况{p->next=temp;//头结点的的next指针指向temptemp->next=NULL;//temp的next指针指向NULL(保证最后一个数据节点的next指向空)temp->pre=NULL;temp的pre指针指向NULL(保证第一个数据节点的pre指向空)p->length++;//不要忘记记录双链表的大小return;//完成插入}node* pcur=p->next;//定义一个指向第一个数据节点的指针;if(pos==0)//插在头结点和第一个数据节点之间(即头插)的情况{p->next=temp;//头结点的next指针指向temptemp->pre=NULL;//temp此时为第一个数据节点所以前指针pre指向空temp->next=pcur;//pcur为上文记录的插入前的第一个数据节点pcur->pre=temp;//作为第二个数据节点的前指针pre指向第一个数据节点tempp->length++;return;}for(int i=1;i<pos;i++){pcur=pcur->next;}//此时pcur指向要插入的位置的前一个数据节点,例如将2插入到1,3中间,那pcur就指向1.if(pos==p->length)//尾插的情况{pcur->next=temp;temp->next=NULL;temp->pre=pcur;}else//既不是头插,也不是尾插(可能比较难理解,建议画个草图){temp->next=pcur->next;pcur->next->pre=temp;temp->pre=pcur;pcur->next=temp;}p->length++;return;
}

双链表数据节点的删除

双链表的数据节点插入弄明白之后数据节点的删除就简单的多啦,直接附上代码:

void listdelete(head* p,int x)//头结点地址,要删除的元素
{node* temp=p->next;//定义一个指向第一个数据节点的指针while(temp->val!=x&&temp!=NULL)//遍历链表寻找要删除的数据节点{temp=temp->next;}if(temp->val!=x)//链表中没有找到要删除的数据节点{printf("listdelete():error");return;//退出程序}node* pRe=temp->pre;//指向要删除的元素的前一个数据节点node* pnext=temp->next;//指向要删除的元素的后一个节点if(pRe==NULL)//即要删除的数据节点是第一个数据节点的情况{p->next=pnext;//头结点的next指针直接指向第二个数据节点pnext->pre=NULL;//第二个数据节点变成第一个数据节点}else if(pnext==NULL)//要删除的数据节点是最后一个的情况{pRe->next=NULL;}else//要删除的数据节点不是第一个也不是最后一个{pRe->next=pnext;pnext->pre=pRe;}free(temp);p->length--;return;
}

双链表的数据节点插入我们也完成了,为了方便使用,我们也可以写一个遍历打印(即输出)双链表的函数,具体代码如下:

void print(head* p)
{if(p==NULL){printf("listprint():error\n");return;}node* temp=p->next;while(temp!=NULL){printf("%d ",temp->val);temp=temp->next;}printf("\n");return;
}

好了,双链表的各个操作差不多就弄明白了,完整的代码如下:

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
typedef struct header
{int length;struct node* next;
}head;
typedef struct node
{int val;struct node* pre;struct node* next;}node;
head* listcreat()//创建双链表
{head* p;p=(head*)malloc(sizeof(head));p->length=0;p->next=NULL;return p;
}
void listinsert(head* p,int pos,int x)//单链表数据节点的插入
{node* temp;temp=(node*)malloc(sizeof(node));node* pcur=p->next;//定义一个指向第一个数据节点的指针;temp->val=x;if(p==NULL||pos<0||pos>p->length){printf("listinsert():error\n");return;}if(p->length==0){p->next=temp;temp->next=NULL;temp->pre=NULL;p->length++;return;}if(pos==0){p->next=temp;temp->pre=NULL;temp->next=pcur;pcur->pre=temp;p->length++;return;}for(int i=1;i<pos;i++)//使pcur指向要插入的位置{pcur=pcur->next;}if(pos==p->length){pcur->next=temp;temp->next=NULL;temp->pre=pcur;}else{temp->next=pcur->next;pcur->next->pre=temp;temp->pre=pcur;pcur->next=temp;}p->length++;return;
}
void listdelete(head* p,int x)
{node* temp=p->next;while(temp->val!=x&&temp!=NULL){temp=temp->next;}if(temp->val!=x){printf("listdelete():error");return;}node* pRe=temp->pre;node* pnext=temp->next;if(pRe==NULL){p->next=pnext;pnext->pre=NULL;}else if(pnext==NULL){pRe->next=NULL;}else{pRe->next=pnext;pnext->pre=pRe;}free(temp);p->length--;return;
}
void print(head* p)
{if(p==NULL){printf("listprint():error\n");return;}node* temp=p->next;while(temp!=NULL){printf("%d ",temp->val);temp=temp->next;}printf("\n");return;
}
int main()
{int number;head* p=listcreat();printf("请输入双链表数据节点初始个数\n");scanf("%d",&number);printf("请依次输入初始数据\n");int a[number];for(int i=0;i<number;i++){scanf("%d",&a[i]);}for(int i=number-1;i>=0;i--){listinsert(p,0,a[i]);}printf("输出初始链表\n");print(p);printf("请输入插入的位置和元素\n");int m,n;scanf("%d%d",&m,&n);listinsert(p,m,n);printf("输出插入后的链表\n");print(p);printf("请输入要删除的元素\n");int del;scanf("%d",&del);listdelete(p,del);printf("输出删除后的元素\n");print(p);return 0;
}

随便写点代码运行一下就是下面这个效果啦 (因为双链表和单链表的差别其实不大,而我也写过一篇单链表的博客,所以感觉没什么写的了,有什么遗漏的希望大家见谅)

请输入双链表数据节点初始个数
6
请依次输入初始数据
1 2 3 4 5 6
输出初始链表
1 2 3 4 5 6
请输入插入的位置和元素
6 7
输出插入后的链表
1 2 3 4 5 6 7
请输入要删除的元素
7
输出删除后的元素
1 2 3 4 5 6

注:本文需要一定单链表基础,想了解单链表的也可以看看我的前一篇博客,点此链接可以直接进入: C语言数据结构篇——单链表的创建,插入,节点删除和打印等操作_Grande joie的博客-CSDN博客

C语言数据结构篇——双链表的创建,插入,节点删除,打印等操作相关推荐

  1. C语言数据结构篇——单循环链表的创建,插入,节点删除,打印等操作

     作者名:Demo不是emo  主页面链接:主页传送门 创作初心:对于计算机的学习者来说,初期的学习无疑是最迷茫和难以坚持的,中后期主要是经验和能力的提高,我也刚接触计算机1年,也在不断的探索,在CS ...

  2. 数据结构——双链表(C语言详述通用双链表)

    说明:   本文章旨在总结备份.方便以后查询,由于是个人总结,如有不对,欢迎指正:另外,内容大部分来自网络.书籍.和各类手册,如若侵权请告知,马上删帖致歉.   QQ 群 号:513683159 [相 ...

  3. R语言数据可视化 ggplot2基础2 创建单图层的散点图 创建facet

    R语言数据可视化 ggplot2基础2 创建单图层的散点图 创建facet 单图层散点图 单图层散点图的facet 单图层散点图 这一讲我们从最简单的散点图开始介绍ggplot2应用的基础,首先我们下 ...

  4. 双链表的创建,求长,插入,删除,打印,释放(循环和非循环)

    链接地址:http://blog.csdn.net/stpeace/article/details/8112462 #include<iostream>using namespace st ...

  5. 数据结构--双链表的创建和操作

    http://www.cnblogs.com/jingliming/p/4602144.html#0-tsina-1-42616-397232819ff9a47a7b7e80a40613cfe1 一. ...

  6. 双链表的基本操作---插入,删除,交,并,相邻元素的交换,不相邻元素的交换...

    这个链表是带有表头的双链表.实现链表的一些规范操作,初始化,插入,删除等.包括两个头文件list.h,fatal.h,库函数list.c,测试函数testlist.c.头文件放的都是函数声明,库函数l ...

  7. C语言双链表遍历,插入,删除

    #include<stdio.h> #include<stdlib.h> #include <string.h> #define bzero(a, b) memse ...

  8. c语言用链表对学生成绩排序,学生成绩排序和平均分计算利用c语言链表的创建插入删除.doc...

    #define NULL 0 #define LEN sizeof(struct student) struct student { long num; float score; struct stu ...

  9. c语言数据结构篇之栈(线性栈与链式栈)

    线性栈 1.判空条件:S.top==-1; 2.满栈条件:S.top=maxn-1 #include<cstdio> #include<stdlib.h>#define max ...

最新文章

  1. 2.innodb后台线程
  2. 2020年球云计算市值或将达4490亿欧元
  3. php渲染页面简单例子,微信小程序如何渲染html内容(示例讲解)
  4. 涂鸦智能 dubbo-go 亿级流量的实践与探索
  5. CVPR 2021 | 从理论和实验角度深入剖析对比损失中的温度超参数
  6. C++类中不能定义自身类类型成员变量
  7. 数据可视化机器学习工具在线_为什么您不能跳过学习数据可视化
  8. 与计算机相关的课外活动,课外活动学生论文,关于应用型院校计算机专业课外活动相关参考文献资料-免费论文范文...
  9. 吴恩达深度学习1.3练习_Neural Networks and Deep Learning
  10. 09年关门歇业的15大网站 雅虎旗下4网站上榜
  11. 阶段1 语言基础+高级_1-3-Java语言高级_05-异常与多线程_第6节 Lambda表达式_5_Lambda表达式的无参数无返回值的...
  12. Atitti 存储引擎支持的国内点与特性attilax总结
  13. 做JSP大学实用教程实验
  14. 疑难杂症篇(一)--安装Visio与已安装的office冲突的解决方案
  15. CANape编程语言CASL之Script的创建与调用
  16. Android设备运用Clockworkmod Recovery恢复模式安装定制的Rom
  17. Google谷歌关键词监控系统
  18. matlab两矩阵乘除,MATLAB矩阵乘法
  19. 伪装学渣未删减部分_慎重勇者:破坏神和圣哉做了什么?第9话战帝被删减剧情补充...
  20. 硬盘分区-增加C盘容量教程

热门文章

  1. 车船税业务知识学习--北京(五)
  2. 判断三个老师教哪门课命题c语言,语文教学论复习资料
  3. 游戏本连oracle,新平台游戏本接连到来,怎么选择合适的硬件配置?
  4. MIT-BIH的影响(译)
  5. 什么是次世代?次世代游戏制作工作流程
  6. 骨传导耳机发声原理是什么,如何选购骨传导耳机
  7. Java语言制作吃豆人游戏
  8. OneNote 2003 中文版 完整 单独安装程序 下载
  9. JMX超详细解读(转)
  10. 阿里云计算巢加速企业软件云化,助力企业业务创新