【数据结构】顺序表专题(详细代码及配图)

小编主页详情<-请点击
小编gitee代码仓库<-请点击


本文主要介绍了数据结构的顺序表,内容全由作者原创(无AI),同时深度解析了顺序表增删查改等功能,并带有配图帮助博友们更好的理解,点个关注不迷路,下面进入正文~~


目录

前言:什么是数据结构?

1.顺序表

1.1线性表的概念及结构

1.2顺序表和数组的关系

2.顺序表的分类

2.1静态顺序表

2.2动态顺序表

3.动态顺序表的具体实现

3.1源文件及头文件的建立

3.2动态顺序表需要实现的功能

3.2.1动态顺序表的初始化

3.2.2动态顺序表的销毁

3.2.3动态顺序表的打印

3.2.4动态顺序表的尾插

3.2.5动态顺序表的头插

3.2.6动态顺序表的尾删

3.2.7动态顺序表的头删

3.2.8在动态顺序表的指定位置插入数据

3.2.9在动态顺序表的指定位置删除数据

3.2.10在动态顺序表查找指定数据

4.全部代码的呈现

4.1SeqList.h

4.2SeqList.c

4.3test.c

结语:


前言:什么是数据结构?

当我们学习完C语言后,我们要开始学习数据的内容,那么你是否会好奇,数据结构是什么?

简单的说,数据结构就是数据的存放方式+组织方式

例如,班里面的学生或许是按学号排列,或许是按姓名排列,这些都叫数据结构

当我们面对一堆非常庞大的数据时,就需要通关数据结构去排序

1.顺序表

1.1线性表的概念及结构

线性表=排成一条直线的数据集合

例如:蔬菜分为绿叶类、瓜类、菌类等,指的是有某一类相同特性数据的集合

常见的线性表:顺序表、链表、栈、队列、字符串......

逻辑结构:线性表是线性结构,是一条连续的结构

物理结构:在物理结构上不一定是连续的,及在内存上不一定是连续

1.2顺序表和数组的关系

顺序表的底层结构是数组,对数组的封装,实现了常用的增删查改等接口

2.顺序表的分类

2.1静态顺序表

概念:使用定长数组存储元素

下面我们实现静态顺序表

cs 复制代码
typedef int SLDataType;
cs 复制代码
#define MAX 100
typedef struct SeqList
{
	SLDataType arr[MAX]; 
	int size;
}SL;

注意:一个顺序表不一定是存一种类型的数据,因此,为了方便我们后续的使用,我们将数据类型命名位SLDataType,这样当我们想要存其他类型的数据时,只需改变一处地方即可(如上图所示的int)

arr[MAX]为定长数组

size为有效数据个数

++静态顺序表缺陷:空间给少了不够用,空间给多了造成浪费++

因此,更推荐使用动态顺序表

2.2动态顺序表

cs 复制代码
typedef struct SeqList
{
	SLDataType* arr;
	int size;
	int capacity;
}SL;

arr为指向一块空间的指针,可以用malloc、realloc等内存函数来分配内存

size为有效数据个数

capacity为空间容量

3.动态顺序表的具体实现

3.1源文件及头文件的建立

为了方便后续代码的实现,我们将建立一个SeqList的头文件、一个SeqList的源文件及一个用来测试代码的test源文件

3.2动态顺序表需要实现的功能

cs 复制代码
void SLInit(SL* ps);
void SLDestory(SL* ps);
void SLprint(SL s);
void SLCheckCapacity(SL* ps);
void SLPushBack(SL* ps, SLDataType x);
void SLPopBack(SL* ps);
void SLPushFront(SL* ps, SLDataType x);
void SLPopFront(SL* ps);
void SLInsert(SL* ps, int pos, SLDataType x);
void SLErase(SL* ps, int pos);
int SLFind(SL* ps, SLDataType x);

3.2.1动态顺序表的初始化

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

