C语言数据结构双向链表之温故而知新
单向链表:http://blog.csdn.net/morixinguan/article/details/77756216
单向链表理解了,那双向就非常简单了,没什么好说的,看图:
双链表的引入是为了解决单链表的不足:
(1)双链表可以往前遍历,也可以往后遍历,具有两个方向
双链表的节点 = 有效数据 + 两个指针(分别指向前一个节点和后一个节点)
双向链表的图形结构描述:
可以用一个简单的数据结构来描述上面的这个图:
struct double_list struct double_list
{ {数据域; ep :-------> int data ;指针域(前向指针) ; struct double_list *prev ;指针域(后向指针) ; struct double_list *next ;
}; };
2、双向链表的创建
struct list *create_node(int data) ;
创建步骤(与单链表类似,就是多了一个指针):
(1)给节点申请空间:ep : struct double_list *p = malloc(sizeof(struct double_list));
(2)初始化数据域ep : p->data = data ;
(3)初始化指针域ep : p->prev = NULL ; p->next = NULL ;
3、双向链表的尾插
双向链表尾插节点的函数可以定义如下:
void double_list_tail_insert(struct double_list *header , struct double_list *new) ;
尾插图示操作:
尾插的步骤:
(1)找到链表的尾节点ep : 和单链表差不多DL *p = header ;while(NULL != p->next)p = p->next ;
(2)将新的节点连接到尾节点的后面成为新的节点1.原来的next指针指向新节点的首地址。 p->next = new ;2.新节点的prev指针指向原来的尾节点的首地址。 new->prev = p;
4、双向链表的头插
双向链表头插节点的函数可以定义如下:
void double_list_top_insert(struct double_list *header , struct double_list *new) ;
5、双向链表的遍历
5.1 正向遍历void double_list_for_each(DL *header)步骤:和单链表完全一致,没什么好写的。5.2 反向遍历void double_list_for_each_nx(DL *header)步骤:(1)和单链表一样,先循环找到最后一个节点的地址(2)再依靠prev指针循环往前移动2.1 先打印最后一个数据 ep : printf("%d ",p->data);2.2 向前循环遍历 ep : p = p->prev ;判断条件:header->prev != p->prev,header保存的是头节点的地址,header->prev保存的是头节点的prev的地址,header->next保存的是头节点的next的地址,头节点在创建的时候:header->prev = NULL ;header->next = NULL ;所以这个条件这样写header->prev = NULL也是对的。
6、双向链表节点的删除
假设需要删除节点1: 首先:(1)获取当前节点的地址: ep : p = header;(2)遍历所有的节点,找到要删除的节点:ep : while(NULL != p->next){p = p->next ;if(p->data == data){}}(3)找到要删除的数据以后,需要做判断,判断两种情况,这和单链表差不多3.1 如果找到当前节点的下一个节点不为空3.1.1 那就把当前节点的prev节点指向要删除的这个节点的prev因为当前的prev节点保存的是要删除的上一个节点的指针 p->next->prev = p->prev ;3.1.2 然后将当前节点的prev指针(也就是上一个节点的指针)指向当前节点(要删除的)的下一个节点:p->prev->next = p->next ;3.1.3 最后释放删除指针的空间:free(p);3.2 如果找到当前节点的下一个节点为空3.2.1 直接把当前指针(要删除的节点)的prev指针(保存着当前指针的上一个节点的地址)的下一个next指针设置为空。p->prev->next = NULL ;3.2.2将删除的指针的空间释放:free(p);
看来,双链表学起来比单链表容易多了!确实啊,多了一个方向,操作起来就更加容易了,但是多了一个方向,一维多了一个指针,相比增加了一定的复杂度,但是,只要牢记prev指针和next指针的指向,那么,手画一图,代码即可写出!
下面给一个案例实现一下双向链表:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
//创建一个双链表的数据结构
typedef struct __double_list
{int data ;struct __double_list *prev ;struct __double_list *next ;
}DL ; //创建双向链表并插入一个节点
DL *create_dl_node(int data)
{DL *p = malloc(sizeof(DL));if(NULL == p){printf("create dl node fair!\n");return NULL ;}//初始化数据 p->data = data ;//初始化指针 p->next = NULL ;p->prev = NULL ;
}//双向链表的尾插
void double_list_tail_insert(DL *header , DL *new)
{//取得当前节点的地址 DL *p = header ;//找到链表的尾节点 while(NULL != p->next){//找不到接着找 p = p->next ;}//找到了尾节点,指向新节点的首地址 p->next = new ;//新节点的prev指针指向原来的尾节点的首地址。new->prev = p;
}//双向链表的头插(也就是插在两个节点之间的插入方式)
void double_list_top_insert(DL *header , DL *new)
{//新节点的next指针指向原来的节点一的地址new->next = header->next ; //判断当前节点的下一个节点的地址是否为空if(NULL != header->next) header->next->prev = new ; //节点1的prev指针指向新节点的地址 header->next = new ;new->prev = header ;
}//双向链表的正向遍历
void double_list_for_each(DL *header)
{DL *p = header ;while(NULL != p->next){p = p->next ;printf("%d ",p->data);}
}//双向链表的反向遍历
void double_list_for_each_nx(DL *header)
{DL *p = header ;//先找到尾节点while(NULL != p->next){p = p->next ; } //已经找到了尾节点,向前遍历,注意,遍历到头节点之前//限制条件: != 头结点 while(NULL != p->prev){printf("%d ",p->data);p = p->prev ;}
}//双向链表节点的删除
int double_list_delete_node(DL *header , int data)
{//取得当前节点 DL *p = header;//遍历所有的节点 while(NULL != p->next){p = p->next ;//找到了对应要删除的数据了 if(p->data == data){//一样存在两种情况//(1)当前节点的下一个节点不为空if(p->next != NULL){//那就把当前节点的prev节点指向要删除的这个节点的prev//因为当前的prev节点保存的是要删除的上一个节点的指针 p->next->prev = p->prev ;//还要指定它的next节点 p->prev->next = p->next ;free(p);}//(2)当前节点的下一个节点为空 else{//把 p->prev->next = NULL ;free(p); }return 0 ;}}printf("\n没有找到对应要删除的节点,或者节点已经被删除!\n");return -1 ;
} int main(void)
{int i ;DL *header = create_dl_node(0);for(i = 0 ; i < 10 ; i++){//双向链表的尾插 //double_list_tail_insert(header,create_dl_node(i));//双向链表的头插 double_list_top_insert(header,create_dl_node(i));}//双向链表的正向遍历 printf("双向链表的正向遍历:");double_list_delete_node(header,5);double_list_for_each(header);
// double_list_delete_node(header,9);double_list_delete_node(header,5);putchar('\n');printf("双向链表的反向遍历:");double_list_for_each_nx(header);return 0 ;
}
运行结果:
C语言数据结构双向链表之温故而知新相关推荐
- 8.C语言数据结构 双向链表基本操作
前面学习了如何创建一个双向链表,本节学习有关双向链表的一些基本操作,即如何在双向链表中添加.删除.查找或更改数据元素. 本节知识基于已熟练掌握双向链表创建过程的基础上,我们继续上节所创建的双向链表来学 ...
- c语言数据结构之队列
前言 不同于栈,队列是一个先进先出的数据结构,规定数据节点从队列尾插入,从队列头取出,禁止对头尾两端以外的数据进行操作.队列可以分为顺序队列和循环队列. C语言数据结构之单链表 C语言数据结构之双向链 ...
- Go语言-数据结构与算法
go语言之专业数据结构与算法 3.golang实现数组结构 code\ArrayList\ArrayList.go package ArrayListimport ("errors" ...
- 嵌入式C语言数据结构精讲-曹国辉-专题视频课程
嵌入式C语言数据结构精讲-236人已学习 课程介绍 系统学习嵌入式开发中常用的数据结构知识,包括顺序表,链表,栈和队列. 包括理论讲解和代码实现,配套课件和源码资料齐全,代码全部采用C ...
- 使用c语言实现双向链表
使用c语言实现双向链表 最近在学习C语言,在学习中,对很多知识又有了新的认识. 我是从java开始学习编程的,现在学了一遍C以后,更坚定了我对自身学习路线的认可. C是你必须要学的一门编程语言,但绝不 ...
- c语言将一个已知头结点的单链表逆序_C语言数据结构实现链表逆序并输出
C语言数据结构实现链表逆序并输出 将一个链表逆序并输出.我用了两种方法来实现,第一种是借助了一个新的空链表:第二种是在原来链表的基础上直接实现逆序. 实例代码: 头文件: #include #incl ...
- 数据结构 — 双向链表
目录 文章目录 目录 双向链表 双向链表结点的数据结构 双向链表的操作集合 应用示例 创建双向链表 清理双向链表 查询链表结点 更新链表结点的数据 插入链表结点 删除结点 打印链表数据 双向链表 双向 ...
- 数据结构c语言版第一章答案,《c语言数据结构》第一章概论自测题答案
<<c语言数据结构>第一章概论自测题答案>由会员分享,可在线阅读,更多相关<<c语言数据结构>第一章概论自测题答案(4页珍藏版)>请在人人文库网上搜索. ...
- 一些可运行的C语言数据结构代码
网上有很多C语言数据结构代码:有的不能运行:下面是一些能运行的,和运行截图:备用一下: 1 队列 #include<stdio.h> #include<stdlib.h>#de ...
最新文章
- 代码中设置excel自定义格式为[红色]的处理方法
- 虚拟机开启mysql密码报错_Linux虚拟机下mysql 5.7安装配置方法图文教程
- 计算 1!+2!+3!+……+10!
- c++语言 xml数据绑定技术简介
- 分治回溯-分治的应用-全排列问题
- Android 增强版百分比布局库 为了适配而扩展
- 浅谈权限设计(从接口权限到数据权限)
- 大数据可视化学习总结
- selenium不定位元素直接操作键盘之Keys.CONTROL
- NIPS 2016 Tutorial:Generative Adversarial Networks学习记录
- 链接提交提示安全验证,网站辅助快排不行了吗?
- 《数据通信与网络》笔记--广域网SONET/SDH
- 会议OA项目之我的会议(会议排座送审)
- 7033: Lounge Lizards(lis)
- 【汇智学堂】-div+css布局十二(商品列表图文展示)
- 蓝牙电话协议HFP(Hands-Free Profile) 接听来电/挂断来电(HFP Accept/Reject incoming call)
- 关于RTC(实时时钟)
- 屏避小米盒子开机广告方法
- 6.2 用迹求特征多项式
- 【MEMS】【1】微机电系统与比例尺度定律(尺寸效应)