广告
返回顶部
首页 > 资讯 > 后端开发 > 其他教程 >C语言数据结构之双链表&循环链表&静态链表详解
  • 466
分享到

C语言数据结构之双链表&循环链表&静态链表详解

2024-04-02 19:04:59 466人浏览 八月长安
摘要

目录单链表 VS 双链表双链表双链表的初始化(带头结点)双链表的插入双链表的删除双链表的遍历循环单链表循环双链表循环双链表的初始化循环双链表的插入循环双链表的删除静态链表什么是静态链

单链表 VS 双链表

我们都知道,单链表只有一个指向下一个结点的指针,当我们想要找到前一个结点时就比较麻烦,而双链表拥有两个指针

总的来说:

  • 单链表 —— 无法逆向检索,有时候不太方便
  • 双链表 —— 可进可退,存储密度更低一丢丢

定义双链表结点类型

typedef struct Dnode{
    ElemType data;                //数据域
    struct DNode *prior, *next;    //前驱和后继指针
}DNode, *DLinklist;

双链表

双链表的初始化(带头结点)

定义一个 InitLinklist 函数,参数为双链表的引用,加引用是因为要改变这个双链表

注意:头结点的前驱指针永远指向 NULL

#include <stdio.h>
#include <stdlib.h>

typedef int ElemType;

typedef struct DNode{
	ElemType data;				//数据域
	struct DNode *prior, *next;	//前驱和后继指针
}DNode, *DLinklist;

//初始化双链表
bool InitLinklist(DLinklist &L) {
	L = (DNode *)malloc(sizeof(DNode));		//分配一个头结点
	if (L == NULL) return false;			//内存不足,分配失败
	L->prior = NULL;						//头结点的 prior 永远指向 NULL
	L->next = NULL;							//头结点之后暂时还没有结点
	return true;
}

//判断双链表是否为空(带头结点)
bool Empty(DLinklist L) {
	if (L->next == NULL)
		return true;
	else
		return false;
}

void testDLinklist() {
	//初始化双链表
	DLinklist L;
	InitLinklist(L);
}

双链表的插入

后插法

//在p结点之后插入s结点
bool InsertNextDNode(DNode *p, DNode *s) {
	if (p == NULL || s == NULL) return false;	//非法参数

	s->next = p->next;
	if (p->next != NULL)		//如果p结点有后继结点
		p->next->prior = s;
	s->prior = p;
	p->next = s; 
	return true;
}

学会了后插操作,我们也就学会了按位序插入和前插法,大概思路为找到目标结点的前驱结点,然后对其进行后插操作

双链表的删除

//删除p结点的后继结点
bool DeleteNextDNode(DNode *p) {
	if (p == NULL) return false;

	DNode *q = p->next;				//找到p结点的后继结点q
	if (q == NULL) return false;	//p没有后继
	
	p->next = q->next;
	if (q->next != NULL)			//q结点不是最后一个结点
		q->next->prior = p;
	free(p);						//释放结点空间
	return true;
}

//销毁双链表
void DestoryList(DLinklist &L) {
	//循环释放各个数据结点
	while (L->next != NULL) {
		DeleteNextDNode(L);
	}
	free(L);	//释放头结点
	L = NULL;	//头指针指向NULL
}

双链表的遍历

由于双链表不可随机存取,所以按位查找、按值查找等操作都只能用遍历的方式实现,时间复杂度为 O(n)

//后向遍历
while (p != NULL) {
	//对结点p做相应处理,比如打印
	p = p->next;
}

//前向遍历
while (p != NULL) {
	//对结点p做相应处理
	p = p->prior;
}

//前向遍历(跳过头结点)
while (p->prior != NULL) {
	//对结点p做相应处理
	p = p->prior;
}

循环单链表

我们都知道,单链表的表尾结点的 next 指针是指向 NULL,顾名思义,循环单链表的表尾结点的 next 指针就是指向头结点的

循环单链表的优点:从一个结点出发可以找到其他任何一个结点

typedef int ElemType;

typedef struct LNode{
	ElemType data;			//每个节点存放一个数据元素
	struct LNode *next;		//指针指向下一个节点
}LNode, *LinkList;

