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

小编主页详情<-请点击
小编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)

arrMAX为定长数组

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->arrps-\>size就是我们需要插入的地方,如图所示

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

3.2.5动态顺序表的头插

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

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

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

如此往复

到最后一步,我们需要把下标为0的元素移动到下标为1的位置,及arr1=arr0,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的元素,及arr0=arr1, i 的初始值为0

最后一步,将下标为size-1的元素替换下标为size-2的元素,及arrsize-2=arrsize-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,及arrsize=arrsize-1,i 的初始值是size

最后一步,我们需要将下标为pos的元素移动到下标为pos+1的位置,及arrpos+1=arrpos,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的位置,及arrpos=arrpos+1,所以 i 的初始值是pos

最后一步,将下标为size-1的元素替换下标为size-2的元素,及arrsize-2=arrsize-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制作,希望各位博友能有所收获

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

相关推荐
地平线开发者4 小时前
profiler debug 工具用法与高一致性策略
算法·自动驾驶
编程大师哥4 小时前
匿名函数 lambda + 高阶函数
java·python·算法
isyangli_blog4 小时前
OpenDayLight (Carbon 版本) 启动与组件安装
开发语言·php
vb2008114 小时前
FastAPI APIRouter
开发语言·python
Benszen4 小时前
KVM虚拟化解决方案
开发语言·perl
会编程的土豆4 小时前
Go 语言反射(Reflection)详解
开发语言·后端·golang
東雪木4 小时前
多线程与并发编程 专属复习笔记
java·开发语言·笔记·java面试
我叫袁小陌4 小时前
算法解题思路指南
算法
地平线开发者5 小时前
Conv+BN+Add+ReLU 融合机制简介
算法·自动驾驶
也曾看到过繁星5 小时前
数据结构---顺序表
数据结构