顺序表--C语言版(从0开始,超详细解析 ,小白一听就懂!!!)

news2024/11/15 10:21:00

目录

一、前言

🍎什么是数据结构 

🍐学习数据结构有什么用

二、顺序表概念 ------- (线性表)

🍉什么是线性表

🍓顺序表概念详解

💦 顺序表与数组的区别 

三、顺序表详解

🍌顺序表结构

💦静态顺序表

💦动态顺序表 

🍊动态顺序表各个接口的实现

⭕ 接口1:定义结构体 SL

⭕ 接口2:初始化结构体 (SLInit)

⭕ 接口3:检查结构体中的数组是否需要扩容(SLCheckCapacity)   

⭕ 接口4:尾插  (SLPushBack)

⭕ 接口5:尾插删 (SLPopBack) 

⭕ 接口6:头插 (SLPushFront)  

⭕ 接口8:在指定位置插入数据(SLInsert)    

⭕ 接口9:在指定位置删除数据(SLErase)     

⭕ 接口10:查找某一个数据的位置(SLFind)     

⭕ 接口11:查找某一个数据的起始位置(SLFinds)      

⭕ 接口13:销毁(SLDestory)

四、顺序表的完整代码

🍇SeqList.h

🍋Seqlist.c

 🥝test.c

 🍍代码运行的菜单界面 

五、 共勉


一、前言

     在我们学习顺序表之前呢,我们大家肯定会有疑问,什么是数据结构,为什么要去学习数据结构,顺序表在数据结构里面代表什么呢?,这里我来给大家一次解惑,让大家真正的搞懂数据结构,学习起来才更加有动力。

🍎什么是数据结构 

在面对数据结构,许多同学肯定会感到头疼,因为它很麻烦,那么到底什么是数据结构呢?

大家可以这样去思考:

在平时的学习中,经常用什么方式把 数据 放在一起?

有的老铁可能会说:变量(差的有点远)

还有的老铁会说是:数组  (差不多) :数组 能够看成  一种  数据结构的形式

我的理解: 数据结构就是一群数据按照一定的结构组合在一起就可以理解为 数据结构

官方解释:数据结构(Data Structure)是计算机存储、组织数据的方式,指相互之间存在一种或多种特定关系的 数据元素集合 叫做:数据结构

常见的数据结构的体现: 有线性结构、树形结构、图形结构、等

🍐学习数据结构有什么用

大家可以继续思考,学习数据结构能干什么?

有的老铁可能会说:将一些四处 飘泊  的数据收集起来  (有道理)

还有的老铁会说是:将这些凌乱的数据,整理一下,变得有规律,方便查找  (很有道理)

我的理解 :既然说的是 结构 ,我们肯定可以通过结构,进行数据的查询、数据的创建、进行一系列的 增删改查 的操作。

二、顺序表概念 ------- (线性表)

🍉什么是线性表

本次我们要来介绍,第一种数据结构,也是数据结构中最简单的一部分:线性表

此时此刻,肯定会有老铁会有疑问,为什么难道他会像一条线一样一次连接吗?

没错,当数据首尾一次相连接,这种数据结构就被叫做线性表。

注意 :相连接是逻辑上的连接,不是空间上的连接。

此时,可能还会有老铁站出来说:你说的这不就是数组嘛,小意思,我会。

其实 数组只是一种线性表,可是线性表还有很多种形式哦!

线性表的形式: 数组、链表、顺序表、队列等   (其中数组我们在C语言已经学过,不再提及) 。

🍓顺序表概念详解

在讲解是是顺序表之前,肯定会有老铁再问,顺序表和数组,都是 线性表 中最简单的体现,那它们之间有什么区别呢?

💦 顺序表与数组的区别 

顺序表:顺序表是用 一段物理地址连续存储单元 ,依次存储数据元素的线性结构

解释:顺序表就是将数据连着存放,存放的数据空间也是连着的

数组:数据不用按顺序的存放,可以随意的存放

区别:数组不按空间顺序随意地存放数据,但是顺序表的数据是要按照空间的的顺序存放

说的这里估计有些老铁已经开始有点 晕晕的状态了,我来给大家画图解释一下:

三、顺序表详解

🍌顺序表结构

💦静态顺序表

知识点1:静态顺序表

静态顺序表:使用定长数组存储

优点:操作简单,代码实现容易

缺点:定长数组很受限制,数组开小了不够用,开大了又浪费

💦动态顺序表 

知识点2:动态顺序表

动态顺序表:使用动态开辟的数组进行数据的存储

优点:数组可以根据自己的需求进行调解

缺点:代码过于麻烦

 

由于在我们平时的代码需求中,动态顺序表的的需求是很高的,所以今天以动态顺序表为例,来进行代码书写。

🍊动态顺序表各个接口的实现

这里先建立三个文件:

1️⃣ :SeqList.h文件,用于函数声明

2️⃣ :SeqList.c文件,用于函数的定义