注意:当我们想通过函数改变结构体里的值时,应当使用传址调用,因此函数的接受值应是指针,及SL* ps,当我们使用函数时要传如结构体的地址,如&sl。

3.2.2动态顺序表的销毁

当我们使用动态顺序表时,我们必然会为arr分配内存,因此我们必须要将分配给arr的内存释放掉,防止内存泄露

cs 复制代码
void SLDestory(SL* ps)
{
	if (ps->arr)
	{
		free(ps->arr);
	}
	ps->arr = NULL;
	ps->capacity = ps->size = 0;
}

3.2.3动态顺序表的打印

cs 复制代码
void SLprint(SL s)
{
	for (int i = 0; i < s.size; i++)
	{
		printf("%d ", s.arr[i]);
	}
	printf("\n");
}

3.2.4动态顺序表的尾插

尾插,顾名思义实在动态顺序表的最后插入一个值。但同时存在顺序表空间不足的可能,及size==capacity,因此在头插之前,我们要先检查动态顺序表是否有空间插入值。为此我们将定义一个检查空间容量的函数。

cs 复制代码
void SLCheckCapacity(SL* ps)
{
	if (ps->capacity == ps->size)
	{
		int newCapacity = ps->capacity == 0 ? 4 : 2 * ps->capacity;
		SLDataType* tmp = realloc(ps->arr, newCapacity * sizeof(SLDataType));
		if (tmp == NULL)
		{
			perror("realloc");
			exit(1);
		}
		ps->arr = tmp;
		ps->capacity = newCapacity;
	}
}

注意:
1.新的空间大小通常是原来空间大小的2倍或3倍
2.原来的capacity可能是0,不能直接翻倍。可以用三目操作符判断capacity是否为0,若为0;赋值为4;若不为0,则翻倍。

下面开始实现动态顺序表的尾插

cs 复制代码
void SLPushBack(SL* ps, SLDataType x)
{
	assert(ps);
	SLCheckCapacity(ps);
	ps->arr[ps->size++] = x;
}

需要注意的几个细节:
1.传入的ps有可能为空指针,需要用assert断言
2.ps->arr[ps->size]就是我们需要插入的地方,如图所示

3.插入后size要加1,具体如代码所示

3.2.5动态顺序表的头插

头插,在最前面的位置插如一个数据

为了实现头插,我们要把数据从前向后移动,先移动最后面的数据,防止数据丢失

第一步,我们需要把下标为size-1的数据移动到下标为size的位置,及arr[size]=arr[size-1],由此可得 i 的初始值为size

如此往复

到最后一步,我们需要把下标为0的元素移动到下标为1的位置,及arr[1]=arr[0],i 的最后一个值为1,所以 i 的范围应当是 i > 0

cs 复制代码
void SLPushFront(SL* ps, SLDataType x)
{
	assert(ps);
	SLCheckCapacity(ps);
	for (int i = ps->size; i > 0; i--)
	{
		ps->arr[i] = ps->arr[i - 1];
	}
	ps->arr[0] = x;
	ps->size++;
}

**注意:**千万不要忘了size++

3.2.6动态顺序表的尾删

尾删就是将最后一个位置的数据删掉

我们想想看,如果size--,是不是就相当于尾删?

答案:是的!

cs 复制代码
void SLPopBack(SL* ps)
{
	assert(ps);
	assert(ps->size);
	--ps->size;
}

如果size已经为0了,那删除数据就会出现问题,因此我们需要检测size是否等于0,如果是,就报错。

3.2.7动态顺序表的头删

头删,将最前面的位置删掉

第一步,将下标为1的元素替换下标为0的元素,及arr[0]=arr[1], i 的初始值为0

最后一步,将下标为size-1的元素替换下标为size-2的元素,及arr[size-2]=arr[size-1],i 的最大值为size-2,所以 i <size-1

下面为头删的实现代码

cs 复制代码
void SLPopFront(SL* ps)
{
	assert(ps);
	assert(ps->size);
	for (int i = 0; i < ps->size - 1; i++)
	{
		ps->arr[i] = ps->arr[i + 1];
	}
	--ps->size;
}

