#include <stdio.h>
#include <assert.h>
#include <stdlib.h>
#include <malloc.h>
//带头节点双向循环
//带头节点优点容易写删除操作 双向优点可以找到节点前一个,循环优点容易找到尾节点
typedef int LTDateType;
typedef struct ListNode//节点的属性有单和双向之分但是无法区别带头还是不带头
{
LTDateType _data;
struct ListNode *_next;
struct ListNode *_prev;
}ListNode;
typedef struct List
{
ListNode *_head;
}List;
//函数的声明
void ListInit(List *list);//建立
void ListDestory(List *plist);//销毁
void ListPrint(List *plist);//显示,可以传List型参数但效率低,因为要构造新的List变量
ListNode *BuyListNode();
void ListPushBack(List *plist,LTDateType x);
void ListPopBack(List *plist);
void ListPushFront(List *plist,LTDateType x);
void ListPopFront(List *plist);
ListNode* ListFind(List* plist,LTDateType x);
void ListInsert(ListNode* pos,LTDateType x);//在pos节点前链接值为x的节点
void ListErase(ListNode* pos);
void ListRemove(List* plist,LTDateType x);//找到x的节点删除
int ListSize(List* plist);
int ListEmpty(List* plist);
//函数的实现
ListNode *BuyListNode(LTDateType x)
{
ListNode *node= (ListNode*)malloc(sizeof(ListNode));
node->_data = x;
node->_next = NULL;//初始化要有头尾节点
node->_prev = NULL;
return node;
}
void ListInit(List *plist)
{
assert(plist);
plist->_head = BuyListNode(-1);
plist->_head->_next = plist->_head;
plist->_head->_prev = plist->_head;
}
void ListDestory(List *plist)
{
assert(plist);
ListNode* cur = plist->_head->_next;
ListNode* next ;
while(cur!=plist->_head)
{
next = cur->_next;
free(cur);
cur = next;
}
free(plist->_head);
plist->_head = NULL;
}
void ListPushBack(List *plist,LTDateType x)
{
assert(plist);
ListNode* head = plist->_head;
ListNode* tail = head->_prev;
ListNode* newnode = BuyListNode(x);
tail->_next = newnode;
newnode->_prev = tail;
head->_prev = newnode;
newnode->_next = head;
}
void ListPopBack(List *plist)
{
ListNode *cur = plist->_head;
while(cur->_next!=plist->_head)
{
cur = cur->_next;
}
if(cur!=plist->_head)
{
cur->_prev->_next = cur->_next;
cur->_next->_prev = cur->_prev;
free(cur);
cur = NULL;
}
}
void ListPushFront(List *plist,LTDateType x)
{
assert(plist);
ListNode* newnode = BuyListNode(x);
ListNode* next = plist->_head->_next;
plist->_head->_next = newnode;
newnode->_prev = plist->_head;
next->_prev = newnode;
newnode->_next = next;
}
void ListPopFront(List *plist)
{
assert(plist&& plist->_head->_next!=plist->_head);
ListNode *cur = plist->_head->_next;
plist->_head->_next = cur->_next;
cur->_next->_prev = plist->_head;
free(cur);
}
void ListPrint(List *plist)
{
assert(plist&&plist->_head);
ListNode *cur = plist->_head->_next;
if(cur!=plist->_head)
{
printf("%d->",cur->_data);
cur = cur->_next;
}
while(cur!=plist->_head)
{
printf("<-%d->",cur->_data);
cur = cur->_next;
}
printf("\n");
}
ListNode* ListFind(List* plist,LTDateType x)
{
ListNode *cur = plist->_head;
while(cur->_next!=plist->_head)
{
if(cur->_data == x)
return cur;
cur = cur->_next;
}
return nullptr;
}
void ListInsert(ListNode* pos,LTDateType x)
{
ListNode* prev = pos->_prev;
ListNode* cur =BuyListNode(x);
prev->_next = cur;
cur->_prev = prev;
cur->_next = pos;
pos->_prev = cur;
}
void ListErase(ListNode* pos)
{
assert(pos);
ListNode* next = pos->_next;
ListNode* prev = pos->_prev;
next->_prev = pos->_prev;
prev->_next = pos->_next;
free(pos);
}
void ListRemove(List* plist,LTDateType x)
{
ListNode *cur = ListFind(plist,x);
if(cur!=nullptr)
{
ListErase(cur);
}
}
int ListSize(List* plist)
{
assert(plist);
ListNode *cur = plist->_head;
int size = 0;
while(cur->_next!=plist->_head)
{
size++;
cur = cur->_next;
}
return size;
}
int ListEmpty(List* plist)
{
assert(plist);
ListNode *cur = plist->_head;
if(cur->_next!=cur)
{
return 1;
}
else
{
return 0;
}
}
//测试函数
void test()
{
List plist;
ListInit(&plist);
ListPushBack(&plist,1);
ListPushBack(&plist,2);
ListPushBack(&plist,3);
ListPushBack(&plist,4);
ListPushBack(&plist,5);
ListPrint(&plist);
ListRemove(&plist,4);
ListPrint(&plist);
printf("%d ",ListSize( &plist));
ListDestory(&plist);
ListInit(&plist);
printf("%d ",ListEmpty(&plist));
}
//主函数
int main()
{
test();
}
双向循环有头链表,是一种结构复杂,但是操作简单的数据结构,是一种对于单向无循环无头链表的优化后的数据结构,需要注意以下几点
(1)双向链表有三个成员分别为数据域以及前后指针,在双向链表的初始化(Insert)中要让前后指针指向自己,方便之后的函数实现,
(2)通过链表的尾的后面指向头可以实现很多操作
(3)对于节点的增删要注意增加删除的指针要修改指向方向如下图
在加入一个新节点需要
删除节点则为