6)头插函数实现。😊
代码实现思路详解:
//6)头插函数实现。先assert断言一下确保传入进来的指针有效。定义一个指向首节点的指针然后生成一个新节点,让新节点与头结点相连,让新节点的next指针指向原来首节点,原来首节点的prev指向新节点让新节点位于原来首节点的前面从而实现头插。
void ListPushFront(ListNode* phead, LTDataType x) { assert(phead); ListNode* first = phead->next; ListNode* newnode = BuyListNode(x); phead->next = newnode; newnode->prev = phead; newnode->next = first; first->prev = newnode; }
7)头删函数实现。😊
代码实现思路详解:
//7)头删函数实现。assert确保传入指针有效和确保头结点不要被删掉。定义first指针指向链表首节点,second指向first下一个。然后让头结点与second指针指向的节点相连,然后free掉first指向的节点。
void ListPopFront(ListNode* phead) { assert(phead); assert(phead->next != phead); ListNode* first = phead->next; ListNode* second = first->next; phead->next = second; second->prev = phead; free(first); first = NULL; }
8)尾删函数的实现。😊
代码实现思路详解:
//8)尾删函数的实现。头删函数实现。assert确保传入指针有效和确保头结点不要被删掉。定义tail函数指向尾节点,定义prev指针指向tail的前一个节点,让prev指向的那个节点与头结点相连,然后删掉tail指向的尾节点,实现尾删。
void ListPopBack(ListNode* phead) { assert(phead); assert(phead->next != phead); ListNode* tail = phead->prev; ListNode* prev = tail->prev; prev->next = phead; phead->prev = prev; free(tail); tail = NULL; }
9)查找函数实现。😊
代码实现思路详解:
//9)查找函数,先assert断言确保传入指针有效性,定义一个cur指向首节点,然后利用while遍历链表,找到的话就返回指针。找不到则返回空。
ListNode* ListFind(ListNode* phead, LTDataType x) { assert(phead); ListNode* cur = phead->next; while (cur != phead) { if (cur->data == x) { return cur; } cur = cur->next; } return NULL; }
10)pos位置之前插入x的函数实现。😊
代码实现思路详解:
// 10)pos位置之前插入x。定义一个prev指针指向pos指向的前一个节点,然后新生成一个节点,通过指针相连方式将新生成的节点放到pos与prev的中间。
void ListInsert(ListNode* pos, LTDataType x) { assert(pos); ListNode* prev = pos->prev; ListNode* newnode = BuyListNode(x); // prev newnode pos prev->next = newnode; newnode->prev = prev; newnode->next = pos; pos->prev = newnode; }
11)删除pos位置的值的函数实现。😊
代码实现思路详解:
// 11)删除pos位置的值。定义一个prev指针指向pos前一个节点,定义一个next指向pos后一个节点,然后让这两个节点相连,删掉pos指向的节点。
void ListErase(ListNode* pos) { assert(pos); ListNode* prev = pos->prev; ListNode* next = pos->next; prev->next = next; next->prev = prev; free(pos); }
12)逆序输出的函数实现。😊
代码实现思路详解:
//12)逆序输出函数实现。定义一个phead指针指向尾节点,从后往前遍历链表,直到cur走到头结点为止。
void ListPrintBack(ListNode* phead) { assert(phead); ListNode* cur = phead->prev; while (cur != phead) { printf("%d ", cur->data); cur = cur->prev; } printf("\n"); }
13)判空函数实现。😊
代码实现思路详解:
//13)判空函数实现,只要phead的前指针指向自己,则认为这链表为空链表。
bool ListEmpty(ListNode* phead) { assert(phead); if (phead->prev == phead) { return 1; } return -1;
3.测试文件源码分享:🙌
#include "SlistNode.h" void TestList1() { //创建带头节点的空双向链表 ListNode* plist = ListInit(); //判空 int ret = ListEmpty(plist); if (ret == 1) { printf("链表为空\n"); } else { printf("链表不为空\n"); } //尾插1,2,3,4,5 ListPushBack(plist, 1); ListPushBack(plist, 2); ListPushBack(plist, 3); ListPushBack(plist, 4); ListPushBack(plist, 5); ListPrintFront(plist); //头插0,-1 ListPushFront(plist, 0); ListPushFront(plist, -1); ListPrintFront(plist); //头删三个数据 ListPopFront(plist); ListPopFront(plist); ListPopFront(plist); ListPrintFront(plist); //尾删一个数据 ListPopBack(plist); ListPrintFront(plist); //判空 int ret1 = ListEmpty(plist); if (ret1 == 1) { printf("链表不为空\n"); } else { printf("链表为空\n"); } // 查找,附带着修改的作用 ListNode* pos = ListFind(plist, 3); if (pos) { pos->data *= 10; printf("找到了,并且节点的值乘以10\n"); } else { printf("没有找到\n"); } ListPrintFront(plist); //在pos前插入一个300 ListInsert(pos, 300); ListPrintFront(plist); //删除pos位置的节点 ListErase(pos); //顺序输出链表数据 ListPrintFront(plist); //逆序输出链表数据 ListPrintBack(plist); //删除链表 ListDestory(plist); } int main() { TestList1(); return 0; }
程序功能测试结果图:
总结撒花💞
本篇文章旨在分享详解C语言动态实现带头结点的双向循环链表结构。希望大家通过阅读此文有所收获!实现带头结点的双向循环链表结构,相比于单链表结构更加复杂一点,它的成员相比单链表多了一个指针。本次实现难点在于对指针的运用和对多种情况的考虑。在实现前一定要通过画图的方式将思路和需要注意的情况想清楚然后再来尝试用代码进行实现。基本实现出双链表后可以思考能不能优化代码的问题。
😘如果我写的有什么不好之处,请在文章下方给出你宝贵的意见😊。如果觉得我写的好的话请点个赞赞和关注哦~😘😘😘