【数据结构】顺序表深度剖析

目录

前言:

一、线性表概述:

️二、顺序表️:

        1.概念及结构:

        2.接口实现:

        ①.工程文件:

        ②.接口实现:

        ③.头文件与函数实现文件全部源码:

总结:


️博客主页:✈️銮同学的干货分享基地

️欢迎关注:点赞收藏✍️留言

️系列专栏: 数据结构

                       【进阶】C语言学习

                         C语言学习

️代码仓库:数据结构仓库

                       VS2022_C语言仓库

        家人们更新不易,你们的点赞和⭐关注⭐真的对我真重要,各位路过的友友麻烦多多点赞关注,欢迎你们的私信提问,感谢你们的转发!

        关注我,关注我,关注我,你们将会看到更多的优质内容!!


 本文重点

线性表概述 顺序表 

【数据结构】顺序表深度剖析_第1张图片

前言:

        在上节课中我们已经对数据结构有了一定的了解,我们说到数据结构是计算机存储、组织数据的方式,我们通过精心选择更恰当数据结构可以带来更高的运行或存储效率。至此我们就知道了数据结构的重要性,所以今天我们将要了解和学习一种实用的数据结构——线性表

一、线性表概述:

        线性表(linear list)是数据结构的一种,一个线性表是 n 个具有相同特性的数据元素的有限序列,是最基本、最简单也最常用的一种数据结构

        线性表中数据元素之间的关系是一对一的关系,即除了第一个和最后一个数据元素之外,其它数据元素都是首尾相接的(注意,这句话只适用大部分线性表,而不是全部。比如,循环链表逻辑层次上也是一种线性表,但存储层次上属于链式存储,是把最后一个数据元素的尾指针指向了首位结点)。

        线性表是一种在实际中广泛使用的数据结构,线性表在逻辑上是线性结构,也就说是连续的一条直线。但是在物理结构上并不一定是连续的,线性表在物理上存储时,通常以数组和链式结构的形式存储常见的线性表:顺序表、链表、栈、队列、字符串等等。

【数据结构】顺序表深度剖析_第2张图片

️二、顺序表️:

        对线性表有了总体上的了解之后,我们今天的主要学习内容就是线性表中的顺序表

        1.概念及结构:

        顺序表是用一段物理地址连续的存储单元依次存储数据元素的线性结构,一般情况下采用数组存储,并在数组上完成数据的增、删、查、改。其本质就是数组,但与数组不同的是,顺序表在其数组本质的基础上,还要求数据连续存储,不能跳跃或间隔存储

        顺序表一般可以分为两类:

  • 静态顺序表:使用定长数组存储元素。
  • 静态顺序表存在很明显的缺陷,即大小固定,数据少了造成空间浪费,数据多了申请的空间又可能不够用
  • size 表示当前顺序表中已经存放的有效数据个数
#define N 10

typedef int SLDataType;    //自定义类型SLDataType,将类型重命名,后续要存储其它类型时方便更改

typedef struct SeqList
{
	SLDataType array[N];    //定长数组
	size_t size;    //有效数据个数
}SeqList;
  • 动态顺序表:使用动态开辟的数组存储元素。 
  • 动态顺序表克服了静态顺序表的弊端,使空间申请变得灵活,我们可以随时根据需求申请合适大小的空间
  • size 表示当前顺序表中已经存放的有效数据个数
  • capacity 表示当前顺序表中可容纳数据个数的上限
typedef int SLDataType;    //自定义类型SLDataType,将类型重命名,后续要存储其它类型时方便更改

typedef struct SeqList
{
	SLDataType* a;    //指向动态开辟的数组
	size_t size;    //有效数据个数
	size_t capacity;    //容量大小
}SeqList;

        2.接口实现:

        我们在这里研究接口实现时,直接使用工程来进行说明。同时为了展示更多的接口实现,我将直接使用动态顺序表来为各位小伙伴们进行讲解。

        ①.工程文件:

        跟之前我们写过的通讯录与几个简易小游戏一样,我们同样使用模块化开发格式,使用 SeqList.h 、SeqList.c 、test.c 三个文件进行代码书写:

  • SeqList.h:用于存放函数声明、包含其他头文件、定义宏等等。
  • SeqList.c:用于书写函数定义,书写函数实现等。
  • test.c:用于书写程序整体执行逻辑等。

