带头节点 (非头指针) 双向链表 (doubly linked list)
带头节点 (非头指针) 双向链表 (doubly linked list)
线性表是一种线性结构,它具有相同类型的 n(n≥0)n \ (n ≥ 0)n (n≥0) 个数据元素组成的有限序列。线性表:数组、单向链表、双向链表。
doubly (bidirectional) linked list:双向链表
1. 单向链表 (singly linked list)
单向链表是一种使用指针来存储值的数据结构。链表中的每个节点包含一个字段,用于指向链表的下一个节点。另外有一个独立的根指针指向链表的第 1 个节点。由于节点在创建时是采用动态分配内存的方式,所以它们可能分布于内存之中。遍历链表是根据指针进行的,所以节点的物理排列无关紧要。单向链表只能以一个方向进行遍历。
为了把一个新值插入到一个有序的单链表中,你首先必须找到链表中合适的插入位置。对于无序单链表,新值可以插入到任何位置。把一个新节点链接到链表中需要两个步骤。首先,新节点的 link
字段必须设置为指向它的目标后续节点。其次,前一个节点的 link
字段必须设置为指向这个新节点。在许多其他语言中,插入函数保存一个指向前一个节点的指针来完成第 2 个步骤。但是,这个技巧使插入到链表的起始位置成为一种特殊情况,需要单独处理。在 C 语言中,你可以通过保存一个指向必须进行修改的 link
字段的指针,而不是保存一个指向前一个节点的指针,从而消除了这个特殊情况。
2. 双向链表 (doubly linked list)
双向链表中的每个节点包含两个 link
字段:其中一个指向链表的下一个节点,另一个指向链表的前一个节点。双向链表可以设置两个根指针,分别指向第 1 个节点和最后一个节点。因此,遍历双向链表可以从任何一端开始,而且在遍历过程中可以改变方向。为了把一个新节点插入到双向链表中,我们必须修改 4 个指针。新节点的前向和后向 link
字段必须被设置,前一个节点的后向 link
字段和后一个节点的前向 link
字段也必须进行修改,使它们指向这个新节点。
将类的声明和实现分离,在头文件 (.h 文件或 .hpp) 中尽量只包含声明,而在实现文件 (.cpp 文件) 中负责实现!C++ 编译器不支持对模板的分离式编译。
3. 带头节点 (非头指针) 双向链表 (doubly linked list)
3.1 insert_first - delete_node - display
//============================================================================
// Name : doubly linked list
// Author : Yongqiang Cheng
// Version : Version 1.0.0
// Copyright : Copyright (c) 2019 Yongqiang Cheng
// Description : Hello World in C++, Ansi-style
//============================================================================#ifndef _CRT_SECURE_NO_WARNINGS
#define _CRT_SECURE_NO_WARNINGS
#endif#define MAX_NODE_LEN 401#include <stdio.h>typedef struct NODE {int data;struct NODE *prev;struct NODE *next;
} Node;Node node_array[MAX_NODE_LEN];
int node_array_idx = 0;void insert_first(Node *head, Node *node)
{node->next = head->next;node->prev = head;// if (head->next != nullptr)if (node->next != nullptr){node->next->prev = node;}head->next = node;
}void delete_node(const Node *node)
{Node *prev_node = node->prev;Node *next_node = node->next;// current node - nodeprev_node->next = next_node;// if (node->next != nullptr)if (next_node != nullptr){next_node->prev = prev_node;}
}void display(const Node *head)
{int n = 1;Node *node = head->next;while (node != nullptr){printf("node %d: %d\n", n, node->data);++n;node = node->next;}
}int main()
{// 头节点 (非头指针)Node root;// initializationroot.prev = nullptr;root.next = nullptr;root.data = 0;for (int i = 0; i < MAX_NODE_LEN; ++i){node_array[i].prev = nullptr;node_array[i].next = nullptr;node_array[i].data = 0;}// insert 0node_array[0].data = 0;insert_first(&root, &(node_array[0]));// insert 2node_array[2].data = 2;insert_first(&root, &(node_array[2]));// insert 4node_array[4].data = 4;insert_first(&root, &(node_array[4]));// insert 6node_array[6].data = 6;insert_first(&root, &(node_array[6]));// insert 8node_array[8].data = 8;insert_first(&root, &(node_array[8]));display(&root);// delete 4delete_node(&(node_array[4]));printf("\ndelete data %d\n", 4);display(&root);// delete 0delete_node(&(node_array[0]));printf("\ndelete data %d\n", 0);display(&root);// delete 8delete_node(&(node_array[8]));printf("\ndelete data %d\n", 8);display(&root);// insert 10node_array[10].data = 10;insert_first(&root, &(node_array[10]));printf("\ninsert data %d\n", 10);display(&root);return 0;
}
node 1: 8
node 2: 6
node 3: 4
node 4: 2
node 5: 0delete data 4
node 1: 8
node 2: 6
node 3: 2
node 4: 0delete data 0
node 1: 8
node 2: 6
node 3: 2delete data 8
node 1: 6
node 2: 2insert data 10
node 1: 10
node 2: 6
node 3: 2
请按任意键继续. . .
3.2 insert_first - delete_node - display - traverse function
//============================================================================
// Name : doubly linked list
// Author : Yongqiang Cheng
// Version : Version 1.0.0
// Copyright : Copyright (c) 2019 Yongqiang Cheng
// Description : Hello World in C++, Ansi-style
//============================================================================#ifndef _CRT_SECURE_NO_WARNINGS
#define _CRT_SECURE_NO_WARNINGS
#endif#define MAX_NODE_LEN 401
#define NULL 0#include <stdio.h>typedef struct NODE {int data;struct NODE *prev;struct NODE *next;
} Node;Node node_array[MAX_NODE_LEN];
int node_array_idx = 0;void insert_first(Node *head, Node *node)
{node->next = head->next;node->prev = head;// if (head->next != NULL)if (node->next != NULL){node->next->prev = node;}head->next = node;
}void delete_node(const Node *node)
{Node *prev_node = node->prev;Node *next_node = node->next;// current node - nodeprev_node->next = next_node;// if (node->next != NULL)if (next_node != NULL){next_node->prev = prev_node;}
}void display(const Node *head)
{int n = 1;Node *node = head->next;while (node != NULL){printf("node %d: %d\n", n, node->data);++n;node = node->next;}
}int main()
{// 头节点 (非头指针)Node root;// initializationroot.prev = NULL;root.next = NULL;root.data = 0;for (int i = 0; i < MAX_NODE_LEN; ++i){node_array[i].prev = NULL;node_array[i].next = NULL;node_array[i].data = 0;}// insert 0node_array[0].data = 0;insert_first(&root, &(node_array[0]));// insert 2node_array[2].data = 2;insert_first(&root, &(node_array[2]));// insert 4node_array[4].data = 4;insert_first(&root, &(node_array[4]));// insert 6node_array[6].data = 6;insert_first(&root, &(node_array[6]));// insert 8node_array[8].data = 8;insert_first(&root, &(node_array[8]));display(&root);// delete 4delete_node(&(node_array[4]));printf("\ndelete data %d\n", 4);display(&root);// delete 0delete_node(&(node_array[0]));printf("\ndelete data %d\n", 0);display(&root);// delete 8delete_node(&(node_array[8]));printf("\ndelete data %d\n", 8);display(&root);// insert 10node_array[10].data = 10;insert_first(&root, &(node_array[10]));printf("\ninsert data %d\n", 10);display(&root);/********************************* traverse function *********************************/Node *head = &root;Node *ptr_node = head->next;Node *tmp_node;while (ptr_node != NULL){tmp_node = ptr_node->next;if (2 == ptr_node->data) {delete_node(ptr_node);}ptr_node = tmp_node;}/********************************* traverse function *********************************/printf("\ndelete data %d\n", 2);display(&root);return 0;
}
node 1: 8
node 2: 6
node 3: 4
node 4: 2
node 5: 0delete data 4
node 1: 8
node 2: 6
node 3: 2
node 4: 0delete data 0
node 1: 8
node 2: 6
node 3: 2delete data 8
node 1: 6
node 2: 2insert data 10
node 1: 10
node 2: 6
node 3: 2delete data 2
node 1: 10
node 2: 6
请按任意键继续. . .
3.3 insert_first - delete_node - display - traverse function
//============================================================================
// Name : doubly linked list
// Author : Yongqiang Cheng
// Version : Version 1.0.0
// Copyright : Copyright (c) 2019 Yongqiang Cheng
// Description : Hello World in C++, Ansi-style
//============================================================================#ifndef _CRT_SECURE_NO_WARNINGS
#define _CRT_SECURE_NO_WARNINGS
#endif#define MAX_NODE_LEN 401
#define NULL 0#include <stdio.h>typedef struct NODE {int data;struct NODE *prev;struct NODE *next;
} Node;Node node_array[MAX_NODE_LEN];
int node_array_idx = 0;void insert_first(Node *head, Node *node)
{node->next = head->next;node->prev = head;// if (head->next != NULL)if (node->next != NULL){node->next->prev = node;}head->next = node;
}void delete_node(const Node *node)
{Node *prev_node = node->prev;Node *next_node = node->next;// current node - nodeprev_node->next = next_node;// if (node->next != NULL)if (next_node != NULL){next_node->prev = prev_node;}
}void delete_node_v1(const Node *node)
{// current node - nodenode->prev->next = node->next;// if (node->next != NULL)if (node->next != NULL){node->next->prev = node->prev;}
}void display(const Node *head)
{int n = 1;Node *node = head->next;while (node != NULL){printf("node %d: %d\n", n, node->data);++n;node = node->next;}
}int main()
{// 头节点 (非头指针)Node root;// initializationroot.prev = NULL;root.next = NULL;root.data = 0;for (int i = 0; i < MAX_NODE_LEN; ++i){node_array[i].prev = NULL;node_array[i].next = NULL;node_array[i].data = 0;}// insert 0node_array[0].data = 0;insert_first(&root, &(node_array[0]));// insert 2node_array[2].data = 2;insert_first(&root, &(node_array[2]));// insert 4node_array[4].data = 4;insert_first(&root, &(node_array[4]));// insert 6node_array[6].data = 6;insert_first(&root, &(node_array[6]));// insert 8node_array[8].data = 8;insert_first(&root, &(node_array[8]));display(&root);// delete 4delete_node_v1(&(node_array[4]));printf("\ndelete data %d\n", 4);display(&root);// delete 0delete_node_v1(&(node_array[0]));printf("\ndelete data %d\n", 0);display(&root);// delete 8delete_node_v1(&(node_array[8]));printf("\ndelete data %d\n", 8);display(&root);// insert 10node_array[10].data = 10;insert_first(&root, &(node_array[10]));printf("\ninsert data %d\n", 10);display(&root);/********************************* traverse function *********************************/Node *head = &root;Node *ptr_node = head->next;Node *tmp_node;while (ptr_node != NULL){tmp_node = ptr_node->next;if (2 == ptr_node->data) {delete_node_v1(ptr_node);}ptr_node = tmp_node;}/********************************* traverse function *********************************/printf("\ndelete data %d\n", 2);display(&root);return 0;
}
node 1: 8
node 2: 6
node 3: 4
node 4: 2
node 5: 0delete data 4
node 1: 8
node 2: 6
node 3: 2
node 4: 0delete data 0
node 1: 8
node 2: 6
node 3: 2delete data 8
node 1: 6
node 2: 2insert data 10
node 1: 10
node 2: 6
node 3: 2delete data 2
node 1: 10
node 2: 6
请按任意键继续. . .
References
https://www.thecrazyprogrammer.com/2015/09/doubly-linked-list-in-c-and-cpp.html
https://www.alphacodingskills.com/ds/doubly-linked-list.php
带头节点 (非头指针) 双向链表 (doubly linked list)相关推荐
- 双向链表(Doubly Linked List)
双向链表(Doubly Linked List) 1. 双向链表的概念 1.1 双向链表的定义 双向链表又称为双链表,是链表的一种. 1.2 双向链表的结点结构 双向链表的结点包括三个部分:前驱指针域 ...
- C语言实现双向链表Doubly Linked List(附完整源码)
双向链表Doubly Linked List list结构体 实现以下6个接口 双向链表Doubly Linked List完整源码(定义,实现,main函数测试) list结构体 typedef s ...
- 【头结点】【头指针】【首元结点】
2022 -1-14 文章目录 2022 -1-14 1. 定义: 2. 哨兵(头结点) 3. 有无头结点的单链表的创建 3.1 有头结点 3.1.1 头插法: 3.1.2 尾插法: 3.2 无头结点 ...
- c语言链表不带头节点的排序,不带头结点的单向链表排序——插入排序(C语言)...
LinkList* LinkListInsertSort(LinkList* pHead) { LinkList *pFirst = (LinkList *)NULL; /* 原链表剩下未排序节点的头 ...
- 软考题目之头结点、头指针和首元节点
遇到一个让人迷惑的题目. 以下关于线性表采用链式存储时删除节点运算的描述,正确的是() A.带头结点的线性链表删除结点时,不需要更改头指针. B.带头结点的线性链表删除第一个结点时,需要更改头指针. ...
- 带头结点单链表、不带头结点单链表(头指针单链表)
1.头结点和头指针的区别 1.1区别: 头指针表明了链表的结点,可以唯一确定一个单链表. 头指针指向链表的第一个结点,其记录第一个存储数据的结点的地址. 头结点是点链表的第一个结点,若单链表有头结点, ...
- 怎么样让指针指向尾结点C语言,带头结点头指针与带头结点尾指针的学习
单循环链表 对于单链表而言,如果每次在遍历到单链表中间处时需要遍历整个链表,此时只能往后遍历,前方的指针便会丢失.如图1所示,此时若链表遍历到a2处依旧可以通过尾结点循环到a1处,这是单链表所不能解决 ...
- C++Doubly Linked List双向链表(附完整源码)
C++AVL树自平衡二叉查找树 node结构体定义 实现了以下几个接口 Doubly Linked List双向链表算法的完整源码(定义,实现,main函数测试) node结构体定义 struct n ...
- C++之链表中头指针、头节点、首元结点的
头指针:顾名思义是一个指针,指向链表的开始地址: 头结点:第一个节点,该节点只有地址信息,改地址指向下一个结点,数据域无信息: 首元结点:含第一个元素的结点,为链表的实际开始位置,数据域包含第一个数据 ...
- 头指针为head的带头结点的单链表判空条件head->next==null?
由于考研需求,又乖乖滚回来捧起数据结构了,一年没碰书,忘得都差不多了,还得捡回来,哭死了. 进入正题,为何头指针为head的带头结点的单链表判空条件head->next==null?其实一开始这 ...
最新文章
- Oracle 树操作(select…start with…connect by…prior)
- python 3d大数据可视化软件_十大顶级大数据可视化工具推荐
- centos 6.5网卡dhcp不能获得网关
- Python数据可视化之Excel气泡图
- Real-Time Rendering 3 彩图
- Linux 命令(65)—— ld 命令
- php 判断是否是机器人,如何用PHP检测搜索引擎机器人?
- CheckedListBoxControl 实现复选框的单选与多选功能
- Centos7配置ThinkPHP5.0完整过程(二)
- HDU 2054 大数比较
- 1.1.2 Greedy Gift Givers 贪婪的送礼者
- 使用mergeAssets对Android的assets文件在构建的时候进行修改处理
- 一个学计算机的打字速度慢,电脑打字速度慢怎么办
- 大觉山漂流,男人的欢笑女人的尖叫
- DS线性表—多项式相加
- 4、如果体彩中了500万,我买房、买车、资助希望工程、去欧洲旅游;如果没中,我买下一期体彩,继续烧高香。
- warnings模块
- RxJava操作符学习APP
- HTML常用标签、文本格式化标签:加粗、倾斜、删除线、下划线等
- CSS3选择器-属性选择器
热门文章
- 一个算法面试题的5种不同解法
- asp、php、asp.net、jsp介绍及优缺点比较
- asp.net 视频教程
- crt图形显示装置_CRT消防控制室图形显示装置图形显示装置_使用说明书_V1.0.doc...
- 【安全知识分享】重磅|消防控制室培训.ppt(附下载)
- python cryptography key加密_python加密解密库cryptography使用openSSL生成的密匙加密解密...
- Cisco(思科)远程登录交换机
- 思科里服务器的dns配置文件,cisco设置dns
- UE5实现HTC Vive VR功能
- 基于PHP的华为手机商城系统(完整前后台)