??其实网上也有好多关于双链表理解,知乎上同样有写的很好文章。这里主要看双链表概念,应用场景,举例。
1,双链表概念
????????双链表是一种更复杂的线性数据结构,它由一系列节点组成,每个节点包含数据元素和两个链接,这两个链接分别指向前一个节点和下一个节点。
????????双链表的主要优点是它可以从两个方向进行遍历,这使得在双链表中的插入和删除操作更加高效。与单链表相比,双链表在插入和删除节点时不需要遍历整个链表,因此时间复杂度更低。
????????在双链表中,每个节点包含一个数据元素和两个链接。前驱链接指向当前节点的上一个节点,后继链接指向当前节点的下一个节点。这种结构使得我们可以从任何节点开始向前或向后遍历整个链表。
????????在创建新的双链表节点时,我们需要为前驱和后继链接分配内存并初始化它们。同时,我们还需要为数据域分配内存并存储数据元素。
????????双链表的主要操作包括初始化、打印、尾插、尾删、头插、头删、任意插入、任意删除、查找、更改等。这些基本操作与单链表类似,但双链表具有更高的灵活性和效率。
????????总的来说,双链表是一种非常有用的数据结构,它可以在需要双向遍历或在链表中间进行插入和删除操作的场合中使用。
双链表的基本操作包括以下几种:
(1)、创建链表:初始化一个空的双链表。
(2)、插入节点:在链表的头部、尾部或中间插入新的节点。
(3)、删除节点:从链表中删除指定的节点。
(4)、查找节点:在链表中查找特定的节点。
(5)、打印链表:遍历链表并打印出每个节点的数据。
(6)、清空链表:删除链表中的所有节点。
这些基本操作在双链表的操作中非常常见,可以用于创建、修改和查看双链表。
2,双链表适合哪些场景
双链表适合用于以下场景:
(1)、需要频繁在链表中间插入或删除节点的场合。双链表相比于单链表,可以更快地找到某个节点的前驱节点和后继节点,因此在插入和删除节点时效率更高。
(2)、需要从两个方向遍历链表的场合。双链表的每个节点都保存了前驱节点和后继节点的指针,因此可以从任何一个节点开始向前或向后遍历整个链表。
总的来说,双链表提供了更高的灵活性和效率,尤其是在需要双向遍历或在链表中间进行插入和删除操作的场合。
3,双链表操作的例子,包括插入节点、删除节点和打印链表的操作:
#include <stdio.h>
#include <stdlib.h>
// 定义双链表节点
struct Node {
int data;
struct Node* prev;
struct Node* next;
};
// 在链表头部插入新节点
void insertAtHead(struct Node** head, int data) {
struct Node* newNode = (struct Node*)malloc(sizeof(struct Node));
newNode->data = data;
newNode->prev = NULL;
newNode->next = *head;
if (*head != NULL) {
(*head)->prev = newNode;
}
*head = newNode;
}
// 在链表尾部插入新节点
void insertAtTail(struct Node** head, int data) {
struct Node* newNode = (struct Node*)malloc(sizeof(struct Node));
newNode->data = data;
newNode->prev = NULL;
newNode->next = NULL;
if (*head == NULL) {
*head = newNode;
return;
}
struct Node* current = *head;
while (current->next != NULL) {
current = current->next;
}
current->next = newNode;
newNode->prev = current;
}
// 删除指定节点
void deleteNode(struct Node** head, int data) {
if (*head == NULL) {
return;
}
if ((*head)->data == data) {
*head = (*head)->next;
if (*head != NULL) {
(*head)->prev = NULL;
}
free((*head)->prev);
return;
}
struct Node* current = *head;
while (current->next != NULL && current->next->data != data) {
current = current->next;
}
if (current->next != NULL) {
current->next = current->next->next;
if (current->next != NULL) {
current->next->prev = current;
} else {
current->prev->next = NULL;
}
free(current->next);
}
}
// 打印链表
void printList(struct Node* head) {
struct Node* current = head;
while (current != NULL) {
printf("%d ", current->data);
current = current->next;
}
printf("\n");
}
// 主函数
int main() {
struct Node* head = NULL; // 初始化链表头为空
insertAtHead(&head, 1); // 在链表头部插入节点1,此时链表为 1 -> NULL
insertAtTail(&head, 2); // 在链表尾部插入节点2,此时链表为 1 -> 2 -> NULL
insertAtTail(&head, 3); // 在链表尾部插入节点3,此时链表为 1 -> 2 -> 3 -> NULL
insertAtHead(&head, 0); // 在链表头部插入节点0,此时链表为 0 -> 1 -> 2 -> 3 -> NULL
deleteNode(&head, 2); // 删除节点2,此时链表为 0 -> 1 -> 3 -> NULL,注意删除后需要更新节点的prev指针。
printList(head); // 打印链表:0 1 3,注意打印时需要遍历整个链表。
return 0;
}