【数据结构初阶】二、 线性表里的顺序表

news2025/2/26 22:01:03

=========================================================================

相关代码gitee自取

C语言学习日记: 加油努力 (gitee.com)

 =========================================================================

接上期

【数据结构初阶】一. 复杂度讲解_高高的胖子的博客-CSDN博客

 =========================================================================

                     

1 . 线性表

               

线性表linear list)是n个具有相同特性的数据元素的有限序列

线性表是一种在实际中广泛使用的数据结构

常见线性表顺序表链表队列字符串...

顺序表示例:

              

              

线性表逻辑上线性结构,也就说是连续的一条直线

但是在物理结构上并不一定是连续的

线性表物理上存储时,通常以数组链式结构形式存储

链表示例:

         

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

             

2 . 顺序表

顺序表概念及结构:

               

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

一般情况下采用数组存储

数组上完成数据的增删查改

顺序表一般可以分为 静态顺序表动态顺序表

               

               

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

                

因为静态顺序表使用定长数组存储元素

对空间的运用不够灵活,可能造成空间浪费或不够的问题
所以在实际情况下静态顺序表并不常用不够实用

示例:

                    

                    

动态顺序表:使用动态开辟的数组存储元素

             

静态顺序表适用于确定知道需要存多少数据的场景

静态顺序表定长数组导致N定大了空间开多了浪费开少了不够用

所以现实中基本都是使用动态顺序表根据需要动态地分配空间大小

示例:

         

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

             

3 .接口实现(实现动态顺序表):

(详细解释在注释,代码分文件放最后)

                

数据结构可以管理数据

通过 增删改查 等操作就可以实现管理数据

              

现在有了动态顺序表后

就可以对其进行增删改查等操作实现动态顺序表

                      

                        

--------------------------------------------------------------------------------------------------------------------------

                  

                      

SLInit函数 -- 顺序表初始化

                      

                      

--------------------------------------------------------------------------------------------------------------------------

                  

                      

SLDestroy函数 -- 顺序表销毁

                      

                        

--------------------------------------------------------------------------------------------------------------------------

                  

                      

SLPrint函数 -- 测试函数

                      

                        

--------------------------------------------------------------------------------------------------------------------------

                  

                      

SLPushBack函数 -- 将值插入顺序表尾部(尾插)

尾插函数SLPushBack测试:

                      

                        

--------------------------------------------------------------------------------------------------------------------------

                  

                      

上面尾插需要考虑空间不够进行扩容

后面的头插同样也需要考虑

所以可以在顺序表实现文件设置一个内部函数SLCheckCapacity,

在需要的时候直接调用该函数进行扩容操作

↓↓↓↓↓

                 

SLCheckCapacity内部函数 -- 进行扩容操作

                      

                        

--------------------------------------------------------------------------------------------------------------------------

                  

                      

SLPopBack函数 -- 将值从顺序表尾部删除(尾删)

尾删函数SLPopBack测试:

                      

                        

--------------------------------------------------------------------------------------------------------------------------

                  

                      

SLPushFront函数 -- 将值插入顺序表头部(头插)

头插函数SLPushFront测试:

                      

                        

--------------------------------------------------------------------------------------------------------------------------

                  

                      

SLPopFront函数 -- 将值从顺序表头部删除(头删)

头删函数SLPopFront测试:

                      

                        

--------------------------------------------------------------------------------------------------------------------------

                  

                      

SLInsert函数 -- 在指定位置(pos)插入想要的值(x)

指定添加函数SLInsert测试:

             

这里写了指定位置插入SLInsert函数

可以想到其实 头插 尾插 也是可以用 SLInsert函数 实现的

所以可以在头插和尾插函数中复用 SLInsert函数减少代码量

↓↓↓↓↓

                  

复用SLInsert函数 -- 改写头插函数SLPushFront

                     

复用SLInsert函数 -- 改写尾插函数SLPushBack

                      

                        

--------------------------------------------------------------------------------------------------------------------------

                  

                      

上面SLInsert函数涉及了插入位置pos下标

有时在增删改查操作时,需要知道有效元素中某个元素的下标再进行操作,

所以我们可以定义一个函数SLFind查找该元素的下标

↓↓↓↓↓

                 

SLFind函数 -- 查找x这个值在顺序表中的下标是多少

查找函数SLFind测试:

                      

                        

