一、预备知识(先说到这么多,具体问题和所需的内容在后面的编程中再说)
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");
}
测试结果
小小的总结
今天的内容就是上面的内容。由于水平有限还有许多不足的地方还请谅解(轻点喷。。。),当然有错误的地方或者更优秀的算法可以一起讨论(等你哦。。。亲)。