数据结构 | 带头双向循环链表专题

数据结构 | 带头双向循环链表专题

前言

前面我们学了单链表,我们这次来看一个专题带头的双向循环链表~~

文章目录

  • 数据结构 | 带头双向循环链表专题
  • 前言
    • 带头双向循环链表的结构
    • 实现双向链表
      • 头文件的定义
      • 哨兵位初始化
      • 创建节点
      • 尾插
      • 尾删
      • 头插
      • 头删
      • 打印
      • 查找
      • 指定位置前插入
      • 删除指定位置
      • 销毁链表
      • List.h
      • List.c

带头双向循环链表的结构

在这里插入图片描述

  • 注意:这里的“带头”跟前面我们说的“头节点”是两个概念,实际前面的在单链表阶段称呼不严
    谨,但是为了同学们更好的理解就直接称为单链表的头节点。
  • 带头链表里的头节点,实际为“哨兵位”,哨兵位节点不存储任何有效元素,只是站在这里“放哨
    的”

哨兵位存在的意义:

  • 遍历循环链表避免死循环。

  • 每个节点有三部分内容:
    • 保存数据的val
    • 保存下一个节点的地址next指针
    • 保存前一个节点的地址prev指针

实现双向链表

我们需要实现以下功能

头文件的定义

List.h

#pragma once
#include<stdio.h>
#include<stdlib.h>
#include<assert.h>// 带头+双向+循环链表增删查改实现
typedef int LTDataType;
typedef struct ListNode
{LTDataType _val;struct ListNode* _next;struct ListNode* _prev;
}ListNode;//哨兵位初始化
ListNode* ListInit();// 创建返回链表的头结点.
ListNode* ListCreate(ListNode* pHead);
// 双向链表销毁
void ListDestory(ListNode* pHead);
// 双向链表打印
void ListPrint(ListNode* pHead);
// 双向链表尾插
void ListPushBack(ListNode* pHead, LTDataType x);
// 双向链表尾删
void ListPopBack(ListNode* pHead);
// 双向链表头插
void ListPushFront(ListNode* pHead, LTDataType x);
// 双向链表头删
void ListPopFront(ListNode* pHead);
// 双向链表查找
ListNode* ListFind(ListNode* pHead, LTDataType x);
// 双向链表在pos的前面进行插入
void ListInsert(ListNode* pos, LTDataType x);
// 双向链表删除pos位置的节点
void ListErase(ListNode* pos);

哨兵位初始化

  • 这里我们初始化成-1代表是哨兵位,然后让前驱指针和next指针指向自己
ListNode* ListInit()
{ListNode* pHead = ListCreate(-1);pHead->_next = pHead;pHead->_prev = pHead;return pHead;
}

创建节点

  • malloc一个节点,然后让新节点的next和prev赋值为空,将值给了val,最后返回空间
ListNode* ListCreate(LTDataType* x)
{ListNode* newnode = (ListNode*)malloc(sizeof(ListNode));if (newnode == NULL){perror("malloc fail!\n");exit(-1);}newnode->_val = x;newnode->_next = NULL;newnode->_prev = NULL;return newnode;
}

尾插

void ListPushBack(ListNode* pHead, LTDataType x)
{assert(pHead);ListNode* tail = pHead->_prev;ListNode* newnode = ListCreate(x);// phead   tail   newnodetail->_next = newnode;newnode->_prev = tail;newnode->_next = pHead;pHead->_prev = newnode;
}

尾删

void ListPopBack(ListNode* pHead)
{assert(pHead);assert(pHead->_next != pHead);ListNode* tail = pHead->_prev;ListNode* tailprev = tail->_prev;free(tail);tailprev->_next = pHead;pHead->_prev = tailprev;
}

头插

void ListPushFront(ListNode* pHead, LTDataType x)
{assert(pHead);ListNode* cur = pHead->_next;ListNode* newnode = ListCreate(x);pHead->_next = newnode;newnode->_prev = pHead;newnode->_next = cur;cur->_prev = newnode;
}

头删

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 ListPrint(ListNode* pHead)
{ListNode* tail = pHead->_next;printf("哨兵位->");while (tail != pHead){printf("%d->", tail->_val);tail = tail->_next;}printf("NULL\n");
}

查找