--------------------------------------------------------------------------------------------------------------------------

                  

                      

SLErase函数 -- 删除指定位置(pos)的值

删除指定位置函数SLErase测试:

                   

完成指定删除SLErase函数

头删 尾删 函数中也可以进行复用 SLErase函数 减少代码量

↓↓↓↓↓

                  

用SLErase函数 -- 改写头删函数SLPopFront

                     

用SLErase函数 -- 改写尾删函数SLPopBack

                      

                        

--------------------------------------------------------------------------------------------------------------------------

                  

                      

SLModify函数 -- 把某个位置(pos)的值修改为某值(x)

修改函数SLModify测试:

          

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

             

4 . 对应代码

SeqList.h -- 顺序表头文件

#pragma once

定义一个静态顺序表:使用定长数组存储元素
因为静态顺序表使用定长数组存储元素,对空间的运用不够灵活
所以在实际情况下,静态顺序表并不常用(不够实用)
//
//#define N 1000  //“表”的大小的值
//typedef int SLDataType;  //定义顺序表中存储的类型,这里是int类型
//
//struct SeqList
//{
//	SLDataType a[N]; //定义表的大小
//	int size; //记录表中存储了多少个有效数据
//};


//将需要的头文件都包含在 SeqList.h 头文件中
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>


//定义一个动态顺序表:使用动态开辟的数组存储元素
typedef int SLDataType;  //定义顺序表中存储的类型,这里是int类型

typedef struct SeqList
{
	//定义一个顺序表类型的指针,指向动态开辟的数组
	SLDataType* a; 
	
	int size; //记录表中存储了多少个有效数据
	int capactity; //容量空间的大小
}SL;


//数据结构 --> 管理数据 --> 增删查改

//顺序表初始化  --  头文件中声明
void SLInit(SL* ps); 

//顺序表销毁 --  头文件中声明
//内存是动态开辟地,不销毁的话可能会导致内存泄漏)
void SLDestroy(SL* ps);

//写一个测试函数(声明),方便检查各步骤有没有问题:
void SLPrint(SL* ps);

//尾插(声明) -- 将值插入顺序表尾部:
void SLPushBack(SL* ps, SLDataType x);

//尾删(声明) -- 将值从顺序表尾部删除:
void SLPopBack(SL* ps);

//头插(声明) -- 将值插入顺序表头部:
void SLPushFront(SL* ps, SLDataType x);

//头删(声明) -- 将值从顺序表头部删除:
void SLPopFront(SL* ps);

//在指定位置(pos)插入想要的值(x)
void SLInsert(SL* ps, int pos, SLDataType x);

//查找x这个值在顺序表中的下标是多少:
int SLFind(SL* ps, SLDataType x); //返回找到的下标

//删除指定位置(pos)的值:
void SLErase(SL* ps, int pos);

//把某个位置(pos)的值修改为某值(x)
void SLModify(SL* ps, int pos, SLDataType x);

                        

--------------------------------------------------------------------------------------------------------------------------

                  

                      

SeqList.c -- 顺序表实现文件

#define _CRT_SECURE_NO_WARNINGS 1

//包含我们写的 SeqList.h 头文件
#include "SeqList.h"


//顺序表初始化 -- 实现
void SLInit(SL* ps)
{
	//assert断言,防止接收空指针:
	assert(ps);

	//初始化顺序表类型指针
	//初始化时要先开辟一些动态空间:
	//开辟的空间为顺序表类型,大小为4个顺序表类型的大小
	ps->a = (SLDataType*)malloc(sizeof(SLDataType)*4); 
	
	//顺序表作为一个独立的程序,之后可能会应用于其他程序,
	//所以要对开辟的动态空间进行检查:
	if (ps->a == NULL)
	{
		//可能开辟的空间过大 或 前面开辟太多空间不够再开辟
		perror("malloc failed");  //打印错误

		//让程序以异常的形式结束程序
		//和 return 不同,return后主函数还会继续进行
		exit(-1);
	}

	//将顺序表中的有效数据初始化为0:
	ps->size = 0;

	//将已动态开辟的容量空间初始化为4:
	ps->capactity = 4;
}



//顺序表销毁 -- 实现
//内存是动态开辟地,不销毁的话可能会导致内存泄漏)
void SLDestroy(SL* ps)
{
	//assert断言,防止接收空指针:
	assert(ps);

	//释放前面开辟的动态空间:
	free(ps->a);
	
	//将释放的指针置为空指针:
	ps->a = NULL;

	//将已开辟的动态空间置为0,顺序表有效数据也置为0
	ps->capactity = ps->size = 0;
}



