阅读本文前, 请先阅读以下一篇文章.

数据结构 – 单链表 – ()

一. 带头双向循环链表各种接口的完结

数据结构 - 带头双向循环链表

typedef int LTDataType;
typedef struct ListNode
{
    LTDataType data;    // 数据域
    struct ListNode* prev;    // 指向前驱节点的指针
    struct ListNode* next;    // 指向后继节点的指针域
}LTNode;

1. 动态请求一个节点

使用 malloc 函数在堆区上动态拓荒一个节点, data 赋值为 x , prev 指针置空, next 指针置空.

数据结构 - 带头双向循环链表

LTNode* BuyListNode(LTDataType x)
{
    LTNode* newnode = (LTNode*)malloc(sizeof(LTNode));
    if (newnode == NULL) {
        perror("malloc fail");
        return NULL;
    }
    newnode->prev = NULL;
    newnode->next = NULL;
    newnode->data = x;
    return newnode;
}

2. 初始化

初始化一个带头双向循环链表, 创造出虚拟头节点 phead, 其 prev 指针指向本身, 其 next 指针也指向本身.

数据结构 - 带头双向循环链表

LTNode* LTInit()
{
    LTNode* phead = BuyListNode(0);    // 创造出虚拟头节点 phead
    phead->prev = phead;    // prev 指针指向本身
    phead->next = phead;    // next 指针指向本身
    return phead;
}

3. 销毁

从第一个节点开端逐一销毁链表中的每个节点, 最后销毁虚拟头节点, 然后完结对链表的销毁.

void LTDestroy(LTNode* phead)
{
    assert(phead);
    LTNode* curr = phead->next;
    while (curr != phead) {
        LTNode* curr = phead->next;
        free(curr);
        curr = curr->next;
    }
    free(phead);
}

4. 打印

逐一打印链表中的数据.

void LTPrint(LTNode* phead)
{
    assert(phead);
    printf("<=head=>");
    LTNode* curr = phead->next;
    while (curr != phead) {
        printf("%d<=>", curr->data);
        curr = curr->next;
    }
    printf("\n");
}

5. 判空

判断链表是否为空(虚拟头节点的 next 指针 或 prev 指针指向本身链表即为空).

bool LTEmpty(LTNode* phead)
{
    assert(phead);
    return phead->next == phead;
}

6. 尾插

尾插, 即在链表的尾节点后刺进一个新节点.

尾插前.

数据结构 - 带头双向循环链表

LTNode* newnode = BuyListNode(x);

数据结构 - 带头双向循环链表

LTNode* tail = phead->prev;

数据结构 - 带头双向循环链表

tail->next = newnode;

数据结构 - 带头双向循环链表

newnode->prev = tail;

数据结构 - 带头双向循环链表

newnode->next = phead;

数据结构 - 带头双向循环链表

phead->prev = newnode;

数据结构 - 带头双向循环链表

完结尾插后.

数据结构 - 带头双向循环链表

void LTPushBack(LTNode* phead, LTDataType x)
{
    assert(phead);
    LTNode* newnode = BuyListNode(x);
    LTNode* tail = phead->prev;
    tail->next = newnode;
    newnode->prev = tail;
    newnode->next = phead;
    phead->prev = newnode;
}

7. 尾删

尾删, 即删去链表的尾节点.

尾删前.

数据结构 - 带头双向循环链表

LTNode* tail = phead->prev;

数据结构 - 带头双向循环链表

LTNode* tailPrev = tail->prev;

数据结构 - 带头双向循环链表

tailPrev->next = phead;

数据结构 - 带头双向循环链表

phead->prev = tailPrev;

数据结构 - 带头双向循环链表

free(tail);

数据结构 - 带头双向循环链表

完结尾删后.

数据结构 - 带头双向循环链表

void LTPopBack(LTNode* phead)
{
    assert(phead);
    assert(!LTEmpty(phead));
    LTNode* tail = phead->prev;
    LTNode* tailPrev = tail->prev;
    tailPrev->next = phead;
    phead->prev = tailPrev; 
    free(tail); 
}

