数据结构(C描述)——顺序表的功能实现(全)

顺序表的定义&缘由

由于我们在使用数组的时候,由于C语言语法的局限性,我们不得不提前对数组的元素个数进行规定
但是很多时候我们对数据个数的估计都是存在偏差的,估计少了会造成数组的越界,估计多了会造成内存的浪费,于是我们采用结构体+指针的方法实现一个可以自己动态开辟空间的数组,并且可以实现一定的“增删查改排…”等功能,我们称之为“顺序表”

头文件SeqList.h的书写

常用函数的预定义

#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
typedef int SLDateType;

由于我使用的是vs2022的编译器,为了防止编译器在scanf上面进行报警告,于是加上第一行代码,下面的两个include代码是包含我们常用到的函数
同时为了方便修改顺序表中的数据类型,利用typedef对int类型进行重命名

顺序表结构体的书写

typedef struct Seqlist
{
	SLDateType* a;
	int size;//表示数组中存储了多少个有效数据
	int capacity;//表示数组的实际能存空间的数据容量是多大
}SL;

同时对结构体的名字进行typedef,这样可以减少代码书写时候的长度和复杂度

完成头文件中的接口函数的书写

ps:所谓接口函数,就是在头文件中进行定义的函数,用来表示我们的顺序表中需要实现的功能

void SeqListInit(SL* ps);//顺序表的初始化
void SeqListDestory(SL* ps);//顺序表的内存释放
void SeqListCheckCapacity(SL* ps);//顺序表的检测空间是否足够
void SeqListPushBcak(SL* ps, SLDateType x);//顺序表的尾插
void SeqListPopBcak(SL* ps);//顺序表的尾删
void SeqListPushFront(SL* ps, SLDateType x);//顺序表的头插
void SeqListPopFront(SL* ps);//顺序表的头删
int SeqListFind(SL* ps, SLDateType x);//顺序表的查找功能
void SeqListInsert(SL* ps, int pos, SLDateType x);//顺序表在表内插入功能
void SeqListErase(SL* ps, int pos);//顺序表在表内删除功能
void SeqListCheck(SL* ps);//顺序表的去重功能
void SeqListSort(SL* ps);//顺序表的排序功能

具体函数的功能我都在代码块中进行注释了

SeqList.cpp/c文件的书写

在这个文件中,我们需要实现上面的每个接口函数

顺序表的初始化

void SeqListInit(SL* ps)
{
	ps->a = NULL;
	ps->size = 0;
	ps->capacity = 0;
}

顺序表的内存销毁

void SeqListDestory(SL* ps)
{
	free(ps->a);
	ps->a = NULL;
	ps->size = 0;
	ps->capacity = 0;
}

顺序表的检查是否需要扩容

void SeqListCheckCapacity(SL* ps)
{
	//如果没有空间或者空间不足我们就扩容
	if (ps->size == ps->capacity)
	{
		int newcapacity = ps->capacity == 0 ? 4 : ps->capacity * 2;
		SLDateType* tmp = (SLDateType*)realloc(ps->a, newcapacity * sizeof(SLDateType));
		if (tmp == NULL)
		{
			printf("realloc fail\n");
			exit(-1);//在函数内部结束程序不能用return而要用exit(-1)
		}
		ps->a = tmp;
		ps->capacity = newcapacity;
	}
}

顺序表的尾插数据

void SeqListPushBcak(SL* ps, SLDateType x)//尾插数据
{
	SeqListCheckCapacity(ps);
	ps->a[ps->size] = x;
	ps->size++;
}

顺序表的尾删数据

void SeqListPopBcak(SL* ps)
{
	//ps->a[ps->size - 1] = 0; //这一句可要可不要
	//要注意size不可以小于0,即顺序表为空后不可以再继续--
	if(ps->size > 0)
	{
		ps->size--;//size标识我们存了多少个有效数据,只要让size--那么有意义的数字就会减少一个
	}

}

顺序表的头插数据

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

顺序表的头删数据

void SeqListPopFront(SL* ps)
{
	//ps->size--;  //如果仅仅让size--,那么代表尾删
	assert(ps->size > 0);
	int begin = 1;
	while (begin < ps->size)
	{
		ps->a[begin - 1] = ps->a[begin];
		begin++;
	}
	ps->size--;
}

