当前位置: 首页 > news >正文

数据结构——链表

【本节内容】

1.链表

1.链表的概念及结构

概念:链表是一种 物理存储结构上非连续、非顺序的存储结构,数据元素的 逻辑顺序是通过链表中的 指针链接次序实现的 。
就像我们一节一节的小火车一样,靠中间的链子链接在一起。

现实中 数据结构中
 

1.2 链表的分类


实际中链表的结构非常多样,以下情况组合起来就有8种链表结构:


1. 单向或者双向
 

2. 带头或者不带头
 

3. 循环或者非循环
 

虽然有这么多的链表的结构,但是我们实际中最常用还是两种结构:
 

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

1、无头+单向+非循环链表增删查改实现

SList.h

#pragma once
#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
typedef int SLTDataType;
typedef struct SListNode
{SLTDataType data;struct SListNode* next;
}SLTNode;
void SLTPrint(SLTNode* phead);//打印链表
void SLPushFront(SLTNode** pphead, SLTDataType x);//头插
void SLPushBack(SLTNode** pphead, SLTDataType x);//尾插
void SLPopFront(SLTNode** pphead);//头删
void SLPopBack(SLTNode** pphead);//尾删
void SLErase(SLTNode** pphead, SLTNode* pos);// 删除pos位置的值
void SLInsert(SLTNode** pphead, SLTNode* pos, SLTDataType x);//在pos位置插入
SLTNode* STFind(SLTNode* phead, SLTDataType x);//查找与x值相同的节点位置

SList.c

#define _CRT_SECURE_NO_WARNINGS 1
#include"Slist.h"
void SLTPrint(SLTNode* phead)//打印链表
{SLTNode* cur = phead;while (cur != NULL){printf("%d->", cur->data);cur = cur->next;}printf("NULL\n");
}SLTNode* BuyLTNode(SLTDataType x)//初始化节点
{SLTNode* newnode = (SLTNode*)malloc(sizeof(SLTNode));if (newnode == NULL){perror("malloc fail");return NULL;}newnode->data = x;newnode->next = NULL;return newnode;
}void SLPushFront(SLTNode** pphead, SLTDataType x)//头插
{SLTNode* newnode = BuyLTNode(x);newnode->next = *pphead;*pphead = newnode;
}void SLPushBack(SLTNode** pphead, SLTDataType x)//尾插
{SLTNode* newnode = BuyLTNode(x);// 1、空链表if (*pphead == NULL){*pphead = newnode;}// 2、非空链表else{SLTNode* tail = *pphead;while (tail->next != NULL){tail = tail->next;}tail->next = newnode;}
}void SLPopFront(SLTNode** pphead)//头删
{// 判空assert(*pphead);SLTNode* del = *pphead;*pphead = (*pphead)->next;free(del);
}void SLPopBack(SLTNode** pphead)//尾删
{assert(*pphead);// 一个节点if ((*pphead)->next == NULL){free(*pphead);*pphead = NULL;}// 多个节点else{SLTNode* tail = *pphead;// 找尾while (tail->next->next){tail = tail->next;}free(tail->next);tail->next = NULL;}
}SLTNode* STFind(SLTNode* phead, SLTDataType x)//查找与x值相同的节点位置
{SLTNode* cur = phead;while (cur){if (cur->data == x){return cur;}cur = cur->next;}return NULL;
}void SLInsert(SLTNode** pphead, SLTNode* pos, SLTDataType x)//在pos位置插入
{assert(pphead);assert(pos);if (*pphead == pos){SLPushFront(pphead, x);}else{SLTNode* prev = *pphead;while (prev->next != pos){prev = prev->next;}SLTNode* newnode = BuyLTNode(x);prev->next = newnode;newnode->next = pos;}
}void SLErase(SLTNode** pphead, SLTNode* pos)// 删除pos位置的值
{assert(pphead);assert(pos);if (pos == *pphead){SLPopFront(pphead);}else{SLTNode* prev = *pphead;while (prev->next != pos){prev = prev->next;}prev->next = pos->next;free(pos);}
}


