说明:数组提供了连续内存空间的访问和使用,而链表是对内存零碎空间的有效组织和使用。链表又分为单向链表和双向链表,单向链表仅提供了链表的单方向访问,相比之下,双向链表则显得十分方便。

一.单向链表的节点

如下代码所示,双向链表的节点包含两个指向关系和一个数据空间,两个指向分别连接该节点的上一个和下一个节点,数据类型可以是一个结构体类型,也可以是其他类型。

  1 typedef struct node
2 {
3 int data;
4 struct node *pre;
5 struct node *next;
6 }Node;

二.双向链表的创建

头插法和尾插法只看代码比较难以与理解,建议画出插入节点时的链表变化图则会非常容易理解,另外,个人认为头插法较优,因为其插入逻辑一步到位,不像尾插法还需在后面完成双向链表的环状连接。

1.头插法

  1 Node * creatList()
2 {
3 Node * head = (Node*)malloc(sizeof(Node));
4 Node * cur = NULL;
5 head->next = head;
6 head->pre = head;
7 int data;
8 scanf("%d",&data);
9 while(data)
10 {
11 cur = (Node*)malloc(sizeof(Node));
12 cur->data = data;
13 cur->next = head->next;
14 cur->pre = head;
15 head->next = cur;
16 cur->next->pre = cur;
17 scanf("%d",&data);
18 }
19 return head;
20 }

2.尾插法

  1 Node * creatList()
2 {
3 Node * head = (Node*)malloc(sizeof(Node));
4 Node * phead = head;
5 Node * cur = NULL;
6 phead->next = NULL;
7 phead->pre = NULL;
8 int data;
9 scanf("%d",&data);
10 while(data)
11 {
12 cur = (Node*)malloc(sizeof(Node));
13 cur->data = data;
14 phead->next = cur;
15 cur->pre = phead;
16 phead = cur;
17 scanf("%d",&data);
18 }
19 //完成回环
20 cur->next = head;
21 head->pre = cur;
22 return head;
23 }

三.双向链表的元素插入(头插法)

插入方法:先让插入的节点有所指向,再考虑指向它的指针,具体插入如下:

  1 void insertList(Node * head)
2 {
3 printf("intsert new node:");
4 int data;
5 scanf("%d",&data);
6 Node * cur;
7 cur = (Node*)malloc(sizeof(Node));
8 cur->data = data;
9 cur->next = head->next;
10 cur->pre = head;
11 head->next = cur;
12 cur->next->pre = cur;
13 }

四.双向链表的查找

既然是双向链表,其查找方式也应该是是双向查找,比起单向链表的单向查找,双向查找同时从两个方向进行查找,加快了查找的速度。

  1 Node * searchList(Node * head,int find)
2 {
3 Node * pClock = head->next;
4 Node * pAntiClock = head->pre;
5 while (pAntiClock != pClock->pre)
6 {
7 if(pClock->data == find)
8 return pClock;
9 if(pAntiClock->data == find)
10 return pAntiClock;
11 if(pClock == pAntiClock)
12 return NULL;
13 pClock = pClock->next;
14 pAntiClock = pAntiClock->pre;
15 }
16 return NULL;
17 }

五.删除某个节点

  1 void deleteList(Node * pfind)
2 {
3 if(pfind == NULL)
4 return;
5 else
6 {
7 pfind->pre->next = pfind->next;
8 pfind->next->pre = pfind->pre;
9 free(pfind);
10 }
11 }

六.链表排序(按值排序)

  1 void sortList(Node * head,int n)
2 {
3 Node * p,*q;
4 for(int i=0; i<n-1; i++)
5 {
6 p = head->next;
7 q = p->next;
8 for(int j=0; j<n-1-i; j++)
9 {
10 if(p->data > q->data)
11 {
12 p->data = p->data ^ q->data;
13 q->data = p->data ^ q->data;
14 p->data = p->data ^ q->data;
15 }
16 p = p->next;
17 q = q->next;
18 }
19 }
20 }

七.链表的销毁

  1 void destroyList(Node * head)
2 {
3 head->pre->next = NULL;
4 Node * pre = head;
5 while(head != NULL)
6 {
7 head = head->next;
8 free(pre);
9 pre = head;
10 }
11 }

说明:链表的操作还有如求长度、打印以及交换指针排序等,由于相对较为简单,此处就不再例举。重要提醒:链表的某些操作较难理解,最好画图加以辅助理解。