3.2.8在动态顺序表的指定位置插入数据

我们将实现在指定位置之前插入数据

比如说,我们想在pos=1的位置插如一个数据,那我们应当将2 3 4都向后移动一位,并且是从前向后移动,先移动4,及arr[size]=arr[size-1],i 的初始值是size

最后一步,我们需要将下标为pos的元素移动到下标为pos+1的位置,及arr[pos+1]=arr[pos],i>pos

下面为具体代码的实现

cs 复制代码
void SLInsert(SL* ps, int pos, SLDataType x)
{
	assert(ps);
	assert(pos >= 0 && pos <= ps->size);
	SLCheckCapacity(ps);
	for (int i = ps->size; i > pos; i--)
	{
		ps->arr[i] = ps->arr[i - 1];
	}
	ps->arr[pos] = x;
	ps->size++;
}

**注意:**我们还应当检查pos的范围,pos的范围是大于等于0并且小于等于size

3.2.9在动态顺序表的指定位置删除数据

比如说,我们要将pos=1的数据删除

第一步,将下标为pos+1的元素移动到下标为pos的位置,及arr[pos]=arr[pos+1],所以 i 的初始值是pos

最后一步,将下标为size-1的元素替换下标为size-2的元素,及arr[size-2]=arr[size-1],i 的最大值为size-2,所以 i <size-1

cs 复制代码
void SLErase(SL* ps, int pos)
{
	assert(ps);
	assert(ps->size);
	for (int i = pos; i < ps->size - 1; i++)
	{
		ps->arr[i] = ps->arr[i + 1];
	}
	--ps->size;
}

3.2.10在动态顺序表查找指定数据

在动态顺序表查找指定数据,如果找到了,返回指定数据的下标;如果没找到,返回无效值(如-1)

cs 复制代码
int SLFind(SL* ps, SLDataType x)
{
	assert(ps);
	for (int i = 0; i < ps->size; i++)
	{
		if (ps->arr[i] == x)
		{
			return i;
		}
	}
	return -1;
}

4.全部代码的呈现

4.1SeqList.h

cs 复制代码
#pragma once
#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
#include<string.h>
#include "Contact.h"
typedef int SLDataType;
//typedef peoInfo SLDataType;
#define MAX 100
//typedef struct SeqList
//{
//	SLDataType arr[MAX];
//	int size;
//}SL;

typedef struct SeqList
{
	SLDataType* arr;
	int size;
	int capacity;
}SL;

void SLInit(SL* ps);
void SLDestory(SL* ps);
void SLprint(SL s);
void SLCheckCapacity(SL* ps);
void SLPushBack(SL* ps, SLDataType x);
void SLPopBack(SL* ps);
void SLPushFront(SL* ps, SLDataType x);
void SLPopFront(SL* ps);
void SLInsert(SL* ps, int pos, SLDataType x);
void SLErase(SL* ps, int pos);
int SLFind(SL* ps, SLDataType x);

4.2SeqList.c