8. 头插

头插, 即在链表的头节点前刺进一个新节点.

头插前.

数据结构 - 带头双向循环链表

LTNode* newnode = BuyListNode(x);

数据结构 - 带头双向循环链表

LTNode* first = phead->next;

数据结构 - 带头双向循环链表

phead->next = newnode;

数据结构 - 带头双向循环链表

newnode->prev = phead;

数据结构 - 带头双向循环链表

newnode->next = first;

数据结构 - 带头双向循环链表

first->prev = newnode;

数据结构 - 带头双向循环链表

完结头插后.

数据结构 - 带头双向循环链表

void LTPushFront(LTNode* phead, LTDataType x)
{
    assert(phead);
    LTNode* newnode = BuyListNode(x);
    LTNode* first = phead->next;
    phead->next = newnode; 
    newnode->prev = phead;
    newnode->next = first;
    first->prev = newnode;
}

9. 头删

头删, 删去链表的头节点.

头删前.

数据结构 - 带头双向循环链表

LTNode* first = phead->next;

数据结构 - 带头双向循环链表

LTNode* second = first->next;

数据结构 - 带头双向循环链表

phead->next = second;

数据结构 - 带头双向循环链表

second->prev = phead;

数据结构 - 带头双向循环链表

free(first);

数据结构 - 带头双向循环链表

完结头删后.

数据结构 - 带头双向循环链表

void LTPopFront(LTNode* phead)
{
    assert(phead);
    assert(!LTEmpty(phead));
    LTNode* first = phead->next;
    LTNode* second = first->next;
    phead->next = second;
    second->prev = phead;
    free(first);
}

10. 查找

查找到存放数据 x 的节点的地址, 若查找不到, 返回 NULL .

LTNode* LTFind(LTNode* phead, LTDataType x)
{
    assert(phead);
    LTNode* curr = phead->next;
    while (curr != phead) {
        if (curr->data == x) {
            return curr;
        }
        curr = curr->next;
    }
    return NULL;
}

11. pos 之前刺进

在内存地址为 pos 的节点前刺进一个新节点.

void LTInsert(LTNode* pos, LTDataType x)
{
    assert(pos);
    LTNode* posPrev = pos->prev;
    LTNode* newnode = BuyListNode(x);
    posPrev->next = newnode;
    newnode->prev = posPrev;
    newnode->next = pos;
    pos->prev = newnode;
}

12. pos 方位删去

删去内存地址为 pos 的节点.

void LTErase(LTNode* pos)
{
    assert(pos);  
    LTNode* posPrev = pos->prev;
    LTNode* posNext = pos->next;
    posPrev->next = posNext;
    posNext->prev = posPrev;
    free(pos);
}

13. 尾插, 尾删, 头插, 头删的常态化

我们可以认为, 头插、尾插是任意下标方位刺进的特殊化, 头删、尾删是任意下标方位删去的特殊化.

// 尾插
void LTPushBack(LTNode* phead, LTDataType x)
{
    assert(phead);
    LTInsert(phead, x);
}
// 尾删
void LTPopBack(LTNode* phead)
{
    assert(phead);
    assert(!LTEmpty(phead));
    LTErase(phead->prev);
}
// 头插
void LTPushFront(LTNode* phead, LTDataType x)
{
    assert(phead);
    LTInsert(phead->next, x);  
}
// 头删
void LTPopFront(LTNode* phead)
{
    assert(phead);
    assert(!LTEmpty(phead));
    LTErase(phead->next);
}

二. 带头双向循环链表的源码

List.h