3️⃣ :Test.c文件,用于测试函数

建立三个文件的目的: 将顺序表作为一个项目来进行书写,方便我们的学习与观察。

⭕ 接口1:定义结构体 SL

 🔑在动态顺序表的结构由 三个成员组成:

▶  指向动态开辟空间的 a 指针

▶  记录当前有效数据个数的 size 变量

▶  记录当前容量的 capacity 变量

🔑 我们会发现,动态顺序表的结构体比静态顺序表的结构体多了一个 capacity 成员。

 我们用这个成员记录当前顺序表的最大容量,当有效数据个数 size 和 capacity 相等时,说明了当前顺序表空间已满,需要进行扩容。

typedef int SLDateType;   // 数据类型
typedef struct Seqlist
{
	SLDateType* a;  // 指向动态开辟的空间
	int size;  // 记录存储了多少个有效数据
	int capacity; //空间容量大小
}SL;

首先:先定义初始的变量,并记录 空间中存储数据的个数 :举例 初始有三个数据

⭕ 接口2:初始化结构体 (SLInit)

知识点3:顺序表进行初始化

为什么要进行结构体的初始化呢?

在顺序表进行操作之前,需要先将其内容进行初始化,防止之后的操作出现错误

在实现初始化接口之前,大家先思考一下哈,参数可不可以 为结构体变量?

例如: ❌ 写法

void SLInit(SL ps)
{
	ps.a = NULL;
	ps.sz = ps.capacity = 0;
}

估计大部分老铁都会觉得这样是对滴,在这里我要告诉大家,这总写法是绝对行不通的!!

大家要知道,实参在传参的时候,会形成一个份临时拷贝,叫做形参。

当我们在函数中对形参的内容进行修改时,是不会影响到实参的,所以不可以。

正确的写法:

要正确的进行的初始化结构体,我们需要传递  SL 的地址,通过指针对结构体的内容进行修改。

传递 SL 的地址,通过指针的方式进行初始化结构体
函数原型:void SLInit(SL *ps)      // 初始化

函数实现: ✔ 写法

void SLInit(SL *ps)   // 初始化
{
	assert(ps);     // 断言 指针ps 防止出现空指针
	ps->a = NULL;   
	ps->size = 0;    // 进行结构体的初始化
	ps->capacity = 0;
}

⭕ 接口3:检查结构体中的数组是否需要扩容(SLCheckCapacity)   

🔑 当顺序表需要插入数据时,可能会遇到三种情况:

▶  整个顺序表没有空间 

▶  空间不够,需要扩容

▶  空间足够,直接插入数据

🔑 如果顺序表空间足够,那么不需要扩容,通过相关操作插入数据

🔑 如果空间不足或者根本没有空间,那么就得扩容。

▶  当顺序表没有空间时,我们开辟四个空间

当顺序表空间不足,我们将当前空间扩大为两倍(扩两倍是为了防止扩容过度,或扩小了频繁扩容,消耗过大)。

▶当顺序表空间足够,不进行任何操作,if语句判断后,直接返回。

知识点4:给顺序表扩充容量
函数原型:void SLCheckCapacity(SL* ps)

函数的实现:

注意:在扩容的的时候 我们用到了 动态分配函数 realloc ()函数 ,如果大家对这个函数不太了解,请看我的上一篇文章。

动态分配讲解:(55条消息) 动态内存分配:malloc、calloc、realloc(超详解析,多维度分析,小白一看就懂!!!!)_sunny-ll的博客-CSDN博客_calloc malloc realloc

//检查是否需要扩容
void SLCheckCapacity(SL* ps)
{
	assert(ps);
	// 扩容
    // 顺序表没有空间 或者 顺序表空间不足
	if (ps->size == ps->capacity)//检查是否越界
	{
		int newCapacity = ps->capacity == 0 ? 4 : ps->capacity * 2;
		SLDateType* temp = (SLDateType*)realloc(ps->a, newCapacity * sizeof(SLDateType));    //realloc 的用法
		if (temp == NULL)
		{
			perror("realloc fail");
			exit(-1);      //异常终止
		}
		ps->a = temp;
		ps->capacity = newCapacity;
	}
}

⭕ 接口4:尾插  (SLPushBack)

知识点5:在顺序表的尾部插入数据

函数原型:void SLPushBack(SL* ps, SLDateType x)   // 尾部插入数据

函数实现:

void SLPushBack(SL* ps, SLDateType x)   // 尾部插入数据
{
	assert(ps);
	// 检查是否需要扩容
	SLCheckCapacity(ps);
	// 进行尾部插入
	ps->a[ps->size] = x;
	ps->size++;
}

⭕ 接口5:尾插删 (SLPopBack) 

知识点6:在顺序表的尾部删除数据

函数原型:void SLPopBack(SL* ps)  //尾部删除数据

函数实现:

