一、原理
双链表又称双向链表,通常情况下是带头循环结构,在C++STL标准模板库中封装的<list.h>头文件就是带头双向循环链表。
特性:增删灵活且高效,支持随机增删但不支持随机访问
设计思路:
- 链表包含一个头节点head,不存储数据,用于链表的维护,提高数据增删效率
- 每一个链表节点Node都包含一个数据和两个指针(前驱指针prev和后继指针next)
- 前驱指针prev指向前一个节点,后继指针next指向后一个节点
- 当链表为空时,头结点head的prev指针和next指针都指向head自身
- 节点的增删通过前后指针指向的改变即可完成,无需数据移动,效率高
二、DoubleList.h
#define _CRT_SECURE_NO_WARNINGS 1#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>typedef int DataType;typedef struct Node
{DataType data;struct Node* next;struct Node* prev;
}Node;typedef struct List
{Node* head;
}List;void Init(List* plist)
{plist->head = (Node*)malloc(sizeof(Node));plist->head->prev = plist->head;plist->head->next = plist->head;
}bool Empty(List* plist)
{return plist->head == plist->head->next;
}Node* BuyNode(DataType x)
{Node* node = (Node*)malloc(sizeof(Node));node->data = x;node->next = NULL;node->prev = NULL;
}void PushFront(List* plist, DataType x)
{Node* node = BuyNode(x);if (Empty(plist)){node->next = plist->head;node->prev = plist->head;plist->head->next = node;plist->head->prev = node;}else{Node* next = plist->head->next;node->prev = plist->head;node->next = next;next->prev = node;plist->head->next = node;}
}void PushBack(List* plist, DataType x)
{Node* node = BuyNode(x);if (Empty(plist)){node->next = plist->head;node->prev = plist->head;plist->head->next = node;plist->head->prev = node;}else{Node* prev = plist->head->prev;node->next = plist->head;node->prev = prev;prev->next = node;plist->head->prev = node;}
}void PopFront(List* plist)
{if (Empty(plist)){printf("双链表为空,头删失败\n");return;}Node* cur = plist->head->next;plist->head->next = cur->next;cur->next->prev = plist->head;free(cur);cur = NULL;
}void PopBack(List* plist)
{if (Empty(plist)){printf("双链表为空,尾删失败\n");return;}Node* cur = plist->head->prev;plist->head->prev = cur->prev;cur->prev->next = plist->head;free(cur);cur = NULL;
}Node* Find(List* plist, DataType x)
{Node* cur = plist->head->next;while (cur != plist->head){if (cur->data == x)return cur;cur = cur->next;}return NULL;
}void InsertFront(Node* pos, DataType x)
{if (pos == NULL){printf("pos为空,插入失败\n");return;}Node* node = BuyNode(x);Node* prev = pos->prev;prev->next = node;node->prev = prev;node->next = pos;pos->prev = node;
}void Delete(Node* pos)
{if (pos == NULL){printf("pos为空,Delete失败\n");return;}Node* next = pos->next;Node* prev = pos->prev;next->prev = prev;prev->next = next;free(pos);pos = NULL;
}void Destroy(List* plist)
{while (!Empty(plist)){PopFront(plist);}free(plist->head);plist->head = NULL;printf("双链表销毁成功\n");
}void Print(List* plist)
{if (plist->head == NULL){printf("双链表不存在\n");return;}Node* cur = plist->head->next;printf("head -> ");while (cur != plist->head){printf("%2d -> ", cur->data);cur = cur->next;}printf("head\n");
}
三、test.c
#define _CRT_SECURE_NO_WARNINGS 1#include "DoubleList.h"int main()
{List list;Init(&list);Print(&list); // head -> head// 尾插数据PushBack(&list, 1);PushBack(&list, 3);PushBack(&list, 5);PushBack(&list, 7);Print(&list); // head -> 1 -> 3 -> 5 -> 7 -> head// 头插数据PushFront(&list, 2);PushFront(&list, 4);PushFront(&list, 6);PushFront(&list, 8);Print(&list); // head -> 8 -> 6 -> 4 -> 2 -> 1 -> 3 -> 5 -> 7->head// 尾删数据PopBack(&list);PopBack(&list);PopBack(&list);Print(&list); // head -> 8 -> 6 -> 4 -> 2 -> 1 -> head// 头删数据PopFront(&list);PopFront(&list);PopFront(&list);Print(&list); // head -> 2 -> 1 -> head// 在查询的节点前插入数据InsertFront(Find(&list, 1), 11);InsertFront(Find(&list, 11), 111);Print(&list); // head -> 2 -> 111 -> 11 -> 1 -> head// 删除查询的节点Delete(Find(&list, 1));Delete(Find(&list, 11));Delete(Find(&list, 111));Print(&list); // head -> 2 -> head// 销毁链表Destroy(&list); // 链表销毁成功Print(&list); // 链表不存在return 0;
}