20分钟写一个链表

目录

  • 前言
  • 1.带头结点的循环双链表
    • 1.1 链表的分类、线性表的对比
    • 1.2 双链表基本操作代码实现
      • 1.2.1 初始化
      • 1.2.2 销毁、打印链表
  • 总结

前言

有一个学长在面试的时候被问到这样一个问题,“你可以用20分钟写一个链表吗?”学长第一反应是,至少要一两个小时吧,链表的基本操作实现,增删查改等。
但是带头结点的循环双链表真的可以在20分钟写出来,这个谜底我们文末揭晓。


1.带头结点的循环双链表

在这里插入图片描述
带头结点的循环双链表的结构如上图所示,双链表每个结点有两个指针,prev和next,prev指向前驱结点,next指向后继结点。

哨兵位的头结点不存储有效数据,OJ题中提到的头结点一般都是第一个结点。没有明确说明,一般认为单链表不带哨兵位的头结点。而且即使尾插要讨论链表是否为空的情况,一般也不用哨兵位的头结点,除非题目需要多个单链表进行尾插,每次都讨论过于麻烦,考虑使用哨兵位的头结点,这篇文章的第二部分是一个例子,感兴趣可以看一下。链表OJ经典题目及思路总结(二)头结点

1.1 链表的分类、线性表的对比

带哨兵位的头结点,尾插以及其他操作不需要考虑链表是否为空;
双链表,两个指针,可以很方便找到前驱结点和后继结点。
循环的双链表,在有头指针的情况下可以方便访问头、尾结点。

链表一共有八种类型,如下图所示
在这里插入图片描述

顺序表、单链表、双链表的简单比较如下
在这里插入图片描述

1.2 双链表基本操作代码实现

1.2.1 初始化

  1. 带头结点的循环双链表,初始化只有头结点,prev和next指针都指向自己。这也表明,只要头指针的next域与头指针相等,即可判定链表为空
  2. 与单链表相比,单链表是没有必要单独写一个初始化函数的;顺序表要初始化size等内容,也需要初始化函数。
  3. 带头结点的循环双链表很多操作,插入、删除都不需要更改头指针,因为有头结点的存在,链表不可能为空。所以插入、删除函数形参都是一级指针,为了保持接口的一致性,初始化函数也用一级指针,在函数内部动态申请空间、初始化,返回其地址即可。而单链表很多场景下一级指针搞不定,只能用二级指针,因此单链表的函数实现是一级、二级指针皆有。

代码实现如下方所示

//初始化
LTNode* LTInit()
{LTNode* phead = BuyListNode(-1);phead->prev = phead;phead->next = phead;return phead;
}

1.2.2 销毁、打印链表

销毁的思路是遍历并释放链表的结点,打印的思路是遍历并打印链表的结点。二者有一个共同点,就是遍历。值得一提的是,遍历的时候用临时变量cur(命名的可读性)来遍历,尽量不要动头指针,因为回头可能还有用。

List.h

#pragma once
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <stdbool.h>
typedef int LTDataType;
typedef struct ListNode
{struct ListNode* prev;struct ListNode* next;LTDataType data;
}LTNode;LTNode* LTInit();
void LTDestroy(LTNode* phead);bool LTEmpty(LTNode* phead);
LTNode* BuyListNode(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);void LTInsert(LTNode* phead, LTDataType x);
LTNode* LTFind(LTNode* phead, LTDataType x);
void LTErase(LTNode* phead);

基本操作代码实现
Test.c