【数据结构】顺序表深度剖析_第3张图片  

        这其中,我们的接口实现主要研究的是头文件 SeqList.h 与 函数实现文件 SeqList.c 中的内容,对 test.c 文件中的内容分不关心。

  • 头文件 SeqList.h 中代码
#pragma once  //防止头文件被二次引用

#include  /*perror, printf*/
#include  /*assert*/
#include  /*realloc*/

typedef int SLDataType;  //后续要存储其它类型时方便更改

//顺序表的动态存储
typedef struct SeqList
{
	SLDataType* a;  //指向动态开辟的数组
	size_t size;  //有效数据个数
	size_t capacity;  //容量大小
}SeqList;

//初始化与销毁:
void SeqListInit(SeqList* psl);  //初始化顺序表
void SeqListDestory(SeqList* psl);  //销毁顺序表
void CheckCapacity(SeqList* psl);  //检查顺序表容量是否满了,好进行增容

//顺序表尾部处理:
void SeqListPushBack(SeqList* psl, SLDataType x);  //顺序表尾插 O(1)
void SeqListPopBack(SeqList* psl);  //顺序表尾删  O(1)

//顺序表头部处理:
void SeqListPushFront(SeqList* psl, SLDataType x);  //顺序表头插  O(n)
void SeqListPopFront(SeqList* psl);  //顺序表头删  O(n)

//顺序表元素的查找、删除与修改:
void SeqListPrint(const SeqList* psl);  //打印顺序表
int SeqListFind(const SeqList* psl, SLDataType x);  //在顺序表中查找指定值
void SeqListInsert(SeqList* psl, size_t pos, SLDataType x);  //在顺序表指定下标位置插入数据
void SeqListErase(SeqList* psl, size_t pos);  //在顺序表中删除指定下标位置的数据
size_t SeqListSize(const SeqList* psl);  //查看顺序表中数据个数
void SeqListAt(SeqList* psl, size_t pos, SLDataType x);  //修改指定下标位置的数据

        ②.接口实现:

        这里是本文重点中的重点,即 SeqList.c 文件中的接口具体实现:

  • 初始化顺序表
  • 顺序表在初始化之前要注意记得断言,以防止传入空指针
void SeqListInit(SeqList* psl)
{
	assert(psl != NULL);  //断言
	psl->a = NULL;  //初始顺序表为空
	psl->size = 0;  //初始数据个数为0
	psl->capacity = 0;  //初始空间容量为0
}
  • 销毁顺序表
  • 同样在执行操作前要注意断言,防止传入空指针
void SeqListDestory(SeqList* psl)
{
	assert(psl != NULL);  //断言
	free(psl->a);  //释放动态开辟的空间
	psl->a = NULL;  //置空
	psl->size = 0;  //数据个数置0
	psl->capacity = 0;  //空间容量大小置0
}
  • 检查顺序表容量
  • 当我们创建并初始化好一个顺序表后,在添加数据前应当先行判断顺序表中剩余的容量是否足以容纳存入的数据
  • 足以容纳存入数据,则不执行操作开始存入数据
  • 若不足以容纳存入数据,要再次进行判断,若原容量为 0,则扩容至可以容纳 4 个元素的空间(根据实际需求确定);若不为 0 则扩容至顺序表原空间二倍的大小
  • 扩容至二倍的原因是,存入一个扩容一个的方式过于繁琐且极其消耗程序执行时间不扩容多倍的原因是为了尽可能的防止造成空间的浪费,于是我们通常就每次扩容折中的二倍空间大小
