【数据结构】万字超详解顺序表

我这个人走得很慢,但是我从不后退。                                ——亚伯拉罕·林肯

目录

一.什么是线性表?

二.什么是顺序表?

三.接口函数的实现

1.创建工程

2.构造顺序表

3.初始化顺序表

3.初始化顺序表

4.顺序表的尾插

5.顺序表的头插 

6.顺序表的尾删 

7.顺序表的头删 

8.在顺序表中查找一个数 

9.在顺序表中指定位置插入

10.在顺序表中指定位置删除 

11.在头插和尾插的功能实现可以使用指定位置插入的函数进行复用

四.很被动的实现顺序表

1.SeqList.h:

2.SeqList.c:

3.test.c:

五.以菜单的形式玩转顺序表 

1.以菜单的形式写顺序表

六.主动的输入实现顺序表全部功能的代码

1.SeqList.h:

2.SeqList.c:

3.test.c:


一.什么是线性表?

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

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

二.什么是顺序表?

顺序表是用一段物理地址连续的存储单元依次存储数据元素的线性结构,一般情况下采用数组存储。在数组上完成数据的增删查改

顺序表其实就是数组,但是在数组的基础上,它还要求数据是从头开始的,并且是连续储存的不能跳跃间隔

这句话什么意思呢?我们举个例子来看:

#include<stdio.h>
int main()
{
	int arr[5] = { 0 };
	arr[4] = 5;
	arr[1] = 6;
	for (int i = 0; i < 5; i++)
	{
		printf("%d ", arr[i]);
	}
}

可以看出:数组可以跳着存入数据,不一定要连续。

总结:数组内存是连续的,但是储存数据可以不连续。 所以顺序表在数组的基础上还有一定的要求。

三.接口函数的实现

1.创建工程

创建工程我们也是像三子棋那样创建三个文件。SeqList.c,SeqList.h和test.c。

SeqList.h:函数的声明以及各种头文件。

SeqList.c:函数的实现,定义。

test.c:书写程序整体执行逻辑。

2.构造顺序表

构造顺序表一般有两种。

第一种:静态顺序表,使用定长数组来实现顺序表。



静态顺序表只适用于确定知道需要存多少数据的场景。静态顺序表的定长数组导致N定大了,空间开多了浪费,开秒了不够用。

所以现实中基本都是使用动态顺序表,根据需要动态的分配空间大小,所以下面我们实现动态顺序表。

第二种:动态顺序表,使用动态开辟的数组。
 

动态顺序表相对于静态顺序表来说,优点就是空间不够可以增容。

3.初始化顺序表

typedef int SLDateType;
typedef struct SeqList
{
	SLDateType* a; //动态数组
	size_t size; //有效的数据个数
	size_t Capacity; //数组的容量大小
}SL;

这里我们使用了两个typedef(类型重定义)。

第一个typedef将int定义为SLDateType,如果要定义其他的数据类型,如double,short,char等等只需要改变类型重定义这里,后面的也会跟着改变。

第二个typedef将结构体重新命名为SL。为了后面写结构体名称时,不那么麻烦,更方便简洁。

3.初始化顺序表

void SeqListInit(SL ps)//ps是形参
{
	ps.a = 0;
	ps.size = ps.Capacity = 0;
}

 所以我们应当写成指针的形式,使用传址调用,这样改变形参也就会改变实参了。

正确的写法:

  //初始化顺序表
void SeqListInit(SL*ps)
{
	ps->a = NULL;//先将动态数组置为空指针
	ps->size = ps->Capacity = 0;//有效个数和容量大小都设为0
}

4.顺序表的尾插

尾插目的就是在动态数组的结尾开始放入数据,逐渐填充数组。

思路:

1.刚开始size和Capacity都初始化为的0,两个大小相等,肯定没法存放数据。然后我们开始扩容,把Capacity的值扩大为两倍,但是第一次Capacity的值为0,扩大两倍还是0。所以第一次我们把Capacity的值扩大为4下一次就依次扩大为两倍。

2.然后把扩容的大小赋给动态数组的大小。

3.对动态数组进行尾插进数据,每插一个数据进去,a就加一次,直到a和Capacity的值大小一致,又重复1步骤,继续扩容。