void SLPopBack(SL* ps)  //尾部删除数据
{
	assert(ps);
	//ps->a[ps->size - 1] = 0;   // size 是从 0 开始的 所以要减去 1
	// 温柔的方式
	/*if (ps->size == 0)
	{
		printf("顺序表已空\n");
		return;
	}*/
	// 暴力的方式
	assert(ps->size > 0);
	ps->size--;
}

🔑注意:当顺序表没有元素时,也就是 sz 为 0 时,不可以进行删除

🔑举例: 假如顺序表有 5 个数据,此时我们尾删 6 个数据,那么这时,我们顺序表的 size = -1。此时程序不会报错,因为本身就没有数据可以删除,但是让我们在进行尾插的时候,程序就会报错啦,因为尾插数据会访问 size 的下表 -1 此时出现了越界访问,程序出错。

🔑解决方案 :加入断言进行判断,防止size 的下标越界 

⭕ 接口6:头插 (SLPushFront)  

知识点7:在顺序表的头部插入数据

函数原型:void SLPushFront(SL* ps, SLDateType x)  

头插原理 :头插就是将数据放在下标为 0 的地方 其余数据依次向后挪一位,此时出现两种情况:

再向后挪数据的过程中

▶  先从第一个数据开始挪动

▶  先从最后一个数据开始挪动

函数图解:情况(1)先从第一个数据开始挪动  :会发生 数据覆盖  ❌

 函数图解:情况(2)先从最后一个数据开始挪动  :符合我们的理想状态 ✔

函数实现:

void SLPushFront(SL* ps, SLDateType x)  
{
	assert(ps);
	// 扩容
	SLCheckCapacity(ps);
	// 挪动数据
	int end = ps->size - 1;
	while (end >= 0)
	{
		ps->a[end + 1] = ps->a[end];
		end--;
	}
	ps->a[0] = x;
	ps->size++;
}

⭕ 接口7:头删(SLPopFront)   

知识点8:在顺序表的头部删除数据

函数原型:void SLPopFront(SL* ps) 
头删原理:头删就是将下标为 0 的数据删除,其余数据依次向前挪动,此时同样出现两情况。

在向前挪动的过程中

▶  先从下标为 1 的数据向前挪动

▶  先从最后一个数据向前挪动

函数图解:情况(1):先从最后一个数据开始挪动  ❌

 函数图解:情况(2):先从小标为 1 的数据开始挪动

函数实现:
 

void SLPopFront(SL* ps) 
{
	assert(ps);
	assert(ps->size > 0);  //暴力检查
	int begin = 1;
	while (begin < ps->size)
	{
		ps->a[begin - 1] = ps->a[begin];
		begin++;
	}
	ps->size--;
}

⭕ 接口8:在指定位置插入数据(SLInsert)    

知识点9:在顺表的指定的 pos 下标处插入数据

函数的原型:void SLInsert(SL* ps, int pos, SLDateType x)

注意:要实现这一功能,我们依然需要一个end下标,数据从后往前依次后挪,直到pos下标移动完毕。另外,别忘了检查容量。

函数的实现:

void SLInsert(SL* ps, int pos, SLDateType x)
{
	assert(ps);
	assert(pos >= 0);    // pos 的位置,因该在有效位置
	assert(pos <= ps->size);  // 等于 “=” size 相当于尾插
	SLCheckCapacity(ps); // 扩容
	int end = ps->size - 1;
	while (end >= pos)
	{
		ps->a[end + 1] = ps->a[end];
		end--;
	}
	ps->a[pos] = x;
	ps->size++;
}

函数拓展:该功能其实也可以实现头插和尾插,所以我们可以在头插尾插中复用该功能

// 头插
void SeqListPushFront(SL* ps, SLDataType x)
{
	SeqListInsert(ps, 0, x);
}

// 尾插
void SeqListPushBack(SL* ps, SLDataType x)
{
	SeqListInsert(ps, ps->sz, x);
}

⭕ 接口9:在指定位置删除数据(SLErase)     

知识点10:顺序表在指定的 pos 下标删除数据

函数原型:void SLErase(SL* ps, int pos)

注意:要实现这一功能,我们需要一个begin下标,数据从前往后依次前挪,直到sz-1下标移动完毕。

函数实现:

void SLErase(SL* ps, int pos)
{
	assert(ps);
	assert(pos >= 0);
	assert(pos < ps->size);
	assert(ps->size > 0);  //检查 size 是否为空
	int begin = pos + 1;
	while (begin < ps->size)
	{
		ps->a[begin - 1] = ps->a[begin];
		begin++;
	}
	ps->size--;
}

函数拓展:同样的,该接口也可复用于头删尾删

// 头删
void SeqListPopFront(SL* ps)
{
	SeqListErase(ps, 0);
}

// 尾删
void SeqListPopBack(SL* ps)
{
	SeqListErase(ps, ps->sz - 1);
}

⭕ 接口10:查找某一个数据的位置(SLFind)     

