带头双向循环链表的实现

目录

认识带头双向循环链表 

双向链表

循环链表

带头链表

带头双向循环链表

双向链表的优势和不足:

顺序表的优势和不足: 

实现带头双向循环链表

创建带头双向循环链表

 初始化

创建返回链表的头结点

打印链表

 尾插

尾删

头插

头删

查找

在pos位置前插入

删除pos位置

销毁

总代码

ListNode.h

ListNode.c

test.c


认识带头双向循环链表 

双向链表

我们之前认学习的单链表,是包含一个next指针指向下一个结点,而双向链表既有next指针,又有一个前指针指向前一个结点

循环链表

循环链表就是最后一个结点的next不指向NULL,指向第一个结点

带头链表

带头链表就是带哨兵位的头结点head,头结点不存数据

带头双向循环链表

  1. 无头单向非循环链表结构简单,一般不会单独用来存数据。实际中更多是作为其他数据结构的子结构,如哈希桶、图的邻接表等等。另外这种结构在笔试面试中出现很多。
  2. 带头双向循环链表结构最复杂,一般用在单独存储数据。实际中使用的链表数据结构,都是带头双向循环链表。另外这个结构虽然结构复杂,但是使用代码实现以后会发现结构会带来很多优势,实现反而简单

双向链表的优势和不足:

双向链表的优势

  • 任意位置插入删除都是O(1)
  • 按需申请释放,合理利用空间,不存在浪费

问题

  • 下标的随机访问不方便O(N)

顺序表的优势和不足: 

顺序表的优势

  • 支持下标的随机访问O(1)

问题

  • 头插或中间插入的效率低O(N)
  • 空间不够需要扩容,有一定的消耗,且可能存在一定的空间浪费
  • 只适合尾插尾删

实现带头双向循环链表

同样我们创建三个文件来实现:

创建带头双向循环链表

我们在结构体中定义val存数据,prev指向前一个结点,next指向下一个结点

 初始化

让phead->next和phead->prev都指向phead,给phead->val赋值为-1,最后返回phead

创建返回链表的头结点

打印链表

 尾插

尾删

头插

头删

头结点不能删!!!

所以我们要assert(phead->next != phead)

查找

在pos位置前插入

特殊情况:

  • LTInsert(phead->next,x)就是头插
  • LTInsert(phead,x)就是尾插

删除pos位置

特殊情况:

  • LTErase(phead->next)就是头删
  • LTErase(phead->prev)就是尾删

销毁

总代码

ListNode.h

#pragma once
#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
typedef int LTDataType;
typedef struct ListNode
{LTDataType val;struct ListNode* prev;struct ListNode* next;
}LTNode;//初始化
LTNode* LTInit();
//创建返回链表的头结点.
LTNode* CreateLTNode(LTDataType x);
//打印
void LTPrint(LTNode* phead);//尾插
void LTPushBack(LTNode* phead, LTDataType x);
//尾删
void LTPopBack(LTNode* phead);
//头插
void LTPushFront(LTNode* phead, LTDataType x);
//头删
void LTPopFront(LTNode* phead);
//查找
LTNode* LTFind(LTNode* phead, LTDataType x);
//在pos位置前插入
void LTInsert(LTNode* pos, LTDataType x);
//删除pos位置
void LTErase(LTNode* pos);
//销毁
void LTDestroy(LTNode* phead);

ListNode.c

#define _CRT_SECURE_NO_WARNINGS 1
#include"ListNode.h"
//初始化
LTNode* LTInit()
{LTNode* phead = CreateLTNode(-1);phead->next = phead;phead->prev = phead;return phead;
}
//创建返回链表的头结点.
LTNode* CreateLTNode(LTDataType x)
{LTNode* newnode = (LTNode*)malloc(sizeof(LTNode));if (newnode == NULL){perror("malloc fail");exit(-1);}newnode->val = x;newnode->next = NULL;newnode->prev = NULL;return newnode;
}
//打印
void LTPrint(LTNode* phead)
{assert(phead);LTNode* cur = phead->next;printf("哨兵位");while (cur != phead){printf("%d<=>", cur->val);cur = cur->next;}printf("哨兵位\n");
}
//尾插
void LTPushBack(LTNode* phead, LTDataType x)
{assert(phead);LTNode* tail = phead->prev;LTNode* newnode = CreateLTNode(x);tail->next = newnode;newnode->prev = tail;phead->prev = newnode;newnode->next = phead;
}
//尾删
void LTPopBack(LTNode* phead)
{assert(phead);assert(phead->next != phead);LTNode* tail = phead->prev;LTNode* tailPrev = tail->prev;free(tail);tailPrev->next = phead;phead->prev = tailPrev;
}
//头插
void LTPushFront(LTNode* phead, LTDataType x)
{assert(phead);LTNode* newnode = CreateLTNode(x);LTNode* first = phead->next;newnode->next = first;first->prev = newnode;phead->next = newnode;newnode->prev = phead;
}
//头删
void LTPopFront(LTNode* phead)
{assert(phead);assert(phead->next != phead);LTNode* first = phead->next;LTNode* second = first->next;phead->next = second;second->prev = phead;free(first);first = NULL;
}
//查找
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;
}
//在pos位置前插入
void LTInsert(LTNode* pos, LTDataType x)
{assert(pos);LTNode* newnode = CreateLTNode(x);LTNode* posprev = pos->prev;posprev->next = newnode;newnode->prev = posprev;newnode->next = pos;pos->prev = newnode;
}
//删除pos位置
void LTErase(LTNode* pos)
{assert(pos);LTNode* posprev = pos->prev;LTNode* posnext = pos->next;posprev->next = posnext;posnext->prev = posprev;free(pos);pos = NULL;
}
//销毁
void LTDestroy(LTNode* phead)
{assert(phead);LTNode* cur = phead->next;while (cur != phead){LTNode* next = cur->next;free(cur);cur = next;}free(phead);phead = NULL;
}