顺序表的查找功能

int SeqListFind(SL* ps, SLDateType x)
{
	int i = 0;
	for (i = 0;i < ps->size;i++)
	{
		if (ps->a[i] == x)
		{
			return i;
		}
	}
	return -1;
}

顺序表的指定位置插入功能

void SeqListInsert(SL* ps, int pos, SLDateType x)
{
	printf("请输入需要插入的下标:>");
	scanf("%d", &pos);
	if (pos > ps->size - 1)
	{
		printf("需要插入的下标不存在\n");
	}
	else
	{
		int i = 0;
		int tmp = 0;
		SeqListCheckCapacity(ps);
		printf("请输入需要插入的元素为:>");
		scanf("%d", &x);
		for (i = ps->size-1;i >= pos;i--)
		{
			ps->a[i + 1] = ps->a[i];
			
		}
		ps->a[pos] = x;
		ps->size++;
	}
}

顺序表的指定位置删除功能

void SeqListErase(SL* ps, int pos)
{
	printf("请输入需要删除的下标:>");
	scanf("%d", &pos);
	if (pos > ps->size - 1)
	{
		printf("需要删除的下标不存在\n");//default子句的定义
	}
	else
	{
		int i = 0;
		int tmp = 0;
		for (i = pos;i < ps->size;i++)
		{
			ps->a[i] = ps->a[i + 1];//用后一个的数据覆盖前一个来实现删除
		}
		ps->size--;
	}
}

顺序表的查重功能

void SeqListCheck(SL* ps)//这里采用的方法是如果遇到相同的数据,就把数组往前面挪,用来覆盖数据
{
	int i = 0;
	int j = 0;
	int k = 0;
	for (i = 0;i < ps->size - 1;i++)
	{
		for (j = i + 1;j < ps->size;j++)
		{
			if (ps->a[i] == ps->a[j])
			{
				for (k = j;k < ps->size - 1;k++)
				{
					ps->a[k] = ps->a[k + 1];
				}
				ps->size--;//数组的元素个数减少
				j--;//从j+1后面的位置一直依次向钱挪 j位置被换了新值,所以--j还要再次看
			}
		}
	}
}

顺序表的排序功能

void SeqListSort(SL* ps)//这里采用的是冒泡排序的方法
{
	int i = 0;
	int j = 0;
	for (i = 0;i < ps->size;i++)
	{
		for (j = 0;j < ps->size - 1 - i;j++)
		{
			if (ps->a[j] > ps->a[j + 1])
			{
				int tmp = 0;
				tmp = ps->a[j];
				ps->a[j] = ps->a[j + 1];
				ps->a[j + 1] = tmp;
			}
		}
	}
}

main函数的书写

菜单的书写

void menu()
{
	printf("********************\n");
	printf("********************\n");
	printf("1、头插****2、头删***\n");
	printf("3、尾插****4、尾删***\n");
	printf("5、中插****6、中删***\n");
	printf("7、查找****8、展示***\n");
	printf("9、去重***10、排序***\n");
	printf("******0、退出*******\n");
	printf("********************\n");
	printf("********************\n");
	printf("*******请选择你的操作:>");
}

switch语句main函数