//尾插
void SeqListPushBack(SL*ps, SLDateType x)
{
	if (ps->size == ps->Capacity)//初始化都为0,肯定if成立进入语句
	{                              //这里一定要写成==,因为这里判断语句
		int NewCapacity = ps->Capacity == 0 ? 4 : ps->Capacity * 2;//这里使用一个三目操作符
		SLDateType* temp = (SLDateType*)realloc(ps->a, sizeof(SLDateType) * NewCapacity);
		if (temp == NULL)//如果开辟空间错误
		{
			printf("realloc is error\n");
			exit(-1);//退出程序
		}
		ps->a = temp;
		ps->Capacity = NewCapacity;
	}
	ps->a[ps->size] = x;
	ps->size++;
}

在test.c中的文件中,下面是我们要插入的5个数字。 

void SeqListtest1()
{
	SL s1;
	SeqListInit(&s1);
	SeqListPushBack(&s1, 1);
	SeqListPushBack(&s1, 2);
	SeqListPushBack(&s1, 3);
	SeqListPushBack(&s1, 4);
	SeqListPushBack(&s1, 5);
}

我们再写一个打印函数,打印一下我们尾插的数据。 

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

这里说明我们尾插成功了,还是非常喜悦的。然后我们开始头插。

5.顺序表的头插 

头插的方法:

注意事项:在头插的时候我们也要考虑容量的大小和数据个数的大小的关系,不够了,就要扩容。 尾插的时候也要考虑这种情况。我们不妨把扩容写成一个函数。每次有地方要扩容时,就调用一次,这样就很方便。

检查容量的函数:

//检查容量
void SeqListCheckCapacity(SL* ps)
{
	if (ps->size == ps->Capacity)//初始化都为0,肯定if成立进入语句
	{                              //这里一定要写成==,因为这里判断语句
		int NewCapacity = ps->Capacity == 0 ? 4 : ps->Capacity * 2;//这里使用一个三目操作符
		SLDateType* temp = (SLDateType*)realloc(ps->a, sizeof(SLDateType) * NewCapacity);
		if (temp == NULL)//如果开辟空间错误
		{
			printf("realloc is error\n");
			exit(-1);//退出程序
		}
		ps->a = temp;
		ps->Capacity = NewCapacity;
	}
}

开始头插:

//头插
void SeqListPushFront(SL* ps, SLDateType x)
{
	SeqListCheckCapacity(ps);//检查容量
	int end = ps->size - 1;
	while (end >= 0)
	{
		ps->a[end + 1] = ps->a[end];
		end--;
	}
	ps->a[0] = x;
	ps->size++;
}

 我们头插6,7两个数之后,打印出来看一下。

    SeqListPushFront(&sl, 6);
	SeqListPushFront(&sl, 7);
	SeqListprint(&sl);

6.顺序表的尾删 

尾删的方法非常简单,我们只需要把ps->size的值--即可,这样最后的数据自然会被删除。

//尾删
void SeqListPopBack(SL* ps)
{
	assert(ps->size > 0);//这里断言一下,如果ps->size小于0之后,直接报错
	ps->size--;
}

 这里调用三次尾删函数,所以就会依次删除三个后面的数字。

//尾删
	printf("尾删之后为 ");
	SeqListPopBack(&sl);
	SeqListPopBack(&sl);
	SeqListPopBack(&sl);
	SeqListprint(&sl);

7.顺序表的头删 

头删和头插的方法其实很相似,头插是往后面移动数据,而头删就是相反的,往前面移动数据。

后一个数字把前一个数字给覆盖掉,也就是头删了。

开始头删: 

//头删
void SeqListPopFront(SL* ps)
{
	int start = 0;
	while (start < ps->size)
	{
		ps->a[start] = ps->a[start + 1];
		start++;
	}
	ps->size--;
}

8.在顺序表中查找一个数 

//在数组里面找一个数字,找到就返回下标,否则就是返回-1
int SeqListfind(SL* ps, SLDateType x)
{
	int i = 0;
	while (i < ps->size)
	{
		if (ps->a[i] == x)
		{
			return i;
		}
		i++;
	}
	return -1;
}
//在数组里面找一个数字,找到就返回下标,否则就是返回-1
	int ret=SeqListfind(&sl, 1);
	if (ret != -1)
	{
		printf("找到数字1的下标为%d\n", ret);
	}
	else
		printf("没找到\n");