//写一个测试函数(实现),方便检查各步骤有没有问题:
void SLPrint(SL* ps)
{
	//assert断言,防止接收空指针:
	assert(ps);

	//打印动态顺序表现有的有效数据:
	for (int i = 0; i < ps->size; i++)
	{
		printf("%d ", ps->a[i]);
	}

	//打印完当前动态顺序表有效数据后进行换行:
	printf("\n");
}



//在顺序表实现文件中设置一个内部函数SLCheckCapacity,
//在需要的时候直接调用该函数进行扩容操作
void SLCheckCapacity(SL* ps)
{
	//assert断言,防止接收空指针:
	assert(ps);

	//判断开辟的空间是否已满,满了再开辟:
	if (ps->size == ps->capactity)
		//顺序表有效个数 等于 已开辟容量空间
	{
		//使用 realloc函数 进行扩容,每次扩容2倍:
		SLDataType* tmp = (SLDataType*)realloc(ps->a, ps->capactity * 2 * (sizeof(SLDataType)));
		// realloc 是把空间扩容到第二个参数的大小,而不是直接把空间扩容第二个参数的大小

		//同样进行检验:
		if (tmp == NULL)
		{
			//打印错误:
			perror("realloc failed");
			//出现错误直接终止程序:
			exit(-1);
		}

		//realloc函数,有两种扩容情况:一种是原地扩容,另一种是异地扩容
		//原地扩容:扩容时看原空间后的内容有没有分配给别人,如果没有则把原空间后面的空间标记出来进行扩容,返回原空间的地址
		//异地扩容:如果扩容时原空间后面的内容已被分配,则另找一个足够原空间扩容后的空间进行存放,
		//		   原本的数据都搬到这个空间来,原空间会被释放,返回这个新空间的地址。
		//所以使用 realloc函数 扩容后,不要对原空间指针进行释放,
		//如果realloc执行后是原地扩容返回原空间指针,扩容后后对原空间指针释放就会出问题


		//把扩容返回的指针赋给原指针:
		ps->a = tmp;

		//将已动态开辟的容量空间置为原来的2倍:
		ps->capactity *= 2;
	}
}



//尾插(实现) -- 将值插入顺序表尾部:
void SLPushBack(SL* ps, SLDataType x)
{
	//assert断言,防止接收空指针:
	assert(ps);

	调用内部函数进行扩容操作:
	//SLCheckCapacity(ps);

	空间容量足够后将要插入尾部的值插入:
	//ps->a[ps->size] = x; 
	因为下标从0开始,所以size的值会等于现有元素下一位的下标

	//ps->size++; //尾部插入元素后,更新顺序表中有效数据个数

	//复用SLInsert函数 -- 改写尾插函数SLPushBack
	SLInsert(ps, ps->size, x); //在size位置插入就相当于尾插
}



//尾删(实现) -- 将值从顺序表尾部删除:
void SLPopBack(SL* ps)
{
	//assert断言,防止接收空指针:
	assert(ps);

	检查一下:如果有效数据size等于0,则不能继续删除了
	防止越界,可能一直删除到空间外了导致越界
	//
	检查方法一:太“温柔”,返回后不知道自己错了
	if (ps->size == 0)
	{
		return; //直接返回 即可
	}
	//
	检查方法二:使用断言,错误了会直接报错并给出错误信息
	//assert(ps->size > 0); //顺序表中有效数据大于0才进行下面的操作

	直接有效数据size--即可
	尾插是也是用size插入的,所以下次添加时直接就覆盖了原来值
	//ps->size--;

	不能局部释放,不能说不要末尾的值就把末尾的这个空间直接释放掉
	C++有个规定,malloc一次就要free一次,要free释放的话只能整体释放
	顺序表的物理内存是连续的,释放空间是不能“分期”的


	//复用SLErase函数 -- 改写尾删函数SLPopBack
	SLErase(ps, ps->size-1); //size-1 就是最末元素下标
}