int main()
{
	int input = 0;
	SL sl;
	SeqListInit(&sl);
	int i = 0;
	//menu();
	//TestSeqList1();
	//TestSeqList2();
	//TestSeqList3();
	do
	{
		menu();
		scanf("%d", &input);
		switch (input)
		{
		case 1:
		{
			printf("请输入需要插入的数据:>");
			scanf("%d", &i);
			SeqListPushFront(&sl, i);
			break;
		}
		case 2:
		{
			SeqListPopFront(&sl);
			break;
		}
		case 3:
		{
			printf("请输入需要插入的数据:>");
			scanf("%d", &i);
			SeqListPushBcak(&sl, i);
			break;
		}
		case 4:
		{
			SeqListPopBcak(&sl);
			break;
		}
		case 5:
		{
			int x = 0;
			int y = 0;
			SeqListInsert(&sl, x, y);
			break;
		}
		case 6:
		{
			SeqListErase(&sl, i);
			break;
		}
		case 7:
		{
			printf("请输入需要查找的元素:>");
			scanf("%d", &i);
			printf("\n");
			int ans = SeqListFind(&sl, i);
			printf("该元素的下标为%d\n", ans);
			break;
		}
		case 8:
		{
			SeqListPrint(&sl);
			break;
		}
		case 9:
		{
			SeqListCheck(&sl);
			SeqListPrint(&sl);
			break;
		}
		case 10:
		{
			SeqListSort(&sl);
			SeqListPrint(&sl);
			break;
		}
		default:
		{
			printf("输入错误,请重新输入\n");
			break;
		}
		
		}

	} while (input);
	SeqListDestory(&sl);
	return 0;
}

最后完整的代码

SeqList.h文件

#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
typedef int SLDateType;
typedef struct Seqlist
{
	SLDateType* a;
	int size;//表示数组中存储了多少个有效数据
	int capacity;//表示数组的实际能存空间的数据容量是多大
}SL;

void SeqListPrint(SL* ps);

//接口函数
void SeqListInit(SL* ps);
void SeqListDestory(SL* ps);
void SeqListCheckCapacity(SL* ps);
void SeqListPushBcak(SL* ps, SLDateType x);
void SeqListPopBcak(SL* ps);
void SeqListPushFront(SL* ps, SLDateType x);
void SeqListPopFront(SL* ps);
//...

//如果找到了就返回x位置的下标,没有找到就返回-1
int SeqListFind(SL* ps, SLDateType x);

//在顺序表指定的下标位置插入
void SeqListInsert(SL* ps, int pos, SLDateType x);

//删除pos位置的数据
void SeqListErase(SL* ps, int pos);

//除去重复的数据
void SeqListCheck(SL* ps);

//排序顺序表中的数据
void SeqListSort(SL* ps);

SeqList.cpp文件的书写

#include "SeqList.h"

void SeqListInit(SL* ps)
{
	ps->a = NULL;
	ps->size = 0;
	ps->capacity = 0;
}

void SeqListDestory(SL* ps)
{
	free(ps->a);
	ps->a = NULL;
	ps->size = 0;
	ps->capacity = 0;
}

void SeqListCheckCapacity(SL* ps)
{
	//如果没有空间或者空间不足我们就扩容
	if (ps->size == ps->capacity)
	{
		int newcapacity = ps->capacity == 0 ? 4 : ps->capacity * 2;
		SLDateType* tmp = (SLDateType*)realloc(ps->a, newcapacity * sizeof(SLDateType));
		if (tmp == NULL)
		{
			printf("realloc fail\n");
			exit(-1);//在函数内部结束程序不能用return而要用exit(-1)
		}
		ps->a = tmp;
		ps->capacity = newcapacity;
	}
}

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

void SeqListPushBcak(SL* ps, SLDateType x)//尾插数据
{
	SeqListCheckCapacity(ps);
	ps->a[ps->size] = x;
	ps->size++;
}

