(1)实验内容
编程实现顺序表下教材第二章定义的线性表的基本操作,并根据已经实现的基本操作,实现两个非递减有序的线性表的合并,注意,合并时,如果有重复的元素,请保留一个。
(2)实验要求
(a)求前驱是指,输入一个元素值(而不是位置),求该元素在顺序表中的直接前驱元素值。求后继是指:输入一个元素值(而不是位置),求该元素在顺序表中的直接后继元素值;
(b)为了方便修改数据元素的类型,请使用类型重定义,可以方便修改线性表中的数据元素的类型;
(c)大部分函数的返回结果应是函数执行是否成功的一种状态,执行成功了,才返回具体的结果值;
(d)对每个功能进行测试时,要求把不合法的情况也测试一下。具体见下面的测试用例;
(e)采用菜单形式对应各个操作,使其编成一个完整的小软件,参考界面如下。
注:销毁是指free(L.elem); L.elem=NULL; L.length=0; L.listsize=0; return TRUE。
清空是指:L.length=0 ;return TRUE。
(3)设计思想
顺序表是用一段物理地址连续的存储单元依次存储数据元素的线性结构,一般情况下采用数组存储。在数组上完成数据的增删查改。
(4)验收/测试用例
通过菜单调用各个操作,测试点:
- 没有初始化前进行其他操作,程序是否能控制住;即,如果没有初始化线性表,其他的功能是无法正常进行的,如果选择进行其他操作,要提示先进行初始化;
- 初始化一个顺序表
- 插入数据(位置, 数据),要测插入位置不合法的情况(0,1)、(2,1),正确插入3个数据(1,20)、(1,10)、(3,30);
- 显示顺序表中的数据,屏幕输出10, 20, 30;
- 判空,屏幕输出顺序表非空;
- 输出顺序表长度,屏幕输出3;
- 获取指定位置元素,要测指定位置在【1,3】范围之外的情况和之内的情况;
- 定位,输入:40, 输出:不存在,输入20,输出位置为2;
- 求直接前驱,要测求第一个元素的前驱、不存在顺序表中的元素的直接前驱,其他元素的直接前驱;输入10,输出:第一个元素没有前驱,输入20,输出前驱是10,输入40,输出该元素不存在;
- 求直接后继,要测最后一个元素的后继、不存在顺序表中的元素的直接后继,其他元素的直接后继;同上求前驱;
- 删除,要测位置在【1,3】范围之外的情况和之内的情况;
- 清空操作后再测长度,判断是否为空;
- 销毁顺序表,销毁线性表之后还能不能做插入,删除等操作,如果选其他操作,就要提示线性表已经销毁不存在;
- 测试合并操作,第一个线性表中的元素是(2,3,4,5),第二个线性表中的内容是(1,4,5,6,7),合并后的结果,请输出。
(5)代码实现
0.定义一个顺序表
typedef struct sqlist
{
int length;//线性表中当前元素的数量
int listsize;//线性表的存储空间大小
elemtype* data;
int is_initialized; // 线性表是否已初始化的标志
}sqlist;
1.初始化一个线性表
void InitList(sqlist* list)
{
if (list->is_initialized) { // 检查线性表是否已初始化
printf("线性表已经存在,不能重复初始化\n");
return;
}
printf("请输入线性表的长度:\n");
scanf("%d", &list->length);
list->listsize = list->length;
list->data = (elemtype*)malloc(list->length * sizeof(elemtype));
printf("请依次输入线性表中的元素:\n");
for (int i = 0; i < list->length; i++)
{
scanf("%d", &list->data[i]);
}
list->is_initialized = 1; // 初始化完成后,设置线性表已初始化的标志
printf("初始化完成\n");
}
函数最开始检线性表是否已经进行初始化,如果 is_initialized 值等于1,那么执行 if 语句中 return 跳出 case 1。通过malloc函数为data动态分配空间。初始化完成后将is_initialized 值等于1。
2.销毁线性表
void DestoryList(sqlist* list)
{
if (!list->is_initialized) { // 检查线性表是否已初始化
printf("线性表为空,请先创建一个线性表!\n");
return;
}
assert(list);
free(list->data);
list->data = NULL;
list->length = 0;
list->listsize = 0;
list->is_initialized = 0; // 销毁完成后,设置线性表未初始化的标志
printf("线性表已销毁\n");
}
通过if函数首先判断线性表是不是已经完成初始化,随后assert来判断传递过来的表是否为空,free释放list->data所占用的空间,将指针置为空,顺序表长度和判断标志等于0。
3.清空线性表
void ClearList(sqlist* list)
{
if (!list->is_initialized) { // 检查线性表是否已初始化
printf("线性表为空,请先创建一个线性表!\n");
return;
}
assert(list);
list->length = 0;
printf("线性表已清空\n");
}
与销毁线性表不同,清空线性表只是将记录长度的变量置为零,然后传入新的值进行覆盖。
4.判断线性表是否为空
int ListEmpty(sqlist* list)
{
if (!list->is_initialized)
{ // 检查线性表是否已初始化
return 1;
}
if (list->length == 0)//如果长度为0,那么线性表便为空
return 1;
else
return 0;
}
通过观察线性表记录元素的变量是否为0,观察线性表是否为空
5.求线性表长度
void ListLength(const sqlist* list)
{
if (!list->is_initialized)
{ // 检查线性表是否已初始化
printf("线性表未初始化,线性表为空\n");
return;
}
printf("线性表长度为:%d\n", list->length);
}
通过观察线性表记录元素的变量的大小,得到线性表的长度。
6.获取线性表中指定位置的元素
void PositionElem(const sqlist* list)//6
{
if (!list->is_initialized) { // 检查线性表是否已初始化
printf("线性表为空,请先创建一个线性表!\n");
return ;
}
int pos;
printf("请输入位置:\n");
scanf("%d", &pos);
if (pos<1 || pos>list->length)
printf("该元素不存在\n");
else
{
printf("位置%d的元素为:%d\n", pos, list->data[pos - 1]);
}
}
首先设定输入数字大小的范围。如果越界,提示错误。然后输出对应元素。
7.获取线性表中元素的位置
void ElemPosition(const sqlist* list)//7
{
if (!list->is_initialized)
{ // 检查线性表是否已初始化
printf("线性表为空,请先创建一个线性表!\n");
return;
}
printf("请输入要查询的元素:\n");
elemtype elem = 0;
scanf("%d", &elem);
int i = 0;
int flag = 0;
for (i = 0; i < list->length; i++)
{
if (list->data[i] == elem)
{
flag = 1;
printf("元素的位置为:%d\n", i + 1);//返回该元素在线性表中的位置
}
}
if (flag == 0)
{
printf("您所查询的元素在线性表中不存在,请重新输入!\n");
}
}
将输入元素在线性表中进行遍历,如果找到相等的值,便输出 i+1,如果没有找到,便提示错误
8.求前驱
void PositionElemBefore(const sqlist* list)//8
{
if (!list->is_initialized) { // 检查线性表是否已初始化
printf("线性表为空,请先创建一个线性表!\n");
return;
}
printf("请输入位置:\n");
int pos = 0;
scanf("%d", &pos);
if (pos<1 || pos>list->length)
printf("该元素不存在\n");
else if (pos == 1)
printf("该元素不存在直接前驱\n");
else
printf("位置%d的元素的前驱为:%d\n", pos,list->data[pos - 2]);
}
9.求后继
void PositionElemAfter(const sqlist* list)//9
{
if (!list->is_initialized) { // 检查线性表是否已初始化
printf("线性表为空,请先创建一个线性表!\n");
return;
}
int pos = 0;
printf("请输入位置:\n");
scanf("%d", &pos);
if (pos<1 || pos>list->length)
printf("该元素不存在\n");
else if (pos== list->length)
printf("该元素没有后继节点\n");
else
printf("位置%d的元素的后继为:%d\n", pos, list->data[pos]);
}
10.在线性表指定位置插入元素
void InsertElem(sqlist* list, int pos, elemtype elem)//10
{
assert(list);
if (pos < 1 || pos > list->length + 1)
{
printf("插入位置无效\n");
return;
}
if (list->length >= list->listsize)
{
list->listsize *= 2;
list->data = (elemtype*)realloc(list->data, list->listsize * sizeof(elemtype));
}
for (int i = list->length; i >= pos; i--)
{
list->data[i] = list->data[i - 1];
}
list->data[pos - 1] = elem;
list->length++;
printf("插入完成\n");
}
首先判断插入位置是否合理,然后在插入元素时检查线性表是否已满,如果已满,则将线性表的容量扩大一倍,并重新分配内存空间,然后使用循环将要插入位置的元素一一往后移动一个单位,然后插入元素,最后长度变量加一。
PS.realloc函数用法:
语法:指针名=(数据类型*)realloc(要改变内存大小的指针名,新的大小)。
11.删除线性表指定位置的元素
void DeleteElem(sqlist* list, int pos) // 11
{
assert(list);
if (pos < 1 || pos > list->length)
{
printf("删除位置无效\n");
return;
}
for (int i = pos; i < list->length; i++)
{
list->data[i - 1] = list->data[i];
}
list->length--;
printf("删除完成\n");
}
类似插入元素
12.显示线性表
void DisplayList(const sqlist* list) // 12
{
if (!list->is_initialized) { // 检查线性表是否已初始化
printf("线性表为空,请先创建一个线性表!\n");
return;
}
assert(list);
for (int i = 0; i < list->length; i++)
{
printf("%d ", list->data[i]);
}
printf("\n");
}
13.合并两个非递减排有序的线性表
void MergeList(sqlist* list1, sqlist* list2, sqlist* result) // 13
{
if (!list1->is_initialized || !list2->is_initialized) { // 检查线性表是否已初始化
printf("线性表仍为空,请先选择指令一来创建一个线性表!\n");
return;
}
assert(list1);
assert(list2);
assert(result);
if (result->is_initialized) { // 检查result是否已初始化
free(result->data);
}
result->length = list1->length + list2->length;
result->listsize = result->length;
result->data = (elemtype*)malloc(result->length * sizeof(elemtype));
result->is_initialized = 1; // 设置result已初始化的标志
int i = 0, j = 0, k = 0;
while (i < list1->length && j < list2->length)
{
if (list1->data[i] < list2->data[j])
{
result->data[k++] = list1->data[i++];
}
else if (list1->data[i] > list2->data[j])
{
result->data[k++] = list2->data[j++];
}
else
{
result->data[k++] = list1->data[i++];
j++;
}
}
while (i < list1->length)
{
result->data[k++] = list1->data[i++];
}
while (j < list2->length)
{
result->data[k++] = list2->data[j++];
}
result->length = k; // 更新result的长度
printf("合并完成,结果为:\n");
DisplayList(result);
}
原理很简单:题目条件是非递减排有序的线性表,那么我们可以一一将两个线性表比对,将更小的数值放在result中,在此同时,将线性表一中的元素与result中进行比较,如果相同,便跳过这个元素。如果有一个线性表遍历完成,便将另一个线性表的元素直接放入result之中。最后显示合并完成的线性表
14.菜单函数
void menu()
{
printf("***------------指令菜单-------------***\n");
printf("*** 1--初始化一个线性表 ***\n");
printf("*** 2--销毁线性表 ***\n");
printf("*** 3--清空线性表 ***\n");
printf("*** 4--判断线性表是否为空 ***\n");
printf("*** 5--求线性表长度 ***\n");
printf("*** 6--获取线性表中指定位置的元素 ***\n");
printf("*** 7--获取线性表元素的位置 ***\n");
printf("*** 8--求前驱 ***\n");
printf("*** 9--求后继 ***\n");
printf("*** 10-在线性表指定位置插入元素 ***\n");
printf("*** 11-删除线性表指定位置的元素 ***\n");
printf("*** 12-显示线性表 ***\n");
printf("*** 13-合并两个非递减排有序的线性表 ***\n");
printf("*** 退出,请输入一个负数 ***\n");
}
15.全部代码
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<stdlib.h>
#include <assert.h>
typedef int elemtype;
typedef struct sqlist
{
int length;//线性表中当前元素的数量
int listsize;//线性表的存储空间大小
elemtype* data;
int is_initialized; // 线性表是否已初始化的标志
}sqlist;
void InitList(sqlist* list)
{
if (list->is_initialized) { // 检查线性表是否已初始化
printf("线性表已经存在,不能重复初始化\n");
return;
}
printf("请输入线性表的长度:\n");
scanf("%d", &list->length);
list->listsize = list->length;
list->data = (elemtype*)malloc(list->length * sizeof(elemtype));
printf("请依次输入线性表中的元素:\n");
for (int i = 0; i < list->length; i++)
{
scanf("%d", &list->data[i]);
}
list->is_initialized = 1; // 初始化完成后,设置线性表已初始化的标志
printf("初始化完成\n");
}
void DestoryList(sqlist* list)
{
if (!list->is_initialized) { // 检查线性表是否已初始化
printf("线性表为空,请先创建一个线性表!\n");
return;
}
assert(list);
free(list->data);
list->data = NULL;
list->length = 0;
list->listsize = 0;
list->is_initialized = 0; // 销毁完成后,设置线性表未初始化的标志
printf("线性表已销毁\n");
}
void ClearList(sqlist* list)
{
if (!list->is_initialized) { // 检查线性表是否已初始化
printf("线性表为空,请先创建一个线性表!\n");
return;
}
assert(list);
list->length = 0;
printf("线性表已清空\n");
}
int ListEmpty(sqlist* list)
{
if (!list->is_initialized)
{ // 检查线性表是否已初始化
return 1;
}
if (list->length == 0)//如果长度为0,那么线性表便为空
return 1;
else
return 0;
}
void ListLength(const sqlist* list)
{
if (!list->is_initialized)
{ // 检查线性表是否已初始化
printf("线性表未初始化,线性表为空\n");
return;
}
printf("线性表长度为:%d\n", list->length);
}
void ElemPosition(const sqlist* list)//7
{
if (!list->is_initialized)
{ // 检查线性表是否已初始化
printf("线性表为空,请先创建一个线性表!\n");
return;
}
printf("请输入要查询的元素:\n");
elemtype elem = 0;
scanf("%d", &elem);
int i = 0;
int flag = 0;
for (i = 0; i < list->length; i++)
{
if (list->data[i] == elem)
{
flag = 1;
printf("元素的位置为:%d\n", i + 1);//返回该元素在线性表中的位置
}
}
if (flag == 0)
{
printf("您所查询的元素在线性表中不存在,请重新输入!\n");
}
}
void PositionElem(const sqlist* list)//6
{
if (!list->is_initialized) { // 检查线性表是否已初始化
printf("线性表为空,请先创建一个线性表!\n");
return ;
}
int pos;
printf("请输入位置:\n");
scanf("%d", &pos);
if (pos<1 || pos>list->length)
printf("该元素不存在\n");
else
{
printf("位置%d的元素为:%d\n", pos, list->data[pos - 1]);
}
}
void PositionElemBefore(const sqlist* list)//8
{
if (!list->is_initialized) { // 检查线性表是否已初始化
printf("线性表为空,请先创建一个线性表!\n");
return;
}
printf("请输入位置:\n");
int pos = 0;
scanf("%d", &pos);
if (pos<1 || pos>list->length)
printf("该元素不存在\n");
else if (pos == 1)
printf("该元素不存在直接前驱\n");
else
printf("位置%d的元素的前驱为:%d\n", pos,list->data[pos - 2]);
}
void PositionElemAfter(const sqlist* list)//9
{
if (!list->is_initialized) { // 检查线性表是否已初始化
printf("线性表为空,请先创建一个线性表!\n");
return;
}
int pos = 0;
printf("请输入位置:\n");
scanf("%d", &pos);
if (pos<1 || pos>list->length)
printf("该元素不存在\n");
else if (pos== list->length)
printf("该元素没有后继节点\n");
else
printf("位置%d的元素的后继为:%d\n", pos, list->data[pos]);
}
void InsertElem(sqlist* list, int pos, elemtype elem)//10
{
assert(list);
if (pos < 1 || pos > list->length + 1)
{
printf("插入位置无效\n");
return;
}
if (list->length >= list->listsize)
{
list->listsize *= 2;
list->data = (elemtype*)realloc(list->data, list->listsize * sizeof(elemtype));
}
for (int i = list->length; i >= pos; i--)
{
list->data[i] = list->data[i - 1];
}
list->data[pos - 1] = elem;
list->length++;
printf("插入完成\n");
}
void DeleteElem(sqlist* list, int pos) // 11
{
assert(list);
if (pos < 1 || pos > list->length)
{
printf("删除位置无效\n");
return;
}
for (int i = pos; i < list->length; i++)
{
list->data[i - 1] = list->data[i];
}
list->length--;
printf("删除完成\n");
}
void DisplayList(const sqlist* list) // 12
{
if (!list->is_initialized) { // 检查线性表是否已初始化
printf("线性表为空,请先创建一个线性表!\n");
return;
}
assert(list);
for (int i = 0; i < list->length; i++)
{
printf("%d ", list->data[i]);
}
printf("\n");
}
void MergeList(sqlist* list1, sqlist* list2, sqlist* result) // 13
{
if (!list1->is_initialized || !list2->is_initialized) { // 检查线性表是否已初始化
printf("线性表仍为空,请先选择指令一来创建一个线性表!\n");
return;
}
assert(list1);
assert(list2);
assert(result);
if (result->is_initialized) { // 检查result是否已初始化
free(result->data);
}
result->length = list1->length + list2->length;
result->listsize = result->length;
result->data = (elemtype*)malloc(result->length * sizeof(elemtype));
result->is_initialized = 1; // 设置result已初始化的标志
int i = 0, j = 0, k = 0;
while (i < list1->length && j < list2->length)
{
if (list1->data[i] < list2->data[j])
{
result->data[k++] = list1->data[i++];
}
else if (list1->data[i] > list2->data[j])
{
result->data[k++] = list2->data[j++];
}
else
{
result->data[k++] = list1->data[i++];
j++;
}
}
while (i < list1->length)
{
result->data[k++] = list1->data[i++];
}
while (j < list2->length)
{
result->data[k++] = list2->data[j++];
}
result->length = k; // 更新result的长度
printf("合并完成,结果为:\n");
DisplayList(result);
}
void menu()
{
printf("***------------指令菜单-------------***\n");
printf("*** 1--初始化一个线性表 ***\n");
printf("*** 2--销毁线性表 ***\n");
printf("*** 3--清空线性表 ***\n");
printf("*** 4--判断线性表是否为空 ***\n");
printf("*** 5--求线性表长度 ***\n");
printf("*** 6--获取线性表中指定位置的元素 ***\n");
printf("*** 7--获取线性表元素的位置 ***\n");
printf("*** 8--求前驱 ***\n");
printf("*** 9--求后继 ***\n");
printf("*** 10-在线性表指定位置插入元素 ***\n");
printf("*** 11-删除线性表指定位置的元素 ***\n");
printf("*** 12-显示线性表 ***\n");
printf("*** 13-合并两个非递减排有序的线性表 ***\n");
printf("*** 退出,请输入一个负数 ***\n");
}
int main()
{
sqlist l;
l.is_initialized = 0; // 在main函数开始处,设置线性表未初始化的标志
menu();
int input = 0;
printf("请输入指令:\n");
scanf("%d", &input);
while (input >= 0)
{
switch (input)
{
case(1):
InitList(&l);
break;
case(2):
DestoryList(&l);
break;
case(3):
ClearList(&l);
break;
case(4):
if (ListEmpty(&l))
printf("线性表为空\n");
else
printf("线性表不为空\n");
break;
case(5):
ListLength(&l);
break;
case(6):
PositionElem(&l);
break;
case(7):
ElemPosition(&l);
break;
case(8):
PositionElemBefore(&l);
break;
case(9):
PositionElemAfter(&l);
break;
case(10):
if (!l.is_initialized) { // 检查线性表是否已初始化
printf("线性表为空,请先创建一个线性表!\n");
break;
}
elemtype elem;
int pos = 0;
printf("请输入位置和元素:\n");
scanf("%d %d", &pos, &elem);
InsertElem(&l, pos, elem);
break;
case(11):
if (!l.is_initialized) { // 检查线性表是否已初始化
printf("线性表为空,请先创建一个线性表!\n");
break;
}
printf("请输入位置:\n");
scanf("%d", &pos);
DeleteElem(&l, pos);
break;
case(12):
DisplayList(&l);
break;
case(13):
if (!l.is_initialized) { // 检查线性表是否已初始化
printf("线性表为空,请先创建一个线性表!\n");
break;
}
sqlist l2, result;
l2.is_initialized = 0; // 设置线性表未初始化的标志
result.is_initialized = 0; // 设置线性表未初始化的标志
InitList(&l2);//初始化线性表二
MergeList(&l, &l2, &result);
break;
}
printf("请输入指令:\n");
scanf("%d", &input);
}
return 0;
}