如何用C语言实现双向链表和双向循环链表

发布时间:2022-10-20 14:32:22 作者:iii
来源:亿速云 阅读:210

如何用C语言实现双向链表和双向循环链表

引言

链表是一种常见的数据结构,它通过节点之间的指针连接来存储数据。与数组不同,链表的大小可以动态调整,插入和删除操作也更加高效。双向链表和双向循环链表是链表的两种常见变体,它们在许多应用中都有广泛的使用。本文将详细介绍如何使用C语言实现这两种链表。

双向链表

1. 双向链表的定义

双向链表(Doubly Linked List)是一种链表,其中每个节点包含两个指针:一个指向下一个节点,另一个指向前一个节点。这种结构使得双向链表可以从两个方向遍历。

2. 双向链表的节点结构

在C语言中,双向链表的节点可以定义如下:

struct Node {
    int data;           // 数据域
    struct Node* prev;  // 指向前一个节点的指针
    struct Node* next;  // 指向下一个节点的指针
};

3. 双向链表的基本操作

3.1 创建节点

struct Node* createNode(int data) {
    struct Node* newNode = (struct Node*)malloc(sizeof(struct Node));
    newNode->data = data;
    newNode->prev = NULL;
    newNode->next = NULL;
    return newNode;
}

3.2 插入节点

在双向链表中插入节点有多种方式,例如在头部插入、在尾部插入或在某个节点后插入。

3.2.1 在头部插入
void insertAtHead(struct Node** head, int data) {
    struct Node* newNode = createNode(data);
    if (*head == NULL) {
        *head = newNode;
    } else {
        newNode->next = *head;
        (*head)->prev = newNode;
        *head = newNode;
    }
}
3.2.2 在尾部插入
void insertAtTail(struct Node** head, int data) {
    struct Node* newNode = createNode(data);
    if (*head == NULL) {
        *head = newNode;
    } else {
        struct Node* temp = *head;
        while (temp->next != NULL) {
            temp = temp->next;
        }
        temp->next = newNode;
        newNode->prev = temp;
    }
}
3.2.3 在某个节点后插入
void insertAfter(struct Node* prevNode, int data) {
    if (prevNode == NULL) {
        printf("Previous node cannot be NULL\n");
        return;
    }
    struct Node* newNode = createNode(data);
    newNode->next = prevNode->next;
    if (prevNode->next != NULL) {
        prevNode->next->prev = newNode;
    }
    prevNode->next = newNode;
    newNode->prev = prevNode;
}

3.3 删除节点

删除节点也有多种方式,例如删除头部节点、删除尾部节点或删除某个特定节点。

3.3.1 删除头部节点
void deleteAtHead(struct Node** head) {
    if (*head == NULL) {
        printf("List is empty\n");
        return;
    }
    struct Node* temp = *head;
    *head = (*head)->next;
    if (*head != NULL) {
        (*head)->prev = NULL;
    }
    free(temp);
}
3.3.2 删除尾部节点
void deleteAtTail(struct Node** head) {
    if (*head == NULL) {
        printf("List is empty\n");
        return;
    }
    struct Node* temp = *head;
    while (temp->next != NULL) {
        temp = temp->next;
    }
    if (temp->prev != NULL) {
        temp->prev->next = NULL;
    } else {
        *head = NULL;
    }
    free(temp);
}
3.3.3 删除某个特定节点
void deleteNode(struct Node** head, struct Node* delNode) {
    if (*head == NULL || delNode == NULL) {
        printf("List or node is empty\n");
        return;
    }
    if (*head == delNode) {
        *head = delNode->next;
    }
    if (delNode->next != NULL) {
        delNode->next->prev = delNode->prev;
    }
    if (delNode->prev != NULL) {
        delNode->prev->next = delNode->next;
    }
    free(delNode);
}

3.4 遍历链表

双向链表可以从两个方向遍历:从头到尾或从尾到头。

3.4.1 从头到尾遍历
void traverseForward(struct Node* head) {
    struct Node* temp = head;
    while (temp != NULL) {
        printf("%d -> ", temp->data);
        temp = temp->next;
    }
    printf("NULL\n");
}
3.4.2 从尾到头遍历
void traverseBackward(struct Node* tail) {
    struct Node* temp = tail;
    while (temp != NULL) {
        printf("%d -> ", temp->data);
        temp = temp->prev;
    }
    printf("NULL\n");
}

双向循环链表

1. 双向循环链表的定义

双向循环链表(Doubly Circular Linked List)是双向链表的一种变体,其中最后一个节点的next指针指向第一个节点,第一个节点的prev指针指向最后一个节点,形成一个循环。