void CheckCapacity(SeqList* psl)
{
	assert(psl != NULL);  //断言
	if (psl->size == psl->capacity)  //检查容量,满了则增容
	{
		size_t newcapacity;  //新容量
		if (psl->capacity == 0)
		{
			newcapacity = psl->capacity = 4;  //原来容量为0,扩容为4
		}
		else
		{
			newcapacity = 2 * psl->capacity;  //原来容量不为0,扩容为原来的2倍
		}
		SLDataType* p = (SLDataType*)realloc(psl->a, newcapacity * sizeof(SLDataType));  //扩容
		if (p == NULL)
		{
			perror("realloc");
			exit(-1);
		}
		psl->a = p;  // p 不为空,开辟成功
		psl->capacity = newcapacity;  //更新容量
	}
}
  • 顺序表尾插
  • 尾插即向后依次顺序存入数据
  • 尾插操作执行前注意进行断言,防止传入空指针
void SeqListPushBack(SeqList* psl, SLDataType x)
{
	assert(psl != NULL);  //断言
	CheckCapacity(psl);  //检查顺序表容量是否已满
	psl->a[psl->size] = x;  //尾插数据
	psl->size++;  //有效数据个数+1
}
  • 测试尾插接口功能实现:
int main()
{
	SeqList S;
	SeqListInit(&S);  //初始化顺序表

	//顺序表尾插:
	SeqListPushBack(&S, 1);
	SeqListPushBack(&S, 2);
	SeqListPushBack(&S, 3);
	SeqListPushBack(&S, 4);
	SeqListPushBack(&S, 5);
	//打印顺序表:
	SeqListPrint(&S);
	//销毁顺序表:
	SeqListDestory(&S);

	return 0;
}

【数据结构】顺序表深度剖析_第4张图片

  • 顺序表尾删
  • 在尾删操作执行前需要进行断言,防止传入空指针
  • 在这里要注意,因为顺序表中的数据我们是无法知道确切的数据类型的,因此不能一概而论的通过置零来实现尾删
  • 我们选择的尾删操作方法是,使记录有效数据的 size 减一即可
void SeqListPopBack(SeqList* psl)
{
	assert(psl != NULL);  //断言
	assert(psl->size > 0);  //顺序表不能为空
	//不知道SLDataType是什么类型的数据,不能冒然的赋值为0;即:psl->a[psl->size - 1] = 0;
	psl->size--;  //有效数据个数-1
}
  • 测试尾删接口功能实现:
int main()
{
	SeqList S;
	SeqListInit(&S);  //初始化顺序表

	//顺序表尾插:
	SeqListPushBack(&S, 1);
	SeqListPushBack(&S, 2);
	SeqListPushBack(&S, 3);
	SeqListPushBack(&S, 4);
	SeqListPushBack(&S, 5);
	//打印顺序表:
	SeqListPrint(&S);

	//依次尾删:
	int i = 0;
	for (i = 0; i < 3; i++)
	{
		//顺序表尾删:
		SeqListPopBack(&S);
		//打印顺序表:
		SeqListPrint(&S);
	}
	//销毁顺序表:
	SeqListDestory(&S);

	return 0;
}

【数据结构】顺序表深度剖析_第5张图片

  • 顺序表头插
  • 操作前断言,防止传入空指针
  • 顺序表为连续存储,因此实现头插只需让后面的所有元素依次后移即可
void SeqListPushFront(SeqList * psl, SLDataType x)
{
	assert(psl);  //断言
	CheckCapacity(psl);  //检查顺序表容量是否已满
	int i = 0;
	for (i = psl->size - 1; i >= 0; i--)  //顺序表中[0,size-1]的元素依次向后挪动一位
	{
		psl->a[i + 1] = psl->a[i];
	}
	psl->a[0] = x;  //头插数据
	psl->size++;  //有效数据个数+1
}
  • 测试头插接口功能实现:
int main()
{
	SeqList S;
	SeqListInit(&S);  //初始化顺序表

	//顺序表头插:
	SeqListPushFront(&S, 10);
	SeqListPushFront(&S, 20);
	SeqListPushFront(&S, 30);
	SeqListPushFront(&S, 40);
	SeqListPushFront(&S, 50);
	//打印顺序表:
	SeqListPrint(&S);
	//销毁顺序表:
	SeqListDestory(&S);
	return 0;
}

