[C语言实现]带你手撕带头循环双链表

这篇具有很好参考价值的文章主要介绍了[C语言实现]带你手撕带头循环双链表。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

[C语言实现]带你手撕带头循环双链表

[C语言实现]带你手撕带头循环双链表


目录

什么是双链表?

带头结点的优势:

双链表的实现:


什么是循环双链表?

众所周知,顺序表的插入和删除有时候需要大量移动数据,并且每次开辟空间都可能会浪费大量内存和CPU资源,于是我们有了链表,我们之前已经实现了单链表,我们可以发现单链表的一个劣势——每次查找都必须从头结点开始,并且这是一个不可逆的过程,你不可以通过下一个结点找到前一个,只能通过前一个结点找到下一个。

我们将链表的结点空间不再一分为二,而是一分为三,分别是:存储数据的空间,存储下一个结点地址的空间,存储上一个结点地址的空间。这样我们就可以通过一个结点找到它的上一个结点和下一个结点了。

最后我们再将首结点的prev指向尾结点,尾结点的next指向首结点,就变成了循环双链表。

[C语言实现]带你手撕带头循环双链表

我们在此基础上,再为这个结构加入头结点。

带头结点的优势:

头结点就像是一个哨兵,一直站在第一个位置,它的data域不存储任何值,next域指向第一个有效的链表节点,prev域指向链表的尾结点。

我们为什么需要头结点?

1. 头结点可以让插入操作变得更加方便,不需要分有无结点的情况讨论,因为永远存在一个头结点

2. 头结点可以让我们函数传参的时候不需要传二级指针,因为此时不需要改变head本身。

此外还有其他优点,在之后的代码实现中我们会慢慢体会到头结点的优势。


双链表的代码实现+详细注释:

头文件:

//List.h
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>

typedef int LTDataType;
typedef struct ListNode
{
	LTDataType data;
	struct ListNode* prev;
	struct ListNode* next;
}LTNode;

LTNode* ListNodeInit(LTNode* phead);//初始化
void LTPushBack(LTNode* phead, LTDataType x);//尾插
void LTPushFront(LTNode* phead, LTDataType x);//头插
void LTPopFront(LTNode* phead);//头删
void LTPopBack(LTNode* phead);//尾删
void LTPrint(LTNode* phead);//打印 
void LTInsert(LTNode* pos, LTDataType x);//pos前一个位置的插入
void LTErase(LTNode* pos);//pos当前位置的删除
LTNode* LTFind(LTNode* phead, LTDataType x);//查找
LTNode* LTDestroy(LTNode* phead);//销毁

函数实现:文章来源地址https://www.toymoban.com/news/detail-464006.html

//List.c
#include "List.h"
LTNode* ListNodeInit(LTNode* phead)
{
    //创建头结点
    LTNode* head = (LTNode*)malloc(sizeof(LTNode));
    //防止内存开辟失败
    assert(head);
    //初始化头结点
    head->prev = head->next = head;
    //返回头结点
    return head;
}
void LTPushBack(LTNode* phead, LTDataType x)
{
    //断言 防止用户传入空指针
    assert(phead);
    //尾插
    LTNode* newnode = (LTNode*)malloc(sizeof(LTNode));
    assert(newnode);
    newnode->data = x;
    //找到尾结点
    LTNode* tail = phead->prev;
    //开始插入
    newnode->next = phead;
    phead->prev = newnode;
    tail->next = newnode;
    newnode->prev = tail;
}
void LTPushFront(LTNode* phead, LTDataType x)
{
    //断言
    assert(phead);
    //头插
    LTNode* newnode = (LTNode*)malloc(sizeof(LTNode));
    assert(newnode);
    newnode->data = x;
    //找到第一个有效节点
    LTNode* Next = phead->next;
    //开始插入
    Next->prev = newnode;
    newnode->next = Next;
    phead->next = newonde;
    newnode->prev = phead;
}
void LTPopBack(LTNode* phead)
{
    assert(phead);
    //找尾
    LTNode* tail = phead->prev;
    //判空
    if(tail == phead);
        return;
    //找到尾结点的前一个结点(倒数第二个)
    LTNode* prevTail = tail->prev;
    //删除尾结点
    prevTail->next = phead;
    phead->prev = prevTail;
    free(tail);     
}
void LTPopFront(LTNode* phead)
{
    //同上
    assert(phead);
    LTNode* del = phead->next;
    if(del == phead)
        return;
    LTNode* next = del->next;
    next->prev = phead;
    phead->next = next;
    free(del);
}
//以下两个接口需要配合查找使用 所以删除接口不需要判断是否为头结点
void LTInsert(LTNode* pos, LTDataType x)
{
    assert(pos);
    LTNode* newnode = (LTNode*)malloc(sizeof(LTNode));
    assert(newnode);
    newnode->data = x;
    LTNode* prev = pos->prev;
    //插入
    pos->prev = newnode;
    newnode->next = pos;
    newnode->prev = prev;
    prev->next = newnode;
}
void LTErase(LTNode* pos)
{  
    assert(pos);
    LTNode* prev = pos->prev;
    LTNode* next = pos->next;
    prev->next = next;
    next->prev = prev;
    free(pos);
}
LTNode* LTFind(LTNode* phead, LTDataType x)
{
    assert(phead);
    LTNode* cur = phead;
    while(cur != phead)
    {
        if(cur->data == x)
            return cur;
        cur = cur->next;
    }
    return NULL;
}
void LTPrint(LTNode* phead)
{
    assert(phead);
    LTNode* cur = phead->next;
    printf("head");
    while(cur != phead)
    {
        printf("<-%d->", cur->data);
        cur = cur->next;
    }
    printf("head\n");
}
void ListDestroy(LTNode* phead)
{
	assert(phead);
	LTNode* cur = 	phead->next;
	while(cur != phead)
	{
		LTNode* next = cur->next;
		ListErase(cur);
		cur = next;
	}
	free(phead);
}