ListNode* ListFind(ListNode* pHead, LTDataType x)
{assert(pHead);ListNode* cur = pHead->_next;while (cur != pHead){if (cur->_val == x){return cur;}cur = cur->_next;}return NULL;
}

指定位置前插入

void ListInsert(ListNode* pos, LTDataType x)
{assert(pos);ListNode* newnode = ListCreate(x);ListNode* prev = pos->_prev;prev->_next = newnode;newnode->_prev = prev;pos->_prev = newnode;newnode->_next = pos;
}

删除指定位置

void ListErase(ListNode* pos)
{assert(pos);ListNode* prev = pos->_prev;ListNode* next = pos->_next;prev->_next = next;next->_prev = prev;free(pos);pos = NULL;
}

销毁链表

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

List.h

#pragma once#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
#include<stdbool.h>typedef int LTDataType;typedef struct ListNode {LTDataType val;struct ListNode* next;struct ListNode* prev;
}LTNode;//初始化哨兵位
LTNode* LTInit();
//创建节点
LTNode* LTcreate(LTDataType x);
//销毁
void LTDestroy(LTNode* phead);
//打印
void LTPrint(LTNode* phead);
//判断是否为空
bool LTEmpty(LTNode* phead);
//尾插
void LTPushBack(LTNode* phead, LTDataType x);
//尾删
void LTPopBack(LTNode* phead);
//头插
void LTPushFront(LTNode* phead, LTDataType x);
//头删
void LTPopFront(LTNode* phead);
//指定位置插入
void LTInsert(LTNode* pos, LTDataType x);
//指定位置删除
LTNode* LTErase(LTNode* pos);
//查找
LTNode* LTFind(LTNode* phead, LTDataType x);

List.c

#define _CRT_SECURE_NO_WARNINGS 1#include"List.h"//初始化哨兵位
LTNode* LTInit()
{LTNode* phead = LTcreate(-1);phead->next = phead;phead->prev = phead;return phead;
}
//创建节点
LTNode* LTcreate(LTDataType x)
{LTNode* newnode = (LTNode*)malloc(sizeof(LTNode));if (newnode == NULL){perror("malloc fail!\n");exit(-1);}newnode->next = NULL;newnode->prev = NULL;newnode->val = x;return newnode;
} //销毁
void LTDestroy(LTNode* phead);
//打印
void LTPrint(LTNode* phead)
{assert(phead);printf("哨兵位<->");LTNode* cur = phead->next;while (cur != phead){printf("%d<->", cur->val);cur = cur->next;}printf("\n");
}
//判断是否为空
bool LTEmpty(LTNode* phead)
{assert(phead);return phead->val == 0;
}//尾插
void LTPushBack(LTNode* phead, LTDataType x)
{assert(phead);LTNode* newnode = LTcreate(x);LTNode* tail = phead->prev;tail->next = newnode;newnode->prev = tail;newnode->next = phead;phead->prev = newnode;
}//尾删
void LTPopBack(LTNode* phead)
{assert(phead);LTNode* tail = phead->prev;LTNode* tailprev = tail->prev;free(tail);tail = NULL;tailprev->next = phead;phead->prev = tailprev;
}
//头插
void LTPushFront(LTNode* phead, LTDataType x)
{assert(phead);LTNode* newnode = LTcreate(x);LTNode* cur = phead->next;phead->next = newnode;newnode->prev = phead;cur->prev = newnode;newnode->next = cur;
}
//头删
void LTPopFront(LTNode* phead)
{assert(phead);LTNode* first = phead->next;LTNode* second = first->next;free(first);phead->next = second;second->prev = phead;
}//查找
LTNode* LTFind(LTNode* phead, LTDataType x)
{assert(phead);LTNode* cur = phead->next;while (cur != phead){if (cur->val == x){return cur;}cur = cur->next;}return NULL;
}//指定位置的前面插入
void LTInsert(LTNode* pos, LTDataType x)
{assert(pos);LTNode* newnode = LTcreate(x);LTNode* posprev = pos->prev;posprev->next = newnode;newnode->prev = posprev;newnode->next = pos;pos->prev = newnode;}
//指定位置删除
LTNode* LTErase(LTNode* pos)
{assert(pos);LTNode* posprev = pos->prev;LTNode* posnext = pos->next;free(pos);posprev->next = posnext;posprev = posprev;
}
  • 顺序表和双向链表的分析
