C语言手把手带你掌握带头双向循环链表
作者:平凡的人1
带头双向循环链表:结构最复杂,一般用在单独存储数据。实际中使用的链表数据结构,都是带头双向循环链表。另外这个结构虽然结构复杂,但是使用代码实现以后会发现结构会带来很多优势,实现反而简单
前言
关于链表这一块,写了多篇博客,学习了顺序表、单链表、及其一些练习题
顺序表:传送门:顺序表
链表OJ:传送门:链表OJ
今天,我又来水一水博客, 介绍关于双链表。
带头双向循环链表的结构
实际上,单链表也存在一个比较大的缺陷:
1.不能从后往前遍历
2.无法找到前驱
除了单链表之外,我们自然还有双向链表,我们要说的就是带头双向循环链表,简单理解为:带头结点的,有两个方向的。循环的。结构图如下:
结构虽然比较复杂,但是极大方便我们找结点,比如可以直接找到尾结点,然后再进入相关的操作。实际代码的操作将会比单链表简单,极为方便,这里不做过多说明,直接上手代码
代码操作
我们直奔主题,进入代码实现的操作,之前的操作如果理解了,那我相信这个对于你来说肯定是不难的。下面直接给出源码:
List.h
#pragma once #include <stdio.h> #include <stdlib.h> #include <malloc.h> #include <assert.h> #include <stdbool.h> typedef int LTDataType; //带头双向循环--最优链表结构,在任意位置插入删除数据都是O(1) typedef struct listNode { struct ListNode* next; struct ListNode* prev; LTDataType data; }ListNode; //初始化 ListNode*ListInit(); //销毁 void ListDestory(ListNode* phead); //打印 void ListPrint(ListNode* phead); //尾插 void ListPushBack(ListNode* phead, LTDataType x); //头插 void ListPushFront(ListNode* phead, LTDataType x); //头删 void ListPopFront(ListNode* phead); //尾删 void ListPopBack(ListNode* phead); ListNode* ListFind(ListNode* phead, LTDataType x); //在pos位置之前插入x void ListInsert(ListNode* pos, LTDataType x); //删除pos位置的值 void ListErase(ListNode* pos);
List.c
#include "List.h" //开辟一个新结点 ListNode* BuyListNode(LTDataType x) { ListNode* newnode =(ListNode*)malloc(sizeof(ListNode)); newnode->data = x; newnode->next = NULL; newnode->prev = NULL; return newnode; } //初始化 ListNode* ListInit() { ListNode*phead = BuyListNode(0); phead->next = phead; phead->prev = phead; return phead; } //销毁 void ListDestory(ListNode* phead) { assert(phead); ListNode* cur = phead->next; while (cur != phead) { ListNode* next = cur->next; free(cur); cur = next; } free(phead); phead = NULL; } //打印 void ListPrint(ListNode* phead) { ListNode* cur = phead->next; while (cur != phead) { printf("%d ", cur->data); cur = cur->next; } printf("\n"); } //尾插 void ListPushBack(ListNode* phead, LTDataType x) { assert(phead); ListNode* tail = phead->prev; ListNode* newnode = BuyListNode(x); tail->next = newnode; newnode->prev = tail; newnode->next = phead; phead->prev = newnode; } //头插 void ListPushFront(ListNode* phead, LTDataType x) { assert(phead); ListNode* first = phead->next; ListNode* newnode = BuyListNode(x); newnode->next = first; first->prev = newnode; phead->next = newnode; newnode->prev = phead; } //头删 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; } //尾删 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; } 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; } //在pos位置之前插入x void ListInsert(ListNode* pos, LTDataType x) { assert(pos); ListNode* prev = pos->prev; ListNode* newnode = BuyListNode(x); prev->next = newnode; newnode->prev = prev; newnode->next = pos; pos->prev = newnode; } //删除pos位置的值 void ListErase(ListNode* pos) { assert(pos); ListNode* prev = pos->prev; ListNode* next = pos->next; prev->next = next; next->prev = prev; free(pos); }
Test.c
#include "List.h" void TestList1() { ListNode* plist = ListInit(); ListPushBack(plist, 1); ListPushBack(plist, 2); ListPushBack(plist, 3); ListPushBack(plist, 4); ListPrint(plist); ListPushFront(plist, 0); ListPushFront(plist, -1); ListPrint(plist); ListPopFront(plist); ListPopFront(plist); ListPopFront(plist); ListPrint(plist); ListPopBack(plist); ListPrint(plist); } void TestList2() { ListNode* plist = ListInit(); ListPushBack(plist, 1); ListPushBack(plist, 2); ListPushBack(plist, 3); ListPushBack(plist, 4); ListPrint(plist); ListNode* pos = ListFind(plist, 3); if (pos) { pos->data *= 10; printf("找到了,并且*10\n"); } else { printf("没找到\n"); } ListPrint(plist); ListInsert(pos, 300); ListPrint(plist); ListErase(pos); ListPrint(plist); } int main() { TestList2(); return 0; }
到此这篇关于C语言手把手带你掌握带头双向循环链表的文章就介绍到这了,更多相关C语言带头双向循环链表内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!