//初始化一个循环单链表
bool InitList(LinkList &L) {
	L = (LNode *)malloc(sizeof(LNode));		//分配一个头结点
	if (L == NULL) return false;			//内存不足,分配失败
	L->next = L;			//头结点next指针指向头结点
	return true;
}

//判断循环单链表是否为空
bool Empty(LinkList L) {
	if (L->next == L) 
		return true;
	else 
		return false;
}

//判断结点p是否为循环单链表的表尾结点
bool isTail(LinkList L, LNode *p) {
	if (p->next == L)
		return true;
	else 
		return false;
}

循环双链表

双链表:

  • 表头结点的 prior 指向 NULL
  • 表尾结点的 next 指向 NULL

循环双链表

  • 表头结点的 prior 指向表尾结点
  • 表尾结点的 next 指向头结点

循环双链表的初始化

#include <stdio.h>
#include <stdlib.h>

typedef int ElemType;

typedef struct DNode{
	ElemType data;				//数据域
	struct DNode *prior, *next;	//前驱和后继指针
}DNode, *DLinklist;

//初始化空的循环双链表
bool InitDLinklist(DLinklist &L) {
	L = (DNode *)malloc(sizeof(DNode));		//分配一个头结点
	if (L == NULL) return false;			//内存不足,分配失败
	L->prior = L;							//头结点的 prior 指向头结点
	L->next = L;							//头结点的 next 指向头结点
	return true;
}

//判断循环双链表是否为空
bool Empty(DLinklist L) {
	if (L->next == L)
		return true;
	else
		return false;
}

//判断结点p是否为循环双链表的表尾结点
bool isTail(DLinklist L, DNode *p) {
	if (p->next = L)
		return true;
	else
		return false;
}

void testDLinklist() {
	//初始化双链表
	DLinklist L;
	InitDLinklist(L);
}

循环双链表的插入

//在p结点之后插入s节点
bool InsertNextDNode(DNode *p, DNode *s) {
    s->next = p->next;
    p->next->prior = s;
    s->prior = p;
    p->next = s;
    return true;
}

循环双链表的删除

//删除p的后继结点q
p->next = q->next;
q->next->prior = p;
free(q);

静态链表

什么是静态链表

单链表:各个结点在内存中星罗棋布、散落天涯

静态链表:分配一整片连续的内存空间,各个结点集中安置,0 号结点充当 “头结点”,下一个结点的数组下标(也称为游标)充当 “指针”,游标为 -1 时表示已经到达表尾

静态链表是用数组的方式来实现的链表,其优点为 —— 增、删操作不需要大量移动元素;缺点为 —— 不能随机存取,只能从头结点开始依次往后查找;容量固定不可变

定义静态链表

#define MaxSize 10            //静态链表的最大长度
struct Node{
    ElemType data;            //存储数据元素
    int next;                //下一个元素的数组下标
};

或者

#define MaxSize 10            //静态链表的最大长度
typedef struct {
    ElemType data;            //存储数据元素
    int next;                //下一个元素的数组下标
} SLinkList[MaxSize];

SLinkList a 相当于 struct Node a[MaxSize]

基本操作的实现

初始化

把 a[0] 的 next 设置为 -1

把空的结点的 next 设置为 -2

查找

从头结点出发依次往后遍历结点

插入位序为 i 的结点

  • 找到一个空的结点,存入数据元素
  • 从头结点出发找到位序为 i-1 的结点
  • 修改新结点的 next
  • 修改 i-1 号结点的 next

删除某个结点

  • 从头结点出发找到前驱结点
  • 修改前驱结点的游标
  • 被删除结点的 next 设置为 -2

顺序表和链表的比较

从逻辑结构来说,顺序表和链表都属于线性表,都是线性结构

从存储结构来说,顺序表采用顺序存储,而链表采用链式存储

顺序表

优点:支持随机存取,存取密度高

缺点:大片连续空间分配不方便,改变容量不方便

链表:

优点:离散的小空间分配方便,改变容量方便

缺点:不可随机存取,存储密度低

