简介
与单向不带头不循环链表(单链表)相比,
带头双向循环链表:
1.多了第一位的head---哨兵位,head不能少,少了就是不带头;
2.多了前驱指针prev,指向上一位的data;
3.最后一位的后继指针next不指向NULL,指向head;
实现双向循环链表
创建List.h, List.c, test.c三个文件
初始化链表
typedef int LTDataType;//存储的数据类型
typedef struct ListNode
{
LTDataType data;//数据域
struct ListNode* prev;//前驱指针
struct ListNode* next;//后继指针
}LTNode;
head->prev=head == head->next=head
LTNode* LTBuyNode(LTDataType x)
{
LTNode* newnode = (LTNode*)malloc(sizeof(LTNode));
if (newnode == NULL)
{
perror("malloc fail!");
exit(1);
}
newnode->data = x;
//prev next
newnode->next = newnode->prev = newnode;
return newnode;
}
head随便存个无效值,如-1
//为了保持接口的一致性,优化接口都为一级指针
//初始化
//void LTInit(LTNode** pphead);
LTNode* LTInit();
//初始化
//可以用二级指针
//void LTInit(LTNode** pphead)
//{
// //创建一个头结点(哨兵位)
// *pphead = LTBuyNode(-1);
//}
//也可以用指针传指针,保持接口都是一级指针
LTNode* LTInit()
{
LTNode* phead = LTBuyNode(-1);
return phead;
}
链表判空
bool LTEmpty(LTNode* phead);
bool LTEmpty(LTNode* phead)
{
assert(phead);
return phead->next == phead;
}
打印
1.创建pcur指针,指向phead的下一位,不能用phead指针遍历,会丢失头指针;
2.遍历链表打印;
3.直到pcur->next=phead;
void LTPrint(LTNode* phead);
void LTPrint(LTNode* phead)
{
LTNode* pcur = phead->next;
while (pcur != phead)
{
printf("%d->", pcur->data);
pcur = pcur->next;
}
printf("\n");
}
测试 (test.c)
void ListTest01()
{
//创建双向链表变量
//LTNode* plist = NULL;
//LTInit(&plist);
LTNode* plist = LTInit();
LTPushBack(plist, 1);
LTPushBack(plist, 2);
LTPushBack(plist, 3);
LTPushBack(plist, 4);
LTPrint(plist);
//LTPushFront(plist, 1);
//LTPrint(plist);
//LTPushFront(plist, 2);
//LTPrint(plist);
//LTPushFront(plist, 3);
//LTPrint(plist);
//LTPushFront(plist, 4);
//LTPrint(plist);
//
//LTPopBack(plist);
//LTPrint(plist);
//LTPopBack(plist);
//LTPrint(plist);
//LTPopBack(plist);
//LTPrint(plist);
//LTPopBack(plist);
//LTPrint(plist);
//LTPopBack(plist);
//LTPrint(plist);
//LTPopFront(plist);
//LTPrint(plist);
//LTPopFront(plist);
//LTPrint(plist);
//LTPopFront(plist);
//LTPrint(plist);
//LTPopFront(plist);
//LTPrint(plist);
//LTPopFront(plist);
//LTPrint(plist);
//LTNode* pos = LTFind(plist, 3);
//if (pos == NULL)
//{
// printf("没有找到!\n");
//}
//else
//{
// printf("找到了!\n");
//}
//LTInsert(pos, 11);
//LTErase(pos);
//LTPrint(plist);
//LTDesTroy(&plist);
LTDesTroy2(plist);
plist = NULL;
}
int main()
{
ListTest01();
return 0;
}
插入
尾插
head---------------------d3--------------------newnode
newnode->next=phead(new->head)
newnode->prev=phead->prev(new->d3)
phead->prev->next=newnode(d3->new)
phead->prev=newnode (head->new)
//插入
//第一个参传一级还是二级,要看pphead指向的节点会不会发生改变
//如果发生改变,那么pphead的改变要影响实参,传二级
//如何不发生改变,pphead不会影响实参,传一级
void LTPushBack(LTNode* phead, LTDataType x);
void LTPushBack(LTNode* phead, LTDataType x)
{
assert(phead);
LTNode* newnode = LTBuyNode(x);
//phead phead->prev newnode
newnode->next = phead;
newnode->prev = phead->prev;
phead->prev->next = newnode;
phead->prev = newnode;
}
头插
newnode->next=phead->next(new->d1)
newnode->prev=phead(new->head)
phead->next->prev=newnode(d1->new)
phead->next=newnode(head->new)
void LTPushFront(LTNode* phead, LTDataType x);
void LTPushFront(LTNode* phead, LTDataType x)
{
assert(phead);
LTNode* newnode = LTBuyNode(x);
//phead newnode phead->next(d1)
newnode->next = phead->next;
newnode->prev = phead;
phead->next->prev = newnode;
phead->next = newnode;
}
指定位置插入
//在指定位置插入结点
void ListInsert(ListNode* pos, LTDataType x)
{
assert(pos);
ListNode* before = pos->prev;//记录pos指向结点的前一个结点
ListNode* newnode = BuyListNode(x);//申请一个结点,数据域赋值为x
//建立新结点与before结点之间的双向关系
before->next = newnode;
newnode->prev = before;
//建立新结点与pos指向结点之间的双向关系
newnode->next = pos;
pos->prev = newnode;
}
在指定位置之后插入
//在pos位置之后插入节点
void LTInsert(LTNode* pos, LTDataType x);
//在pos位置之后插入节点
void LTInsert(LTNode* pos, LTDataType x)
{
assert(pos);
LTNode* newnode = LTBuyNode(x);
//pos newnode pos->next
newnode->next = pos->next;
newnode->prev = pos;
pos->next->prev = newnode;
pos->next = newnode;
}
删除
尾删
void LTPopBack(LTNode* phead);
head-------------d2---------------------del
*prev *del
del->prev phead->prev
prev->next=head(d2->head)
phead->prev=prev(head->d2)
void LTPopBack(LTNode* phead)
{
assert(phead);
assert(!LTEmpty(phead));
//phead prev(del->prev) del(phead->prev)
LTNode* del = phead->prev;
LTNode* prev = del->prev;
prev->next = phead;
phead->prev = prev;
free(del);
del = NULL;
}
头删
head-----------------------d1-------------------------------d2
phead *del del->next
d2->head:del->next-prev=phead
head->d2:phead->next=del->next
void LTPopFront(LTNode* phead);
void LTPopFront(LTNode* phead)
{
assert(phead);
assert(!LTEmpty(phead));
//phead del(phead->next) del->next
LTNode* del = phead->next;
del->next->prev = phead;
phead->next = del->next;
free(del);
del = NULL;
}
指定位置删除
head--------------------d2-----------------------d3
pos->next pos->prev pos
d2->head:pos->prev->next=pos->next
head->d2:pos->next->prev=pos->prev
//删除指定位置节点
void LTErase(LTNode* pos);
//删除指定位置节点
void LTErase(LTNode* pos)
{
assert(pos);
// pos->prev pos pos->next
pos->prev->next = pos->next;
pos->next->prev = pos->prev;
free(pos);
pos = NULL;
}
查找
LTNode* LTFind(LTNode* phead, LTDataType x);
LTNode* LTFind(LTNode* phead, LTDataType x)
{
assert(phead);
LTNode* pcur = phead->next;
while (pcur != phead)
{
if (pcur->data == x)
{
return pcur;
}
pcur = pcur->next;
}
return NULL;
}
销毁
//销毁
void LTDesTroy(LTNode** pphead);
//或者
void LTDesTroy2(LTNode* phead);//传一级,需要手动将plist置为NULL
//销毁
void LTDesTroy(LTNode** pphead)
{
assert(pphead && *pphead);
LTNode* pcur = (*pphead)->next;
while (pcur != *pphead)
{
LTNode* Next = pcur->next;
free(pcur);
pcur = Next;
}
//销毁哨兵位结点
free(*pphead);
*pphead = NULL;
pcur = NULL;
}
//或者
void LTDesTroy2(LTNode* phead)
{
assert(phead);
LTNode* pcur = phead->next;
while (pcur != phead)
{
LTNode* Next = pcur->next;
free(pcur);
pcur = Next;
}
free(phead);
phead = pcur = NULL;
}