cs 复制代码
#define _CRT_SECURE_NO_WARNINGS
#include "SeqList.h"
void SLInit(SL* ps)
{
	ps->arr = NULL;
	ps->capacity = ps->size = 0;
}
void SLDestory(SL* ps)
{
	if (ps->arr)
	{
		free(ps->arr);
	}
	ps->arr = NULL;
	ps->capacity = ps->size = 0;
}
void SLprint(SL s)
{
	for (int i = 0; i < s.size; i++)
	{
		printf("%d ", s.arr[i]);
	}
	printf("\n");
}
void SLCheckCapacity(SL* ps)
{
	if (ps->capacity == ps->size)
	{
		int newCapacity = ps->capacity == 0 ? 4 : 2 * ps->capacity;
		SLDataType* tmp = realloc(ps->arr, newCapacity * sizeof(SLDataType));
		if (tmp == NULL)
		{
			perror("realloc");
			exit(1);
		}
		ps->arr = tmp;
		ps->capacity = newCapacity;
	}
}
void SLPushBack(SL* ps, SLDataType x)
{
	assert(ps);
	SLCheckCapacity(ps);
	ps->arr[ps->size++] = x;
}
void SLPopBack(SL* ps)
{
	assert(ps);
	assert(ps->size);
	--ps->size;
}
void SLPushFront(SL* ps, SLDataType x)
{
	assert(ps);
	SLCheckCapacity(ps);
	for (int i = ps->size; i > 0; i--)
	{
		ps->arr[i] = ps->arr[i - 1];
	}
	ps->arr[0] = x;
	ps->size++;
}
void SLPopFront(SL* ps)
{
	assert(ps);
	assert(ps->size);
	for (int i = 0; i < ps->size - 1; i++)
	{
		ps->arr[i] = ps->arr[i + 1];
	}
	--ps->size;
}
void SLInsert(SL* ps, int pos, SLDataType x)
{
	assert(ps);
	assert(pos >= 0 && pos <= ps->size);
	SLCheckCapacity(ps);
	for (int i = ps->size; i > pos; i--)
	{
		ps->arr[i] = ps->arr[i - 1];
	}
	ps->arr[pos] = x;
	ps->size++;
}
void SLErase(SL* ps, int pos)
{
	assert(ps);
	assert(ps->size);
	for (int i = pos; i < ps->size - 1; i++)
	{
		ps->arr[i] = ps->arr[i + 1];
	}
	--ps->size;
}
int SLFind(SL* ps, SLDataType x)
{
	assert(ps);
	for (int i = 0; i < ps->size; i++)
	{
		if (ps->arr[i] == x)
		{
			return i;
		}
	}
	return -1;
}

4.3test.c

cs 复制代码
#define _CRT_SECURE_NO_WARNINGS
#include"SeqList.h"
void SLTest01()
{
	SL sl;
	SLInit(&sl);
	//增删查改
	SLPushBack(&sl, 1);
	SLPushBack(&sl, 2);
	SLPushBack(&sl, 3);
	SLPushBack(&sl, 4);
	SLprint(sl);

	SLPushFront(&sl, 5);
	SLPushFront(&sl, 6);
	SLprint(sl);

	SLPopBack(&sl);
	SLPopBack(&sl);
	SLprint(sl);

	SLPopFront(&sl);
	SLprint(sl);

	SLDestory(&sl);
}
int main()
{
	SLTest01();
	return 0;
}

结语:

这篇文章全文由作者手写,图片由画图软件所制,无AI制作,希望各位博友能有所收获

欢迎各位博友的讨论,觉得不错的小伙伴,别忘了点赞关注哦~

相关推荐
Trouvaille ~2 小时前
【优选算法篇】BFS 解决最短路——寻找最优路径的真谛
c++·算法·leetcode·面试·蓝桥杯·宽度优先·最短路问题
listhi5202 小时前
基于在线优化的快速模型预测控制(Fast Online MPC)MATLAB实现
开发语言·matlab
雅俗共赏1002 小时前
医学图像重建中常用的迭代求解器分类
图像处理·算法
不熬夜的熬润之2 小时前
KCF算法解析
人工智能·算法·计算机视觉·机器人
CoderCodingNo2 小时前
【CSP】CSP-J 2025真题 | 多边形 luogu-P14360 (相当于GESP六级水平)
开发语言·c++·算法
一直都在5722 小时前
AQS详解
java·开发语言
zero15972 小时前
Python 8天极速入门笔记(大模型工程师专用):第二篇-Python基础入门(变量、数据类型、print输出)
开发语言·笔记·python
Magic--2 小时前
【LeetCode 27. 移除元素】C++ 范围 for 极简实现与原理解析
c++·算法·leetcode
koping_wu2 小时前
【Java并发】CompletableFuture详解:常用API和底层原理
java·开发语言·python