到了这里,关于[C语言实现]带你手撕带头循环双链表的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【C语言】数据结构——带头双链表实例探究

    💗个人主页💗 ⭐个人专栏——数据结构学习⭐ 💫点击关注🤩一起学习C语言💯💫 我们在前面学习了单链表和顺序表。 今天我们来学习双向循环链表。 在经过前面的一系列学习,我们已经掌握很多知识,相信今天的内容也是很容易理解的。 关注博主或是订阅专栏,掌握第

    2024年02月03日
    浏览(44)
  • 数据结构入门(C语言版)一篇文章教会你手撕八大排序

    排序 :所谓排序,就是使一串记录,按照其中的某个或某些的大小,递增或递减的排列起来的操作。 稳定性 :假定在待排序的记录序列中,存在多个具有相同的的记录,若经过排序,这些记录的相对次序保持不变,即在原序列中,r[i]=r[j],且r[i]在r[j]之前,而

    2024年02月01日
    浏览(63)
  • 【数据结构】C语言实现双向链表(带头结点、循环)

    结点定义: 接口定义: 我们将申请结点的代码封装成函数,方便后续使用 由于是带头结点的双向链表,因此在使用链表前,我们需要对链表进行初始化。 遍历链表,值得说的是,带头结点的双向链表的循环结束条件是 cur != phead 尾插时,需要先找到尾结点,然后将新结点插

    2024年02月03日
    浏览(68)
  • 【数据结构初阶】四、线性表里的链表(带头+双向+循环 链表 -- C语言实现)

    ========================================================================= 相关代码gitee自取 : C语言学习日记: 加油努力 (gitee.com)  ========================================================================= 接上期 : 【数据结构初阶】三、 线性表里的链表(无头+单向+非循环链表 -- C语言实现)-CSDN博客  ====

    2024年02月08日
    浏览(43)
  • 【数据结构与算法分析】使用C语言实现队列的两种(带头结点与不带头结点)链式存储,并且给出一种循环队列的设计思想

      当我们编写程序时,经常需要处理各种数据结构。队列是一种常见的数据结构,它有着广泛的应用场景。队列的基本操作包括入队和出队,应用于模拟等待队列、消息队列、计算机缓存等场合。   在实际编程中,我们可以用不同的数据结构来实现队列。本文主要介绍了

    2024年02月08日
    浏览(102)
  • 【数据结构】 循环双链表的基本操作 (C语言版)

    目录 一、循环双链表 1、循环双链表的定义: 2、循环双链表的优缺点: 二、循环双链表的基本操作算法(C语言)    1、宏定义  2、创建结构体 3、循环双链表的初始化  4、循环双链表按位查找 5、循环双链表插入 6、循环双链表查找 7、循环双链表删除 8、求循环双链表长

    2024年01月22日
    浏览(53)
  • 带头结点和尾指针的循环单链表(C语言)

    头结点的定义 头结点是链表中的 第一个结点 ,其 数据域 一般无意义(有时可存放链表长度等)。 头结点目的 统一链表的操作 。使得 空表 时的操作不用 特殊处理 ,简化了链表的操作。 尾指针的定义 尾指针是 指向链表尾结点 的指针。 尾指针的作用 用来 找到整个链表

    2024年02月13日
    浏览(51)
  • 【手撕C语言 第四集】分支和循环(上)

    C语句可分为以下五类: 表达式语句 函数调用语句 控制语句 复合语句 空语句 本章后面介绍的是控制语句。 控制语句用于控制程序的执行流程,以实现程序的各种结构方式(C语言支持三种结构:顺序结构、选 择结构、循环结构),它们由特定的语句定义符组成,C语言有九

    2024年01月18日
    浏览(47)
  • 手撕双链表

    作者简介:დ旧言~,目前大一,现在学习Java,c,c++,Python等 座右铭:松树千年终是朽,槿花一日自为荣。 望小伙伴们点赞👍收藏✨加关注哟💕💕          前面我们已经学习了顺序表和单链表,顺序表可以存储动态的数据,但是一旦元素过少,而又要开辟空间,这样就

    2024年02月07日
    浏览(40)
  • 史上最详细的红黑树讲解(一篇文章教你手撕红黑树)

           🔥🔥 欢迎来到小林的博客!!       🛰️博客主页:✈️小林爱敲代码       🛰️博客专栏:✈️数据结构与算法       🛰️欢迎关注:👍点赞🙌收藏✍️留言       今天给大家讲解红黑树,和AVL树一样,这章暂且不讲删除。

    2024年01月16日
    浏览(40)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包