test.c

#define _CRT_SECURE_NO_WARNINGS 1
#include"ListNode.h"
int main()
{LTNode* plist = LTInit();//尾插LTPushBack(plist, 1);LTPushBack(plist, 2);LTPushBack(plist, 3);LTPushBack(plist, 4);LTPrint(plist);//尾删LTPopBack(plist);LTPrint(plist);//头插LTPushFront(plist, 0);LTPrint(plist);//头删LTPopFront(plist);LTPrint(plist);//查找 pos前插LTNode* pos = LTFind(plist, 3);LTInsert(pos, 3);LTPrint(plist);//删除pos位置LTErase(pos);LTPrint(plist);//销毁LTDestroy(plist);return 0;
}

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

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

相关文章

java小游戏之【王者荣耀】

首先创建一个新的Java项目命名为“王者荣耀”&#xff0c;并在src下创建两个包分别命名为“com.sxt"、”com.stx.beast",在相应的包中创建所需的类。 代码 package com.sxt;import javax.swing.*; import java.awt.*;public class Background extends GameObject {p…

android shape绘制半圆

<?xml version"1.0" encoding"utf-8"?><shape xmlns:android"http://schemas.android.com/apk/res/android"android:shape"rectangle"><sizeandroid:width"20dp"android:height"10dp" /><…

【全栈开发】RedwoodJS与BlitzJS:全栈JavaScript元框架的未来

Redwood和Blitz是两个即将出现的全栈元框架&#xff0c;它们提供了创建SPAs、服务器端渲染页面和静态生成内容的工具&#xff0c;并提供了生成端到端支架的CLI。我一直在等待一个有价值的Rails JavaScript替代品&#xff0c;谁知道什么时候。这篇文章是对两者的概述&#xff0c…

opencv-利用DeepLabV3+模型进行图像分割去除输入图像的背景

分离图像中的人物和背景通常需要一些先进的图像分割技术。GrabCut是一种常见的方法&#xff0c;但是对于更复杂的场景&#xff0c;可能需要使用深度学习模型。以下是使用深度学习模型&#xff08;如人像分割模型&#xff09;的示例代码&#xff1a; #导入相关的库 import cv2 …

[C++]指针与结构体

标题 一.指针1.指针的定义和使用2.指针所占的内存空间3.空指针与野指针4.const修饰指针5.指针和数组6.指针和函数 二.结构体1.结构体的定义与使用2.结构体数组3.结构体指针4.结构体的嵌套使用5.结构体做函数参数6.结构体中const使用场景7.案例练习 一.指针 作用: 可以通过指针…

FPGA驱动CS4344 VHDL例程

CS4344是一款非常简单的I2S立体声24bit D/A芯片&#xff0c;采样率高达192KHz&#xff0c;相对于ADAU1761复杂的寄存器配置来说&#xff0c;CS4344非常友好&#xff0c;无需配置寄存器&#xff0c;只要按I2S时序输入数据&#xff0c;即可实现立体声输出&#xff0c;且10PIN TSS…

SpringBoot 拦截器高级篇

Springboot 拦截器 定义使用场景拦截器与过滤器的区别实现步骤全局拦截器的局限性全局拦截器VS局部拦截器局部拦截器自定义局部拦截器使用多个局部拦截器 定义 拦截器是Spring MVC框架中的一个重要组件&#xff0c;它是一种AOP&#xff08;面向切面编程&#xff09;的实现方式&…

探索计算机视觉:深度学习与图像识别的融合

探索计算机视觉&#xff1a;深度学习与图像识别的融合 摘 要&#xff1a; 本文将探讨计算机视觉领域中的深度学习技术&#xff0c;并重点关注图像识别方面的应用。我们将介绍卷积神经网络&#xff08;CNN&#xff09;的原理、常用的图像数据集以及图像识别的实际应用场景&…