知识点11:查找某一个数据的位置

函数的原型:int SLFind(SL* ps, SLDateType x)

函数的实现:

int SLFind(SL* ps, SLDateType x)
{
	assert(ps);
	for (int i = 0; i < ps->size; i++)
	{
		if (ps->a[i] == x)
		{
			return i;
		}
	}
	return -1;
}

⭕ 接口11:查找某一个数据的起始位置(SLFinds)      

知识点12 :查找某一个数据的起始位置

函数原型:int SLFinds(SL* ps, SLDateType x, int begin)

函数实现:

int SLFinds(SL* ps, SLDateType x, int begin)
{
	assert(ps);
	for (int i = begin; i < ps->size; i++)
	{
		if (ps->a[i] == x)
		{
			return i;
		}
	}
	return -1;
}

 ⭕ 接口12:打印函数(SLPrint)

知识点13:打印已经实现的函数
 

函数原型:void SLPrint(SL *ps)

函数实现:在每次操作后,可以打印出顺序表,观察操作情况

void SLPrint(SL *ps)  // 打印函数
{
	assert(ps);
	for (int i = 0; i < ps->size; i++)
	{
		printf("%d ", ps->a[i]);
	}
	printf("\n");
}

 ⭕ 接口13:销毁(SLDestory)

知识点14:销毁顺序表所开辟的空间,防止内存泄漏

函数原型:void SLDestory(SL* ps)


函数实现:

void SLDestory(SL* ps)   //销毁
{
	assert(ps);
	if (ps->a != NULL)
	{
		free(ps->a);
		ps->a = NULL;
		ps->size = ps->capacity = 0;
	}
}

四、顺序表的完整代码

🍇SeqList.h

#pragma once    // 防止重复包含
//---------动态顺序表------------//
#include <stdlib.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <math.h>
#include <assert.h>
#define M 1000

// 加入typedef 可以进行简写
typedef int SLDateType;   // 数据类型
typedef struct Seqlist
{
	SLDateType* a;
	int size;  // 记录存储了多少个有效数据
	int capacity; //空间容量大小
}SL;
void SLInit(SL* ps);  //初始化   

void SLDestory(SL* ps); //销毁   

void SLPushBack(SL* ps, SLDateType x);  // 尾插  

void SLPrint(SL* ps);  //打印函数  

void SLPopBack(SL* ps); //尾删    

void SLPushFront(SL* ps, SLDateType x); //头插 

void SLPopFront(SL* ps);  //头删

void SLCheckCapacity(SL* ps);  //检查是否需要扩容

//中间插入删除
void SLInsert(SL* ps, int pos, SLDateType x);  //在pos位置插入数据

void SLErase(SL* ps, int pos); //删除pos位置的数据

void SLsize(SL* ps);  // 测试 size 的值

int SLFind(SL* ps, SLDateType x);  //查找某一个数字的位置

int SLFinds(SL* ps, SLDateType x, int begin);   // 确定查找数字的起始位置

🍋Seqlist.c

#define  _CRT_SECURE_NO_WARNINGS 1
#include "SeqList.h"

void SLPrint(SL *ps)  // 打印函数
{
	assert(ps);
	for (int i = 0; i < ps->size; i++)
	{
		printf("%d ", ps->a[i]);
	}
	printf("\n");
}

// 测试 size 的值
void SLsize(SL* ps)
{
	assert(ps);
	printf("%d\n", ps->size);
}

void SLInit(SL *ps)   // 初始化
{
	assert(ps);
	ps->a = NULL;
	ps->size = 0;
	ps->capacity = 0;
}

//检查是否需要扩容
void SLCheckCapacity(SL* ps)
{
	assert(ps);
	// 扩容
	if (ps->size == ps->capacity)//检查是否越界
	{
		int newCapacity = ps->capacity == 0 ? 4 : ps->capacity * 2;
		SLDateType* temp = (SLDateType*)realloc(ps->a, newCapacity * sizeof(SLDateType));    //realloc 的用法
		if (temp == NULL)
		{
			perror("realloc fail");
			exit(-1);      //异常终止
		}
		ps->a = temp;
		ps->capacity = newCapacity;
	}
}

void SLDestory(SL* ps)   //销毁
{
	assert(ps);
	if (ps->a != NULL)
	{
		free(ps->a);
		ps->a = NULL;
		ps->size = ps->capacity = 0;
	}
}

void SLPushBack(SL* ps, SLDateType x)   // 尾部插入数据
{
	assert(ps);
	// 检查是否需要扩容
	SLCheckCapacity(ps);
	// 进行尾部插入
	ps->a[ps->size] = x;
	ps->size++;
}

void SLPopBack(SL* ps)  //尾部删除数据
{
	assert(ps);
	//ps->a[ps->size - 1] = 0;   // size 是从 0 开始的 所以要减去 1
	// 温柔的方式
	/*if (ps->size == 0)
	{
		printf("顺序表已空\n");
		return;
	}*/
	// 暴力的方式
	assert(ps->size > 0);
	ps->size--;
}