不同点顺序表链表(单链表)
存储空间上物理上一定连续逻辑上连续,但物理上不一定连续
随机访问支持O(1)不支持:O(N)
任意位置插入或者删除元素可能需要搬移元素,效率低O(N)只需修改指针指向
插入动态顺序表,空间不够时需要扩容没有容量的概念
应用场景元素高效存储+频繁访问任意位置插入和删除频繁

好了,双向链表就到这里结束了,有用的话点个赞吧~~

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/142522.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

揭秘视频号创作者分成计划,带你玩赚视频号流量主,保姆级教程

项目介绍 今天给大家分享一个视频号流量主的一个项目&#xff0c;也就是视频号创作者广告分成计划。这个项目在目前来说是一个蓝海赛道&#xff0c;做的人是比较少&#xff0c;作为副业来说还是非常适合个人来做的。如果大家有工作室的话&#xff0c;也可以进行批量操作&#…

在mac上使用jmap -heap命令报错:Attaching to process ID 96530, please wait...

在mac上执行命令jmap -heap 96530 报错&#xff1a; Attaching to process ID 96530, please wait... ERROR: attach: task_for_pid(96530) failed: (os/kern) failure (5) Error attaching to process: sun.jvm.hotspot.debugger.DebuggerException: Cant attach to the proc…

nginx安装搭建

下载 免费开源版的官方网站&#xff1a;nginx news Nginx 有 Windows 版本和 Linux 版本&#xff0c;但更推荐在 Linux 下使用 Nginx&#xff1b; 下载nginx-1.14.2.tar.gz的源代码文件&#xff1a;wget http://nginx.org/download/nginx-1.14.2.tar.gz 我的习惯&#xff0…

【Go入门】面向对象

【Go入门】面向对象 前面两章我们介绍了函数和struct&#xff0c;那你是否想过函数当作struct的字段一样来处理呢&#xff1f;今天我们就讲解一下函数的另一种形态&#xff0c;带有接收者的函数&#xff0c;我们称为method method 现在假设有这么一个场景&#xff0c;你定义…

蓝桥杯之模拟与枚举day1

发现更多的计算机知识&#xff0c;欢迎访问xiaocr的个人网站 Question1卡片(C/CA组第一题) 这个是一道简单的模拟枚举题目&#xff0c;只要把对应每次的i的各个位都提取出来&#xff0c;然后对应的卡片数目减去1即可。属于打卡题目。注意for循环的特殊使用即可 #include <…

【毕业论文】基于微信小程序的植物分类实践教学系统的设计与实现

基于微信小程序的植物分类实践教学系统的设计与实现https://download.csdn.net/download/No_Name_Cao_Ni_Mei/88519758 基于微信小程序的植物分类实践教学系统的设计与实现 Design and Implementation of Plant Classification Practical Teaching System based on WeChat Mini…

【10套模拟】【4】

关键字&#xff1a; 二分查找比较次数、*广义表头尾链表存储、森林转二叉树、链地址法哈希表、交换所有子树、创建二叉排序树

Mysql Explain工具介绍

使用EXPLAIN关键字可以模拟优化器执行SQL语句&#xff0c;分析查询语句或是结构的性能瓶颈。 准备表 -- 课程表 CREATE TABLE class (id int(11) NOT NULL,name varchar(45) DEFAULT NULL,update_time datetime DEFAULT NULL,PRIMARY KEY (id)) ENGINEInnoDB DEFAULT CHARSET…

【Axure】axure rp 导入元件库和使用,主流元件库下载使用

vant 元件库下载&#xff1a;Vant4 设计资源 element UI 元件库下载&#xff1a;element ui 设计资源 Andt Design Vue 下载设计资源&#xff1a;Andt Design Vue Andt Design Pro下载设计资源&#xff1a;Andt Design Pro Arco Design 设计资源&#xff1a;Arco Design …

Ubuntu环境下为串口设置别名

本文介绍Ubuntu环境下为串口设置别名。 Ubuntu环境下&#xff0c;有时候开发调试会使用到USB转串口&#xff0c;本文介绍在不同使用场景下为串口设置别名的方法。主要分为绑定设备ID和绑定USB端口号。 1.绑定设备ID 绑定设备ID适用于USB转串口的设备ID唯一的情况&#xff0c…

