一、原理
双链表又称双向链表,通常情况下是带头循环结构,在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;
} 
                


















