C语言--实现顺序表的基本操作

一、预备知识(先说到这么多,具体问题和所需的内容在后面的编程中再说)

1、开发环境和开发语言:
环境:visual studio 2019
语言:C
2、形参的生命周期(一定要明白形参的生存周期,特别、特别、特别的重要,许多分析问题的时候都会用到这个东西):
形参会在调用函数时,开辟内存空间,在调用函数并且函数执行结束后会自动收回开辟的内存空间,不管开辟的形参是普通变量(值传递)还是指针变量(地址传递)都会被收回。即被 “释放”。
3、函数参数的传递:

值传递:即将实参(普通变量或常量)做一份备份赋值给形参(普通变量)。

地址传递:同样也是将实参(指针或指针变量)做一份备份赋值给形参(指针变量),但区别的是此时实参和形参都是指向同一空间的。

引用传递:引用传递是C++新增加的参数传递方式,在本实验中不会使用,但是要特别注意许多书籍中都有使用引用传递.而在我们使用c语言编程(特别是源文件的后缀名是“.c”)的时候使用引用传递的时候是会报错的(不知道其他IDE会不会,但visual studio2019肯定会),因为c语言是没有引用传递的。所以此处要特别注意。而引用传递就是在形参的前面加上&符号,标识该形参是实参(实参必须是变量不能是常量,只能给变量取别名,不能给常量取别名)的引用(或别名),此时调用函数时就会给实参取上名为形参的别名。

二、准备工作

1、先创建好工程项目,源文件的后缀名可以为C也可以为C++
工程框架图
2、数据结构准备和常用信息的定义

//引入相关头文件
#include<stdio.h>
#include<stdlib.h>
#include<malloc.h>
//定义常用的宏常量
#define OVERFLOW -1
#define OK 1
#define ERROR 0
//空间初始分配量,为了检验空间扩展,初值取小一点
#define MAXSIZE 6
//空间分配增量
#define INCREMENT 10

//定义相关的新数据类型
typedef int Status;//
typedef int ElemType;
//定义用于存放线性表的数据结构体
typedef struct {
	ElemType* elem;//用于存放空间基地址
	int length;//当前顺序表中实际元素的个数
	int listsize;//当前所分配的存储容量
}SqList;

3、方法清单:

//初始化顺序表的方法
Status InitList01(SqList *L)

//将新元素e插入到顺序表L的第i个位置上
//方法的三个参数,顺序表的地址,插入的位置,插入的元素
Status InsertList(SqList *L,int i, ElemType e)

//查找数据元素,返回该元素的下标
int SearchList(SqList L, ElemType e)

//删除顺序表中指定的元素出现第一次的值
//删除成功返回元素出现的位置,否则返回-1
int Del_List1(SqList L, ElemType e) 

//删除顺序表中的第i个元素,被删除的元素用e带回
Status Del_list2(SqList L, int i, ElemType* e) 

//打印顺序表中的元素
void PrintList(SqList* L)

三、方法实现

一、初始化方法:主要实现对传递过来的顺续表进行初始化,

方法功能:
1、开辟数组空间,
2、初始当前顺序表长度
3、初始顺序的容量

Status InitList01(SqList *L){ 
	L->elem = (ElemType *)malloc(MAXSIZE * sizeof(ElemType));
	if (L->elem == NULL) exit(OVERFLOW);
	//设置数组中的数据为0个元素
	L->length = 0;
	//设置数组的长度,由于上面开辟的空间共MAXSIZE个故而,此处的值也该为MAXSIZE个
	L->listsize = MAXSIZE;
	return OK;
}

二、插入方法:将新元素e插入到顺序表L的第i个位置上

方法功能:
1、检测用户输入的i值是否合法,
2、当数组中的元素已经满了,需要重新开辟新空间,并将原来数组中的内容复制到新数组中(这也是顺序表的一大弊端,当空间不够时需要重新开辟空间,并将原来的内容复制到新数组中,大大增加了了运行时间)
3、移动元素使i之后的元数全部后移一位(顺序表的另一弊端需要移动元素,增大开销)
4、将元素插入到i所指的空间,并修改length的值
知识点:这个方法中用到了realloc函数,该函数有两个参数,第一个参数:原来的地址(基地址),第二个参数:要开辟多大的空间

//将新元素e插入到顺序表L的第i个位置上
//方法的三个参数,顺序表的地址,插入的位置,插入的元素
Status InsertList(SqList *L,int i, ElemType e) {
	//检测用户输入的数据是否合法
	if (i<1 || i>L->length + 1)
		return ERROR;
	//用于暂存数组的新地址
	ElemType* p=NULL;
	//控制数组下标
	int j;
	//判断顺序表是否已满,若满,需要重新分配空间,并更新相关的数据项
	if (L->length >= L->listsize) {
		p = (ElemType*)realloc(L->elem, 
			(L->listsize + INCREMENT) * sizeof(ElemType));
		if (p == NULL) 
			exit(OVERFLOW);
		L->elem = p;
		L->listsize += INCREMENT;
	}
	//插入数据
	//1、移动数据元素
	for (j = L->length - 1; j >= i - 1; j--)
		L->elem[j + 1] = L->elem[j];
	//2、插入新元素
	L->elem[j + 1] = e;
	//3、修改length的值

	L->length++;
	return OK;
}

