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

news2024/11/21 1:24:44

目录

🛫前言🛫:

🚀一、线性表概述🚀:

🛰️二、顺序表🛰️:

        1.概念及结构:

        2.接口实现:

        ①.工程文件:

        ②.接口实现:

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

🛬总结🛬:


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

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

🛰️系列专栏:🎈 数据结构

                       🎈【进阶】C语言学习

                       🎈  C语言学习

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

                       🎉VS2022_C语言仓库

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

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


🏡🏡 本文重点 🏡🏡:

🚅 线性表概述 🚃 顺序表 🚏🚏

🛫前言🛫:

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

🚀一、线性表概述🚀:

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

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

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

🛰️二、顺序表🛰️:

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

        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:用于书写程序整体执行逻辑等。

  

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

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

#include<stdio.h>  /*perror, printf*/
#include<assert.h>  /*assert*/
#include<stdlib.h>  /*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;
}

  • 顺序表尾删
  • 在尾删操作执行前需要进行断言,防止传入空指针
  • 在这里要注意,因为顺序表中的数据我们是无法知道确切的数据类型的,因此不能一概而论的通过置零来实现尾删
  • 我们选择的尾删操作方法是,使记录有效数据的 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;
}

  • 顺序表头插
  • 操作前断言,防止传入空指针
  • 顺序表为连续存储,因此实现头插只需让后面的所有元素依次后移即可
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;
}

  • 顺序表头删
  • 操作前断言,防止传入空指针
  • 与头插类似,同样因为顺序表为连续存储,因此实现头删只需让后面的所有元素依次前移,并使记录有效数据的 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;
}

  • 打印顺序表
  • 同样在执行操作前需要进行断言,防止传入空指针
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;
}

  • 在指定下标位置插入
  • 在执行操作前进行断言,防止传入空指针
  • 同时要注意避免负数给到无符号数,或者避免有符号数变成负数后,被算术转换或整型提升后,变成一个很大的数。
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;
}

  • 删除指定下标位置的元素
  • 执行操作前进行断言,防止传入空指针
  • 与指定插入相同,注意避免负数给到无符号数,或者避免有符号数变成负数后,被算术转换或整型提升后,变成一个很大的数。
  • 并在操作结束后使表示有效数据的 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;
}

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

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;
}

  • 修改指定下标位置数据
  • 在执行操作前进行断言,防止传入空指针。
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;
}

        ③.文件全部源码:

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

#include<stdio.h>  /*perror, printf*/
#include<assert.h>  /*assert*/
#include<stdlib.h>  /*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;
//}

🛬总结🛬:

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

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

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

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

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

相关文章

2023 铁人三项 CTF --- Misc wp

文章目录Misc一生壹世Misc手的必备技能套娃-1套娃-2套娃-3套娃-4套娃-5Misc 一生壹世 根据提示压缩包密码是谐音&#xff0c;所以猜测密码是1314&#xff0c;直接解压得到四个txt文件 然后用010分按照一生一世打开4个文件&#xff0c;发现每个文件的第一个字节拼起来是8950…

LeetCode题目笔记——1807. 替换字符串中的括号内容

文章目录题目描述题目难度——中等方法一&#xff1a;使用字典代码/Python代码/C总结题目描述 给你一个字符串 s &#xff0c;它包含一些括号对&#xff0c;每个括号中包含一个 非空 的键。 比方说&#xff0c;字符串 “(name)is(age)yearsold” 中&#xff0c;有 两个 括号对…

什么是聚宽量化?

聚宽量化交易其实是通过编程将策略写成计算机可识别的代码&#xff0c;具体说可以是以python这门编程语言将与券商那边的平台搭建&#xff0c;例如用聚宽的向导式策略生成器就能很快的将股票交易接口翻译出来的策略&#xff0c;以便将平时需要查询的融资账户的持仓情况来编写代…

区块链将传统的产业运行逻辑,改造成以个体为主导的运行逻辑

新的产业之所以被成为新产业&#xff0c;其中一个很重要的原因在于&#xff0c;它的底层运行逻辑&#xff0c;正在发生一场深刻而又彻底的改变。然而&#xff0c;如果深入分析这种能够给产业的内在运行逻辑产生重塑和改变的&#xff0c;依然在于区块链本身。从某种意义上来讲&a…

YOLOv8 深度详解!一文看懂,快速上手

YOLOv8 是 ultralytics 公司在 2023 年 1月 10 号开源的 YOLOv5 的下一个重大更新版本&#xff0c;目前支持图像分类、物体检测和实例分割任务&#xff0c;在还没有开源时就收到了用户的广泛关注。 考虑到 YOLOv8 的优异性能&#xff0c;MMYOLO 也在第一时间组织了复现&#xf…

一篇文章搞定字符串的旋转问题(数组旋转问题)!

目录 前言 一.如何实现字符串的旋转&#xff1f; 1.用冒泡的思想实现 2.分别逆序左右再整体逆序来实现 二.如何快速判断一个字符串是否为另外一个字符串旋转之后的字符串&#xff1f; 1.相关库函数的简略学习 2.利用库函数快速实现判断 总结 博客主页&#xff1a;张栩睿…

数据结构基础知识(一)

1 数据结构的基本概念和算法 考点 数据结构基本概念算法 1.1 数据结构的基本概念 数据 数据是指所有能输入到计算机中的描述客观事物的符号&#xff0c;包括文本、声音、 图像、符号等。 数据元素 数据元素十数据的基本单位&#xff0c;也称节点或记录。 数据项 数据项…

