双链表是一种链式存储结构,它的每个节点不仅包含数据和指向下一个节点的指针(next),还包含指向前一个节点的指针(prior)。这使得双链表可以从两个方向遍历,即向前和向后。以下是双链表的一些特点:
双链表节点结构:
每个节点(DNode)通常包含以下部分:
data:存储节点的数据。
prior:指向前一个节点的指针。
next:指向下一个节点的指针。
以下代码能运行的包括有:
1、初始化双链表: InitDLinklist
函数用于初始化一个带头节点的空双链表。它通过动态内存分配创建头节点,并将头节点的prior
和next
指针都设置为NULL
。
2、双链表的插入: InsertNextDNode
函数在给定节点p
之后插入一个新节点s
。这个函数首先检查参数是否合法,然后将新节点s
插入到节点p
之后,并更新相关节点的指针。
3、双链表的删除: DeleteNextDNode
函数删除节点p
的后继节点。如果节点p
或其后续节点不存在,则返回失败。否则,它会找到节点p
的后继节点q
,并将其从链表中移除,同时更新指针并释放被删除节点的内存。
4、销毁双链表: DestoryList
函数释放双链表占用的所有内存。它通过循环调用DeleteNextDNode
来删除链表中的所有节点,最后释放头节点并将头指针设置为NULL
。
优点:
双向遍历:由于每个节点都有指向前一个节点的指针,可以很方便地向前遍历。
高效删除:删除操作不需要像单链表那样从头开始遍历,可以直接通过前驱节点的指针进行删除。
缺点:
内存消耗:每个节点需要额外的存储空间来存储指向前一个节点的指针。
实现复杂度:相对于单链表,双链表的操作实现更复杂。
应用场景:
双链表常用于需要频繁进行插入和删除操作的场景,尤其是在需要从两个方向遍历链表的情况。
在提供的代码中,双链表被初始化,并向其中插入了几个节点。之后,代码遍历双链表并打印每个节点的数据,最后销毁整个双链表并释放内存。这是双链表在实践中的基本用法。
#include<stdio.h>
#include<stdlib.h>
typedef struct DNode{
int data;
struct DNode *prior, *next;
}DNode, *DLinklist;
// 初始化双链表
bool InitDLinklist(DLinklist &L){
L = (DNode *)malloc(sizeof(DNode)); // 分配一个节点
if(L == NULL){ // 内存不足,分配失败
return false;
}
L->prior = NULL; // 头节点的prior永远指向NULL
L->next = NULL; // 头节点之后暂时还没有节点
return true;
}
// 双链表的插入:在p节点之后插入s节点
bool InsertNextDNode(DNode *p, DNode *s){
if(p == NULL || s == NULL) // 非法参数
return false;
s->next = p->next; // 将节点*s插入到节点*p之后
if(p->next != NULL){ // 如果p节点有后续节点
p->next->prior = s;
}
s->prior = p;
p->next = s;
return true;
}
// 双链表的删除:删除p节点的后继节点
bool DeleteNextDNode(DNode *p) {
if(p == NULL || p->next == NULL)
return false;
DNode *q = p->next; // 找到p的后续节点q
p->next = q->next;
if(q->next != NULL) // q节点是不是最后一个节点
q->next->prior = p;
free(q);
return true; // 释放节点空间
}
// 双链表的删除
void DestoryList(DLinklist &L) {
DNode *p = L->next; // 从第一个数据节点开始
while(p != NULL) { // 循环释放各个数据节点
DNode *q = p->next; // 保存下一个节点的地址
free(p); // 释放当前节点
p = q; // 移动到下一个节点
}
free(L); // 释放头节点
L = NULL; // 头指针指向NULL
}
int main() {
DLinklist L;
if (!InitDLinklist(L)) {
printf("初始化双链表失败!\n");
return -1;
}
// 插入节点
for (int i = 1; i <= 5; i++) {
DNode *newNode = (DNode *)malloc(sizeof(DNode));
if (newNode == NULL) {
printf("内存分配失败!\n");
DestoryList(L); // 释放已分配的内存
return -1;
}
newNode->data = i;
if (!InsertNextDNode(L, newNode)) { // 在头节点后插入新节点
printf("插入节点失败!\n");
free(newNode); // 释放新节点内存
DestoryList(L); // 释放链表内存
return -1;
}
}
// 遍历打印节点
DNode *p = L->next; // 跳过头节点
while (p != NULL) {
printf("节点数据:%d\n", p->data);
p = p->next;
}
// 销毁双链表
DestoryList(L);
printf("双链表已销毁。\n");
return 0;
}