【数据结构】详解动态顺序表

作者:一个喜欢猫咪的的程序员

专栏:《数据结构》

喜欢的话:世间因为少年的挺身而出,而更加瑰丽。                                  ——《人民日报》

【数据结构】详解动态顺序表_第1张图片

 


目录

顺序表:

顺序表结构: 

SeqLisht.c功能函数的实现: 

 SeqList顺序表的各个功能函数的实现:

基础功能:

初始化SeqList:

销毁SeqList:

打印SeqList:

扩容capacity:

增删查改功能:

尾插:

尾删:

头插:

头删:

在任意位置插入:

删除任意位置:

查找:

SeqList.h函数声明:

Test.c测试代码:


顺序表:

顺序表是在计算机内存中以数组的形式保存的线性表,线性表的顺序存储是指用一组地址连续的存储单元依次存储线性表中的各个元素、使得线性表中在逻辑结构上相邻的数据元素存储在相邻的物理存储单元中,即通过数据元素物理存储的相邻关系来反映数据元素之间逻辑上的相邻关系,采用顺序存储结构的线性表通常称为顺序表。顺序表是将表中的结点依次存放在计算机内存中一组地址连续的存储单元中。


顺序表结构: 

 顺序表本质上是一段连续存放的数据,类似于数组

 【数据结构】详解动态顺序表_第2张图片

 我们想想需要什么参数:

  • 首先是连续存放的数据,我们会想到数组,但是我们的个数不能改变,所以我们需要一个指针a指向malloc开辟一段连续的空间。
  • 然后当我们需要改变这个空间的大小,我们还需要一个变量来表示已有空间的大小capacity
  • 我们如何判断什么时候需要扩容呢?需要一个计算已有数据的个数变量size来判断等于已有空间的大小来决定是否扩容。

 我们这里有多个数据我们可以用结构体比较方便!

typedef int SLDataType;//将int型起个别名为SLDataType,这样方便更改类型
typedef struct SeqList
{
	SLDataType* a;//动态开辟的数组
	int size;//记录储存了多少个数据
	int capacity;//空间容量大小
	//多个数据就可以利用结构体
}SL;

我们在本篇实现的是动态顺序表。

功能为增删查改!

我们在SeqList.h文件中进行函数声明。

SeqList.c函数进行各个函数的实现。

Test.c函数进行函数的测试,以及最后的菜单编写。 


SeqLisht.c功能函数的实现: 

#include"SeqList.h"
void SeqListPrint(SL* s)
{//打印
	assert(s);
	for (int i = 0; i < s->size; i++)
	{
		printf("%d ", s->a[i]);
	}
	printf("\n");
}
void SeqListInit(SL* s)
{//初始化的实现
	assert(s);
	s->a = NULL;
	s->size = 0;
	s->capacity = 0;
}
void SeqListCherkCapacity(SL* s)
{
	assert(s);//扩容capacity
	if (s->capacity == s->size)
	{
		int Newcaoacity = s->capacity == 0 ? 4 : s->capacity * 2;
		SLDataType* tmp = (SLDataType*)realloc(s->a, Newcaoacity * sizeof(SLDataType));
		//realloc可能是返回一个新的地址,为异地扩容
		if (tmp == NULL)
		{
			perror("realloc faile");
			exit(-1);//可以提前结束程序,为异常结束
		}
		s->a = tmp;
		s->capacity = Newcaoacity;
	}
}
void SeqListDestroy(SL* s)
{//销毁SeqList
	assert(s);
	if (s->a)
	{
		free(s->a);
		s->a = NULL;
		s->capacity = 0; s->size = 0;
	}
}
void SeqListPushBack(SL* s, SLDataType x)
{//SeqList尾插
	//扩容
	assert(s);//
	/*SeqListCherkCapacity(s);
	s->a[s->size] = x;
	s->size++;*/
	SeqListInsert(s, s->size, x);
}
void SeqListPopBack(SL* s) {
	//SeqListw尾删
	//if (s->size == 0)
	//{//温柔的检查
	//	return;
	//}
	//assert(s->size>0);//暴力的检查
	//s->size--;
	SeqListErase(s, s->size - 1);
}
void SeqListPushFront(SL* s, SLDataType x)
{//头插
	assert(s);
	//SeqListCherkCapacity(s);
	//int end = s->size - 1;
	//while (end >= 0)
	//{
	//	s->a[end + 1] = s->a[end];
	//	end--;
	//}
	//s->a[0] = x;
	//s->size++;
	SeqListInsert(s, 0, x);
}
void SeqListPopFront(SL* s) {
	//头删
	assert(s);
	assert(s->size > 0);
	int begin = 0;
	while (begin < s->size - 1)
	{
		s->a[begin] = s->a[begin + 1];
		begin++;
	}
	s->size--;
	SeqListErase(s, 0);
}