Leetcode 1727. 具有重排的最大子矩阵

题目要求&#xff1a; 给定一个大小为 m x n 的二进制矩阵&#xff0c;并且允许您以任意顺序重新排列矩阵的列。 对列进行最佳重新排序后&#xff0c;返回矩阵中每个元素都为 1 的最大子矩阵的面积。 输入&#xff1a;矩阵 [[0,0,1],[1,1,1],[1,0,1]] 输出&#xff1a;4 说明…

Java制作“简易王者荣耀”小游戏

第一步是创建项目 项目名自拟 第二部创建个包名 来规范class 然后是创建类 GameFrame 运行类 package com.sxt;import java.awt.Graphics; import java.awt.Image; import java.awt.Toolkit; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; im…

班级管理五步法

亲爱的教师朋友们&#xff01;今天我要和大家分享一个超级实用的班级管理方法——班级管理五步法&#xff01;用这个方法&#xff0c;轻松掌握班级秩序&#xff0c;一起来看看吧&#xff01; 第一步&#xff1a;建立规矩 我们要和孩子们一起建立规矩。规矩要简单明了&#xff…

Go 语言 Printf 函数和格式化动词详解

Printf() 函数可以使用多种格式化动词对输出进行格式化。下面是可以与所有数据类型一起使用的一些通用格式化动词&#xff1a; 通用格式化动词&#xff1a; 以下动词适用于所有数据类型&#xff1a; 动词描述%v以默认格式打印值%#v以 Go 语法格式打印值%T打印值的类型%%打印百…

JAVA小游戏简易版王者荣耀

第一步是创建项目 项目名自拟 第二部创建个包名 来规范class 然后是创建类 GameFrame 运行类 package com.sxt; import java.awt.Graphics; import java.awt.Image; import java.awt.Toolkit; import java.awt.event.ActionEvent; import java.awt.event.ActionListener;…

从0到1建立前端规范

本文适合打算建立前端规范的小伙伴阅读 一、为什么需要规范 规范能给我们带来什么好处&#xff0c;如果没有规范会造成什么后果&#xff1f;这里主要拿代码规范来说。 统一代码规范的好处&#xff1a; 提高代码整体的可读性、可维护性、可复用性、可移植性和可靠性&#xf…

Pytorch项目的文件结构一般都是怎么组织的?

如果是从一些比较典型的论文里弄下来的源码&#xff0c;你会发现它们的论文结构往往都非常复杂。不同的模型、不同的论文&#xff0c;可能代码结构组织的方式都不一样。但它们都不外乎就是经历这几个方面&#xff1a; 1、模型和结构模块定义&#xff1b; 2、数据集获取与处理…

Mybatis反射核心类Reflector

Reflector类负责对一个类进行反射解析&#xff0c;并将解析后的结果在属性中存储起来。 一个类反射解析后都有哪些属性呢&#xff1f;我们可以通过Reflector类定义的属性来查看 public class Reflector {// 要被反射解析的类private final Class<?> type;// 可读属性列…

带你用uniapp从零开发一个仿小米商场_6. 配置uniapp项目底部导航栏tabbar

uniapp底部tabbar介绍 在uni-app中&#xff0c;底部tabbar是一种常见的导航方式&#xff0c;它可以让用户在应用的不同页面之间进行切换。通过tabBar配置项&#xff0c;开发者可以指定一级导航栏和tab切换时显示的对应页。 在底部tabbar中&#xff0c;每个tab都有一个页面路径…

虹科分享 | AR世界揭秘:从二维码的起源到数据识别与位姿技术的奇妙融合!

引言&#xff1a;探索AR的神奇世界&#xff0c;我们将从二维码的诞生谈起。在这个科技的海洋中&#xff0c;二维码是如何帮助AR实现数据获取与位姿识别的呢&#xff1f;让我们一起揭开这层神秘的面纱&#xff01; 一、二维码的由来 二维码是将数据存储在图形中的技术&#xff…

Python | CAP - 累积精度曲线分析案例

CAP通常被称为“累积精度曲线”&#xff0c;用于分类模型的性能评估。它有助于我们理解和总结分类模型的鲁棒性。为了直观地显示这一点&#xff0c;我们在图中绘制了三条不同的曲线&#xff1a; 一个随机的曲线&#xff08;random&#xff09;通过使用随机森林分类器获得的曲线…

Gee教程1.HTTP基础

标准库启动web服务 Go语言内置了 net/http库&#xff0c;封装了HTTP网络编程的基础的接口。这个Web 框架便是基于net/http的。我们先回顾下这个库的使用。 package mainimport ("fmt""log""net/http" )func main() {//可以写成匿名函数(lambda…