前言:
复现带头双向成环链表功能中将
环结点
设置为哨兵结点。虽然带头双向成环链表结构上很复杂,但是实现起来也不是太难。
因为有哨兵结点原因,一方面只需要在初始化的时候进行二级传参,另外一方面是不需要考虑空链表,因此关于增删减查只需要一级指针。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-MByXcvtZ-1636642417217)(演示文稿1.png)]
结构体定义
typedef int DLDateType;
typedef
struct DList
{
struct DList* prev;
DLDateType date;
struct DList* next;
}DList;
初始化
void DListInit(DList** pphead)//初始化
//初始化带头双向链表,需改变实参指向,因此二级指针。
//另外因为因为此时链表为空,要注意哨兵结点中的next和prev。
{
assert(pphead);
DList* node = newnode(0);//哨兵结点存储的元素不需要在意,它只是辅助作用。
//空链表,二级指针
node->next = node;
node->prev = node;
*pphead = node;
}
打印
void DListPrint(DList* phead)
{
assert(phead);
DList* cur = phead->next;
while (cur != phead)//当cur等于哨兵结点时,代码遍历完毕
{
printf("%d->", cur->date);
cur = cur->next;
}
printf("NULL\n");
}
指定pos位置插入
当头插和尾插去复用DListInsert()函数时,是不一样的,需要特殊对待。
尾插其实就是在哨兵结点前插入结点。
头插是在哨兵结点后插,也就是哨兵结点的next结点前,需要特别注意
void DListInsert(DList* pHead, DList* pos, DLDateType x)// 双向链表在pos的前面进行插入
{
//本函数是考虑头插,尾插复用的情况,编写的。
assert(pHead);
assert(pos!=NULL);
//不考虑
//
/*DList* cur = pHead->next;
while (cur != pHead)
{
if (cur == pos)
{
DList* node = newnode(x);
DList* prevcur = cur->prev;
prevcur->next = node;
node->prev = prevcur;
node->next = cur;
cur->prev = node;
return;
}
cur = cur->next;
}
printf("链表中找不到pos\n");*/
//考虑的代码
if (pos != pHead)
{
DList* cur = pHead->next;
while (cur != pHead)
{
if (cur == pos)
{
DList* node = newnode(x);
DList* prevcur = cur->prev;
prevcur->next = node;
node->prev = prevcur;
node->next = cur;
cur->prev = node;
return;
}
cur = cur->next;
}
printf("链表中找不到pos\n");
}
else
{
if (pHead->next == pHead)//链表此时为空。
{
DList* node = newnode(x);
node->prev = pHead->prev;
node->next = pHead;
pHead->prev = node;
pHead->next = node;
}
else//尾插在复用时很特殊,因此特别对待。
{
DList* node = newnode(x);
node->next = pHead;
node->prev = pHead->prev;
pHead->prev->next = node;
pHead->prev = node;
}
}
}
头插
void DListPushBack(DList* phead, DLDateType x)//尾插
{
assert(phead);
DListInsert(phead, phead,x);//复用DlistInsert()
//不复用
/*DList* node = newnode(x);
DList* tail = phead->prev;
tail->next = node;
node->prev = tail;
node->next = phead;
phead->prev = node;*/
}
尾插
void DListPushFront(DList* phead, DLDateType x)//复用DlistInsert不方便
{
assert(phead);
DListInsert(phead, phead->next, x);//复用
//不复用
/*DList* node = newnode(x);
node->next = phead->next;
node->prev = phead;
phead->next->prev = node;
phead->next = node;*/
}
指定pos位置删
删除就不需要考虑头删,尾删的特殊情况
void DListErase(DList* pHead,DList* pos)// 双向链表删除pos位置的节点
{
assert(pHead);
assert(pHead->next != pHead);
assert(pos);
DList* cur = pHead->next;
while (cur!=pHead)
{
if (cur == pos)
{
DList* prevcur = cur->prev;
DList* bankcur = cur->next;
prevcur->next = bankcur;
bankcur->prev = prevcur;
free(cur);
cur = NULL;
printf("删除成功\n");
return;
}
cur = cur->next;
}
printf("链表中找不到pos\n");
}
头删
void DListPopBack(DList* phead)//尾删
{
assert(phead);
assert(phead->next != phead);
DListErase(phead, phead->prev);//复用
//不复用
/*DList* tail = phead->prev;
DList* tailprev = tail->prev;
tailprev->next = phead;
phead->prev = tailprev;
free(tail);
tail = NULL;*/
}
尾删
void DListPopFront(DList* phead)//头删
{
assert(phead);
assert(phead->next != phead);
/*DList* front = phead->next;
DList* frontback = front->next;
phead->next = frontback;
frontback->prev = phead;
free(front);*/
DListErase(phead, phead->next);
}
查找
找到返回结点地址,否则NULL
DList* DListFind(DList* pHead, DLDateType x)//双向链表查找,找到就返回结点地址,否则返回NULL指针。
{
assert(pHead);
assert(pHead->next != pHead);
DList* cur = pHead->next;
while (cur!=pHead)//结点的环是哨兵结点
{
if (cur->date == x)
{
return cur;
}
cur = cur->next;
}
printf("未找到结点\n");
return NULL;
}
销毁
void DlistDestroy(DList* pHead)//为了保持代码整齐性,我们free完所有结点,一定要将实参置为NULL;
{
assert(pHead);
DList* cur = pHead->next;
//我们在销毁的时候,最后一个结点的next是pHead。
while (cur!=pHead)
{
DList* tmp = cur;
cur = cur->next;
free(tmp);
tmp = NULL;
}
free(pHead);
pHead = NULL;
}
main
#include"DList.h"
void Text()
{
DList* plist = NULL;
DListInit(&plist);
DListPushBack(plist, 1);
DListPushBack(plist, 2);
DListPushBack(plist, 3);
DListPushBack(plist, 4);
DListPushBack(plist, 5);
DListPrint(plist);
DListPushFront(plist, 6);
DListPushFront(plist, 7);
DListPushFront(plist, 8);
DListPushFront(plist, 9);
DListPrint(plist);
DList* Find = DListFind(plist,9);
DListInsert(plist, Find, 10);
DListPrint(plist);
DListErase(plist, Find);
DListPrint(plist);
DListPopBack(plist);
DListPopBack(plist);
DListPopBack(plist);
DListPrint(plist);
DListPopFront(plist);
DListPopFront(plist);
DListPopFront(plist);
DListPopFront(plist);
DListPopFront(plist);
DListPrint(plist);
DlistDestroy(plist);
plist = NULL;
printf("\t\t\t\t\t ---BY New Young\n");
}
int main ()
{
Text();
return 0;
}
效果展示
总结
代码的实践,调试能力是一点一点积累,现在不锻炼,以后卖红薯!!!!哈哈哈~。