void SeqListInsert(SL* s, int pos, SLDataType x)
{//任意位置插入
	assert(s);
	assert(pos >= 0 && pos <= s->size);
	SeqListCherkCapacity(s);
	int end = s->size - 1;
	while (end >= pos)
	{
		s->a[end + 1] = s->a[end];
		end--;
	}
	s->a[pos] = x;
	s->size++;
}

void SeqListErase(SL* s, int pos)
{//任意位置删除
	assert(s);
	assert(pos >= 0 && pos <= s->size);
	int begin = pos;
	while (begin <= s->size)
	{
		s->a[begin] = s->a[begin + 1];
		begin++;
	}
	s->size--;
}

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

 SeqList顺序表的各个功能函数的实现:

基础功能:

初始化SeqList:

void SeqListInit(SL* s)
{//初始化的实现
	assert(s);
	s->a = NULL;
	s->size = 0;
	s->capacity = 0;
}

销毁SeqList:

void SeqListDestroy(SL* s)
{//销毁SeqList
	assert(s);
	if (s->a)
	{
		free(s->a);
		s->a = NULL;
		s->capacity = 0; s->size = 0;
	}
}

打印SeqList:

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

扩容capacity:

void SeqListCherkCapacity(SL* s)
{
	assert(s);//扩容capacity
	if (s->capacity == s->size)
	{
		int Newcaoacity = s->capacity == 0 ? 4 : s->capacity * 2;
		SLDataType* tmp = (SLDataType*)realloc(s->a, Newcaoacity * sizeof(SLDataType));
		//realloc可能是返回一个新的地址,为异地扩容
		if (tmp == NULL)
		{
			perror("realloc faile");
			exit(-1);//可以提前结束程序,为异常结束
		}
		s->a = tmp;
		s->capacity = Newcaoacity;
	}
}

增删查改功能:

尾插:

void SeqListPushBack(SL* s, SLDataType x)
{//SeqList尾插
	//扩容
	assert(s);//
	SeqListCherkCapacity(s);
	s->a[s->size] = x;
	s->size++;
	/*SeqListInsert(s, s->size, x);*/
}

尾删:

void SeqListPopBack(SL* s) {
	//SeqListw尾删
	assert(s->size>0);//暴力的检查
	s->size--;
	/*SeqListErase(s, s->size - 1);*/
}

头插:

void SeqListPushFront(SL* s, SLDataType x)
{//头插
	assert(s);
	SeqListCherkCapacity(s);
	int end = s->size - 1;
	while (end >= 0)
	{
		s->a[end + 1] = s->a[end];
		end--;
	}
	s->a[0] = x;
	s->size++;
	/*SeqListInsert(s, 0, x);*/
}

头删:

void SeqListPopFront(SL* s) {
	//头删
	assert(s);
	assert(s->size > 0);
	int begin = 0;
	while (begin < s->size - 1)
	{
		s->a[begin] = s->a[begin + 1];
		begin++;
	}
	s->size--;
	//SeqListErase(s, 0);
}

在任意位置插入:

void SeqListInsert(SL* s, int pos, SLDataType x)
{//任意位置插入
	assert(s);
	assert(pos >= 0 && pos <= s->size);
	SeqListCherkCapacity(s);
	int end = s->size - 1;
	while (end >= pos)
	{
		s->a[end + 1] = s->a[end];
		end--;
	}
	s->a[pos] = x;
	s->size++;
}

删除任意位置:

void SeqListErase(SL* s, int pos)
{//任意位置删除
	assert(s);
	assert(pos >= 0 && pos <= s->size);
	int begin = pos;
	while (begin <= s->size)
	{
		s->a[begin] = s->a[begin + 1];
		begin++;
	}
	s->size--;
}

查找:

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

我们思考一个问题:

头删尾删的情况是不是包含在删除任意位置中?

头插尾插是不是包含在插入在任意位置?

YES。所以我们在头删和尾删中可以复用删除任意位置的函数!头插尾插也是!


SeqList.h函数声明:

#define _CRT_SECURE_NO_WARNINGS  1
#pragma once//防止多次包含
#include
#include
#include

//静态顺序表---不太实用
//#define N 10 //方便全局修改
//typedef int SLDataype;//将int型起个别名为SLDataType,这样方便更改类型
//typedef struct SeqList 
//{
//    SLDataype arr[N];
//	SLDataype size;//记录储存了多少个数据
//	//多个数据就可以利用结构体
//}SL;
//void SeqListInit(SL s);//初始化SeqList
//void SeqListBack(SL s, SLDataype x);//SeqList尾插