#pragma once
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <stdbool.h>
typedef int LTDataType;
typedef struct ListNode
{
    LTDataType data;    // 数据域
    struct ListNode* prev;    // 指向前驱节点的指针域
    struct ListNode* next;    // 指向后继节点的指针域 
}LTNode;
// 动态请求一个节点
LTNode* BuyListNode(LTDataType x);
// 初始化
LTNode* LTInit();
// 销毁
void LTDestroy(LTNode* phead);
// 打印
void LTPrint(LTNode* phead);
// 判空
bool LTEmpty(LTNode* phead);
// 尾插
void LTPushBack(LTNode* phead, LTDataType x);
// 尾删
void LTPopBack(LTNode* phead);
// 头插
void LTPushFront(LTNode* phead, LTDataType x);
// 头删
void LTPopFront(LTNode* phead);
// 查找
LTNode* LTFind(LTNode* phead, LTDataType x);
// pos 之前刺进
void LTInsert(LTNode* pos, LTDataType x);
// pos 方位删去
void LTErase(LTNode* pos);

List.c

#include "List.h"
LTNode* BuyListNode(LTDataType x)
{
    LTNode* newnode = (LTNode*)malloc(sizeof(LTNode));
    if (newnode == NULL) {
        perror("malloc fail");
        return NULL;
    }
    newnode->prev = NULL;
    newnode->next = NULL;
    newnode->data = x;
    return newnode;
}
LTNode* LTInit()      
{
    LTNode* phead = BuyListNode(0);    // 创造出虚拟头节点 phead
    phead->prev = phead;    // prev 指针指向本身
    phead->next = phead;    // next 指针指向本身
    return phead;
}
void LTDestroy(LTNode* phead)
{
    assert(phead);
    LTNode* curr = phead->next;
    while (curr != phead) {
        LTNode* curr = phead->next;
        free(curr);
        curr = curr->next;
    }
    free(phead);
}
void LTPrint(LTNode* phead)
{
    assert(phead);
    printf("<=head=>");
    LTNode* curr = phead->next;
    while (curr != phead) {
        printf("%d<=>", curr->data);
        curr = curr->next;
    }
    printf("\n");
}
bool LTEmpty(LTNode* phead)
{
    assert(phead);
    return phead->next == phead;
}
void LTPushBack(LTNode* phead, LTDataType x)
{
    assert(phead);
    //LTNode* newnode = BuyListNode(x);
    //LTNode* tail = phead->prev;
    //tail->next = newnode;
    //newnode->prev = tail;
    //newnode->next = phead;
    //phead->prev = newnode;
    LTInsert(phead, x);
}
void LTPopBack(LTNode* phead)
{
    assert(phead);
    assert(!LTEmpty(phead));
    //LTNode* tail = phead->prev;
    //LTNode* tailPrev = tail->prev;
    //tailPrev->next = phead;
    //phead->prev = tailPrev; 
    //free(tail); 
    LTErase(phead->prev);
}
void LTPushFront(LTNode* phead, LTDataType x)
{
    assert(phead);
    //LTNode* newnode = BuyListNode(x);
    //LTNode* first = phead->next;
    //phead->next = newnode; 
    //newnode->prev = phead;
    //newnode->next = first;
    //first->prev = newnode;
    LTInsert(phead->next, x);  
}
void LTPopFront(LTNode* phead)
{
    assert(phead);
    assert(!LTEmpty(phead));
    //LTNode* first = phead->next;
    //LTNode* second = first->next;
    //phead->next = second;
    //second->prev = phead;
    //free(first);
    LTErase(phead->next);
}
LTNode* LTFind(LTNode* phead, LTDataType x)
{
    assert(phead);
    LTNode* curr = phead->next;
    while (curr != phead) {
        if (curr->data == x) {
            return curr;
        }
        curr = curr->next;
    }
    return NULL;
}
void LTInsert(LTNode* pos, LTDataType x)
{
    assert(pos);
    LTNode* posPrev = pos->prev;
    LTNode* newnode = BuyListNode(x);
    posPrev->next = newnode;
    newnode->prev = posPrev;
    newnode->next = pos;
    pos->prev = newnode;
}
void LTErase(LTNode* pos)
{
    assert(pos);  
    LTNode* posPrev = pos->prev;
    LTNode* posNext = pos->next;
    posPrev->next = posNext;
    posNext->prev = posPrev;
    free(pos);
}