test.c

#define _CRT_SECURE_NO_WARNINGS 1
#include "SList.h"
int main()
{SLTNode* plist = NULL;SLPushBack(&plist, 1);SLPushBack(&plist, 2);SLPushBack(&plist, 3);SLPushBack(&plist, 4);SLPushFront(&plist, 0);SLPopBack(&plist);SLPopFront(&plist);SLTNode* pos = STFind(plist, 1);SLErase(&plist, pos);SLTPrint(plist);return 0;
}

运行结果:

 

2.双向链表:

DList.h

#pragma once
#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
#include<stdbool.h>
typedef int LTDataType;
typedef struct ListNode
{struct ListNode* next;struct ListNode* prev;LTDataType data;
}LTNode;LTNode* LTInit();//初始化双向链表
void LTPrint(LTNode* phead);//打印双向链表
bool LTEmpty(LTNode* phead);//判断链表是否为空
void LTPushBack(LTNode* phead, LTDataType x);//双向链表尾插
void LTPushFront(LTNode* phead, LTDataType x);//双向链表头插
void LTPopBack(LTNode* phead);//双向链表尾删
void LTPopFront(LTNode* phead);//双向链表头删
LTNode* LTFind(LTNode* phead, LTDataType x);//查找与x值相同的节点
void LTInsert(LTNode* pos, LTDataType x);// 在pos位置插入
void LTErase(LTNode* pos);// 删除pos位置的值
void LTDestroy(LTNode* phead);//销毁双向链表

DList.c

#define _CRT_SECURE_NO_WARNINGS 1
#include"DList.h"
LTNode* BuyLTNode(LTDataType x)//初始化节点
{LTNode* newnode = (LTNode*)malloc(sizeof(LTNode));if (newnode == NULL){perror("malloc fail");return NULL;}newnode->data = x;newnode->next = NULL;newnode->prev = NULL;return newnode;
}LTNode* LTInit()//初始化双向链表
{LTNode* phead = BuyLTNode(-1);phead->next = phead;phead->prev = phead;return phead;
}void LTPrint(LTNode* phead)//打印双向链表
{assert(phead);printf("guard<==>");LTNode* cur = phead->next;while (cur != phead){printf("%d<==>", cur->data);cur = cur->next;}printf("\n");
}bool LTEmpty(LTNode* phead)//判断双向链表是否为空
{assert(phead);return phead->next == phead;
}void LTPushBack(LTNode* phead, LTDataType x)//双向链表尾插
{assert(phead);LTInsert(phead, x);
}void LTPushFront(LTNode* phead, LTDataType x)//双向链表头插
{LTInsert(phead->next, x);
}void LTPopBack(LTNode* phead)//双向链表尾删
{assert(phead);assert(!LTEmpty(phead));LTErase(phead->prev);
}void LTPopFront(LTNode* phead)//双向链表头删
{assert(phead);assert(!LTEmpty(phead));LTErase(phead->next);
}LTNode* LTFind(LTNode* phead, LTDataType x)//查找与x值相同的节点
{assert(phead);LTNode* cur = phead->next;while (cur != phead){if (cur->data == x){return cur;}cur = cur->next;}return NULL;
}void LTInsert(LTNode* pos, LTDataType x)// 在pos位置插入
{assert(pos);LTNode* prev = pos->prev;LTNode* newnode = BuyLTNode(x);prev->next = newnode;newnode->prev = prev;newnode->next = pos;pos->prev = newnode;
}void LTErase(LTNode* pos)//删除pos位置的值
{assert(pos);LTNode* posPrev = pos->prev;LTNode* posNext = pos->next;posPrev->next = posNext;posNext->prev = posPrev;free(pos);
}void LTDestroy(LTNode* phead)//销毁双向链表
{assert(phead);LTNode* cur = phead->next;while (cur != phead){LTNode* next = cur->next;free(cur);cur = next;}free(phead);
}

test.c