// 头插  O(N)  尽量用尾插  
// 需要从最后一个数据开始依次向后挪动,空出第一个位置,保证头插的位置
void SLPushFront(SL* ps, SLDateType x)  
{
	assert(ps);
	// 扩容
	SLCheckCapacity(ps);
	// 挪动数据
	int end = ps->size - 1;
	while (end >= 0)
	{
		ps->a[end + 1] = ps->a[end];
		end--;
	}
	ps->a[0] = x;
	ps->size++;
}

// 头删  O(1)
// 需要从前往后挪
void SLPopFront(SL* ps) 
{
	assert(ps);
	assert(ps->size > 0);  //暴力检查
	int begin = 1;
	while (begin < ps->size)
	{
		ps->a[begin - 1] = ps->a[begin];
		begin++;
	}
	ps->size--;
}

//在pos位置插入数据
void SLInsert(SL* ps, int pos, SLDateType x)
{
	assert(ps);
	assert(pos >= 0);    // pos 的位置,因该在有效位置
	assert(pos <= ps->size);  // 等于 “=” size 相当于尾插
	SLCheckCapacity(ps); // 扩容
	int end = ps->size - 1;
	while (end >= pos)
	{
		ps->a[end + 1] = ps->a[end];
		end--;
	}
	ps->a[pos] = x;
	ps->size++;
}

//删除pos位置的数据

// 其中 SLErase(ps,0) 就是头删
// 其中 SLErase(ps,ps-size-1)  就是尾删

void SLErase(SL* ps, int pos)
{
	assert(ps);
	assert(pos >= 0);
	assert(pos < ps->size);
	assert(ps->size > 0);  //检查 size 是否为空
	int begin = pos + 1;
	while (begin < ps->size)
	{
		ps->a[begin - 1] = ps->a[begin];
		begin++;
	}
	ps->size--;
}

// 查找某一个数据的位置是
int SLFind(SL* ps, SLDateType x)
{
	assert(ps);
	for (int i = 0; i < ps->size; i++)
	{
		if (ps->a[i] == x)
		{
			return i;
		}
	}
	return -1;
}

// begin 查找 x 的起始位置
int SLFinds(SL* ps, SLDateType x, int begin)
{
	assert(ps);
	for (int i = begin; i < ps->size; i++)
	{
		if (ps->a[i] == x)
		{
			return i;
		}
	}
	return -1;
}

 🥝test.c

#define  _CRT_SECURE_NO_WARNINGS 1
//  ----------- 顺序表 ----------- //

// 顺序表:顺序表是用一段物理地址连续的存储单元依次存储数据元素的线性结构,
// 一般情况下采用数组存储。在数组上完成数据的增删查改。
// 重点:要求连续存储   与数组的区别 :数组是随意存储
// 而顺序表 是连续的存储必须是挨着的

// 1.静态顺序表  --- 不太实用
// 对于数组开打了,浪费 。开少了,不够用

// 2.动态顺序表 --- 按需扩展空间
#include "SeqList.h"
// 头插测试 
void TestSeqList3()
{
	SL s1;  // 创建一个结构体变量
	SLInit(&s1);  // 把结构体变量的地址传过去
	SLPushFront(&s1, 1);
	SLPushFront(&s1, 2);
	SLPushFront(&s1, 3);
	SLPushFront(&s1, 4);

	SLPrint(&s1);  // 4 3 2 1
	SLDestory(&s1);
}
//头删测试
void TestSeqList4()
{
	SL s1;  // 创建一个结构体变量
	SLInit(&s1);  // 把结构体变量的地址传过去
	SLPushFront(&s1, 1);
	SLPushFront(&s1, 2);
	SLPushFront(&s1, 3);
	SLPushFront(&s1, 4);
	SLPrint(&s1);

	SLPopFront(&s1);
	SLPopFront(&s1);
	SLPopFront(&s1);
	SLPopFront(&s1); 
	//SLPopFront(&s1);

	SLPrint(&s1);

	SLPushFront(&s1, 9);
	SLPrint(&s1);
	SLDestory(&s1);
}
// 测试 size 的值
// 注意 size 的值是从 0 开始的
void TestSeqList5()
{
	SL s1;  // 创建一个结构体变量
	SLInit(&s1);  // 把结构体变量的地址传过去
	SLPushFront(&s1, 1);
	SLPushFront(&s1, 2);
	SLPushFront(&s1, 3);
	SLPushFront(&s1, 4);
	SLPrint(&s1);   // 4 3 2 1
	SLsize(&s1);    // 4  也就是说,size 占了 5 个位置
	SLDestory(&s1);

}

