📜  数据结构-循环双链表(1)

📅  最后修改于: 2023-12-03 15:10:20.022000             🧑  作者: Mango

数据结构 - 循环双链表

循环双链表是一种经典的数据结构。它与普通的双链表类似,每个节点包含两个指针,一个指向前一个节点,一个指向后一个节点。不同之处在于,循环双链表中,头节点的前驱指针指向尾节点,尾节点的后继指针指向头节点。这样可以实现循环遍历。

在实际应用中,循环双链表常用于实现内存池、LRU缓存淘汰算法等高效的数据结构。

基本操作
创建循环双链表

循环双链表的创建需要先创建一个头节点,其前驱和后继指针均指向自身:

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

Node *createList() {
    Node *head = (Node *) malloc(sizeof(Node));
    head->prev = head;
    head->next = head;
    return head;
}
插入节点

插入节点可以分为在头节点之后插入、在尾节点之前插入、在任意位置插入三种情况。具体实现如下:

void insertAfter(Node *prevNode, int newData) {
    if (prevNode == NULL) {
        return;
    }

    Node *newNode = (Node *) malloc(sizeof(Node));
    newNode->data = newData;

    newNode->next = prevNode->next;
    prevNode->next->prev = newNode;

    newNode->prev = prevNode;
    prevNode->next = newNode;
}

void insertBefore(Node *nextNode, int newData) {
    if (nextNode == NULL) {
        return;
    }
    
    Node *newNode = (Node *) malloc(sizeof(Node));
    newNode->data = newData;

    newNode->prev = nextNode->prev;
    nextNode->prev->next = newNode;

    newNode->next = nextNode;
    nextNode->prev = newNode;
}

void insertAt(Node *head, int index, int newData) {
    if (head == NULL) {
        return;
    }

    Node *curNode = head->next;
    int i = 0;

    while (curNode != head && i < index) {
        curNode = curNode->next;
        i++;
    }

    if (curNode == head) {
        insertBefore(head, newData);
    } else {
        insertBefore(curNode, newData);
    }
}

其中,insertAfter()实现在prevNode节点之后插入新节点;insertBefore()实现在nextNode节点之前插入新节点;insertAt()实现在第index个节点之前插入新节点。

删除节点

删除节点可以分为三种情况:删除头节点、删除尾节点、删除任意节点。具体实现如下:

void deleteNode(Node *head, int key) {
    if (head == NULL) {
        return;
    }

    Node *curNode = head->next;

    while (curNode != head && curNode->data != key) {
        curNode = curNode->next;
    }

    if (curNode == head) {
        return;
    }

    curNode->prev->next = curNode->next;
    curNode->next->prev = curNode->prev;

    free(curNode);
}

void deleteFirst(Node *head) {
    if (head == NULL) {
        return;
    }
    
    Node *firstNode = head->next;
    head->next = firstNode->next;
    firstNode->next->prev = head;

    free(firstNode);
}

void deleteLast(Node *head) {
    if (head == NULL) {
        return;
    }
    
    Node *lastNode = head->prev;
    head->prev = lastNode->prev;
    lastNode->prev->next = head;

    free(lastNode);
}

其中,deleteNode()实现删除某个节点;deleteFirst()实现删除头节点;deleteLast()实现删除尾节点。

遍历循环双链表

遍历循环双链表可以从头节点开始遍历,一直遍历到头节点即可。具体实现如下:

void traverseList(Node *head) {
    if (head == NULL) {
        return;
    }

    Node *curNode = head->next;

    while (curNode != head) {
        printf("%d ", curNode->data);
        curNode = curNode->next;
    }

    printf("\n");
}
总结

循环双链表作为一种经典的数据结构,具有很多优秀的特性,如高效的插入和删除操作、循环遍历等。在实际应用中,循环双链表可以用来实现内存池、LRU缓存淘汰算法等高效的数据结构。