9.在顺序表中指定位置插入

这个和头插是很相似的,只需要把你要指定的位置给往后面移动一位,然后你再把要插入的数字给填到空缺的位置即可。

注意事项:在插入数据的时候,我们必须要判断ps->size和ps->Capacity容量的大小。

即:判断容量的大小,所以我们在插入数据之前,需要调用检查容量的函数。

//在指定的位置插入一个数字
void  SeqListInsert(SL* ps, int pos, SLDateType x)//pos是指定的下标位置
{
	SeqListCheckCapacity(ps);//检查容量
	int end = ps->size-1;
	while (end>=pos)
	{
		ps->a[end+1] = ps->a[end];
		end--;
	}
	ps->a[pos] = x;
	ps->size++;
}

10.在顺序表中指定位置删除 

这和头删是很相似的,只需要把指定的位置的后面的位置依次往前一位,把指定位置的地方给覆盖掉。

//在指定位置删除一个数字
void SeqListErase(SL* ps, int pos)
{
	int end = pos;
	while (end < ps->size)
	{
		ps->a[end] = ps->a[end + 1];
		end++;
	}
	ps->size--;
}

11.在头插和尾插的功能实现可以使用指定位置插入的函数进行复用

之前说了在指定位置插入函数的功能实现是和头插和尾插函数是很相似的,这里我们就可以复用这个函数,来简化代码。

  //头插
void SeqListPushFront(SL* ps, SLDateType x)
{
	SeqListCheckCapacity(ps);//检查容量
	SeqListInsert(ps, 0, x);//调用插入函数来复用头插,头插就是在0的位置进行插入
}
  //头插
void SeqListPushFront(SL* ps, SLDateType x)
{
	SeqListCheckCapacity(ps);//检查容量
	SeqListInsert(ps, 0, x);//调用插入函数来复用头插,头插就是在0的位置进行插入
}

四.很被动的实现顺序表

1.SeqList.h:

#pragma once
#include<stdio.h>
#include<assert.h>
#include<stdlib.h>
typedef int SLDateType;
typedef struct SeqList
{
	SLDateType* a; //动态数组
	size_t size; //有效的数据个数
	size_t Capacity; //数组的容量大小
}SL;
//初始化顺序表
void SeqListInit(SL*ps);

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

//打印数据
void SeqListprint(SL* ps);

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

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

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

//在数组里面找一个数字,找到就返回下标,否则就是返回-1
int SeqListfind(SL* ps, SLDateType x);

//在指定的位置插入一个数字
void SeqListInsert(SL* ps, int pos, SLDateType x);//pos是指定的下标位置

//在指定位置删除一个数字
void SeqListErase(SL* ps, int pos);

2.SeqList.c:

#define _CRT_SECURE_NO_WARNINGS 1
#include"SeqList.h"
//检查容量
void SeqListCheckCapacity(SL* ps)
{
	if (ps->size == ps->Capacity)//初始化都为0,肯定if成立进入语句
	{                              //这里一定要写成==,因为这里判断语句
		int NewCapacity = ps->Capacity == 0 ? 4 : ps->Capacity * 2;//这里使用一个三目操作符
		SLDateType* temp = (SLDateType*)realloc(ps->a, sizeof(SLDateType) * NewCapacity);
		if (temp == NULL)//如果开辟空间错误
		{
			printf("realloc is error\n");
			exit(-1);//退出程序
		}
		ps->a = temp;
		ps->Capacity = NewCapacity;
	}
}
        //初始化顺序表
void SeqListInit(SL*ps)
{
	ps->a = NULL;//先将动态数组置为空指针
	ps->size = ps->Capacity = 0;//有效个数和容量大小都设为0
}

//尾插
void SeqListPushFront(SL* ps, SLDateType x)
{
  SeqListCheckCapacity(ps);//检查容量
  SeqListInsert(ps, ps->size, x);//调用插入函数来复用尾插,尾插就是在ps->size的位置进行插入
}

//打印函数
void SeqListprint(SL* ps) 
{
	int i = 0;
	for (i = 0; i < ps->size; i++)
	{
		printf("%d ", ps->a[i]);
	}
	printf("\n");
}
  //头插
