单向链表: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语言数据结构双向链表之温故而知新相关推荐

  1. 8.C语言数据结构 双向链表基本操作

    前面学习了如何创建一个双向链表,本节学习有关双向链表的一些基本操作,即如何在双向链表中添加.删除.查找或更改数据元素. 本节知识基于已熟练掌握双向链表创建过程的基础上,我们继续上节所创建的双向链表来学 ...

  2. c语言数据结构之队列

    前言 不同于栈,队列是一个先进先出的数据结构,规定数据节点从队列尾插入,从队列头取出,禁止对头尾两端以外的数据进行操作.队列可以分为顺序队列和循环队列. C语言数据结构之单链表 C语言数据结构之双向链 ...

  3. Go语言-数据结构与算法

    go语言之专业数据结构与算法 3.golang实现数组结构 code\ArrayList\ArrayList.go package ArrayListimport ("errors" ...

  4. 嵌入式C语言数据结构精讲-曹国辉-专题视频课程

    嵌入式C语言数据结构精讲-236人已学习 课程介绍         系统学习嵌入式开发中常用的数据结构知识,包括顺序表,链表,栈和队列. 包括理论讲解和代码实现,配套课件和源码资料齐全,代码全部采用C ...

  5. 使用c语言实现双向链表

    使用c语言实现双向链表 最近在学习C语言,在学习中,对很多知识又有了新的认识. 我是从java开始学习编程的,现在学了一遍C以后,更坚定了我对自身学习路线的认可. C是你必须要学的一门编程语言,但绝不 ...

  6. c语言将一个已知头结点的单链表逆序_C语言数据结构实现链表逆序并输出

    C语言数据结构实现链表逆序并输出 将一个链表逆序并输出.我用了两种方法来实现,第一种是借助了一个新的空链表:第二种是在原来链表的基础上直接实现逆序. 实例代码: 头文件: #include #incl ...

  7. 数据结构 — 双向链表

    目录 文章目录 目录 双向链表 双向链表结点的数据结构 双向链表的操作集合 应用示例 创建双向链表 清理双向链表 查询链表结点 更新链表结点的数据 插入链表结点 删除结点 打印链表数据 双向链表 双向 ...

  8. 数据结构c语言版第一章答案,《c语言数据结构》第一章概论自测题答案

    <<c语言数据结构>第一章概论自测题答案>由会员分享,可在线阅读,更多相关<<c语言数据结构>第一章概论自测题答案(4页珍藏版)>请在人人文库网上搜索. ...

  9. 一些可运行的C语言数据结构代码

    网上有很多C语言数据结构代码:有的不能运行:下面是一些能运行的,和运行截图:备用一下: 1 队列 #include<stdio.h> #include<stdlib.h>#de ...

最新文章

  1. 代码中设置excel自定义格式为[红色]的处理方法
  2. 虚拟机开启mysql密码报错_Linux虚拟机下mysql 5.7安装配置方法图文教程
  3. 计算 1!+2!+3!+……+10!
  4. c++语言 xml数据绑定技术简介
  5. 分治回溯-分治的应用-全排列问题
  6. Android 增强版百分比布局库 为了适配而扩展
  7. 浅谈权限设计(从接口权限到数据权限)
  8. 大数据可视化学习总结
  9. selenium不定位元素直接操作键盘之Keys.CONTROL
  10. NIPS 2016 Tutorial:Generative Adversarial Networks学习记录
  11. 链接提交提示安全验证,网站辅助快排不行了吗?
  12. 《数据通信与网络》笔记--广域网SONET/SDH
  13. 会议OA项目之我的会议(会议排座送审)
  14. 7033: Lounge Lizards(lis)
  15. 【汇智学堂】-div+css布局十二(商品列表图文展示)
  16. 蓝牙电话协议HFP(Hands-Free Profile) 接听来电/挂断来电(HFP Accept/Reject incoming call)
  17. 关于RTC(实时时钟)
  18. 屏避小米盒子开机广告方法
  19. 6.2 用迹求特征多项式
  20. 【MEMS】【1】微机电系统与比例尺度定律(尺寸效应)

热门文章

  1. merge卷积和bn层的原理
  2. xshell 5连接NAT模式的虚拟机
  3. [MetalKit]7-Using-MetalKit-part-6使用MetalKit6
  4. android 设备标识
  5. visual studio emmet使用
  6. 强制MySQL查询走索引和强制查询不缓存
  7. IOS 中的XML解析
  8. ospf v3 及WIN XP ipv6
  9. fscache 调研
  10. R1Soft——先进的数据保护系统