栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > C/C++/C#

C语言链表详解(通俗易懂)

C/C++/C# 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

C语言链表详解(通俗易懂)

文章目录
  • 前言
  • 一、什么是线性表?
  • 二、顺序表:
  • 二、链表:
  • 二、顺序表和链表对比:
  • 总结


前言

线性表是实际中广泛应用的重要数据结构,本文用通俗易懂的方法讲解它。


一、什么是线性表?

首先,我们了解下“线性表”的基本概念:

  • 全名为“线性存储结构”,使用线性表存储数据的方式可以这样理解,即“把所有数据用一根线儿串起来,再存储到物理空间中”。
  • 是n个具有相同特性的数据元素的有限序列。线性表是一种在实际中广泛使用的数据结构,常见的线性表有:顺序表、链表、队列…
二、顺序表:

顺序表是用一段物理地址连续的存储单元依次存储数据元素的线性结构,一般情况下采用数组存储。在数组上完成数据的增删查改。

顺序表一般可以分为:

  1. 静态顺序表:使用定长数组存储数据。
  2. 动态顺序表:使用动态开辟的数组存储。


扩容方法:动态开辟一块新的空间(一般为原空间的两倍),将原空间的数据拷贝到新的空间,然后让array指针指向新的空间并且释放旧空间。

对比以上两者:

区别:

  • 静态顺序表和动态顺序表唯一不同的是,静态顺序表在创建顺序表的时候容量已经确定,不可以更改,而动态顺序表的容量是由malloc函数动态开辟,当容量不够用时可以增加容量capacity。

优缺点:

  • 静态顺序表创建空间时为静态开辟,不用malloc函数,代码相对简单(一点点),不存在内存泄露问题。
  • 动态顺序表,动态开辟空间,使用相对灵活,相比于静态开辟空间也可以少空间浪费。

动态顺序表代码演示:初始化、插入数据和检查容量

//初始化顺序表
void SeqList_Init(SeqList* ps)
{
	SLDateType* tmp = (SLDateType*)malloc(5 * sizeof(SLDateType));
	if (tmp == NULL)
	{
		perror(malloc);
		exit(-1);
	}
	ps->arr = tmp;
	ps->size = 0;
	ps->capacity = 5;
}

//检查容量
void Check_Capacity(SeqList* ps)
{
	assert(ps);
	if (ps->size == ps->capacity)
	{
		SLDateType* tmp = (SLDateType*)realloc(ps->arr, 2*ps->capacity* sizeof(SLDateType));
		if (tmp == NULL)
		{
			perror(realloc);
			exit(-1);
		}
		ps->arr = tmp;
		ps->capacity = 2 * ps->capacity;
		printf("扩容成功n");
	}
}
//插入数据
void SeqList_Insert(SeqList* ps, SLDateType pos)
{
	assert(ps);
	Check_Capacity(ps);//检查容量
	SLDateType num = 0;
	printf("请输入需要写入的值:>");
	scanf("%d", &num);
	if (ps->size == 0 || pos == ps->size)
	{
		ps->arr[pos] = num;
	}	
	SLDateType end = ps->size - 1;
	while (end >= pos)
	{
		ps->arr[end + 1] = ps->arr[end];
		end--;
	}
	ps->arr[pos] = num;
	ps->size++;
}
二、链表:

概念:链表是一种物理存储结构上非连续、非顺序的存储结构,数据元素的逻辑顺序是通过链表中的指针链接次序实现的 。

下图为单链表的逻辑结构类型:

注意:

  1. 链式结构在逻辑上是连续的,但在物理上不一定连续
  2. 现实中结点一般都是在堆上申请出来的
  3. 从堆上申请的空间,是按照一定的策略来分配的,两次申请的空间可连续,也可能不连续

链表的分类

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

  1. 单向或者双向:

  1. 带头和不带头:

  2. 循环和不循环:

    经过以上三种可以有2^3=8种类型。

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

  • 无头单向链表和带头双向循环链表:

这边通过单链表头部和尾部插入数据代码帮大家理解过程:

//创建结点
SListNode* BuySListNode(SLTDataType x)
{
	SListNode* newnode = (SListNode*)malloc(sizeof(SListNode));
	assert(newnode);
	newnode->data = x;
	newnode->next = NULL;
	return newnode;
}
//头插数据
void SListPushFront(SListNode** pphead, SLTDataType x)
{
	SListNode* newnode = BuySListNode(x);//读取新建的结点
	newnode->next = *pphead;
	*pphead = newnode;
}
//尾插数据
void SListPushBack(SListNode** pphead, SLTDataType x)
{
	SListNode* newnode = BuySListNode(x);//读取新建的结点
	if (*pphead == NULL)
	{
		*pphead = newnode;
		return;
	}
	SListNode* tail = *pphead;
	while (tail->next != NULL)
	{
		tail = tail->next;
	}
	tail->next = newnode;
}
二、顺序表和链表对比:
不同点顺序表链表
存储空间上物理上一定连续逻辑上连续,但物理上不一定连续
随机访问支持不支持
任意位置插入或删除元素可能搬移元素,效率低只需修改指针指向
插入动态顺序表,空间不够需要扩容没有容量概念
应用场景元素高效存储+频繁访问任意位置插入和删除
缓存利用率高低

总结

以上就是今天要讲的顺序表和链表的内容啦,如果本篇博客对你有所帮助的话,请给博主一个三连哦!

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/994650.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号