void SeqListPushFront(SL* ps, SLDateType x)
{
	SeqListCheckCapacity(ps);//检查容量
	SeqListInsert(ps, 0, x);//调用插入函数来复用头插,头插就是在0的位置进行插入
}
//尾删
void SeqListPopBack(SL* ps)
{
	assert(ps->size > 0);//这里断言一下,如果ps->size小于0之后,直接报错
	ps->size--;
}
//头删
void SeqListPopFront(SL* ps)
{
	int start = 0;
	while (start < ps->size)
	{
		ps->a[start] = ps->a[start + 1];
		start++;
	}
	ps->size--;
}
//在数组里面找一个数字,找到就返回下标,否则就是返回-1
int SeqListfind(SL* ps, SLDateType x)
{
	int i = 0;
	while (i < ps->size)
	{
		if (ps->a[i] == x)
		{
			return i;
		}
		i++;
	}
	return -1;
}
//在指定的位置插入一个数字
void  SeqListInsert(SL* ps, int pos, SLDateType x)//pos是指定的下标位置
{
	SeqListCheckCapacity(ps);//检查容量
	int end = ps->size-1;
	while (end>=pos)
	{
		ps->a[end+1] = ps->a[end];
		end--;
	}
	ps->a[pos] = x;
	ps->size++;
}
//在指定位置删除一个数字
void SeqListErase(SL* ps, int pos)
{
	int end = pos;
	while (end < ps->size)
	{
		ps->a[end] = ps->a[end + 1];
		end++;
	}
	ps->size--;
}

3.test.c:

#define _CRT_SECURE_NO_WARNINGS 1
#include"SeqList.h"
    SL sl;
void SeqListtest1()
{
	SeqListInit(&sl);//初始化顺序表
	//尾插
	printf("尾插的数据为 ");
	SeqListPushBack(&sl, 1);
	SeqListPushBack(&sl, 2);
	SeqListPushBack(&sl, 3);
	SeqListPushBack(&sl, 4);
	SeqListPushBack(&sl, 5);
	SeqListprint(&sl);//打印函数
	printf("\n");
	//头插
	printf("头插之后为 ");
	SeqListPushFront(&sl, 6);
	SeqListPushFront(&sl, 7);
	SeqListprint(&sl);
	printf("\n");
}
void SeqListtest2()
{
	//尾删
	printf("尾删之后为 ");
	SeqListPopBack(&sl);
	SeqListPopBack(&sl);
	SeqListPopBack(&sl);
	SeqListprint(&sl);
	printf("\n");

	//头删
	printf("头删之后 ");
	SeqListPopFront(&sl);
	SeqListprint(&sl);
	printf("\n");
}
void SeqListtest3()
{
	//在数组里面找一个数字,找到就返回下标,否则就是返回-1
	int ret=SeqListfind(&sl, 1);
	if (ret != -1)
	{
		printf("找到数字1的下标为%d\n", ret);
	}
	else
		printf("没找到\n");

	//在指定的位置插入一个数字
	printf("在下标为1的位置插入数字后为 ");
	SeqListInsert(&sl, 1, 8);
	SeqListprint(&sl);

	//在指定位置删数字
	printf("在下标为2的删除数字后为 ");
	SeqListErase(&sl,2);
	SeqListprint(&sl);
}

int main()
{
	SeqListtest1();
	SeqListtest2();
	SeqListtest3();

	return 0;
}

五.以菜单的形式玩转顺序表 

1.以菜单的形式写顺序表

#define _CRT_SECURE_NO_WARNINGS 1
#include"SeqList.h"
    SL sl;
	SL* ps;