【数据结构】顺序表深度剖析_第6张图片

  • 顺序表头删
  • 操作前断言,防止传入空指针
  • 与头插类似,同样因为顺序表为连续存储,因此实现头删只需让后面的所有元素依次前移,并使记录有效数据的 size 减一即可
void SeqListPopFront(SeqList* psl)
{
	assert(psl);  //断言
	assert(psl->size > 0);  //顺序表不能为空

	int i = 0;
	for (i = 1; i < psl->size; i++)  //顺序表中[1,size-1]的元素依次向前挪动一位
	{
		psl->a[i - 1] = psl->a[i];
	}
	psl->size--;  //有效数据个数-1
}
  • 测试头删接口功能实现:
int main()
{
	SeqList S;
	SeqListInit(&S);  //初始化顺序表

	//顺序表头插:
	SeqListPushFront(&S, 10);
	SeqListPushFront(&S, 20);
	SeqListPushFront(&S, 30);
	SeqListPushFront(&S, 40);
	SeqListPushFront(&S, 50);
	//打印顺序表:
	SeqListPrint(&S);

	//顺序表头删:
	int i = 0;
	for (i = 0; i < 3; i++)
	{
		SeqListPopFront(&S);
		SeqListPrint(&S);
	}
	//销毁顺序表:
	SeqListDestory(&S);
	return 0;
}

【数据结构】顺序表深度剖析_第7张图片

  • 打印顺序表
  • 同样在执行操作前需要进行断言,防止传入空指针
void SeqListPrint(const SeqList* psl)
{
	assert(psl != NULL);  //断言
	if (psl->size == 0)  //判断顺序表是否为空
	{
		printf("顺序表为空\n");
		return;
	}
	int i = 0;
	for (i = 0; i < psl->size; i++)  //打印顺序表
	{
		printf("%d ", psl->a[i]);
	}
	printf("\n");
}
  • 在顺序表中查找
  • 在执行操作前断言,防止传入空指针
int SeqListFind(const SeqList* psl, SLDataType x)
{
	assert(psl);  //断言
	int i = 0;
	for (i = 0; i < psl->size; i++)
	{
		if (psl->a[i] == x)
		{
			return i;  //查找到,返回该值在数组中的下标
		}
	}
	return 1;  //没有查找到
}
  • 测试查找接口功能实现:
int main()
{
	SeqList S;
	SeqListInit(&S);  //初始化顺序表
	//尾插:
	int i = 0;
	for (i = 0; i < 5; i++)
	{
		SeqListPushBack(&S, 10 * i);
	}
	SeqListPrint(&S);  //打印顺序表

	//查找:
	int ret = SeqListFind(&S, 30);

	//验证查找结果:
	if (ret == -1)
	{
		printf("没有找到!\n");
	}
	else
	{
		printf("找到了!\nX = %d\n", S.a[ret]);
	}
	
	SeqListDestory(&S);  //销毁顺序表

	return 0;
}

【数据结构】顺序表深度剖析_第8张图片

  • 在指定下标位置插入
  • 在执行操作前进行断言,防止传入空指针
  • 同时要注意避免负数给到无符号数,或者避免有符号数变成负数后,被算术转换或整型提升后,变成一个很大的数。
void SeqListInsert(SeqList* psl, size_t pos, SLDataType x)
{
	assert(psl);  //断言
	assert(pos >= 0 && pos <= psl->size);  //检查pos下标的合法性
	CheckCapacity(psl);  //检查顺序表容量是否已满
	size_t i = 0;
	for (i = psl->size; i > pos; i--)  //将pos位置后面的数据依次向后挪动一位
	{
		psl->a[i] = psl->a[i - 1];
	}
	psl->a[pos] = x;  //插入数据
	psl->size++;  //有效数据个数+1
}
  • 测试指定插入接口功能实现:
int main()
{
	SeqList S;
	SeqListInit(&S);  //初始化顺序表
	//尾插:
	int i = 0;
	for (i = 0; i < 5; i++)
	{
		SeqListPushBack(&S, 10 * i);
	}
	SeqListPrint(&S);  //打印顺序表

	//在指定位置处插入:
	SeqListInsert(&S, 3, 100);
	SeqListPrint(&S);  //打印顺序表

	SeqListDestory(&S);  //销毁顺序表

	return 0;
}

