【探索数据结构】线性表之顺序表

🎉🎉🎉欢迎莅临我的博客空间,我是池央,一个对C++和数据结构怀有无限热忱的探索者。🙌

🌸🌸🌸这里是我分享C/C++编程、数据结构应用的乐园✨

🎈🎈🎈期待与你一同在编程的海洋中遨游,探索未知的技术奥秘💞

📝专栏指路:

📘【C++】专栏:深入解析C++的奥秘,分享编程技巧与实践。

📘【数据结构】专栏:探索数据结构的魅力,助你提升编程能力。

前言

初步认识了数据结构后,我们一起来探索它的逻辑结构里面的线性结构吧。线性结构是一对一的关系。线性表在逻辑结构上是连续的,在物理结构上不一定是连续的。线性表中的顺序表 (本篇的主角)在物理结构上是连续的,而线性表中的链表在物理结构上却是不连续的。

一、线性表

线性表是具有相同数据类型 的n(n≥0)个数据元素的有限序列,其中n为表长,当n=0时线性表是一个空表。

几个概念:

1.ai是线性表中的"第i个"元素线性表中的位序(位序从1开始,注意区分数组下标从0开始

2.a1是表头元素;an是表尾元素。

3.除第一个元素外,每个元素有且仅有一个直接前驱 (前一个元素);除最后一个元素外,每个元素有且仅有一个直接后继(后一个元素)

二、顺序表

正片开始!

1.概念

顺序表------用顺序存储的方式实现线性表顺序存储。把逻辑上相邻的元素存储在物理位置上也相邻的存储单元中,元素之间的关系由存储单元的邻接关系来体现。顺序表的底层是数组。

2.静态顺序表

顺序表的空间大小固定

补充:为了简化代码,我们使用typedef 重命名自定义类型,typedef的优势是什么?

在C或C++中,typedef 关键字用于为已存在的数据类型定义一个新名称(别名)。这在需要简化复杂的数据类型声明,或者为特定的数据类型提供一个更有描述性的名称时非常有用。

代码如下:

cpp 复制代码
typedef int SQLDataType;//顺序表的数据类型
//静态顺序表
typedef struct SeqList
{
	SQLDataType arr[100];
	int size;//有效数据个数
	int capacity;//空间大小
}SL;

3.动态顺序表

顺序表的大小空间不固定,可根据需求改变。

当顺序表存满时,用realloc增容。

cpp 复制代码
typedef int SQLDataType;//顺序表的数据类型
//动态顺序表
typedef struct SeqList
{
	SQLDataType* arr;
	int size;//有效数据个数
	int capacity;//空间大小
}SL;

补充:realloc扩容的规则是什么?

一次扩充一个空间 ,插入一个元素还不会造成空间浪费程序(执行效率低下)

一次扩容固定个大小的空间(10、100...)【小了造成频繁扩容】【大了造成空间浪费】

最优解:成倍数的增加(1.5倍、2倍),数据插入的越多扩容的大小越来越大

扩容后会自动把原有空间释放掉

malloc,realloc,calloc三者区别是什么?

  • malloc函数:用于动态分配指定字节数的内存空间,并返回一个指向它的指针。如果分配成功,则返回非空指针;如果内存空间不足,则返回NULL。需要注意的是,malloc分配的内存空间并未初始化,它们的值是未知的。
  • calloc函数:**也用于动态分配内存空间,与malloc有所不同。calloc在分配内存空间时,会将其初始化为0。**它的参数是要分配的元素个数和每个元素的大小,而不是总的字节数。如果分配成功,则返回指向分配的内存的指针;如果失败,则返回NULL。
  • realloc函数:用于调整之前分配的内存空间大小。它接收一个指向已分配内存的指针和一个新的大小,然后尝试调整内存块的大小。如果成功,则返回指向新的内存块的指针;如果失败,则返回NULL,而原来的内存块保持不变。

代码示例

cpp 复制代码
//是否需要申请空间
void SQLcapacity(SL* ps)
{
	if (ps->capacity == ps->size)//空间已满,需要申请空间
	{
		//realloc增容,一般增加成原本空间大小的二或三倍
		int newcapacity = ps->capacity == 0 ? 4 : ps->capacity * 2;
		SQLDataType* tmp = (SQLDataType*)realloc(ps->arr, newcapacity * sizeof(SQLDataType));
		if (tmp == NULL)
		{
			perror("reacoll fail!");//空间申请失败
			exit(1);//退出程序
		}
		ps->arr = tmp;
		ps->capacity = newcapacity;
	}
}

4.对顺序表的操作

(1)初始化

cpp 复制代码
void InitSql(SL* ps)
{
	ps->arr = NULL;
	ps->size = ps->capacity = 0;
}

(2)尾插

cpp 复制代码
void PushBackSql(SL* ps, SQLDataType x)
{
	assert(ps);
	//插入之前先看空间够不够
	SQLcapacity(ps);
	ps->arr[ps->size++] = x;//size是顺序表尾部,后置++插入x后size加一
}

(3)头插

cpp 复制代码
//头部插入
void PushHeadSql(SL* ps, SQLDataType x)
{
	assert(ps);
	//插入之前先看空间够不够
	SQLcapacity(ps);
	//让原本的数据往后移一位
	for (int i = ps->size;i > 0;i--)
	{
		ps->arr[i] = ps->arr[i - 1];//arr[1]=arr[0]让arr[1]的位置放入原本arr[0]的数据
	}
	ps->arr[0] = x;
	ps->size++;
}

(4)查找

cpp 复制代码
//查找指定数据
int FindPosSql(SL* ps, SQLDataType x)
{
	assert(ps);
	for (int i = 0;i < ps->size;i++)
	{
		if (ps->arr[i] == x)
			return i;
	}
	return -1;
}

找到了返回下标,找不到则返回不存在的下标

(5)尾删

cpp 复制代码
//尾部删除
void DelBackSql(SL* ps)
{
	assert(ps);
	assert(ps->size);//顺序表为空时不能执行删除操作
	ps->size--;
}

(6)头删

cpp 复制代码
//头部删除
void DelHeadSql(SL* ps)
{
	assert(ps);
	assert(ps->size);//顺序表为空时不能执行删除操作
	//顺序表存放数据整体往前挪一位
	for (int i = 0;i < (ps->size) - 1;i++)
	{
		//arr[0]的位置放原本arr[1]的数据,最后是ps->arr[size-2]=ps->arr[size-1]
		ps->arr[i] = ps->arr[i + 1];//arr[0]的位置放原本arr[1]的数据,最后是ps->arr[size-2]=ps->arr[size-1]
	}
	ps->size--;
}

(7)在指定位置之前插入数据

cpp 复制代码
//指定位置前插入
void AddPosSql(SL* ps, int pos, SQLDataType x)
{
	assert(ps);
	assert(pos >= 0 && pos <= ps->size);
	//先看看空间够不够
	SQLcapacity(ps);
	//pos位置上的数和他后面的数整体往后挪一位
	for (int i = ps->size;i > pos;i--)
	{
		ps->arr[i] = ps->arr[i - 1];//结束arr[pos+1]=arr[pos];
	}
	ps->arr[pos] = x;
	ps->size++;
}

(8)在指定位置删除数据

cpp 复制代码
//删除指定位置数据
void DelPosSql(SL* ps, int pos)
{
	assert(ps);
	assert(pos >= 0 && pos <= ps->size);
	//整体往前挪一位
	for (int i = pos;i < ps->size - 1;i++)
	{
		ps->arr[i] = ps->arr[i + 1];//arr[size-2]=arr[size-1]
	}
	ps->size--;
}

(9)销毁

cpp 复制代码
//销毁顺序表
void DestroySql(SL* ps)
{
	if (ps->arr)//不是空表才需要释放
	{
		free(ps->arr);
	}
	ps->arr = NULL;
	ps->size = ps->capacity = 0;
}

顺序表小结

下一篇预告:线性表之单链表

持续更新中...

敬请期待

相关推荐
XiaoLeisj2 小时前
【JavaEE初阶 — 多线程】单例模式 & 指令重排序问题
java·开发语言·java-ee
dayouziei2 小时前
java的类加载机制的学习
java·学习
励志成为嵌入式工程师3 小时前
c语言简单编程练习9
c语言·开发语言·算法·vim
捕鲸叉3 小时前
创建线程时传递参数给线程
开发语言·c++·算法
A charmer3 小时前
【C++】vector 类深度解析:探索动态数组的奥秘
开发语言·c++·算法
Peter_chq3 小时前
【操作系统】基于环形队列的生产消费模型
linux·c语言·开发语言·c++·后端
wheeldown4 小时前
【数据结构】选择排序
数据结构·算法·排序算法
记录成长java5 小时前
ServletContext,Cookie,HttpSession的使用
java·开发语言·servlet
前端青山5 小时前
Node.js-增强 API 安全性和性能优化
开发语言·前端·javascript·性能优化·前端框架·node.js
hikktn5 小时前
如何在 Rust 中实现内存安全:与 C/C++ 的对比分析
c语言·安全·rust