#define _CRT_SECURE_NO_WARNINGS 1
#include "DList.h"
int main()
{LTNode* plist = LTInit();printf("%d\n",LTEmpty(plist));LTPushBack(plist, 1);LTPushBack(plist, 2);LTPushBack(plist, 3);LTPushBack(plist, 4);LTPushBack(plist, 5);LTPushBack(plist, 6);LTPopFront(plist);LTPopBack(plist);LTNode* pos = LTFind(plist,2);LTErase(pos);LTPrint(plist);LTDestroy(plist);return 0;
}

运行结果:

 

PS:看到这里了,码字不易,给个一键三连鼓励一下吧!有不足或者错误之处欢迎在评论区指出!

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • 【Day20240924】05git 两人协作 冲突
  • 零基础到精通Web渗透测试的学习路线,零基础入门到精通,收藏这一篇就够了
  • MySQL—存储过程详解
  • mysql如何快速编写单表查询语句
  • Spring定时任务 - @Scheduled注解详解
  • Flutter 获取手机连接的Wifi信息
  • 秋分之际,又搭建了一款微信记账本小程序
  • Java后端开发中的响应缓存:从HTTP缓存到分布式缓存的最佳实践
  • java日志框架之JUL(Logging)
  • 综合体第三题(DHCP报文分析)
  • [51单片机] 简单介绍 (一)
  • 《数据压缩入门》笔记-Part 2
  • 基于Vue3组件封装的技巧分享
  • 手撕Transformer之Embedding Layer
  • Python Web 与物联网(IoT)集成与实时数据处理
  • ES6指北【2】—— 箭头函数
  • Bootstrap JS插件Alert源码分析
  • exif信息对照
  • Git 使用集
  • JavaScript 基本功--面试宝典
  • jQuery(一)
  • MyEclipse 8.0 GA 搭建 Struts2 + Spring2 + Hibernate3 (测试)
  • PHP的类修饰符与访问修饰符
  • puppeteer stop redirect 的正确姿势及 net::ERR_FAILED 的解决
  • Python进阶细节
  • Redis 懒删除(lazy free)简史
  • Spark RDD学习: aggregate函数
  • vue-router 实现分析
  • 测试如何在敏捷团队中工作?
  • 前端攻城师
  • 十年未变!安全,谁之责?(下)
  • 在GitHub多个账号上使用不同的SSH的配置方法
  • 掌握面试——弹出框的实现(一道题中包含布局/js设计模式)
  • ​马来语翻译中文去哪比较好?
  • ​如何防止网络攻击?
  • ‌分布式计算技术与复杂算法优化:‌现代数据处理的基石
  • # 计算机视觉入门
  • (Arcgis)Python编程批量将HDF5文件转换为TIFF格式并应用地理转换和投影信息
  • (cljs/run-at (JSVM. :browser) 搭建刚好可用的开发环境!)
  • (webRTC、RecordRTC):navigator.mediaDevices undefined
  • (官网安装) 基于CentOS 7安装MangoDB和MangoDB Shell
  • (黑马出品_高级篇_01)SpringCloud+RabbitMQ+Docker+Redis+搜索+分布式
  • (回溯) LeetCode 77. 组合
  • (十五)devops持续集成开发——jenkins流水线构建策略配置及触发器的使用
  • (实战)静默dbca安装创建数据库 --参数说明+举例
  • (译)2019年前端性能优化清单 — 下篇
  • .NET CF命令行调试器MDbg入门(三) 进程控制
  • .net core使用EPPlus设置Excel的页眉和页脚
  • .NET 使用 JustAssembly 比较两个不同版本程序集的 API 变化
  • .NET+WPF 桌面快速启动工具 GeekDesk
  • .Net6支持的操作系统版本(.net8已来,你还在用.netframework4.5吗)
  • .NET8 动态添加定时任务(CRON Expression, Whatever)
  • .NET精简框架的“无法找到资源程序集”异常释疑
  • .net与java建立WebService再互相调用
  • .NET中使用Redis (二)