(C/C++学习)18.C语言双向链表的更多相关文章

  1. GO学习-(18) Go语言基础之并发

    Go语言基础之并发 并发是编程里面一个非常重要的概念,Go语言在语言层面天生支持并发,这也是Go语言流行的一个很重要的原因. Go语言中的并发编程 并发与并行 并发:同一时间段内执行多个任务(你在用微 ...

  2. c语言学习书籍推荐《C语言学习路线图•C语言必须知道的300个问题》下载

    下载地址:点我 <C语言学习路线图•C语言必须知道的300个问题>以基础知识为框架,介绍了c语言各部分知识所对应的常见开发疑难问题,并作了透彻地解析.<C语言学习路线图•C语言必须知 ...

  3. GO学习-(19) Go语言基础之网络编程

    Go语言基础之网络编程 现在我们几乎每天都在使用互联网,我们前面已经学习了如何编写Go语言程序,但是如何才能让我们的程序通过网络互相通信呢?本章我们就一起来学习下Go语言中的网络编程. 关于网络编程其 ...

  4. 值得学习的C语言开源项目

    值得学习的C语言开源项目   - 1. Webbench Webbench是一个在linux下使用的非常简单的网站压测工具.它使用fork()模拟多个客户端同时访问我们设定的URL,测试网站在压力下工 ...

  5. [java学习笔记]java语言核心----面向对象之this关键字

    一.this关键字 体现:当成员变量和函数的局部变量重名时,可以使用this关键字来区别:在构造函数中调用其它构造函数 原理:         代表的是当前对象.         this就是所在函数 ...

  6. [java学习笔记]java语言核心----面向对象之构造函数

    1.构造函数概念 特点: 函数名与类名相同 不用定义返回值类型 没有具体的返回值 作用:                给对象进行初始化 注意: 默认构造函数 多个构造函数是以重载出现的 一个类中如果 ...

  7. Java学习笔记:语言基础

    Java学习笔记:语言基础 2014-1-31   最近开始学习Java,目的倒不在于想深入的掌握Java开发,而是想了解Java的基本语法,可以阅读Java源代码,从而拓展一些知识面.同时为学习An ...

  8. IOS学习笔记07---C语言函数-printf函数

    IOS学习笔记07---C语言函数-printf函数 0 7.C语言5-printf函数 ------------------------- ----------------------------- ...

  9. IOS学习笔记06---C语言函数

    IOS学习笔记06---C语言函数 --------------------------------------------  qq交流群:创梦技术交流群:251572072              ...

随机推荐

  1. 怎样处理Gradle中的这个文件下载慢的问题的

    如图:在build.gradle中的dependencies中加上要依赖的包后,就点击sync gradle.然后就开始了下载.在此过程中我是FQ了的(在此同时我是可以用chrome进入https:/ ...

  2. eclipse导出签名apk的混淆设置

    1.设置project.properties文件: 2.设置proguard-project.txt文件:

  3. 自定义Notification实现例子

    1.自定义view: <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:a ...

  4. 第十四周 Leetcode 315. Count of Smaller Numbers After Self(HARD) 主席树

    Leetcode315 题意很简单,给定一个序列,求每一个数的右边有多少小于它的数. O(n^2)的算法是显而易见的. 用普通的线段树可以优化到O(nlogn) 我们可以直接套用主席树的模板. 主席树 ...

  5. bzoj2594 [Wc2006]水管局长数据加强版——LCT

    题目:https://www.lydsy.com/JudgeOnline/problem.php?id=2594 时间倒序一下,就是 魔法森林 那道题: 有个不解的地方,是 access 里面关于 p ...

  6. TI BLE: Advertisement

    #define GAPROLE_ADVERT_ENABLED 0x305 //!< Enable/Disable Advertising. Read/Write. Size is uint8. ...

  7. unable to unroll loop 报错

    unable to unroll loop, loop does not appear to terminate in a timely manner (1024 iterations) 原本代码 f ...

  8. bzoj 2878: [Noi2012]迷失游乐园【树上期望dp+基环树】

    参考:https://blog.csdn.net/shiyukun1998/article/details/44684947 先看对于树的情况 设d[u]为点u向儿子走的期望长度和,du[u]为u点的 ...

  9. bzoj 1635: [Usaco2007 Jan]Tallest Cow 最高的牛【差分】

    s[i]为差分后的"i这头牛前有几头比它高",计算答案的时候加成前缀和,假设第一头最高减一下即可 用map记录一下被加过的区间,避免重复 #include<iostream& ...

  10. 10.27night清北刷题班

    /* 枚举每个部分的总和,利用前缀和进行检验. 如果能分成4部分就一定能分成2部分,就筛了一边素数优化.清空数组!!! */ #include<bits/stdc++.h> #define ...