//头插(实现) -- 将值插入顺序表头部:
void SLPushFront(SL* ps, SLDataType x)
{
	//assert断言,防止接收空指针:
	assert(ps);

	调用内部函数进行扩容操作:
	//SLCheckCapacity(ps);

	将现有有效数据往后移一位,让出头位置:
	//int end = ps->size - 1; 
	size-1 有效个数-1,就相当于当前最后一个元素的下标

	//while (end >= 0)
	//	//使用while循环循环移动各个有效元素,一直移到下标为0的元素
	//{
	//	ps->a[end + 1] = ps->a[end]; //end下标元素 移到 下一位上
	//	--end; //改变下标
	//}

	将要插入头部的元素x插入头部:
	//ps->a[0] = x;

	有效个数加一:
	//ps->size++;

	Capacity在扩容函数SLCheckCapacity中就修改好了


	//复用SLInsert函数 -- 改写头插函数SLPushFront
	SLInsert(ps, 0, x); //在0位置插入就相当于头插
}



//头删(实现) -- 将值从顺序表头部删除:
void SLPopFront(SL* ps)
{
	//assert断言,防止接收空指针:
	assert(ps);

	因为要将头部的有效元素删除,
	所以直接把第一个有效元素后面的其他元素往前移一位就行了,
	覆盖掉第一个元素

	先进行断言检查,防止没有元素还进行删除:
	//assert(ps->size > 0);

	//int begin = 1; //从下标为1的元素开始往前移,把下标为0的元素覆盖

	//while (begin < ps->size)
	//	//只要begin还小于有效元素个数就继续往前移
	//	//因为是从下标为1的元素开始移动,
	//	//所以最后就只有下标为0的元素没动
	//{
	//	//把当前begin下标的元素往前挪一位:
	//	ps->a[begin - 1] = ps->a[begin]; 

	//	//当前begin下标元素移动后,begin++继续移动下一位:
	//	++begin;
	//}
	//
	因为第一个元素被覆盖,所以有效元素size--
	//ps->size--;


	//复用SLErase函数 -- 改写头删函数SLPopFront
	SLErase(ps, 0); //头元素下标是0
}



//在指定位置(pos)插入想要的值(x)
void SLInsert(SL* ps, int pos, SLDataType x)
{
	//先使用assert检查pos是否合法:
	//在pos位置插入一个值后,顺序表还得是连续的
	assert(pos >= 0 && pos <= ps->size);
	//pos等于0 -- 相等于头插
	//pos等于size -- 相等于尾插
	
	//使用SLCheckCapacity进行扩容操作:
	SLCheckCapacity(ps);

	//定义一个变量end,对应要移动元素的下标
	int end = ps->size - 1; //一开始对应最后一个元素的下标

	while (end >= pos)
		//只要end下标对应的元素还在pos下标元素的右边
		//就把“end元素”向右移,移到pos下标无元素
	{
		//把“end元素”向右移
		ps->a[end + 1] = ps->a[end];
		
		//移动下标进行写一个元素的移动
		--end;
	}

	//让出位置后,将接收的x插入pos位置:
	ps->a[pos] = x;

	//有效元素+1:
	ps->size++;
}



//查找x这个值在顺序表中的下标是多少:
int SLFind(SL* ps, SLDataType x) //返回找到的下标
{
	//assert断言,防止接收空指针:
	assert(ps);

	//数据量不大的话直接暴力查找吧:
	for (int i = 0; i < ps->size; i++)
		//有几个有效元素就循环几次:
	{
		if (ps->a[i] == x)
			//该下标元素等于要找的值x则返回当前下标:
		{
			return i;
		}
	}

	return -1; //表未找到该元素下标
}



//删除指定位置(pos)的值:
void SLErase(SL* ps, int pos)
{
	//同样先使用assert检查pos是否合法:
	//这里检查条件pos不能像SLInsert一样等于size
	//因为size空了能插入(尾插),但不能删除
	assert(pos >= 0 && pos < ps->size);

	//指定删除和头删的思路类似,
	//只要把pos后面的值往前覆盖,覆盖掉pos的值就好了:

	int begin = pos + 1; //从pos+1的位置往前挪
	
	while (begin < ps->size)
		//一直移到size为止(不包括size位置)
	{
		ps->a[begin - 1] = ps->a[begin]; //往前挪
		++begin; //挪完继续挪下一个 
	}

	ps->size--; //覆盖掉pos位置的值后,有效数字减一
}