#include "List.h"
LTNode* BuyListNode(LTDataType x)
{LTNode* node = (LTNode*)malloc(sizeof(LTNode));if(node==NULL){perror("malloc failed");return NULL;//exit(-1);}node->data = x;node->prev = NULL;node->next = NULL;return node;
}
//初始化
LTNode* LTInit()
{LTNode* phead = BuyListNode(-1);phead->prev = phead;phead->next = phead;return phead;
}
void LTDestroy(LTNode* phead)
{assert(phead);LTNode* cur = phead->next;while (cur != phead){LTNode* next = cur->next;free(cur);cur = next;}free(phead);
}
void LTPrint(LTNode* phead)
{assert(phead);printf("<=>head<=>");LTNode* cur = phead->next;while (cur != phead){printf("%d<=>", cur->data);cur = cur->next;}printf("\n");
}
bool LTEmpty(LTNode* phead)
{assert(phead);/*if (phead->next == phead)return true;elsereturn false;*/return phead->next == phead;
}
void LTPushBack(LTNode* phead, LTDataType x)
{LTInsert(phead,x);/*assert(phead);LTNode* newnode = BuyListNode(x);LTNode* tail = phead->prev;tail->next = newnode;newnode->prev = tail;newnode->next = phead;	phead->prev = newnode;*/
}
void LTPopBack(LTNode* phead)
{LTErase(phead->prev);/*assert(phead);assert(!LTEmpty(phead));LTNode* tail = phead->prev;LTNode* tailPrev = tail->prev;tailPrev->next = phead;phead->prev = tailPrev;free(tail);tail = NULL;*/
}
void LTPushFront(LTNode* phead, LTDataType x)
{LTInsert(phead->next,x);/*assert(phead);LTNode* first = phead->next;LTNode* newnode = BuyListNode(x);//改链表指向的时候,可以先存储前驱或后继结点的位置,这样不需要过多考虑改指向的顺序问题phead->next = newnode;newnode->prev = phead;newnode->next = first;first->prev = newnode;*///改结点间指向,也可以直接改,但要注意顺序,因为如果改的过程中,链表断开,找不到原来的前驱或后继结点就麻烦了//注意顺序/*newnode->next = phead->next;phead->next->prev = newnode;phead->next = newnode;newnode->prev = phead;*/
}
void LTPopFront(LTNode* phead)
{LTErase(phead->next);/*assert(phead);assert(!LTEmpty(phead));LTNode* first = phead->next;LTNode* firstNext = first->next;phead->next = firstNext;firstNext->prev = phead;free(first);first = NULL;*/
}
void LTInsert(LTNode* pos, LTDataType x) 
{assert(pos);LTNode* newnode = BuyListNode(x);LTNode* prev = pos->prev;prev->next = newnode;newnode->prev = prev;newnode->next = pos;pos->prev = newnode;
}
void LTErase(LTNode* pos)
{assert(pos);LTNode* p = pos->prev;LTNode* n = pos->next;p->next = n;n->prev = p;free(pos);
}
LTNode* LTFind(LTNode* phead, LTDataType x)
{assert(phead);LTNode* cur = phead->next;while (cur != phead){if (cur->data == x)return cur;cur = cur->next;}return NULL;
}

总结

在实现插入、删除函数后,头插、尾插、头删、尾删直接复用即可,这种复用使得20分钟写一个链表成为可能。而且插入函数不需要像单链表插入那样遍历找尾结点,直接更改链表结点间的指向即可,如下图所示。
在这里插入图片描述
删除函数一般搭配查找函数,查找特定值结点的位置并删除。

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

如若内容造成侵权/违法违规/事实不符,请联系一条长河网进行投诉反馈,一经查实,立即删除!

相关文章

BFS解决多源最短路问题_01矩阵_C++【含多源最短路问题介绍+dist数组介绍】

BFS解决多源最短路问题_01矩阵_C 0. 多源最短路问题介绍1. 题目解析算法分析2. 代码实现 0. 多源最短路问题介绍 如图&#xff0c;红色是出发点&#xff0c;蓝色是终点。以前我们做的题中&#xff0c;出发点只有一个&#xff0c;所谓多源的意思就是&#xff0c;出发点有多个&am…

KubeSphere中集成ApiSix

一、Apache APISIX 介绍 Apache APISIX 是一款开源的高性能、动态云原生网关&#xff0c;由深圳支流科技有限公司于 2019 年捐赠给 Apache 基金会&#xff0c;当前已经成为 Apache 基金会的顶级开源项目&#xff0c;也是 GitHub 上最活跃的网关项目。Apache APISIX 当前已经覆盖…

✨ComfyUI workflow加密工具节点ComfyUI_CryptoCat

✨背景 玩comfyui的朋友都了解&#xff0c;工作流workflow是一种很重要的资产&#xff0c;可以通过workflow把一系列的处理工作组织起来&#xff0c;提升工作效率&#xff0c;甚至分享生成的图片就可以还原整个的工作流&#xff0c;对于分享传播是个好事情&#xff0c;但是对于…

8位单片机与32位单片机

8位单片机与32位单片机 8位与32位指的是什么 单片机的8位或32位说的是什么呢&#xff1f;要搞懂这个问题&#xff0c;首先要搞明白8位或32位说的是单片机上的哪一个部件。 这是单片机的内部框图。单片机内部由这么多部件构成&#xff0c;并不单单是一个CPU&#xff0c;它内部…

微软推出针对个人的 “AI伴侣” Copilot 会根据用户的行为模式、习惯自动进化

微软推出了为每个人提供的“AI伴侣”Copilot&#xff0c;它不仅能够理解用户的需求&#xff0c;还能根据用户的日常习惯和偏好进行适应和进化。帮助处理各种任务和复杂的日常生活场景。 它能够根据用户的生活背景提供帮助和建议&#xff0c;保护用户的隐私和数据安全。Copilot…

【Canvas与色彩】十六等分多彩隔断圆环

【成图】 【代码】 <!DOCTYPE html> <html lang"utf-8"> <meta http-equiv"Content-Type" content"text/html; charsetutf-8"/> <head><title>隔断圆环Draft5十六等分多彩</title><style type"text…

BFS解决FloodFill算法_被围绕的区域_C++

BFS解决FloodFill算法_被围绕的区域_C 1. 题目描述2. 算法分析3. 代码实现 1. 题目描述 leetcode链接&#xff1a;https://leetcode.cn/problems/surrounded-regions/description/ 给你一个m x n的矩阵board&#xff0c;由若干字符X和O组成&#xff0c;捕获 所有 被围绕的区域…

数据结构 ——— 单链表oj题:链表的回文结构

目录 题目要求 手搓简易单链表 代码实现 题目要求 对于一个单链表&#xff0c;设计一个时间复杂度为O(N)&#xff0c;空间复杂度为O(1)的算法&#xff0c;判断其是否为回文结构&#xff0c;给定一个链表的头指针 head&#xff0c;返回一个 bool 值&#xff0c;代表其是否为…

矩阵式键盘接口设计(用单片机读取4x4矩阵式键盘的键号,并将其显示在数码管上)(Proteus 与Keil uVision联合仿真)

一、实验原理 1、分析电路中按键状态检测的方法。 矩阵式&#xff08;也称行列式&#xff09;键盘用于按键数目较多的场合&#xff0c;由行线和列线组成&#xff0c;按键位于行、列交叉点上&#xff0c;见图5-26&#xff0c;一个44的行、列结构可以构成一个16个按键的键盘&…

FastAPI框架使用枚举来型来限定参数、FastApi框架隐藏没多大意义的Schemes模型部分内容以及常见的WSGI服务器Gunicorn、uWSGI了解

一、FastAPI框架使用枚举来型来限定参数 FastAPI框架验证时&#xff0c;有时需要通过枚举的方式来限定参数只能为某几个值中的一个&#xff0c;这时就可以使用FastAPI框架的枚举类型Enum了。publish:December 23, 2020 -Wednesday 代码如下&#xff1a; #引入Enum模块 from fa…

一张图片生成数字人的3D发型:技术创新与应用前景

随着人工智能(AI)和计算机图形学的不断进步,从单张肖像图像生成3D数字头发的技术正在变得越来越成熟。这项技术不仅能够处理复杂的编织和未编织发型,还能在虚拟现实、电影制作和美容行业中找到广泛的应用。本文将详细介绍一种创新的3D头发重建技术,探讨其关键特性、技术创…

Dit架构 diffusion范式分类+应用

1.ping 网址 2.ssh nscc/l20 3.crtl,打开vscode的setting 4.win 10修改ssh配置文件及其密钥权限为600 - 晴云孤魂 - 博客园 整体来看&#xff1a; 使用transformer作为其主干网络&#xff0c;代替了原先的UNet 在latent space进行训练&#xff0c;通过transformer处理潜…

搬砖 网盘一键转存源码

网盘一键转存源码&#xff0c;免费资源没测试 网盘一键转存源码&#xff0c;可以将您的百度网盘资源一键转存到。并支持后台设置开屏广告 源码截图&#xff1a; 下载地址&#xff1a; https://yuncv.lanzouw.com/i8dZk2btyl4h

04. maven 三种项目打包方式 pom、jar、war 的区别(记一次 Spring 项目启动报错)

文章目录 1. 记一次 Spring 项目启动报错1.1 现象1.2 分析1.3 过程复现 2. maven 项目三种打包方式的区别 1. 记一次 Spring 项目启动报错 1.1 现象 我在项目下创建了一个子模块&#xff0c;然后又将该子模块移除&#xff0c;之后启动报错&#xff0c;如下&#xff1a; com.…

深入理解 Java 对象的内存布局

对于 Java 虚拟机&#xff0c;都知道其内存区域划分成&#xff1a;堆、方法区、虚拟机栈等区域。但一个对象在 Java 虚拟机中是怎样存储的&#xff0c;相信很少人会比较清楚地了解。Java 对象在 JVM 中的内存布局&#xff0c;是了解并发编程同步机制的基础。 在 HotSpot 虚拟机…

通信工程学习:什么是IOT物联网

IOT&#xff1a;物联网 IOT物联网&#xff08;Internet of Things&#xff0c;简称IoT&#xff09;是一种通过信息传感设备&#xff0c;按约定的协议&#xff0c;将任何物体与网络相连接&#xff0c;以实现智能化识别、定位、跟踪、监管等功能的技术体系。以下是对IOT物联网的详…

Windows 通过 Docker 安装 GitLab

1. 安装 Docker Desktop 下载网站&#xff1a;Windows | Docker Docs 2. 拉取 GitLab Docker 镜像 打开 PowerShell 或 命令提示符&#xff0c;拉取 GitLab 镜像&#xff1a; docker pull gitlab/gitlab-ee:latest或则使用社区版&#xff1a; docker pull gitlab/gitlab-ce…

电脑无法无线投屏的解决办法

在前司的时候经常遇到电脑无法使用无线投屏器的情况&#xff0c;今天就来聊聊如何解决。 1.不会连接。这种情况&#xff0c;经常发生在WIN10升级WIN11之后&#xff0c;一般是两种办法&#xff0c;一种是同时按键盘上的WINDOWS和K键&#xff0c;右下角就会出来连接的图标&#…

showdoc二次开发

showdoc用的vue版本老&#xff0c;需要安装老版本nodejs&#xff0c;比如node 14.21.3 win32-x64-93_binding.node问题 https://github.com/sass/node-sass/releases 下载 web_src\node_modules\node-sass\vendor\win32-x64-93 下面重命名为binding.node 代理到php后端&…

2-114 基于matlab的CA模型

基于matlab的CA模型&#xff0c;Singer模型对单机动目标进行跟踪算法&#xff0c;具有10页实验文档。采用蒙特卡罗方法对一个二坐标雷达对一平面上运动的目标进行观测&#xff0c;得到跟踪滤波结果。程序已调通&#xff0c;可直接运行。 下载源程序请点链接&#xff1a;2-114 …