【数仓】FLink+CK

1.项目分层 ODS&#xff1a;原始数据&#xff0c;包含日志和业务数据DWD&#xff1a;根据数据对象为单位进行分流。比如订单、页面访问等。DIM&#xff1a;维度数据DWM&#xff1a;对于部分数据对象进行进一步加工&#xff0c;比如独立访问、跳出行为&#xff0c;也可以和维度…

谷粒商城项目笔记之高级篇(三)

目录1.9.22 提交订单的问题1)、订单号显示、应付金额回显2)、提交订单消息回显3&#xff09;、为了确保锁库存失败后&#xff0c;订单和订单项也能回滚&#xff0c;需要抛出异常1.9.23 创建库存上锁、解锁 业务交换机&队列1&#xff09;、流程梳理2&#xff09;、解锁库存实…

Vsftpd服务的部署及优化详解(图文)

目录 前言 实验环境 一、vsftpd的安装及启用 1、具体步骤 2、开启匿名用户访问功能并测试 二、vsftpd基本信息 三、匿名用户访问控制 四、本地用户访问控制 五、虚拟用户访问 1、建立虚拟用户访问 2、虚拟用户家目录的独立设定 3、用户配置独立 前言 vsftpd是“…

TapTap 算法平台的 Serverless 探索之路

分享人&#xff1a;陈欣昊&#xff0c;TapTap/IEM/AI平台负责人 摘要&#xff1a;本文主要介绍心动网络算法平台在Serverless上的实践。 《TapTap算法平台的 Serverless 探索之路》 Serverless 在构建应用上为我们节省了大量的运维与开发人力&#xff0c;在基本没投入基建人力…

(02)Cartographer源码无死角解析-(49) 2D点云扫描匹配→相关性暴力匹配1:SearchParameters

讲解关于slam一系列文章汇总链接:史上最全slam从零开始&#xff0c;针对于本栏目讲解(02)Cartographer源码无死角解析-链接如下: (02)Cartographer源码无死角解析- (00)目录_最新无死角讲解&#xff1a;https://blog.csdn.net/weixin_43013761/article/details/127350885 文末…

LeetCode分类刷题----链表篇

链表链表1.移除链表元素203.移除链表元素707.设计链表2.反转链表206.反转链表3.两两交换链表中的节点24.两两交换链表中的节点4.删除链表中的倒数第N个节点19.删除链表的倒数第N个节点5.链表相交07.链表相交6.环形链表141.环形链表142.环形链表II链表 1.移除链表元素 203.移除…

成功解决VMware安装操作系统出现分辨率的问题

文章目录问题重现问题原因问题解决方法一&#xff1a;拓展&#xff1a;1. 电脑分辨率&#xff1a;2. xrandr命令3. 查询后如果没有合适的分辨率解决方案参考资料问题重现 如下图&#xff1a; 在VMware16上安装ubuntu操作系统的时候&#xff0c;出现分辨率问题&#xff0c; 导致…

如何录屏有声音?如何录制带声音的视频

平常我们会通过录屏的方式录制电脑画面&#xff0c;然后再保存下来。那您是不是遇到过这种情况&#xff1a;录制的录屏文件只有画面没有声音。没有声音的视频还能修复吗&#xff1f;如何录屏有声音&#xff1f;怎样才能录制带声音的视频&#xff1f;今天小编教大家如何在录屏的…

前端基础(十三)_定时器(间歇定时器、延迟定时器)

定时器 定时器共两种&#xff0c;setInterval及setTimeout&#xff1a; 1、setInterval&#xff1a;重复执行或者叫间歇执行&#xff0c;即隔某个时间就执行一次 2、setTimeout&#xff1a;延迟执行&#xff0c;延迟某个特定的时间开始执行&#xff0c;只执行一次 语法&#x…

代码随想录算法训练营第10天 232.用栈实现队列、225. 用队列实现栈

代码随想录算法训练营第10天 232.用栈实现队列、225. 用队列实现栈 用栈实现队列 力扣题目链接(opens new window) 使用栈实现队列的下列操作&#xff1a; push(x) – 将一个元素放入队列的尾部。 pop() – 从队列首部移除元素。 peek() – 返回队列首部的元素。 empty() –…

十分好用的跨浏览器测试工具,建议收藏!!!

跨浏览器测试是确保web应用程序的功能在不同浏览器、浏览器版本和操作系统直接保持功能和质量一致的过程&#xff0c;可以为用户提供更好的用户体验&#xff0c;帮助企业通过更易访问的网站获得满意客户&#xff0c;可以使web应用程序在不同平台上兼容。在跨浏览器测试过程中&a…

Vulnhub靶机:DIGITALWORLD.LOCAL_ DEVELOPMENT

目录介绍信息收集主机发现主机信息探测网站探测SSH登录lshell绕过sudo提权介绍 系列&#xff1a;digitalworld.local&#xff08;此系列共9台&#xff09; 发布日期&#xff1a;2018 年 12 月 28 日 难度&#xff1a;中级 运行环境&#xff1a;Virtualbox运行失败&#xff0c;…

写作的“收益”超乎想象

十余年写作经验倾囊相授&#xff0c;全面提升你的技术写作能力&#xff01; 前言 技术从业人员普遍比较务实&#xff0c;也就是用心做好分配给自己的任务&#xff0c;努力担负起自己应尽的责任&#xff0c;因为大家都相信&#xff0c;付出必有回报&#xff0c;金字总会闪光。 …