//把pos位置的值修改为x
void SLModify(SL* ps, int pos, SLDataType x)
{
	//同样先使用assert断言检查pos是否合法:
	assert(pos >= 0 && pos < ps->size);

	//进行修改:
	ps->a[pos] = x;
}

                        

--------------------------------------------------------------------------------------------------------------------------

                  

                      

test.c -- 测试函数

#define _CRT_SECURE_NO_WARNINGS 1

//包含我们写的 SeqList.h 头文件
#include "SeqList.h"

//分组测试,测试不同的函数--SLPushBack 和 SLPopBack 函数
void TestSeqList1()
{
	SL sl;  //创建顺序表类型变量

	//使用 SLInit函数 初始化顺序表类型变量
	//注意传递的是变量的地址,防止形参改变实参不改变
	SLInit(&sl);

	//使用尾插函数SLPushBack:
	SLPushBack(&sl, 1);
	SLPushBack(&sl, 2);
	SLPushBack(&sl, 3);
	SLPushBack(&sl, 4);
	//此时再调用会进行扩容:
	SLPushBack(&sl, 5);
	SLPushBack(&sl, 6);
	//调用测试函数SPrint查看是否插入成功:
	SLPrint(&sl);

	//测试尾删函数SLPopBack:
	SLPopBack(&sl);
	SLPopBack(&sl);
	//调用测试函数SPrint查看是否“删除”成功:
	SLPrint(&sl);

	//测试完后使用SLDestroy函数销毁顺序表:
	SLDestroy(&sl);
}

//分组测试,测试不同的函数--SLPushFront函数
void TestSeqList2()
{
	SL sl;  //创建顺序表类型变量

	//使用 SLInit函数 初始化顺序表类型变量
	//注意传递的是变量的地址,防止形参改变实参不改变
	SLInit(&sl);

	//使用尾插函数SLPushBack:
	SLPushBack(&sl, 1);
	SLPushBack(&sl, 2);
	SLPushBack(&sl, 3);
	SLPushBack(&sl, 4);
	//此时再调用会进行扩容:
	SLPushBack(&sl, 5);
	SLPushBack(&sl, 6);
	//调用测试函数SPrint查看是否插入成功:
	SLPrint(&sl);

	//测试头插函数SLPushFront:
	SLPushFront(&sl, 10);
	SLPushFront(&sl, 20);
	//调用测试函数SPrint查看是否“删除”成功:
	SLPrint(&sl);

	//测试完后使用SLDestroy函数销毁顺序表:
	SLDestroy(&sl);
}


//分组测试,测试不同的函数--SLPopFront函数
void TestSeqList3()
{
	SL sl;  //创建顺序表类型变量

	//使用 SLInit函数 初始化顺序表类型变量
	//注意传递的是变量的地址,防止形参改变实参不改变
	SLInit(&sl);

	//使用尾插函数SLPushBack:
	SLPushBack(&sl, 1);
	SLPushBack(&sl, 2);
	SLPushBack(&sl, 3);
	SLPushBack(&sl, 4);
	//此时再调用会进行扩容:
	SLPushBack(&sl, 5);
	SLPushBack(&sl, 6);
	//调用测试函数SPrint查看是否插入成功:
	SLPrint(&sl);

	//测试头删函数SLPopFront:
	SLPopFront(&sl);
	SLPopFront(&sl);
	//调用测试函数SPrint查看是否“删除”成功:
	SLPrint(&sl);

	//测试完后使用SLDestroy函数销毁顺序表:
	SLDestroy(&sl);
}

//分组测试,测试不同的函数--SLInsert函数
void TestSeqList4()
{
	SL sl;  //创建顺序表类型变量

	//使用 SLInit函数 初始化顺序表类型变量
	//注意传递的是变量的地址,防止形参改变实参不改变
	SLInit(&sl);

	//使用尾插函数SLPushBack:
	SLPushBack(&sl, 1);
	SLPushBack(&sl, 2);
	SLPushBack(&sl, 3);
	SLPushBack(&sl, 4);
	//此时再调用会进行扩容:
	SLPushBack(&sl, 5);
	SLPushBack(&sl, 6);
	//调用测试函数SPrint查看是否插入成功:
	SLPrint(&sl);

	//测试指定增加函数SLInsert:
	SLInsert(&sl, 2, 100);
	//调用测试函数SPrint查看是否“删除”成功:
	SLPrint(&sl);

	//int x;
	//scanf("%d", &x);
	//int pos = SLFind(&sl, x);
	//if (pos != -1)
	//{
	//	SLInsert(&sl, pos, x * 10);
	//}
	//SLPrint(&sl);

	//测试完后使用SLDestroy函数销毁顺序表:
	SLDestroy(&sl);
}