// 测试任意位置的插入SLInsert
void TestSeqList6()
{
	SL s1;  // 创建一个结构体变量
	SLInit(&s1);  // 把结构体变量的地址传过去
	SLPushBack(&s1, 1);
	SLPushBack(&s1, 2);
	SLPushBack(&s1, 3);
	SLPushBack(&s1, 4);
	SLPrint(&s1);   // 1 2 3 4

	SLInsert(&s1, 2, 20); 
	SLPrint(&s1);    // 1 2 20 3 4

	SLInsert(&s1, 5, 500);  
	SLPrint(&s1);  // 1 2 20 3 4 500   //尾插

	SLInsert(&s1, 0, 400); // 400 1 2 20 3 4 500   // 头插
	SLPrint(&s1);
	SLDestory(&s1);

}

// 测试任意位置的删除 SLErase
void TestSeqList7()
{
	SL s1;  // 创建一个结构体变量
	SLInit(&s1);  // 把结构体变量的地址传过去
	SLPushBack(&s1, 1);
	SLPushBack(&s1, 2);
	SLPushBack(&s1, 3);
	SLPushBack(&s1, 4);
	SLPrint(&s1);   // 1 2 3 4

	SLErase(&s1, 2);
	SLPrint(&s1);  // 1 2 4

	SLErase(&s1, 2);
	SLPrint(&s1);  // 1 2 
	SLErase(&s1, 0);
	SLPrint(&s1);  // 2
	SLDestory(&s1);
}

// 测试查找某一个数字,并将这个是数字删除
void TestSeqList8()
{
	SL s1;  // 创建一个结构体变量
	SLInit(&s1);  // 把结构体变量的地址传过去
	SLPushBack(&s1, 1);
	SLPushBack(&s1, 2);
	SLPushBack(&s1, 3);
	SLPushBack(&s1, 4);
	SLPushBack(&s1, 5);
	SLPushBack(&s1, 6);
	SLPushBack(&s1, 7);
	SLPushBack(&s1, 8);
	SLPrint(&s1);   // 1 2 3 4 5 6 7 8

	int pos = SLFind(&s1, 5);
	if (pos != -1)
	{
		SLErase(&s1, pos);
	}
	SLPrint(&s1);  // 1 2 3 4 6 7 8

	SLDestory(&s1);
}

// 测试 删除顺序表中 所有的 5 
void TestSeqList9()
{
	SL s1;  // 创建一个结构体变量
	SLInit(&s1);  // 把结构体变量的地址传过去
	SLPushBack(&s1, 1);
	SLPushBack(&s1, 5);
	SLPushBack(&s1, 3);
	SLPushBack(&s1, 4);
	SLPushBack(&s1, 5);
	SLPushBack(&s1, 5);
	SLPushBack(&s1, 7);
	SLPushBack(&s1, 8);
	SLPrint(&s1);   // 1 5 3 4 5 5 7 8

	int pos = SLFinds(&s1, 5, 0);
	while (pos != -1)
	{
		SLErase(&s1, pos);
		pos = SLFinds(&s1, 5, pos);
	}
	SLPrint(&s1);  // 1 3 4 7 8

	SLDestory(&s1);  
}

// 越界是不一定报错的
// 越界 读 基本都查不出来 只能是程序的值会出现值
// 越界 写 可能会报错

void menu()
{
	printf("***********************************************************\n");
	printf("1、尾插数据             2、尾删数据\n");
	printf("\n");
	printf("3、头插数据             4、头删数据\n");
	printf("\n");
	printf("5、在任意位置插入数据(位置3插入20)\n");
	printf("\n");
	printf("6、在任意位置删除数据              \n"); 
	printf("\n");
	printf("7、查找某个数据的位置,并删除它     \n");
	printf("\n");
	printf("8、删除顺序表中有的 某个数据        \n");
	printf("\n");
	printf("9、打印数据                       \n");
	printf("\n");
	printf("-1、退出                          \n");
	printf("\n");
	printf("***********************************************************\n");

}

