双向带头循环链表:结构复杂,操作简单
0.结构体定义
这里方便浏览,特地没有将int类型重命名为TLDateType
#define _CRT_SECURE_NO_WARNINGS 1 #pragma once #include<stdio.h> #include<stdlib.h> #include<assert.h> #include<stdbool.h> struct ListNode { int val; struct ListNode* prev; struct ListNode* next; };
1.初始化
- 带头需要初始化一个哨兵位头结点
- 传二级指针
- 初始化自己的prev和next都指向自己
void ListInit(struct ListNode** pphead) { struct ListNode* Guard = (struct ListNode*)malloc(sizeof(struct ListNode)); if (Guard == NULL) { perror("ListInit"); return; } *pphead = Guard; Guard->next = Guard; Guard->prev = Guard; }
2.尾插
- 一级指针
- 直接prev找尾
- 即是无首元结点,也可(头结点自环)
struct ListNode* BuyListNode(int x) { struct ListNode* newnode = (struct ListNode*)malloc(sizeof(struct ListNode)); if (newnode == NULL) { perror("BuySListNode"); return NULL; } newnode->val = x; newnode->prev = NULL; newnode->next = NULL; return newnode; } void ListPushBack(struct ListNode* phead,int x) { assert(phead); struct ListNode* newnode = BuyListNode(x); struct ListNode* tail = phead->prev; newnode->next = phead; phead->prev = newnode; tail->next = newnode; newnode->prev = tail; }
3.打印
- 可assert断言(建议单链表不用断言)---头结点
- 起始条件cur=phead->next;
- 循环终止条件cur==phead
void ListPrint(struct ListNode* phead) { assert(phead); struct ListNode* cur = phead->next; while (cur != phead) { printf("%d->", cur->val); cur = cur->next; } printf("NULL\n"); }
4.头插
- 一级指针
- 即是无首元结点,也可(头结点自环)
void ListPushFront(struct ListNode* phead,int x) { assert(phead); struct ListNode* newnode = BuyListNode(x); struct ListNode* next = phead->next; newnode->next = next; next->prev = newnode; phead->next = newnode; newnode->prev = phead; }
5.任意位置插入前面位置
- 因为有prev,前插不同phead
- 尾插,头插就用ListInsert传不同pos参数
- 如果pos传phead,就相当于于是尾插
- 如果pos传phead->next,就相当于于是头插
void ListInsert(struct ListNode* pos, int x) { assert(pos); struct ListNode* newnode = BuyListNode(x); struct ListNode* prev = pos->prev; prev->next = newnode; newnode->prev = prev; newnode->next = pos; pos->prev = newnode; } 头插:ListNode(phead->next,x); 尾插:ListNode(phead,x);
6.尾删
- 不为空,!ListEmpty(plhead)
- prev,tail,phead
bool ListEmpty(struct ListNode* phead) { return phead->next == phead; } void ListPopBack(struct ListNode* phead) { assert(phead); assert(!ListEmpty(phead)); struct ListNode* tail = phead->prev; struct ListNode* prev = tail->prev; prev->next = phead; phead->prev = prev; free(tail); tail = NULL; }
7.头删
- 不为空,!ListEmpty(plhead)
- phead,first,second
void ListPopFront(struct ListNode* phead) { assert(phead); assert(!ListEmpty(phead)); struct ListNode* first = phead->next; struct ListNode* second = first->next; phead->next = second; second->prev = phead; free(first); first = NULL; }
8.链表长度
- 起始条件:cur=phead->next
- 终止条件:cur!=phead;
size_t ListSize(struct ListNode* phead) { size_t size = 0; struct ListNode* cur = phead->next; while (cur != phead) { ++size; cur = cur->next; } return size; }
9.任意位置删除当前位置
- 不为空,!ListEmpty(plhead)
- 尾删,头删就用ListErase传不同pos参数
- 如果pos传phead->prev,就是尾删
- 如果pos传phead->next,就是头删
void ListErase(struct ListNode* pos) { assert(pos); struct ListNode* prev = pos->prev; struct ListNode* next = pos->next; prev->next = next; next->prev = prev; free(pos); pos = NULL; }
10. 销毁
- 看是否保留哨兵头,来传一级或二级指针
- 先保留哨兵头作为判断循环条件,最后决定是否释放哨兵头
void ListDestory(struct ListNode** pphead) { assert(pphead); struct ListNode* cur = (*pphead)->next; while (cur != *pphead) { struct ListNode* next = cur->next; free(cur); cur = next; } free(*pphead); *pphead = NULL; }