//分组测试,测试不同的函数--SLFind函数
void TestSeqList5()
{
	SL sl;  //创建顺序表类型变量

	//使用 SLInit函数 初始化顺序表类型变量
	//注意传递的是变量的地址,防止形参改变实参不改变
	SLInit(&sl);

	//使用尾插函数SLPushBack:
	SLPushBack(&sl, 1);
	SLPushBack(&sl, 2);
	SLPushBack(&sl, 3);
	SLPushBack(&sl, 4);
	//此时再调用会进行扩容:
	SLPushBack(&sl, 5);
	SLPushBack(&sl, 6);
	//调用测试函数SPrint查看是否插入成功:
	SLPrint(&sl);

	//测试指定增加函数SLFind:
	int pos = SLFind(&sl, 2);
	
	printf("2在元素中是第%d个元素", pos+1);

	//测试完后使用SLDestroy函数销毁顺序表:
	SLDestroy(&sl);
}

//分组测试,测试不同的函数--SLErase函数
void TestSeqList6()
{
	SL sl;  //创建顺序表类型变量

	//使用 SLInit函数 初始化顺序表类型变量
	//注意传递的是变量的地址,防止形参改变实参不改变
	SLInit(&sl);

	//使用尾插函数SLPushBack:
	SLPushBack(&sl, 1);
	SLPushBack(&sl, 2);
	SLPushBack(&sl, 3);
	SLPushBack(&sl, 4);
	//此时再调用会进行扩容:
	SLPushBack(&sl, 5);
	SLPushBack(&sl, 6);
	//调用测试函数SPrint查看是否插入成功:
	SLPrint(&sl);

	int x;
	scanf("%d", &x);
	//配合SLFind函数,找到顺序表中某个值的下标
	int pos = SLFind(&sl, x);
	//再使用SLErase函数通过下标删除该值
	if (pos != -1)
	{
		SLErase(&sl, pos);
	}
	SLPrint(&sl);

	//测试完后使用SLDestroy函数销毁顺序表:
	SLDestroy(&sl);
}


//分组测试,测试不同的函数--SLModify函数
void TestSeqList7()
{
	SL sl;  //创建顺序表类型变量

	//使用 SLInit函数 初始化顺序表类型变量
	//注意传递的是变量的地址,防止形参改变实参不改变
	SLInit(&sl);

	//使用尾插函数SLPushBack:
	SLPushBack(&sl, 1);
	SLPushBack(&sl, 2);
	SLPushBack(&sl, 3);
	SLPushBack(&sl, 4);
	//此时再调用会进行扩容:
	SLPushBack(&sl, 5);
	SLPushBack(&sl, 6);
	//调用测试函数SPrint查看是否插入成功:
	SLPrint(&sl);
	
	//测试指定增加函数SLInsert:
	SLModify(&sl, 2, 100);
	//调用测试函数SPrint查看是否“删除”成功:
	SLPrint(&sl);

	//测试完后使用SLDestroy函数销毁顺序表:
	SLDestroy(&sl);
}

//菜单:
void menu()
{
	printf("********************************\n");
	printf("1、尾插			2、头插\n");
	printf("3、头删			4、尾删\n");
	printf("7、打印			-1、退出\n");
	printf("********************************\n");
}


int main()
{
	//先创建一个顺序表:
	SL sl;

	//再对其进行初始化:
	SLInit(&sl);

	//创建一个变量接收菜单选项:
	int option = 0;

	do
	{
		//使用菜单:
		menu();
		//打印提示信息:
		printf("请选择想要进行的操作的序号:>");
		//接收序号:
		scanf("%d", &option);
		
		printf("\n");

		if (option == 1)
		{
			printf("请依次输入你要插入的数据个数:>");
			int n = 0; //接收数据个数
			scanf("%d", &n); //接收数据个数
			
			printf("\n");
			printf("请依次输入你要插入的数据\n");

			//知道数据个数后,直接使用for循环循环接收数据
			int x = 0;
			for (int i = 0; i < n; i++)
			{
				scanf("%d", &x);
				SLPushBack(&sl, x);
			}
		}
		else if (option == 7)
		{
			SLPrint(&sl);
		}

	} while (option != -1);
	

	//最后销毁顺序表:
	SLDestroy(&sl);


	//TestSeqList1();
	//TestSeqList2();
	//TestSeqList3();
	//TestSeqList4();
	//TestSeqList5();
	//TestSeqList6();
	//TestSeqList7();

	return 0;
}

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

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