2. 双向循环链表的节点结构

双向循环链表的节点结构与双向链表相同:

struct Node {
    int data;
    struct Node* prev;
    struct Node* next;
};

3. 双向循环链表的基本操作

3.1 创建节点

与双向链表相同。

3.2 插入节点

在双向循环链表中插入节点时,需要注意循环的特性。

3.2.1 在头部插入
void insertAtHeadCircular(struct Node** head, int data) {
    struct Node* newNode = createNode(data);
    if (*head == NULL) {
        newNode->next = newNode;
        newNode->prev = newNode;
        *head = newNode;
    } else {
        newNode->next = *head;
        newNode->prev = (*head)->prev;
        (*head)->prev->next = newNode;
        (*head)->prev = newNode;
        *head = newNode;
    }
}
3.2.2 在尾部插入
void insertAtTailCircular(struct Node** head, int data) {
    struct Node* newNode = createNode(data);
    if (*head == NULL) {
        newNode->next = newNode;
        newNode->prev = newNode;
        *head = newNode;
    } else {
        newNode->next = *head;
        newNode->prev = (*head)->prev;
        (*head)->prev->next = newNode;
        (*head)->prev = newNode;
    }
}
3.2.3 在某个节点后插入
void insertAfterCircular(struct Node* prevNode, int data) {
    if (prevNode == NULL) {
        printf("Previous node cannot be NULL\n");
        return;
    }
    struct Node* newNode = createNode(data);
    newNode->next = prevNode->next;
    newNode->prev = prevNode;
    prevNode->next->prev = newNode;
    prevNode->next = newNode;
}

3.3 删除节点

在双向循环链表中删除节点时,同样需要注意循环的特性。

3.3.1 删除头部节点
void deleteAtHeadCircular(struct Node** head) {
    if (*head == NULL) {
        printf("List is empty\n");
        return;
    }
    if ((*head)->next == *head) {
        free(*head);
        *head = NULL;
    } else {
        struct Node* temp = *head;
        (*head)->prev->next = (*head)->next;
        (*head)->next->prev = (*head)->prev;
        *head = (*head)->next;
        free(temp);
    }
}
3.3.2 删除尾部节点
void deleteAtTailCircular(struct Node** head) {
    if (*head == NULL) {
        printf("List is empty\n");
        return;
    }
    if ((*head)->next == *head) {
        free(*head);
        *head = NULL;
    } else {
        struct Node* temp = (*head)->prev;
        temp->prev->next = *head;
        (*head)->prev = temp->prev;
        free(temp);
    }
}
3.3.3 删除某个特定节点
void deleteNodeCircular(struct Node** head, struct Node* delNode) {
    if (*head == NULL || delNode == NULL) {
        printf("List or node is empty\n");
        return;
    }
    if (*head == delNode) {
        deleteAtHeadCircular(head);
    } else {
        delNode->prev->next = delNode->next;
        delNode->next->prev = delNode->prev;
        free(delNode);
    }
}

3.4 遍历链表

双向循环链表的遍历与双向链表类似,但由于是循环的,遍历时需要特别注意终止条件。

3.4.1 从头到尾遍历
void traverseForwardCircular(struct Node* head) {
    if (head == NULL) {
        printf("List is empty\n");
        return;
    }
    struct Node* temp = head;
    do {
        printf("%d -> ", temp->data);
        temp = temp->next;
    } while (temp != head);
    printf("HEAD\n");
}
3.4.2 从尾到头遍历
void traverseBackwardCircular(struct Node* head) {
    if (head == NULL) {
        printf("List is empty\n");
        return;
    }
    struct Node* temp = head->prev;
    do {
        printf("%d -> ", temp->data);
        temp = temp->prev;
    } while (temp != head->prev);
    printf("TL\n");
}

总结

本文详细介绍了如何使用C语言实现双向链表和双向循环链表。通过定义节点结构、实现插入、删除和遍历等基本操作,我们可以灵活地使用这两种链表来解决实际问题。双向链表和双向循环链表在许多应用中都有广泛的使用,例如实现LRU缓存、浏览器历史记录等。希望本文能帮助你更好地理解和应用这两种数据结构。

推荐阅读:
  1. C语言实现双向链表(DoublyLinkedList)
  2. JavaScript数据结构之双向链表和双向循环链表的示例分析

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

c语言

上一篇:如何用C语言代码实现文件复制

下一篇:C语言变量类型怎么使用

相关阅读

您好,登录后才能下订单哦!

密码登录
登录注册
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》