C语言手把手带你掌握带头双向循环链表

作者:平凡的人1 时间:2023-01-14 16:52:59 

前言

关于链表这一块,写了多篇博客,学习了顺序表、单链表、及其一些练习题

顺序表:传送门:顺序表

单链表:传送门:单链表1   链表2

链表OJ:传送门:链表OJ

今天,我又来水一水博客, 介绍关于双链表。

带头双向循环链表的结构

实际上,单链表也存在一个比较大的缺陷:

1.不能从后往前遍历

2.无法找到前驱

 除了单链表之外,我们自然还有双向链表,我们要说的就是带头双向循环链表,简单理解为:带头结点的,有两个方向的。循环的。结构图如下:

C语言手把手带你掌握带头双向循环链表

结构虽然比较复杂,但是极大方便我们找结点,比如可以直接找到尾结点,然后再进入相关的操作。实际代码的操作将会比单链表简单,极为方便,这里不做过多说明,直接上手代码

代码操作

我们直奔主题,进入代码实现的操作,之前的操作如果理解了,那我相信这个对于你来说肯定是不难的。下面直接给出源码:

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;
}

来源:https://blog.csdn.net/weixin_60478154/article/details/124092194

标签:C语言,带头,双向,循环,链表
0
投稿

猜你喜欢

  • Unity3D撤回命令开发详解

    2022-01-15 09:26:21
  • MybatisPlus #{param}和${param}的用法详解

    2023-02-02 13:08:10
  • java中transient关键字用法分析

    2022-01-22 04:27:05
  • Spring在SingleTon模式下的线程安全详解

    2021-10-08 11:39:31
  • Java中的对称加密详解

    2023-09-30 12:17:16
  • Spring Cache和EhCache实现缓存管理方式

    2023-01-17 01:44:40
  • Javassist用法详解

    2023-06-26 17:11:54
  • Android实现语音播放与录音功能

    2022-01-21 15:39:09
  • C#通过反射创建自定义泛型

    2022-12-30 07:12:38
  • string boot 与 自定义interceptor的实例讲解

    2023-10-27 17:03:20
  • C++如何调用已经写好的C接口

    2021-10-16 10:16:14
  • Springboot Vue可配置调度任务实现示例详解

    2023-11-09 03:33:19
  • Java实现将每日新闻添加到自己博客中

    2023-02-08 16:20:43
  • Android中的全局变量与局部变量使用小结

    2023-12-07 10:11:49
  • 一文探寻Java装箱和拆箱的奥妙

    2022-08-15 21:41:21
  • C# 输出参数out问题

    2023-02-27 00:19:32
  • WinForm项目中添加帮助文档功能

    2022-12-30 02:22:50
  • java8 利用reduce实现将列表中的多个元素的属性求和并返回操作

    2021-09-29 06:53:38
  • 浅谈C#单例模式的实现和性能对比

    2022-10-29 10:46:30
  • C#中使用闭包与意想不到的坑详解

    2022-08-15 00:13:58
  • asp之家 软件编程 m.aspxhome.com