void SeqListPopBcak(SL* ps)
{
	//ps->a[ps->size - 1] = 0; //这一句可要可不要
	//要注意size不可以小于0,即顺序表为空后不可以再继续--
	if(ps->size > 0)
	{
		ps->size--;//size标识我们存了多少个有效数据,只要让size--那么有意义的数字就会减少一个
	}

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

void SeqListPopFront(SL* ps)
{
	//ps->size--;  //如果仅仅让size--,那么代表尾删
	assert(ps->size > 0);
	int begin = 1;
	while (begin < ps->size)
	{
		ps->a[begin - 1] = ps->a[begin];
		begin++;
	}
	ps->size--;
}

int SeqListFind(SL* ps, SLDateType x)
{
	int i = 0;
	for (i = 0;i < ps->size;i++)
	{
		if (ps->a[i] == x)
		{
			return i;
		}
	}
	return -1;
}

void SeqListInsert(SL* ps, int pos, SLDateType x)
{
	printf("请输入需要插入的下标:>");
	scanf("%d", &pos);
	if (pos > ps->size - 1)
	{
		printf("需要插入的下标不存在\n");
	}
	else
	{
		int i = 0;
		int tmp = 0;
		SeqListCheckCapacity(ps);
		printf("请输入需要插入的元素为:>");
		scanf("%d", &x);
		for (i = ps->size-1;i >= pos;i--)
		{
			ps->a[i + 1] = ps->a[i];
			
		}
		ps->a[pos] = x;
		ps->size++;
	}
}

void SeqListErase(SL* ps, int pos)
{
	printf("请输入需要删除的下标:>");
	scanf("%d", &pos);
	if (pos > ps->size - 1)
	{
		printf("需要删除的下标不存在\n");
	}
	else
	{
		int i = 0;
		int tmp = 0;
		for (i = pos;i < ps->size;i++)
		{
			ps->a[i] = ps->a[i + 1];
		}
		ps->size--;
	}
}

void SeqListCheck(SL* ps)
{
	int i = 0;
	int j = 0;
	int k = 0;
	for (i = 0;i < ps->size - 1;i++)
	{
		for (j = i + 1;j < ps->size;j++)
		{
			if (ps->a[i] == ps->a[j])
			{
				for (k = j;k < ps->size - 1;k++)
				{
					ps->a[k] = ps->a[k + 1];
				}
				ps->size--;
				j--;//从j+1后面的位置一直依次向钱挪 j位置被换了新值,所以--j还要再次看
			}
		}
	}
}

void SeqListSort(SL* ps)
{
	int i = 0;
	int j = 0;
	for (i = 0;i < ps->size;i++)
	{
		for (j = 0;j < ps->size - 1 - i;j++)
		{
			if (ps->a[j] > ps->a[j + 1])
			{
				int tmp = 0;
				tmp = ps->a[j];
				ps->a[j] = ps->a[j + 1];
				ps->a[j + 1] = tmp;
			}
		}
	}
}

main.c文件的书写

//写一个类似通讯录的菜单
void menu()
{
	printf("********************\n");
	printf("********************\n");
	printf("1、头插****2、头删***\n");
	printf("3、尾插****4、尾删***\n");
	printf("5、中插****6、中删***\n");
	printf("7、查找****8、展示***\n");
	printf("9、去重***10、排序***\n");
	printf("******0、退出*******\n");
	printf("********************\n");
	printf("********************\n");
	printf("*******请选择你的操作:>");
}


int main()
{
	int input = 0;
	SL sl;
	SeqListInit(&sl);
	int i = 0;
	//menu();
	//TestSeqList1();
	//TestSeqList2();
	//TestSeqList3();
	do
	{
		menu();
		scanf("%d", &input);
		switch (input)
		{
		case 1:
		{
			printf("请输入需要插入的数据:>");
			scanf("%d", &i);
			SeqListPushFront(&sl, i);
			break;
		}
		case 2:
		{
			SeqListPopFront(&sl);
			break;
		}
		case 3:
		{
			printf("请输入需要插入的数据:>");
			scanf("%d", &i);
			SeqListPushBcak(&sl, i);
			break;
		}
		case 4:
		{
			SeqListPopBcak(&sl);
			break;
		}
		case 5:
		{
			int x = 0;
			int y = 0;
			SeqListInsert(&sl, x, y);
			break;
		}
		case 6:
		{
			SeqListErase(&sl, i);
			break;
		}
		case 7:
		{
			printf("请输入需要查找的元素:>");
			scanf("%d", &i);
			printf("\n");
			int ans = SeqListFind(&sl, i);
			printf("该元素的下标为%d\n", ans);
			break;
		}
		case 8:
		{
			SeqListPrint(&sl);
			break;
		}
		case 9:
		{
			SeqListCheck(&sl);
			SeqListPrint(&sl);
			break;
		}
		case 10:
		{
			SeqListSort(&sl);
			SeqListPrint(&sl);
			break;
		}
		default:
		{
			printf("输入错误,请重新输入\n");
			break;
		}
		
		}

	} while (input);
	SeqListDestory(&sl);
	return 0;
}

本文有少许内容参考网上的其他代码

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值