从基本操作来看

  • 顺序表需要预分配大片连续空间,若分配空间过小,则之后不方便扩展容量;若分配空间过大,则浪费内存资源。如果采取静态分配的方式,则容量不可改变;如果采取动态分配的方式,则容量可改变,但需要移动大量元素,时间代价高
  • 链表只需分配一个头结点(也可以不要头结点,只声明一个头指针),之后方便拓展

  • 对链表来说,你只需扫描整个链表,依次删除(free)各个结点即可
  • 对顺序表来说,首先你需要修改 length = 0,如果是采用静态分配的方式,当静态数组的生命周期结束时,系统会自动回收空间;如果是采用动态分配的方式,用 malloc 申请的空间是属于内存中的堆区,在堆区的内存空间不会由系统自动回收,需要我们手动 free

增删

  • 对顺序表来说,插入或删除都要讲后续元素全部后移或前移,时间复杂度为 O(n),时间开销主要来自移动元素
  • 对链表来说,插入或删除元素只需要修改指针即可,时间复杂度为 O(n),时间开销主要来自查找目标元素
  • 虽然时间复杂度一样,但是结合实际因素,链表增删的效率要比顺序表高得多

  • 对顺序表来说,按位查找的时间复杂度为 O(1);按值查找的时间复杂度为 O(n),如果表内元素有序,可采用折半查找等方法在 O(log2n) 时间内找到
  • 对链表来说,按位查找的时间复杂度为 O(n);按值查找的时间复杂度也为 O(n)

综上所述

  • 表长难以预估、经常要增加或删除元素 —— 链表
  • 表长可预估、查询操作较多 —— 顺序表

以上就是C语言数据结构之双链表&循环链表&静态链表详解的详细内容,更多关于C语言链表的资料请关注编程网其它相关文章!

--结束END--

本文标题: C语言数据结构之双链表&循环链表&静态链表详解

本文链接: https://www.lsjlt.com/news/168498.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

本篇文章演示代码以及资料文档资料下载

下载Word文档到电脑,方便收藏和打印~