//动态顺序表---按需扩展空间
typedef int SLDataType;//将int型起个别名为SLDataType,这样方便更改类型
typedef struct SeqList
{
	SLDataType* a;//动态开辟的数组
	int size;//记录储存了多少个数据
	int capacity;//空间容量大小
	//多个数据就可以利用结构体
}SL;
void SeqListInit(SL* s);//初始化SeqList
void SeqListDestroy(SL* s);//销毁SeqList
void SeqListPrint(SL* s);//打印SeqList
void SeqListCherkCapacity(SL* s);//扩容capacity

//尾插尾删
void SeqListPushBack(SL* s, SLDataType x);//SeqList尾插
void SeqListPopBack(SL* s);//SeqListw尾删

//头插头删
void SeqListPushFront(SL* s, SLDataType x);//SeqList头插
void SeqListPopFront(SL* s);//SeqListw头删

//任意位置插入删除
void SeqListInsert(SL* s, int pos, SLDataType x);//任意位置插入
void SeqListErase(SL* s, int pos);//任意位置删除

int SeqListFind(SL* s, SLDataType x,int begin);//找到值的位置

Test.c测试代码:

#include"SeqList.h"
void TestSeqList1()
{
	SL sl;
	SeqListInit(&sl);//这里形参不能改变实参,所以我们要传递地址过去
    SeqListPushBack(&sl,1);
	SeqListPushBack(&sl, 2);
	SeqListPushBack(&sl, 3);
	SeqListPushBack(&sl, 4);
	SeqListPrint(&sl);

	SeqListPopBack(&sl);
	SeqListPrint(&sl);

	SeqListPushBack(&sl, 8);
	SeqListPrint(&sl);

	SeqListPopBack(&sl);
	SeqListPopBack(&sl);
	SeqListPopBack(&sl);
	SeqListPopBack(&sl);
	/*SeqListPopBack(&sl);*/
	SeqListPrint(&sl);
	SeqListPushBack(&sl, 1);

	SeqListDestroy(&sl);
}
void Test2()
{
	SL sl;
	SeqListInit(&sl);
	SeqListPushFront(&sl, 10);
	SeqListPushFront(&sl, 20); 
	SeqListPushFront(&sl, 30); 
	SeqListPushFront(&sl, 40);
	SeqListPrint(&sl);
	
	SeqListPopFront(&sl);
	SeqListPrint(&sl);
	SeqListInsert(&sl,2, 100);
	SeqListInsert(&sl, 2, 100);
	SeqListInsert(&sl, 0, 100);
	SeqListInsert(&sl, 6, 600);
	SeqListPrint(&sl);

	SeqListPushFront(&sl, 1000);
	SeqListPushBack(&sl, 110);
	SeqListPrint(&sl);

	SeqListErase(&sl, 2);
	SeqListErase(&sl, 0);
	SeqListPrint(&sl);

	int a=SeqListFind(&sl, 100,0);
	if (a != -1)
	{
		SeqListErase(&sl, a);
		SeqListPrint(&sl);
	}


	SeqListDestroy(&sl);
}
void menu()
{
	printf("***********************************************\n");
	printf("1、尾插数据 2、尾删数据\n");
	printf("3、头插数据 4、头删数据\n");
	printf("5、查找数据 6、打印数据 -1、退出\n");
	printf("***********************************************\n");
}
int main()
{
	//Test2();
	SL sl;
	SeqListInit(&sl);
	int option;
	int val;
	do 
	{
		menu();
		printf("请输入你需要的操作:");
		scanf("%d", &option);
		switch (option)
		{
		case 1:
			printf("请以此输入要插入的数值,以-1为结束标记:");
			scanf("%d", &val);
			while (val != -1)
			{
				SeqListPushBack(&sl, val);
				scanf("%d", &val);
			}
			break;
		case 2:
			SeqListPopBack(&sl);
			break;
		case 3:
			printf("请以此输入要插入的数值,以-1为结束标记:");
			scanf("%d", &val);
			while (val != -1)
			{
				SeqListPushFront(&sl, val);
				scanf("%d", &val);
			}
			break;
		case 4:
			SeqListPopFront(&sl);
			break;
		case 5:
			printf("请以此输入要查找的数值,以-1为结束标记:");
			scanf("%d", &val);
			int p=0;
			while (p

你可能感兴趣的:(数据结构,数据结构,c语言)