void test()
{
	printf("\n*********************************\n");
	printf("1.尾插  2.头插\n");
	printf("3.尾删  4.头删\n");
	printf("5.指定删 6.指定插\n");
	printf("7.找一个数  -1.退出\n");
	printf("**********************************\n");
	printf("请选择你要进行的操作:>\n");
}
void Menutest()
{
	SL sl;
	SeqListInit(&sl);
	int x = 0;
	int y = 0;
	int input = 0;
	while (input != -1)
	{
		test();//每一次输入结束了,都会再次打印菜单
		scanf("%d", &input);
		switch (input)
		{
		case 1:
		{
			printf("请你输入要尾插的数字,以-1结束:");
			scanf("%d", &x);
			while (x != -1)//还是有缺陷,不能插入-1
			{
				SeqListPushBack(&sl, x);
				scanf("%d", &x);
			}
			printf("尾插之后为:");
			SeqListprint(&sl);
			break;
		}
		case 2:
		{
			printf("请你输入要头插的数字,以-1结束:");
			scanf("%d", &x);
			while (x != -1)
			{
				SeqListPushFront(&sl, x);
				scanf("%d", &x);
			}
			printf("尾插之后为:");
			SeqListprint(&sl);
			break;
		}
		case 3:
		{
			SeqListPopBack(&sl);
			printf("尾删之后为:");
			SeqListprint(&sl);
			break;
		}
		case 4:
		{
			SeqListPopFront(&sl);
			printf("头删之后为:");
			SeqListprint(&sl);
			break;
		}
		case 5:
		{
			printf("请你输入要删数字的下标:");
			scanf("%d", &x);
				SeqListErase(&sl, x);
				printf("删除数字后:");
				SeqListprint(&sl);
				break;
		}
		case 6:
		{
			    printf("请你输入要插数字的下标和数字:");
			    scanf("%d %d", &x, &y);
				SeqListInsert(&sl, x, y);
				printf("插入数字后:");
				SeqListprint(&sl);
				break;

		}
		case 7:
		{
			printf("请你输入你要找的数字:");
			scanf("%d", &x);
			int ret = SeqListfind(&sl, x);
			if (ret != -1)
			{
				printf("查找的坐标为:");
				printf("%d", ret);
			}
			break;
		}
		default:
			printf("选择错误,请重新输入");
			break;
		}
	}
}
int main()
{
	Menutest();
	SeqlistDestory(&sl);
	return 0;
}

六.主动的输入实现顺序表全部功能的代码

1.SeqList.h:

#pragma once
#include<stdio.h>
#include<assert.h>
#include<stdlib.h>
typedef int SLDateType;
typedef struct SeqList
{
	SLDateType* a; //动态数组
	size_t size; //有效的数据个数
	size_t Capacity; //数组的容量大小
}SL;
//初始化顺序表
void SeqListInit(SL*ps);

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

//打印数据
void SeqListprint(SL* ps);

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

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

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

//在数组里面找一个数字,找到就返回下标,否则就是返回-1
int SeqListfind(SL* ps, SLDateType x);

//在指定的位置插入一个数字
void SeqListInsert(SL* ps, int pos, SLDateType x);//pos是指定的下标位置

//在指定位置删除一个数字
void SeqListErase(SL* ps, int pos);

//最后销毁空间
void SeqlistDestory(SL* ps);

2.SeqList.c:

#define _CRT_SECURE_NO_WARNINGS 1
#include"SeqList.h"
//检查容量
void SeqListCheckCapacity(SL* ps)
{
	if (ps->size == ps->Capacity)//初始化都为0,肯定if成立进入语句
	{                              //这里一定要写成==,因为这里判断语句
		int NewCapacity = ps->Capacity == 0 ? 4 : ps->Capacity * 2;//这里使用一个三目操作符
		SLDateType* temp = (SLDateType*)realloc(ps->a, sizeof(SLDateType) * NewCapacity);
		if (temp == NULL)//如果开辟空间错误
		{
			printf("realloc is error\n");
			exit(-1);//退出程序
		}
		ps->a = temp;
		ps->Capacity = NewCapacity;
	}
}
        //初始化顺序表
void SeqListInit(SL*ps)
{
	ps->a = NULL;//先将动态数组置为空指针
	ps->size = ps->Capacity = 0;//有效个数和容量大小都设为0
}

//尾插
void SeqListPushBack(SL* ps, SLDateType x)
{
	SeqListCheckCapacity(ps);//检查容量
	SeqListInsert(ps, ps->size, x);//调用插入函数来复用头插,头插就是在0的位置进行插入
}

//打印函数
void SeqListprint(SL* ps) 
{
	int i = 0;
	for (i = 0; i < ps->size; i++)
	{
		printf("%d ", ps->a[i]);
	}
	printf("\n");
}
  //头插