查找元素,并返回其下标

方法功能:通过将e和数组元素依次对比,若找到则返回该数组元素的下标,否则返回-1,表示没有找到

//查找数据元素,返回该元素的下标
int SearchList(SqList L, ElemType e) {
	int i;
	for (i = 0; i < L.length; i++)
		if (L.elem[i] == e)
			return ++i;
	return -1;
}

删除方法一:删除顺序表中指定的元素e在数组中第一次出现的元素

方法功能:
1、移动下标i使之指到元素和e相同的元素
2、删除元素,将该元素后面的全部元素向向前移动一位即可实现对该元素的删除,最后修改length的值

//删除顺序表中指定的元素出现第一次的值
//删除成功返回元素出现的位置,否则返回-1
int Del_List1(SqList L, ElemType e) {
	int i, j;
	for (i = 0; i < L.length; i++)
		if (L.elem[i] == e)
			break;
	if (i < L.length) {
		for (j = i; j < L.length; j++)
			L.elem[j] = L.elem[j + 1];
		L.length--;
		return ++i;
	}
	return -1;
}

删除方法二;删除顺序表中的第i个位置元素,并由e带回该元素

方法功能:
1、判断用户输入的数据是否合法,即是否大于数组的最大下标或者小于数组的最小下标
2、将下标i的内容赋值给*e
2、将i之后的元素全部向前移动一个位置,最后修改length的值

//删除顺序表中的第i个元素,被删除的元素用e带回
Status Del_list2(SqList L, int i, ElemType* e) {
	if (i<1 || i>L.length)
		return ERROR;
	int j;
	*e = L.elem[i - 1];
	for (j = i; j < L.length; j++) 
		L.elem[j - 1] = L.elem[j];
	L.length--;
	return OK;
}

打印顺序表

方法功能:实现顺序的输出

//打印顺序表中的元素
void PrintList(SqList* L) {
	int i;
	if (L->length == 0)
		printf("当前的顺序表为空表\n");
	printf("当前顺序的状态如下:\n");
	for (i = 0; i < L->length; i++)
		printf("%d ", L->elem[i]);
	printf("\n");
}

四、测试代码和测试结果

在测试这里我多bb两句:你可以将每个功能的测试写成一个函数,然后在主函数中调用测试即可,这种方式更直观也更便于调试。也可以直接在主函数种直接写测试代码,但维护就测试就比较麻烦一点,还需要理清方法之间的先后顺序等等。。。但可以偷懒

测试初始化方法;

 	SqList L;
	int i;
	int j = 1;
	int e;
	//测试初始化
	i = InitList01(&L);
	if ( i==OK)
		printf("初始化成功\n");
	else
		printf("初始化失败\n");

测试结果:
测试初始化结果

测试插入方法:

当输入-1时候表示插入完成,并退出插入,每插入一个数据后都会打印当前顺序表的状态

//测试插入功能
	while (1)
	{
		printf("请输入一个数据进行插入;");
		scanf_s("%d", &e);
		if (e == -1)
			break;
		i = InsertList(&L, j, e);
		if (i == OK)
			printf("插入成功\n");
		else
			printf("插入失败\n");
		j++;
		PrintList(&L);
	}

测试结果
插入的测试结果

测试查询功能和删除功能

//测试查找功能
	int result;
	printf("请输入一个数据进行查找;");
	scanf_s("%d", &e);
	printf("查询的结果:%d\n", SearchList(L, e));
	//测试删除功能并返回指定元素
	while (1)
	{
		printf("请输入一个数据进行删除;");
		scanf_s("%d", &e);
		if (e == -1)
			break;
		i = Del_List1(L, e);
		if (i != -1) {
			printf("删除成功\n");
			printf("删除元素的位置是:%d\n", i);
		}
		else
			printf("删除失败\n");
		j++;
		PrintList(&L);
	}
	//测试删除功能删除指定位置的元素,并返回该位置的元素
	while (1) {
		printf("请输入一个索引删除:");
		scanf_s("%d", &j);
		if (j == -1)
			break;
		i = Del_list2(L, j, &e);
		if (i == OK) {
			printf("删除成功\n");
			printf("被删除的元素是:%d\n", e);
		}
		else
			printf("删除失败\n");
		
	}

测试结果
查询功能和删除功能的测试结果

小小的总结

今天的内容就是上面的内容。由于水平有限还有许多不足的地方还请谅解(轻点喷。。。),当然有错误的地方或者更优秀的算法可以一起讨论(等你哦。。。亲)。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值