C语言之双链表理解与应用

  其实网上也有好多关于双链表理解,知乎上同样有写的很好文章。这里主要看双链表概念,应用场景,举例。

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;  
}

  • 24
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

十启树

您的认可是我最大的动力!

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值