【数据结构】顺序表深度剖析_第9张图片

  • 删除指定下标位置的元素
  • 执行操作前进行断言,防止传入空指针
  • 与指定插入相同,注意避免负数给到无符号数,或者避免有符号数变成负数后,被算术转换或整型提升后,变成一个很大的数。
  • 并在操作结束后使表示有效数据的 size 减一即可
void SeqListErase(SeqList* psl, size_t pos)
{
	assert(psl);  //断言
	assert(psl->size > 0);  //顺序表不能为空
	assert(pos >= 0 && pos < psl->size);  //检查pos下标的合法性
	size_t i = 0;
	for (i = pos + 1; i < psl->size; i++)  //将pos位置后面的数据依次向前挪动一位
	{
		psl->a[i - 1] = psl->a[i];
	}
	psl->size--;  //有效数据个数-1
}
  • 测试指定删除接口功能实现:
int main()
{
	SeqList S;
	SeqListInit(&S);  //初始化顺序表
	//尾插:
	int i = 0;
	for (i = 0; i < 5; i++)
	{
		SeqListPushBack(&S, 10 * i);
	}
	SeqListPrint(&S);  //打印顺序表

	//删除指定下标位置数据:
	SeqListErase(&S, 3);
	SeqListPrint(&S);  //打印顺序表

	SeqListDestory(&S);  //销毁顺序表

	return 0;
}

【数据结构】顺序表深度剖析_第10张图片

  • 查看有效数据个数
  • 在执行操作前进行断言,防止传入空指针
  • 在数据结构中有约定,如果要访问或修改数据结构中的数据,不能直接访问,要调用它的函数来访问和修改,这样更加规范安全,也便于检查是否出现了越界等一些错误情况,因此不直接查看而是使用函数进行操作。

size_t SeqListSize(const SeqList* psl)
{
	assert(psl);  //断言
	return psl->size;
}
  • 测试有效数据查看接口功能实现:
int main()
{
	SeqList S;
	SeqListInit(&S);  //初始化顺序表
	//尾插:
	int i = 0;
	for (i = 0; i < 5; i++)
	{
		SeqListPushBack(&S, 10 * i);
	}
	SeqListPrint(&S);  //打印顺序表

	//查看有效数据个数:
	int ret = SeqListSize(&S);
	printf("有效数据个数为:%d\n", ret);

	SeqListDestory(&S);  //销毁顺序表

	return 0;
}

【数据结构】顺序表深度剖析_第11张图片

  • 修改指定下标位置数据
  • 在执行操作前进行断言,防止传入空指针。
void SeqListAt(SeqList* psl, size_t pos, SLDataType x)
{
	assert(psl);  //断言
	assert(psl->size > 0);  //顺序表不能为空
	assert(pos >= 0 && pos < psl->size);  //检查pos下标的合法性

	psl->a[pos] = x;  //修改pos下标处对应的数据
}
  • 测试修改接口功能实现:
int main()
{
	SeqList S;
	SeqListInit(&S);  //初始化顺序表
	//尾插:
	int i = 0;
	for (i = 0; i < 5; i++)
	{
		SeqListPushBack(&S, 10 * i);
	}
	SeqListPrint(&S);  //打印顺序表

	//修改指定下标处数据:
	SeqListAt(&S, 3, 100);
	SeqListPrint(&S);  //打印顺序表

	SeqListDestory(&S);  //销毁顺序表

	return 0;
}

【数据结构】顺序表深度剖析_第12张图片

        ③.文件全部源码:

  •  SeqList.h:
#pragma once  //防止头文件被二次引用

#include  /*perror, printf*/
#include  /*assert*/
#include  /*realloc*/

typedef int SLDataType;  //后续要存储其它类型时方便更改

//顺序表的动态存储
typedef struct SeqList
{
	SLDataType* a;  //指向动态开辟的数组
	size_t size;  //有效数据个数
	size_t capacity;  //容量大小
}SeqList;