下载Word文档
猜你喜欢
  • C语言数据结构之双链表&循环链表&静态链表详解
    目录单链表 VS 双链表双链表双链表的初始化(带头结点)双链表的插入双链表的删除双链表的遍历循环单链表循环双链表循环双链表的初始化循环双链表的插入循环双链表的删除静态链表什么是静态链...
    99+
    2022-11-13
  • Python数据结构之循环链表详解
    目录0. 学习目标1. 循环链表简介2. 循环单链表实现2.1 循环单链表的基本操作2.2 简单的实现方法2.3 循环单链表应用示例2.4 利用循环单链表基本操作实现复杂操作3. 循...
    99+
    2022-11-13
  • C语言实现循环双链表
    本文实例为大家分享了C语言实现循环双链表的具体代码,供大家参考,具体内容如下 #include<stdio.h> #include<stdlib.h> #...
    99+
    2022-11-12
  • C语言线性表之双链表详解
    目录定义1.删除2.插入3.建立4.查找总结定义 链表是通过一组任意的存储单元来存储线性表中的数据元素,每一个结点包含两个域:存放数据元素信息的域称为数据域,存放其后继元素地址的域称...
    99+
    2022-11-13
  • C语言如何实现双向链表和双向循环链表
    本文小编为大家详细介绍“C语言如何实现双向链表和双向循环链表”,内容详细,步骤清晰,细节处理妥当,希望这篇“C语言如何实现双向链表和双向循环链表”文章能帮助大家解决疑惑,下面跟着小编的思路慢慢深入,一起来学习新知识吧。双向链表和双向循环链表...
    99+
    2023-06-16
  • C语言超详细讲解数据结构中双向带头循环链表
    目录一、概念二、必备工作2.1、创建双向链表结构2.2、初始化链表2.3、动态申请节点2.4、打印链表2.5、销毁链表三、主要功能3.1、在pos节点前插入数据尾插头插3.2、删除p...
    99+
    2022-11-13
  • C语言编程数据结构带头双向循环链表全面详解
    目录前言一、什么是带头循环双向链表二、链表初始化三、链表接口函数1.尾插2.头插3.头删4.尾删5.任意位置插入数据6.任意位置删除数据四、打印链表总结前言 上一篇数据结构专栏:C语...
    99+
    2022-11-12
  • C++数据结构之双向链表
    本文实例为大家分享了C++数据结构之双向链表的具体代码,供大家参考,具体内容如下 #include <iostream> using std::cout; using ...
    99+
    2022-11-13
  • JavaScript数据结构之双向链表和双向循环链表的示例分析
    这篇文章主要为大家展示了“JavaScript数据结构之双向链表和双向循环链表的示例分析”,内容简而易懂,条理清晰,希望能够帮助大家解决疑惑,下面让小编带领大家一起研究并学习一下“JavaScript数据结...
    99+
    2022-10-19
  • C++数据结构之链表详解
    目录前言一、删除链表中给定值为key的节点二、反转链表三、返回链表的中间节点四、删除链表的倒数第K个节点五、分割链表六、合并两个有序链表七、删除有序链表中重复节点八、环形链表九、相交...
    99+
    2022-11-12
  • C语言数据结构之单链表存储详解
    目录1、定义一个链表结点2、初始化单链表3、输出链表数据4、完整代码如果说,顺序表的所占用的内存空间是连续的,那么链表则是随机分配的不连续的,那么为了使随机分散的内存空间串联在一起形...
    99+
    2022-11-13
  • C语言数据结构之单链表操作详解
    目录1、插入操作2、删除操作3、查找操作4、修改操作5、完整代码1、插入操作 (1)创建一个新的要插入的结点 (2)将新结点的 next 指针指向插入位置后的结点 (3)将插入位置前...
    99+
    2022-11-13
  • Python数据结构之双向链表详解
    目录0. 学习目标1. 双向链表简介1.1 双向链表介绍1.2 双向链表结点类1.3 双向链表优缺点2. 双向链表实现2.1 双向链表的初始化2.2 获取双向链表长度2.3 读取指定...
    99+
    2022-11-13
  • 详解C语言中双向循环链表的实现
    目录实现细节辅助理解图具体实现代码1、对链表进行初始化2、任意位置前的插入3、任意位置的删除4、头插和尾删完整代码头文件具体函数测试实现细节 1、带一个哨兵位(哨兵节点,初始节点,不...
    99+
    2022-11-13
  • C语言怎么实现循环双链表
    这篇文章主要介绍“C语言怎么实现循环双链表”,在日常操作中,相信很多人在C语言怎么实现循环双链表问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”C语言怎么实现循环双链表”的疑惑有所帮助!接下来,请跟着小编一起来...
    99+
    2023-06-25
  • C语言数据结构之顺序表和单链表
    一、顺序表的创建、删除和插入 #define _CRT_SECURE_NO_WARNINGS 1 #include<stdio.h> struct sqlist { ...
    99+
    2022-11-12
  • C语言数据结构之单向链表详解分析
    链表的概念:链表是一种动态存储分布的数据结构,由若干个同一结构类型的结点依次串连而成。 链表分为单向链表和双向链表。 链表变量一般用指针head表示,用来存放链表首结点的地址。 每个...
    99+
    2022-11-12
  • C语言数据结构之单链表与双链表的增删改查操作实现
    目录前言单链表的增删改查定义结构体以及初始化增加结点删除结点查找修改结点移除结点最终效果双链表的基本操作初始化建表遍历双链表指定位置插入结点指定位置删除结点查找结点位置最终效果结语前...
    99+
    2022-11-13
  • C语言数据结构中双向带头循环链表怎么实现
    这篇文章主要讲解了“C语言数据结构中双向带头循环链表怎么实现”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“C语言数据结构中双向带头循环链表怎么实现”吧!一、概念来画张图总体回顾下:在我们学习...
    99+
    2023-06-30
  • Java数据结构之链表实现(单向、双向链表及链表反转)
    前言 之前学习的顺序表查询非常快,时间复杂度为O(1),但是增删改效率非常低,因为每一次增删改都会元素的移动。可以使用另一种存储方式-链式存储结构。 链表是一种物理存储单元上非连续、...
    99+
    2022-11-12
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作