void SeqListPushFront(SL* ps, SLDateType x)
{
	SeqListCheckCapacity(ps);//检查容量
	SeqListInsert(ps, 0, x);//调用插入函数来复用头插,头插就是在0的位置进行插入
}
//尾删
void SeqListPopBack(SL* ps)
{
	assert(ps->size > 0);//这里断言一下,如果ps->size小于0之后,直接报错
	ps->size--;
}
//头删
void SeqListPopFront(SL* ps)
{
	int start = 0;
	while (start < ps->size)
	{
		ps->a[start] = ps->a[start + 1];
		start++;
	}
	ps->size--;
}
//在数组里面找一个数字,找到就返回下标,否则就是返回-1
int SeqListfind(SL* ps, SLDateType x)
{
	int i = 0;
	while (i < ps->size)
	{
		if (ps->a[i] == x)
		{
			return i;
		}
		i++;
	}
	return -1;
}
//在指定的位置插入一个数字
void  SeqListInsert(SL* ps, int pos, SLDateType x)//pos是指定的下标位置
{
	SeqListCheckCapacity(ps);//检查容量
	int end = ps->size-1;
	while (end>=pos)
	{
		ps->a[end+1] = ps->a[end];
		end--;
	}
	ps->a[pos] = x;
	ps->size++;
}
//在指定位置删除一个数字
void SeqListErase(SL* ps, int pos)
{
	int end = pos;
	while (end < ps->size)
	{
		ps->a[end] = ps->a[end + 1];
		end++;
	}
	ps->size--;
}
//最后销毁空间
void SeqlistDestory(SL* ps)
{
	free(ps->a = NULL);
	ps->size = ps->Capacity = 0;
}

3.test.c:

#define _CRT_SECURE_NO_WARNINGS 1
#include"SeqList.h"
    SL sl;
	SL* ps;
void test()
{
	printf("\n*********************************\n");
	printf("1.尾插  2.头插\n");
	printf("3.尾删  4.头删\n");
	printf("5.指定删 6.指定插\n");
	printf("7.找一个数  -1.退出\n");
	printf("**********************************\n");
	printf("请选择你要进行的操作:>\n");
}
void Menutest()
{
	SL sl;
	SeqListInit(&sl);
	int x = 0;
	int y = 0;
	int input = 0;
	while (input != -1)
	{
		test();//每一次输入结束了,都会再次打印菜单
		scanf("%d", &input);
		switch (input)
		{
		case 1:
		{
			printf("请你输入要尾插的数字,以-1结束:");
			scanf("%d", &x);
			while (x != -1)//还是有缺陷,不能插入-1
			{
				SeqListPushBack(&sl, x);
				scanf("%d", &x);
			}
			printf("尾插之后为:");
			SeqListprint(&sl);
			break;
		}
		case 2:
		{
			printf("请你输入要头插的数字,以-1结束:");
			scanf("%d", &x);
			while (x != -1)
			{
				SeqListPushFront(&sl, x);
				scanf("%d", &x);
			}
			printf("尾插之后为:");
			SeqListprint(&sl);
			break;
		}
		case 3:
		{
			SeqListPopBack(&sl);
			printf("尾删之后为:");
			SeqListprint(&sl);
			break;
		}
		case 4:
		{
			SeqListPopFront(&sl);
			printf("头删之后为:");
			SeqListprint(&sl);
			break;
		}
		case 5:
		{
			printf("请你输入要删数字的下标:");
			scanf("%d", &x);
				SeqListErase(&sl, x);
				printf("删除数字后:");
				SeqListprint(&sl);
				break;
		}
		case 6:
		{
			    printf("请你输入要插数字的下标和数字:");
			    scanf("%d %d", &x, &y);
				SeqListInsert(&sl, x, y);
				printf("插入数字后:");
				SeqListprint(&sl);
				break;

		}
		case 7:
		{
			printf("请你输入你要找的数字:");
			scanf("%d", &x);
			int ret = SeqListfind(&sl, x);
			if (ret != -1)
			{
				printf("查找的坐标为:");
				printf("%d", ret);
			}
			break;
		}
		default:
			printf("选择错误,请重新输入");
			break;
		}
	}
}
int main()
{
	Menutest();
	SeqlistDestory(&sl);
	return 0;
}

  • 53
    点赞
  • 46
    收藏
    觉得还不错? 一键收藏
  • 42
    评论