//初始化与销毁:
void SeqListInit(SeqList* psl);  //初始化顺序表
void SeqListDestory(SeqList* psl);  //销毁顺序表
void CheckCapacity(SeqList* psl);  //检查顺序表容量是否满了,好进行增容

//顺序表尾部处理:
void SeqListPushBack(SeqList* psl, SLDataType x);  //顺序表尾插 O(1)
void SeqListPopBack(SeqList* psl);  //顺序表尾删  O(1)

//顺序表头部处理:
void SeqListPushFront(SeqList* psl, SLDataType x);  //顺序表头插  O(n)
void SeqListPopFront(SeqList* psl);  //顺序表头删  O(n)

//顺序表元素的查找、删除与修改:
void SeqListPrint(const SeqList* psl);  //打印顺序表
int SeqListFind(const SeqList* psl, SLDataType x);  //在顺序表中查找指定值
void SeqListInsert(SeqList* psl, size_t pos, SLDataType x);  //在顺序表指定下标位置插入数据
void SeqListErase(SeqList* psl, size_t pos);  //在顺序表中删除指定下标位置的数据
size_t SeqListSize(const SeqList* psl);  //查看顺序表中数据个数
void SeqListAt(SeqList* psl, size_t pos, SLDataType x);  //修改指定下标位置的数据
  • SeqList.c:
#define _CRT_SECURE_NO_WARNINGS 1

#include"SeqList.h"

//初始化顺序表:
void SeqListInit(SeqList* psl)
{
	assert(psl != NULL);  //断言
	psl->a = NULL;  //初始顺序表为空
	psl->size = 0;  //初始数据个数为0
	psl->capacity = 0;  //初始空间容量为0
}

//销毁顺序表:
void SeqListDestory(SeqList* psl)
{
	assert(psl != NULL);  //断言
	free(psl->a);  //释放动态开辟的空间
	psl->a = NULL;  //置空
	psl->size = 0;  //数据个数置0
	psl->capacity = 0;  //空间容量大小置0
}

//顺序表容量检查与扩容:
void CheckCapacity(SeqList* psl)
{
	assert(psl != NULL);  //断言
	if (psl->size == psl->capacity)  //检查容量,满了则增容
	{
		size_t newcapacity;  //新容量
		if (psl->capacity == 0)
		{
			newcapacity = psl->capacity = 4;  //原来容量为0,扩容为4
		}
		else
		{
			newcapacity = 2 * psl->capacity;  //原来容量不为0,扩容为原来的2倍
		}
		SLDataType* p = (SLDataType*)realloc(psl->a, newcapacity * sizeof(SLDataType));  //扩容
		if (p == NULL)
		{
			perror("realloc");
			exit(-1);
		}
		psl->a = p;  // p 不为空,开辟成功
		psl->capacity = newcapacity;  //更新容量
	}
}

//顺序表尾插:
void SeqListPushBack(SeqList* psl, SLDataType x)
{
	assert(psl != NULL);  //断言
	CheckCapacity(psl);  //检查顺序表容量是否已满
	psl->a[psl->size] = x;  //尾插数据
	psl->size++;  //有效数据个数+1
}

//顺序表尾删:
void SeqListPopBack(SeqList* psl)
{
	assert(psl != NULL);  //断言
	assert(psl->size > 0);  //顺序表不能为空
	//不知道SLDataType是什么类型的数据,不能冒然的赋值为0;即:psl->a[psl->size - 1] = 0;
	psl->size--;  //有效数据个数-1
}

//顺序表头插:
void SeqListPushFront(SeqList * psl, SLDataType x)
{
	assert(psl);  //断言
	CheckCapacity(psl);  //检查顺序表容量是否已满
	int i = 0;
	for (i = psl->size - 1; i >= 0; i--)  //顺序表中[0,size-1]的元素依次向后挪动一位
	{
		psl->a[i + 1] = psl->a[i];
	}
	psl->a[0] = x;  //头插数据
	psl->size++;  //有效数据个数+1
}

