Table of contents
Leading two-way circular linked list initialization
Leading two-way circular linked list printing
Tail insertion of leading bidirectional circular linked list
The head plug of the headed two-way circular linked list
Tail deletion of leading two-way circular linked list
Head deletion of leading two-way circular linked list
Search for leading two-way circular linked list
Leading two-way circular linked list inserts x before pos
Delete the value of pos position in the leading two-way circular linked list
Destruction of leading two-way circular linked list
Before learning to take the lead in a two-way circular linked list: Sentinel bit? Both ways? cycle? The more buffs, the harder the linked list?
After learning the leading two-way circular linked list: take the leading two-way circular linked list to the top! ! ! Goodbye singly linked list!
Preface
Compilation environment: VS2022
Programming language: C
Memory management (dynamic/static): Dynamic memory management
Whether to bring sentry position: Yes
Linked list type: two-way circular linked list
code analysis
type of data
typedef struct ListNode { LTDataType data; //数据域 struct ListNode* prev; //指向前一个结点 struct ListNode* next; //指向后一个结点 }LTNode;
Dynamically apply for a node
LTNode* BuyLTNode(LTDataType x) { LTNode* newnode = (LTNode*)malloc(sizeof(LTNode)); //考虑申请空间失败的情况 if (newnode == NULL) { perror("malloc"); return NULL; } newnode->data = x; newnode->prev = NULL; newnode->next = NULL; return newnode; }
Leading two-way circular linked list initialization
初始化需要申请一个结点设置哨兵位 LTNode* LTInit() { //此处哨兵位的数据域(data)随便存放一个LTDataType类型的数据即可 //如果data的数据类型为int,我们也可以用哨兵位的数据域来存放链表的长度 LTNode* phead = BuyLTNode(-1); phead->next = phead; phead->prev = phead; return phead; }
Leading two-way circular linked list printing
void LTPrint(LTNode* phead) { assert(phead); //如何不遗漏不重复地打印一遍双向循环链表呢? LTNode* cur = phead->next; printf("guard<=>"); while (cur != phead) { printf("%d<=>", cur->data); cur = cur->next; } printf("\n"); }
Tail insertion of leading bidirectional circular linked list
建议在插入和删除的时候不要吝啬开辟新的空间 创建两个新的结构体指针能够提高代码的可读性,计算机不缺这点内存 void LTPushBack(LTNode* phead, LTDataType x) { assert(phead); LTNode* newnode = BuyLTNode(x); LTNode* tail = phead->prev; //下面四条语句的顺序可以随意交换吗? tail->next = newnode; phead->prev = newnode; newnode->next = phead; newnode->prev = tail; } //但是我们也需要能够看懂别人的代码 尝试只创建一个结构体指针完成上述操作
The head plug of the headed two-way circular linked list
带头双向循环链表的插入(包括头插、尾插)和删除(包括头删、尾删)极具相似性 void LTPushFront(LTNode* phead, LTDataType x) { assert(phead); LTNode* newnode = BuyLTNode(x); LTNode* next = phead->next; phead->next = newnode; next->prev = newnode; newnode->next = next; newnode->prev = phead; }
Tail deletion of leading two-way circular linked list
void LTPopBack(LTNode* phead) { assert(phead); assert(!LTEmpty(phead)); LTNode* tail = phead->prev; LTNode* tailPrev = tail->prev; phead->prev = tailPrev; tailPrev->next = phead; free(tail); }
Head deletion of leading two-way circular linked list
void LTPopFront(LTNode* phead) { assert(phead); assert(!LTEmpty(phead)); LTNode* first = phead->next; LTNode* second = first->next; phead->next = second; second->prev = phead; free(first); }
Search for leading two-way circular linked list
LTNode* LTFind(LTNode* phead, LTDataType x) { assert(phead); //遍历 LTNode* cur = phead->next; while (cur != phead) { if (cur->data == x) return cur; cur = cur->next; } return NULL; }
Leading two-way circular linked list inserts x before pos
// 在pos之前插入 void LTInsert(LTNode* pos, LTDataType x) { assert(pos); //试分析一下,头插、尾插的情况是否被包含在内 LTNode* prev = pos->prev; LTNode* newnode = BuyLTNode(x); newnode->next = pos; newnode->prev = prev; prev->next = newnode; pos->prev = newnode; }
Delete the value of pos position in the leading two-way circular linked list
// 删除pos位置的值 void LTErase(LTNode* pos) { assert(pos); //试分析一下,头删、尾删的情况是否被包含在内 LTNode* prev = pos->prev; LTNode* next = pos->next; prev->next = next; next->prev = prev; free(pos); }
Destruction of leading two-way circular linked list
void LTDestroy(LTNode* phead) { assert(phead); //遍历 LTNode* cur = phead->next; while (cur != phead) { LTNode* next = cur->next; free(cur); cur = next; } free(phead); //此处是否需要置空哨兵位phead呢? //形参的改变不会影响实参,还是交给链表的使用者置空吧 }
Complete code
List.h
#pragma once #include <stdio.h> #include <stdlib.h> #include <assert.h> #include <stdbool.h> typedef int LTDataType; typedef struct ListNode { LTDataType data; struct ListNode* prev; struct ListNode* next; }LTNode; LTNode* LTInit(); void LTPrint(LTNode* phead); bool LTEmpty(LTNode* phead); void LTPushBack(LTNode* phead, LTDataType x); void LTPushFront(LTNode* phead, LTDataType x); void LTPopBack(LTNode* phead); void LTPopFront(LTNode* phead); LTNode* LTFind(LTNode* phead, LTDataType x); // 在pos之前插入 void LTInsert(LTNode* pos, LTDataType x); // 删除pos位置的值 void LTErase(LTNode* pos); void LTDestroy(LTNode* phead);
List.c
#include "List.h" LTNode* BuyLTNode(LTDataType x) { LTNode* newnode = (LTNode*)malloc(sizeof(LTNode)); if (newnode == NULL) { perror("malloc"); return NULL; } newnode->data = x; newnode->prev = NULL; newnode->next = NULL; return newnode; } LTNode* LTInit() { LTNode* phead = BuyLTNode(-1); phead->next = phead; phead->prev = phead; return phead; } void LTPrint(LTNode* phead) { assert(phead); LTNode* cur = phead->next; printf("guard<=>"); while (cur != phead) { printf("%d<=>", cur->data); cur = cur->next; } printf("\n"); } bool LTEmpty(LTNode* phead) { return phead->next == phead; } void LTPushBack(LTNode* phead, LTDataType x) { assert(phead); LTNode* newnode = BuyLTNode(x); LTNode* tail = phead->prev; tail->next = newnode; phead->prev = newnode; newnode->next = phead; newnode->prev = tail; } void LTPushFront(LTNode* phead, LTDataType x) { assert(phead); LTNode* newnode = BuyLTNode(x); LTNode* next = phead->next; phead->next = newnode; next->prev = newnode; newnode->next = next; newnode->prev = phead; } void LTPopBack(LTNode* phead) { assert(phead); assert(!LTEmpty(phead)); LTNode* tail = phead->prev; LTNode* tailPrev = tail->prev; phead->prev = tailPrev; tailPrev->next = phead; free(tail); } void LTPopFront(LTNode* phead) { assert(phead); assert(!LTEmpty(phead)); LTNode* first = phead->next; LTNode* second = first->next; phead->next = second; second->prev = phead; free(first); } LTNode* LTFind(LTNode* phead, LTDataType x) { assert(phead); LTNode* cur = phead->next; while (cur != phead) { if (cur->data == x) return cur; cur = cur->next; } return NULL; } // 在pos之前插入 void LTInsert(LTNode* pos, LTDataType x) { assert(pos); LTNode* prev = pos->prev; LTNode* newnode = BuyLTNode(x); newnode->next = pos; newnode->prev = prev; prev->next = newnode; pos->prev = newnode; } // 删除pos位置的值 void LTErase(LTNode* pos) { assert(pos); LTNode* prev = pos->prev; LTNode* next = pos->next; prev->next = next; next->prev = prev; free(pos); } void LTDestroy(LTNode* phead) { assert(phead); LTNode* cur = phead->next; while (cur != phead) { LTNode* next = cur->next; free(cur); cur = next; } free(phead); }
Test.c
#include "List.h" void TestList1() { LTNode* plist = LTInit(); LTPushBack(plist, 1); LTPushBack(plist, 2); LTPushBack(plist, 3); LTPushBack(plist, 4); LTPrint(plist); LTPopBack(plist); LTPrint(plist); LTPopBack(plist); LTPrint(plist); LTPopBack(plist); LTPrint(plist); LTPopBack(plist); LTPrint(plist); //LTPopBack(plist); //LTPrint(plist); LTDestroy(plist); plist = NULL; } void TestList2() { LTNode* plist = LTInit(); LTPushFront(plist, 5); LTPushFront(plist, 6); LTPushFront(plist, 7); LTPushFront(plist, 8); LTPrint(plist); LTPopFront(plist); LTPrint(plist); LTPopFront(plist); LTPrint(plist); LTPopFront(plist); LTPrint(plist); LTPopFront(plist); LTPrint(plist); /*LTPopFront(plist); LTPrint(plist);*/ LTDestroy(plist); plist = NULL; } void TestList3() { LTNode* plist = LTInit(); LTPushFront(plist, 1); LTPushFront(plist, 3); LTPushFront(plist, 5); LTPushFront(plist, 7); LTPrint(plist); LTNode* pos = LTFind(plist, 3); if (pos) { LTInsert(pos, 2); } LTPrint(plist); LTDestroy(plist); plist = NULL; } int main() { //TestList1(); //TestList2(); TestList3(); return 0; }