### 回答1: ST表(Sparse Table)是一种用于解决区间查询问题的数据结构。它可以支持在 O(1) 的时间复杂度内查询一个区间中的最大值、最小值、和、积等等。 ST表的基本思想是利用区间重叠的性质,将区间划分成若干个长度为2的子区间,对每个子区间记录其区间内的最大值、最小值、和、积等信息。这些子区间的信息可以通过递归的方式预处理出来,构建出一张类似二维表格的 ST表。查询一个区间的信息时,可以通过查询两个子区间的信息并取其合并得到。 ST表的构建时间复杂度为 O(n log n),其中 n 是数据的规模。查询一个区间的信息的时间复杂度为 O(1)。ST表的空间复杂度为 O(n log n)。 ST表常用于解决区间查询问题,例如在数组中查询一个区间的最大值、最小值、和、积等信息。同时,ST表也可以用于支持动态区间查询,即在不断修改数组元素的情况下,仍然能够在 O(1) 的时间复杂度内查询任意一个区间的信息。 ### 回答2: ST表,全称Sparse Table,是一种常见的数据结构,用于支持高效地查询一段区间内的最值操作。它主要用于快速处理静态的区间最值查询问题。 ST表的构建过程很简单。首先,我们需要预处理一个二维数组dp,其中dp[i][j]表示从位置i开始,长度为2^j的区间内的最值。这个数组的大小需要根据具体问题来确定。 接下来,我们对dp数组进行初始化。假设我们要求最小值,那么dp[i][0]就等于位置i的元素值。然后,我们可以通过以下递推公式计算出dp数组的其他元素:dp[i][j] = min(dp[i][j-1], dp[i + 2^(j-1)][j-1])。这个公式表示,从位置i开始,长度为2^j的区间内的最值等于从位置i开始,长度为2^(j-1)的两个子区间的最值之间的较小值。 构建好dp数组后,我们就可以通过查询来快速得到区间的最值了。对于一个查询操作,我们只需要找到最小的k,使得2^k大于等于查询区间的长度。然后,我们可以通过以下递推公式计算出查询结果:min(dp[left][k], dp[right - 2^k + 1][k])。其中,left和right分别表示查询区间的左右边界。 ST表的时间复杂度主要来自于构建dp数组的过程,为O(nlogn),其中n为数据的长度。查询的时间复杂度为O(1),因为我们只需要进行常数次操作即可得到结果。 总结来说,ST表是一种用于高效查询区间最值的数据结构。它通过预处理和递推的方式构建二维数组,可以快速回答各种区间最值查询问题。它的时间复杂度比较低,适用于快速查询静态数据的场景。 ### 回答3: ST表是一种可以高效求解多种区间查询问题的数据结构。ST表全称为Sparse Table,它通过预处理输入序列建立一个二维表格,用于快速回答各种区间查询问题。 在ST表中,将序列中的每个元素作为第0层,每个区间的最小值或最大值作为第1层,第2层是第1层区间的最小值或最大值,以此类推,直到第log(n)层。其中n是输入序列的长度。 ST表的构建是通过动态规划的思想来完成的。假设有一个区间[a, b],查询区间的长度为query_len,则可以将该查询区间分为两个长度为query_len/2的子区间[a, a+query_len/2-1]和[a+query_len/2, b]。通过之前已经计算到的结果,可以很快得到子区间的最小值或最大值,然后将两个子区间的最小值或最大值作为该查询区间的结果。这样,将自顶向下地计算每个查询区间的结果,即可构造出整个ST表。 ST表的查询是通过将查询区间拆解成若干个长度为2的幂次的小区间,然后对应每个小区间查询结果进行合并得到的。例如,查询区间[a, b]可以拆解成多个小区间,分别是[a, a+2^k-1]、[a+2^k, a+2^(k+1)-1]、…、[b-2^k+1, b],其中k是满足2^k <= b-a+1的最大整数。然后对于每个小区间,在ST表中查找得到最小值或最大值,再通过合并获得整个查询区间的结果。 ST表的构建时间复杂度为O(n log(n)),其中n是输入序列的长度。每次查询的时间复杂度为O(1)。ST表适用于各种区间查询问题,如最小值、最大值、和、乘积等。但只适用于静态问题,即查询的区间不会发生改变。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 42
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值