//顺序表头删:
void SeqListPopFront(SeqList* psl)
{
	assert(psl);  //断言
	assert(psl->size > 0);  //顺序表不能为空
	int i = 0;
	for (i = 1; i < psl->size; i++)  //顺序表中[1,size-1]的元素依次向前挪动一位
	{
		psl->a[i - 1] = psl->a[i];
	}
	psl->size--;  //有效数据个数-1
}

//打印顺序表:
void SeqListPrint(const SeqList* psl)
{
	assert(psl != NULL);  //断言
	if (psl->size == 0)  //判断顺序表是否为空
	{
		printf("顺序表为空\n");
		return;
	}
	int i = 0;
	for (i = 0; i < psl->size; i++)  //打印顺序表
	{
		printf("%d ", psl->a[i]);
	}
	printf("\n");
}

//在顺序表中查找:
int SeqListFind(const SeqList* psl, SLDataType x)
{
	assert(psl);  //断言
	int i = 0;
	for (i = 0; i < psl->size; i++)
	{
		if (psl->a[i] == x)
		{
			return i;  //查找到,返回该值在数组中的下标
		}
	}
	return -1;  //没有查找到
}

//在指定下标位置插入数据:
void SeqListInsert(SeqList* psl, size_t pos, SLDataType x)
{
	assert(psl);  //断言
	assert(pos >= 0 && pos <= psl->size);  //检查pos下标的合法性
	CheckCapacity(psl);  //检查顺序表容量是否已满
	size_t i = 0;
	for (i = psl->size; i > pos; i--)  //将pos位置后面的数据依次向后挪动一位
	{
		psl->a[i] = psl->a[i - 1];
	}
	psl->a[pos] = x;  //插入数据
	psl->size++;  //有效数据个数+1
}

//删除指定下标位置数据:
void SeqListErase(SeqList* psl, size_t pos)
{
	assert(psl);  //断言
	assert(psl->size > 0);  //顺序表不能为空
	assert(pos >= 0 && pos < psl->size);  //检查pos下标的合法性
	size_t i = 0;
	for (i = pos + 1; i < psl->size; i++)  //将pos位置后面的数据依次向前挪动一位
	{
		psl->a[i - 1] = psl->a[i];
	}
	psl->size--;  //有效数据个数-1
}

//查看有效数据个数:
size_t SeqListSize(const SeqList* psl)
{
	assert(psl);  //断言
	return psl->size;
}

//修改指定下标处数据:
void SeqListAt(SeqList* psl, size_t pos, SLDataType x)
{
	assert(psl);  //断言
	assert(psl->size > 0);  //顺序表不能为空
	assert(pos >= 0 && pos < psl->size);  //检查pos下标的合法性

	psl->a[pos] = x;  //修改pos下标处对应的数据
}
  • test.c:
#define _CRT_SECURE_NO_WARNINGS 1

#include"SeqList.h"

int main()
{
	SeqList S;
	SeqListInit(&S);  //初始化顺序表
	//尾插:
	int i = 0;
	for (i = 0; i < 5; i++)
	{
		SeqListPushBack(&S, 10 * i);
	}
	SeqListPrint(&S);  //打印顺序表

	//修改指定下标处数据:
	SeqListAt(&S, 3, 100);
	SeqListPrint(&S);  //打印顺序表

	SeqListDestory(&S);  //销毁顺序表

	return 0;
}

//查看有效数据个数:
//int main()
//{
//	SeqList S;
//	SeqListInit(&S);  //初始化顺序表
//	//尾插:
//	int i = 0;
//	for (i = 0; i < 5; i++)
//	{
//		SeqListPushBack(&S, 10 * i);
//	}
//	SeqListPrint(&S);  //打印顺序表
//
//	//查看有效数据个数:
//	int ret = SeqListSize(&S);
//	printf("有效数据个数为:%d\n", ret);
//
//	SeqListDestory(&S);  //销毁顺序表
//
//	return 0;
//}