相关文章

Top 15 开源3D分子蛋白质建模与渲染软件

如今&#xff0c;WebGL 是一种趋势技术&#xff0c;因为它允许开发人员使用现代浏览器作为客户端来创建复杂的 3D 交互式图形、游戏&#xff0c;而无需安装额外的插件、扩展或软件。 WebGL允许浏览器直接与GPU&#xff08;图形处理单元&#xff09;一起工作。 推荐&#xff1a;…

Java中使用JTS实现WKT字符串读取转换线、查找LineString的list中距离最近的线、LineString做缓冲区扩展并计算点在缓冲区内的方位角

场景 Java中使用JTS对空间几何计算(读取WKT、距离、点在面内、长度、面积、相交等)&#xff1a; Java中使用JTS对空间几何计算(读取WKT、距离、点在面内、长度、面积、相交等)_jts-core_霸道流氓气质的博客-CSDN博客 JavaGeoTools实现WKT数据根据EPSG编码进行坐标系转换&…

分布式、锁、延时任务

1. redission 2.zk 2.1 指令 ls / / 下有哪些子节点 get /zookeeper 查看某个子节点内容 create /aa “test” delete /aa set /aa “test01” 2.2 创建节点 模式 默认创建永久 create -e 创建临时 create -e /zz “hello zz” create -s 创建 有序节点 create -s -e 临…

测试平台项目部署一(手动部署)

手动部署 一、项目框架图1、首先创建一个桥接网络:2、redis3、启动mariadb4、跨域配置5、JWT配置6、celery配置7、启动ck14_django 容器8、安装gunicorn9、数据库迁移10、创建用户11、添加工作进程12、验证异步执行任务、定时执行任务通过二、supervisor1、安装2、创建配置文件…

开源|HDR-ISP开源项目介绍

引言 拖更很久了&#xff0c;本着出品必精的原则&#xff0c;我们更新就来点干货。想起刚入行时&#xff0c;网上并没有很多以及系统的ISP的学习资料&#xff0c;都是边工作、边搜集资料然后边学习&#xff0c;一路坎坎坷坷走到今天算是刚入了ISP的大门。 为了解决新人入门的…

openGauss学习笔记-63 openGauss 数据库管理-资源池化架构

文章目录 openGauss学习笔记-63 openGauss 数据库管理-资源池化架构 openGauss学习笔记-63 openGauss 数据库管理-资源池化架构 本文档主要介绍资源池化架构下的一些最佳实践和使用注意事项&#xff0c;用于支撑对相关特性感兴趣的开发者可以快速部署、实践或进行定制化开发。…

【时空融合:改进MRA】

Multiresolution Analysis Pansharpening Based on Variation Factor for Multispectral and Panchromatic Images From Different Times &#xff08;基于变化因子的多光谱和全色图像多分辨率分析&#xff09; 大多数泛锐化方法是将同一区域上同时获取的原始低分辨率多光谱(M…

Redis的数据持久化方案

目录 前言 RDB方式 概述&#xff1a; 1.RDB手动 &#xff12;.RDB自动 RDB优缺点 AOF方式 概述 AOF写数据的三种策略 AOF相关配置 AOF重写 AOF重写方式 手动重写 bgrewriteaof 自动重写 总结 前言 Redis是一个内存型数据库&#xff0c;也就是说如果不将内存中的…

overleaf 参考文献引用,创建引用目录.bib文件,在文档中引用参考文献,生成参考文献列表

目录 1 创建一个Overleaf项目 2 导入或创建 .bib 文件 2.1 导入 .bib 文件&#xff1a; 参考文献的 .bib文件获取步骤 &#xff08;1&#xff09;打开谷歌学术 &#xff08;2&#xff09;输入文献题目 &#xff08;3&#xff09;点击引用&#xff0c;然后选择BibTex格式…

af-table-column插件的使用 element el-table-column宽度自适应