int main()
{
	printf("*************  欢迎大家来到动态顺序表的测试  **************\n");
	int option = 0;
	SL s;
	SLInit(&s);
	do
	{
		menu();
		printf("请输入你的操作:>");
		scanf("%d", &option);
		int sum = 0;
		int x = 0;
		int y = 0;
		int z = 0;
		int pos = 0;
		int w = 0;
		switch (option)
		{
		case 1:
			printf("请依次输入你要尾插的数据:,以-1结束\n");
			scanf("%d", &sum);
			while (sum != -1) 
			{
				SLPushBack(&s, sum);    // 1.尾插
				scanf("%d", &sum);
			}
			break;
		case 2:  
			SLPopBack(&s);             // 2.尾删
			break;
		case 3:
			scanf("%d", &x);
			SLPushFront(&s, x);       // 3.头插
			break;
		case 4:
			SLPopFront(&s);           // 4.头删
			break;
		case 5:
			SLInsert(&s, 3, 20);     // 5.在任意位置插入数据
			break;
		case 6:
			SLErase(&s, 3);          // 6.在任意位置删除数据
			break;
		case 7:
			printf("请输入要删除序列的中的某个数字\n");
			scanf("%d", &z);
			y = SLFind(&s, z);        // 7.查找某个数字的位置,并且删除它
			printf("%d的位置在%d处: \n", z, y);
			if (y != -1)
			{
				SLErase(&s, y);
			}
			break;
		case 8:
			printf("请输入要删除序列的中的数字\n");  //8.删除顺序表中 所有的 某个数据 
			scanf("%d", &w);
		     pos = SLFinds(&s, w, 0);
			while (pos != -1)
			{
				SLErase(&s, pos);
				pos = SLFinds(&s, w, pos);
			}
			break;
		case 9:
			SLPrint(&s);
			break;
		default:
			if (option == -1)
			{
				exit(0);  // 退出程序 
			}
			else
			{
				printf("输入错误,请重新输入\n");
			}
			break;

		}
	} while (option != -1);   // 退出程序
	SLDestory(&s);
	return 0;
}

🍍代码运行的菜单界面 

 

五、 共勉

以下就是我对数据结构---顺序表的理解,如果有不懂和发现问题的小伙伴,请在评论区说出来哦,同时我还会继续更新对数据结构-------单链表的理解,请持续关注我哦!!!!!  

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/12778.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

为数字化深水区“量身定制”,华为品质服务再迭代

作者 | 曾响铃 文 | 响铃说 因为工作数据没有及时更新、版本对不上&#xff0c;不得不带着文件和数据跑上跑下&#xff0c;与其他部门反复确认&#xff0c;拿回来最新的数据&#xff0c;才能开始安心工作——如果找不到人&#xff0c;工作就得等着&#xff0c;领导又在催&…

SpringBoot项目基础设施搭建

本文为《从零打造项目》系列第二篇文章&#xff0c;首发于个人网站。 《从零打造项目》系列文章 比MyBatis Generator更强大的代码生成器 SpringBoot项目基础设施搭建 前言 准确点说&#xff0c;这不是《从零打造项目》系列的第一篇文章&#xff0c;模版代码生成的那个项目讲解…

【非纯小白勿进】计算机的基本操作

计算机的基本操作 ​ 追看了前面文章&#xff0c;你就会对于计算机已经有了一个初步的认识&#xff0c;那么下面我们就要来使用计算机了。 计算机中只有文件和文件夹 ​ 计算机中&#xff0c;只有两样东西&#xff0c;文件和文件夹。 文件夹&#xff1a;本身不存储数据内容…

为什么用php的人越来越少了?

首先这张图反映的只是某个编程语言的热门程度。 以下代表个人观点: php这几年热度下降的原因: 1.存活时间长,在互联网技术日新月异的时代,一些更先进的技术会吸引一部分开发者 2.存活时间长,为了对历史版本作出一定的兼容,函数库的体积增大,一定程度上加大了程序员的负担 …

FRNet:Feature Reconstruction Network for RGB-D Indoor Scene Parsing实验补充

FRNet做了大量的消融实验&#xff0c;这里仔细来分析一下。 1&#xff1a;ResNet backbone&#xff1a; 作者消融实验使用了ResNet34作为backbone来提取特征&#xff0c;将最后一层的输出简单相加起来&#xff0c;然后通过不断的上采样获得最终的输出。并且只在最后一层进行监督…

FAM DBCO, 6-isomer,DBCO-羧基荧光素琥珀酰亚胺酯-6-异构体

产品名称&#xff1a;DBCO-羧基荧光素琥珀酰亚胺酯-6-异构体 英文名称&#xff1a;FAM DBCO, 6-isomer 荧光素 (FAM) 是荧光染料之一。FAM 的这种衍生物含有环辛炔基团&#xff08;二苯并环辛炔&#xff0c;缩写为 DBCO 或 ADIBO&#xff09;&#xff0c;用于通过无铜、应变促…

MyBatis 关联映射

文章目录一、关联映射概述二、一对一查询1.association 元素2.嵌套查询实例演示3.嵌套结果集实例演示三、一对多查询1.collection 元素2.嵌套结果集实例演示四、多对多查询1.嵌套查询实例演示2.嵌套结果集实例演示五、自动补全 get、set 方法一、关联映射概述 在此之前&#x…

飞瞳引擎™集装箱AI检测云服务,集装箱信息识别功能免费,全球顶尖AI高泛化性,正常集装箱识别率99.98%,全球2000企业用户

党的二十大报告指出&#xff0c;加快发展物联网&#xff0c;建设高效顺畅的流通体系&#xff0c;降低物流成本。空箱闸口智慧监管为青岛港提高集装箱运输物流效率提供了保障。飞瞳引擎™AI集装箱识别检测云服务&#xff0c;自动化识别检测集装箱信息大幅降低物流成本提升效率&a…

EFK部署centos7.9(三)Kibana部署