//删除指定下标位置数据:
//int main()
//{
//	SeqList S;
//	SeqListInit(&S);  //初始化顺序表
//	//尾插:
//	int i = 0;
//	for (i = 0; i < 5; i++)
//	{
//		SeqListPushBack(&S, 10 * i);
//	}
//	SeqListPrint(&S);  //打印顺序表
//
//	//删除指定下标位置数据:
//	SeqListErase(&S, 3);
//	SeqListPrint(&S);  //打印顺序表
//
//	SeqListDestory(&S);  //销毁顺序表
//
//	return 0;
//}

//在指定下标出插入:
//int main()
//{
//	SeqList S;
//	SeqListInit(&S);  //初始化顺序表
//	//尾插:
//	int i = 0;
//	for (i = 0; i < 5; i++)
//	{
//		SeqListPushBack(&S, 10 * i);
//	}
//	SeqListPrint(&S);  //打印顺序表
//
//	//在指定位置处插入:
//	SeqListInsert(&S, 3, 100);
//	SeqListPrint(&S);  //打印顺序表
//	SeqListDestory(&S);  //销毁顺序表
//
//	return 0;
//}

//查找:
//int main()
//{
//	SeqList S;
//	SeqListInit(&S);  //初始化顺序表
//	//尾插:
//	int i = 0;
//	for (i = 0; i < 5; i++)
//	{
//		SeqListPushBack(&S, 10 * i);
//	}
//	SeqListPrint(&S);  //打印顺序表
//
//	//查找:
//	int ret = SeqListFind(&S, 30);
//
//	//验证查找结果:
//	if (ret == -1)
//	{
//		printf("没有找到!\n");
//	}
//	else
//	{
//		printf("找到了!\nX = %d\n", S.a[ret]);
//	}
//	
//	SeqListDestory(&S);  //销毁顺序表
//
//	return 0;
//}

//头插与头删:
//int main()
//{
//	SeqList S;
//	SeqListInit(&S);  //初始化顺序表
//
//	//顺序表头插:
//	SeqListPushFront(&S, 10);
//	SeqListPushFront(&S, 20);
//	SeqListPushFront(&S, 30);
//	SeqListPushFront(&S, 40);
//	SeqListPushFront(&S, 50);
//	//打印顺序表:
//	SeqListPrint(&S);
//
//	//顺序表头删:
//	int i = 0;
//	for (i = 0; i < 3; i++)
//	{
//		SeqListPopFront(&S);
//		SeqListPrint(&S);
//	}
//	//销毁顺序表:
//	SeqListDestory(&S);
//	return 0;
//}

//尾插与尾删:
//int main()
//{
//	SeqList S;
//	SeqListInit(&S);  //初始化顺序表
//
//	//顺序表尾插:
//	SeqListPushBack(&S, 1);
//	SeqListPushBack(&S, 2);
//	SeqListPushBack(&S, 3);
//	SeqListPushBack(&S, 4);
//	SeqListPushBack(&S, 5);
//	//打印顺序表:
//	SeqListPrint(&S);
//
//	//依次尾删:
//	int i = 0;
//	for (i = 0; i < 3; i++)
//	{
//		//顺序表尾删:
//		SeqListPopBack(&S);
//		//打印顺序表:
//		SeqListPrint(&S);
//	}
//	//销毁顺序表:
//	SeqListDestory(&S);
//
//	return 0;
//}

总结:

        在今天的学习内容中,很重要的一点就是无论何时,在执行操作前都一定要进行断言操作,使用空指针的后果很有可能将会是毁灭性的,甚至将有可能会对整个计算机的工作造成未知的破坏,切记切记。文章很长,也有几分晦涩,但是静下心来认真揣摩之后定能将其掌握。将来当我们回望来路,我相信每一位努力奋斗的小伙伴们都一定会感谢今天努力拼搏的自己

        日日行,不怕千万里;常常做,不怕千万事

        更新不易,辛苦各位小伙伴们动动小手,三连走一走 ~ ~ ~  你们真的对我很重要!最后,本文仍有许多不足之处,欢迎各位认真读完文章的小伙伴们随时私信交流、批评指正!

你可能感兴趣的:(数据结构,数据结构,c语言,c++,线性回归,gitee)