af-table-column 是一个用于 Vue.js 的表格列组件&#xff0c;用于在表格中定义列的样式和行为。下面是 af-table-column 的使用方法&#xff1a; 首先&#xff0c;确保已经安装了 af-table-column 包。可以使用以下命令进行安装&#xff1a; npm install af-table-column --…

MySQL——事务

一、事务的开始与结束 一个数据库事务由一条或多条sql语句构成&#xff0c;它们形成一个逻辑的工作单元。这些sql语句要么全部执行成功&#xff0c;要么全部执行失败。 1.1.事物的开始 1.对于DDL&#xff08;create&#xff0c;alter&#xff0c;drop&#xff09;和DCL&…

render函数使用和详解

背景 在平时编程时&#xff0c;大部分是通过template来创建html。但是在一些特殊的情况下&#xff0c;使用template方式时&#xff0c;就无法很好的满足需求&#xff0c;在这个时候就需要 通过JavaScript 的编程能力来进行操作。此时&#xff0c;就到了render函数展示拳脚去时…

【Python】迭代器__iter__、__next__

这里主要纠正迭代器的用法&#xff0c;因为一些教程传播错误示例让我很无语。 最大的错误就是&#xff0c;把__iter__和__next写在同个类里&#xff0c;每每看见都感到诧异。不是说这方法不行&#xff0c;主要是&#xff0c;一旦出现预期之外的运行结果往往很难查到原因(因为它…

Nomad 系列-Nomad+Traefik+Tailscale 集成实现零信任安全

系列文章 Nomad 系列文章Traefik 系列文章Tailscale 系列文章 概述 终于到了令人启动的环节了&#xff1a;NomadTraefikTailscale 集成实现零信任安全。 在这里&#xff1a; Nomad 负责容器调度&#xff1b;&#xff08;容器编排工具&#xff09;Traefik 负责入口流量&…

文件导入之Validation校验List对象数组

背景&#xff1a; 我们的接口是一个List对象&#xff0c;对象里面的数据基本都有一些基础数据校验的注解&#xff0c;我们怎么样才能校验这些基础规则呢&#xff1f; 我们在导入excel文件进行数据录入的时候&#xff0c;数据录入也有基础的校验规则&#xff0c;这个时候我们又…

Linux下C语言使用 netlink sockets与内核模块通信

netlink简介 Netlink套接字是用以实现用户进程与内核进程通信的一种特殊的进程间通信(IPC) ,也是网络应用程序与内核通信的最常用的接口。在Linux标准内核中&#xff0c;系统默认集成了很多netlink实例&#xff0c;比如日志上报、路由系统等&#xff0c;netlink消息是双向的&a…

解决 tesserocr报错 Failed to init API, possibly an invalid tessdata path : ./

问题描述 我们在初次使用tesserocr库的时候&#xff0c;可能会报以下错误&#xff1a; RuntimeError: Failed to init API, possibly an invalid tessdata path: ./ 这是因为我们在使用 conda 创建的环境中找不到"tessdata"这个文件夹。 解决办法 这时候把Tessera…

【CMake工具】工具CMake编译轻度使用(C/C++)

目录 CMake编译工具 一、CMake概述 二、CMake的使用 2.1 注释 2.1.1 注释行 2.1.2 注释块 2.2 源文件 2.1.1 共处一室 2.1.2 VIP包房 2.3 私人定制 2.2.1 定义变量 2.2.2 指定使用的C标准 2.2.3 指定输出的路径 2.4 搜索文件 2.3.1 方式1 2.3.2 方式2 2.5 包含…

CRM软件系统能否监控手机的使用

CRM可以监控手机吗&#xff1f;答案是不可以。CRM是一款帮助企业优化业务流程&#xff0c;提高销售效率的工具。例如Zoho CRM&#xff0c;最多也就是听一下销售的通话录音&#xff0c;却不可以监控手机&#xff0c;毕竟CRM不是一款监控软件。 CRM的主要作用有以下几点&#xf…

CASAIM与南京航空航天大学在自动化叶片曲面分析系统开展合作,推动航空航天发动机零部件自动化3D检测进程

近期&#xff0c;CASAIM与南京航空航天大学在自动化叶片曲面分析系统展开深入合作&#xff0c;充分发挥双方在航空航天和智能检测领域优势&#xff0c;共同推动航空航天发动机零部件自动化3D检测进程。 南京航空航天大学创建于1952年10月&#xff0c;是新中国自己创办的第一批…