系统类型&#xff1a;Centos7.9 节点IP&#xff1a; 192.168.11.140 软件版本&#xff1a;nginx-1.14.2、kibana-6.5.4-linux-x86_64.tar.gz 上传或者下载安装包 Wget https://artifacts.elastic.co/downloads/kibana/kibana-6.5.4-linux-x86_64.tar.gz tar zvxf kibana-6.5.…

供应链解决方案SRM是什么?企业实施SRM有什么价值?

企业业务对外的两个最重要的出口就是广义的 “买”和“卖”。在“卖”的方面&#xff0c;企业为了使自己的产品和服务赢得市场、赢得客户&#xff0c;更为重视这方面的管理和更加投入了在市场上的力度。管理软件供应商纷纷推出了CRM产品&#xff0c;企业也开始利用这种管理思想…

字符串的算法题目

题目一&#xff1a; 描述 对于一个长度为 n 字符串&#xff0c;我们需要对它做一些变形。 首先这个字符串中包含着一些空格&#xff0c;就像"Hello World"一样&#xff0c;然后我们要做的是把这个字符串中由空格隔开的单词反序&#xff0c;同时反转每个字符的大小写…

RabbitMQ 服务启动失败问题小结(Windows环境)

RabbitMQ 服务启动失败问题小结&#xff08;Windows环境&#xff09; 最近在Windows环境上安装RabbitMQ服务时&#xff0c;踩了不少坑&#xff0c;往上的回答让人很崩溃&#xff0c;几乎一样的回答&#xff0c;起不到帮助作用&#xff1b;特此做个记录总结&#xff1b; *****…

Nginx缓存配置教程

问题引出 假设某电商平台商品详情页需要实现 700 QPS&#xff08;假设宽带是千兆宽带&#xff09; 千M局域网宽带网卡速率按照1000进位&#xff0c;所以1Gbps1,000,000,000bps125,000,000Bps≈119.21MB/s 当达到500QPS 的时候很难继续压测上去。 假设每个页面主体渲染所需要的…

java的static关键字及类加载顺序

Java中static可以修饰类、变量、方法甚至可以构成静态块&#xff0c;让我们来了解下它们各自的使用以及加载顺序吧。 基本用法 static关键字修饰类 java里面用static修饰内部类&#xff0c;普通类是不允许声明为静态的&#xff0c;只有内部类才可以。 public class StaticT…

苹果电脑硬盘读写软件有哪些?Tuxera NTFS2023mac读写硬盘软件

格式化是将硬盘重置到初始状态或者是转换硬盘格式所需的一项重要步骤&#xff0c;格式化可以解决大部分用户遇到的硬盘问题&#xff0c;不过在进行格式化之前&#xff0c;大家需要提前了解格式化的具体注意事项&#xff0c;以避免不必要的损失。下面本文就来着重介绍磁盘格式化…

windows xp 邮件服务器漏洞溢出

缓冲区溢出攻击过程概念解释&#xff1a;第一步&#xff1a;入侵着测试目标机的25和110端口第二步&#xff1a;入侵着测试目标机缓冲区溢出第三步&#xff1a;判断目标机器是否发生缓冲区溢出第四步&#xff1a;得到确切缓冲区溢出位置所在的区间。第五步&#xff1a;得到确切缓…

基于低代码开发平台搭建的生产制造管理系统

在现代化社会中&#xff0c;信息化管理模式早已成为企业管理的主流趋势。尤其是随着企业信息化的程度已经成为影响企业创新、发展以和企业经济效益的重要因素之后&#xff0c;生产管理信息化就变得至关重要。因此&#xff0c;拥有一套完备的生产制造管理系统对于提高企业的工作…

Nginx安全控制

安全隔离 通过代理分开了客户端到应用程序服务器端的连接&#xff0c;实现了安全措施。在反向代理之前设置防火墙&#xff0c;仅留一个入口供代理服务器访问。 使用SSL对流量进行加密 常用的http请求转变成https请求&#xff0c;因为http协议是明文传输数据&#xff0c;存在…

黑马redis学习记录Ⅲ SpringDataRedis客户端

学习视频&#xff1a;https://www.bilibili.com/video/BV1cr4y1671t/ SpringDataRedis客户端 SpringData 是 Spring 中数据操作的模块&#xff0c;包含对各种数据库的集成&#xff0c;其中对 Redis 的集成模块就叫做 SpringDataRedis&#xff0c;官网地址&#xff1a;https://…

基于eNSP中大型校园/企业网络规划与设计_综合大作业

作者&#xff1a;BSXY_19计科_陈永跃BSXY_信息学院注&#xff1a;未经允许禁止转发任何内容基于eNSP中大型校园/企业网络规划与设计_综合大作业前言及技术/资源下载说明&#xff08; **未经允许禁止转发任何内容** &#xff09;一、设计topo图与设计要求(简单列举18个)二、相应…