SQL-----STUDENT

【学生信息表】 【宿舍信息表】 【宿舍分配表】 为了相互关联&#xff0c;我们需要在表中添加外键。在宿舍分配表中添加用于关联学生信息表的外键 student_id&#xff0c;以及用于关联宿舍信息表的外键 dormitory_id&#xff1b; sql代码 -- 创建学生信息表 CREATE TABLE st…

key的性能保障,事件处理器,表单控件等介绍

4-2key设置-性能的保障 不能修改原数组的方法,如果想要修改原数组,就进行重新赋值 this.items this.items.filter((item) > item.message.match(/Foo/)) keyCode键的值**key设置-性能的保障**提高性能,可以对比老的虚拟dom,一样的就留着,不一样就补上Vue默认按照"就地…

美团拼图滑块

有时候放弃也是一种智慧。 就像这说的一样&#xff0c;美团的拼图滑块&#xff0c;不知道这个缺口该怎么去处理&#xff0c;正常划顶到最外面去了&#xff0c;所以就不知道这个是咋计算的。 先来看看他的这个加密&#xff0c;跟原来的一划到底其实是一样的&#xff0c;难度只是…

一例plugx样本的分析(AcroRd32cWP)

这是一例plugx的样本&#xff0c;使用了一个合法签名的程序 &#xff0c;使用侧加载的方式加载一个恶意的dll&#xff0c;解密一个dat文件来&#xff0c;在内存中执行一个反射型dll来完成恶意功能。 这个病毒会使用摆渡的方式的来窃取内网的文档数据&#xff0c;具有严重的失泄…

【FastCAE源码阅读9】鼠标框选网格、节点的实现

一、VTK的框选支持类vtkInteractorStyleRubberBandPick FastCAE的鼠标事件交互类是PropPickerInteractionStyle&#xff0c;它扩展自vtkInteractorStyleRubberBandPick。vtkInteractorStyleRubberBandPick类可以实现鼠标框选物体&#xff0c;默认情况下按下键盘r键开启框选模式…

【JVM】类加载器 Bootstrap、Extension、Application、User Define 以及 双亲委派

以下环境为 jdk1.8 两大类 分类成员语言继承关系引导类加载器bootstrap 引导类加载器C/C无自定义类加载器extension 拓展类加载器、application 系统/应用类加载器、user define 用户自定义类加载器Java继承于 java.lang.ClassLoader 四小类 Bootstrap 引导类加载器 负责加…

Jenkins的介绍与相关配置

Jenkins的介绍与配置 一.CI/CD介绍 &#xff11;.CI/CD概念 ①CI 中文意思是持续集成 (Continuous Integration, CI) 是一种软件开发流程&#xff0c;核心思想是在代码库中的每个提交都通过自动化的构建和测试流程进行验证。这种方法可以帮助团队更加频繁地交付软件&#x…

【教3妹学编辑-mysql】mybatis查询条件遇到的坑及解决方案

2哥 :3妹&#xff0c;今天怎么下班这么晚啊。 3妹&#xff1a;嗨&#xff0c;别提了&#xff0c;今天线上出bug了&#xff0c; 排查了好久。 2哥&#xff1a;啊&#xff0c;什么问题呀&#xff1f; 3妹&#xff1a;我们内部的一个管理系统报错了&#xff0c; 最近排查下来是myb…

AR工业眼镜:智能化生产新时代的引领者!!

科技飞速发展&#xff0c;人工智能与增强现实&#xff08;AR&#xff09;技术结合正在改变生活工作方式。AR工业眼镜在生产领域应用广泛&#xff0c;具有实时信息展示、智能导航定位、远程协作培训、智能安全监测等功能&#xff0c;提高生产效率、降低操作风险&#xff0c;为企…

dolphinscheduler

架构说明 MasterServer MasterServer采用分布式无中心设计理念&#xff0c;MasterServer主要负责 DAG 任务切分、任务提交监控&#xff0c;并同时监听其它MasterServer和WorkerServer的健康状态。 MasterServer服务启动时向Zookeeper注册临时节点&#xff0c;通过监听Zookeep…