(1)实验目的
通过该实验,深入理解顺序表的逻辑结构、物理结构等概念,掌握顺序表基本操作的编程实现,注意顺序表插入、删除等操作过程中数据元素的移动现象,培养学生编写程序时,要考虑程序的健壮性,全面考虑问题,熟练掌握通过函数参数返回函数结果的办法。
(2)实验内容
编程实现顺序表下教材第二章定义的线性表的基本操作,并根据已经实现的基本操作(函数),通过调用函数,实现两个非递减有序的线性表的合并,注意,合并时,如果有重复的元素(一个表内部的重复元素和两个表之间的重复元素),请保留一个。
(3)实验要求
(a)求前驱是指,输入一个元素值(而不是位置),求该元素在顺序表中的直接前驱元素值。求后继是指:输入一个元素值(而不是位置),求该元素在顺序表中的直接后继元素值;(b)为了方便修改数据元素的类型,请使用类型重定义,可以方便修改线性表中的数据元素的类型;(c)大部分函数的返回结果应是函数执行是否成功的一种状态,执行成功了,才返回具体的结果值;(d)对每个功能进行测试时,要求把不合法的情况也测试一下。具体见下面的测试用例;(e)采用菜单形式对应各个操作,使其编成一个完整的小软件,参考界面如下。注意:程序运行过程中菜单不要做成刷屏的效果,测试过的数据不要清除,这样方便截图和查看。
注:销毁是指free(L.elem); L.elem=NULL; L.length=0; L.listsize=0; return TRUE。清空是指:L.length=0 ;return TRUE。
(4)验收/测试用例
通过菜单调用各个操作,测试点:
- 没有初始化前进行其他操作,程序是否能控制住;即,如果没有初始化线性表,其他的功能是无法正常进行的,如果选择进行其他操作,要提示先进行初始化;
- 先选择菜单1,初始化一个顺序表(初始化顺序表,是指初始化一个空的线性表,里面的元素个数是0);
- 选择菜单10,插入数据(位置, 数据),要测插入位置不合法的情况如:(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】范围之外的情况和之内的情况,非法的情况要做出合理的提示;
- 清空操作后再测长度,判断是否为空;清空后,测试菜单6到11的功能,看是否能够正确提示。
- 销毁顺序表,销毁线性表之后还能不能做插入,删除等操作,如果选其他操作,就要提示线性表已经销毁不存在;
- 测试合并操作,第一个线性表中的元素是(2,3,3,4,5),第二个线性表中的内容是(1,4,5,6,6,7),合并后的结果,请输出。
#include<iostream>
using namespace std;
typedef int Status;
typedef int ElemType;
#define LIST_INIT_SIZE 100 //符号常量 //线性表存储空间的初始分配量
#define LISTINCREMENT 10 //线性表存储空间的分配增量
#define OK 1
#define ERROR 0
#define true 1
#define false 0
typedef struct {
ElemType* elem;//表基址,申请的内存首地址
int length;//表长(特指元素个数)
int listsize;//表当前存储容量(最大长度)
}Sqlist;
//1.初始化
//构造一个空的线性表L
Status InitList(Sqlist& L) {
//为数据元素开辟一维数组空间
L.elem = (ElemType*)malloc(LIST_INIT_SIZE * sizeof(ElemType));
if (!L.elem) {
printf("存储空间分配失败\n");
exit(OVERFLOW);
}//存储分配失败
L.length = 0;//空表长度为零
L.listsize = LIST_INIT_SIZE;//初始存储容量
printf("线性表初始化成功\n");
return OK;
}
//2.销毁
Status DestroyList(Sqlist& L) {
free(L.elem);
L.elem = NULL;//重置elem的值为null
L.length = 0;//重置线性表元素个数为0
L.listsize = 0;//重置线性表存储容量为0
printf("线性表销毁成功\n");
return OK;
}
//3.清空
Status ClearList(Sqlist& L) {
L.length = 0;//重置线性表容量为0
printf("线性表已清空\n");
return OK;
}
//4.判断是否为空
Status ListEmpty(Sqlist& L) {
if (L.length != 0) {
printf("线性表不为空\n");
return false;
}
else//如果线性表元素为0,则说明线性表为空
printf("线性表为空\n");
return true;
}
//5.求线性表长度
Status ListLength(Sqlist& L) {
int x = L.length;
printf("线性表长度为%d\n", x);
return OK;
}
//6.获取指定位置的元素
Status GetElem(Sqlist& L, int i, ElemType e) {
if (L.length == 0) {
printf("线性表为空\n");
return ERROR;
}
if (i - 1 < 0 || i > L.length) {//判断元素的位置是否出界
printf("请输入有效数字\n");
return ERROR;
}
else {
e = L.elem[i - 1];
printf("第%d个位置的元素是%d\n", i, e);
return OK;
}
}
//7.获取元素的位置
Status LocateElem(Sqlist& L, ElemType e) {
if (L.length == 0) {
printf("线性表为空\n");
return ERROR;
}
int i = 1;
for (i = 1;i <= L.length;i++) {
if (e == L.elem[i - 1]) {
int l = i;
printf("元素%d的位置是%d\n", e, l);
return OK;
}
if (i == L.length && e != L.elem[L.length - 1]) {
printf("不存在该元素\n");
return ERROR;
}
}
}
//8.前驱
Status PriorElem(Sqlist& L, ElemType e, ElemType prior_e) {
int i = 1;
if (L.length == 0) {
printf("线性表为空\n");
return false;
}
if (e != L.elem[0]) {
while (i <= L.length && e != L.elem[i - 1]) {//当输入的值与元素范围相同时,跳出循环
i++;
}
if (i <= L.length || e == L.elem[i - 1]) {
prior_e = L.elem[i - 2];
printf("元素%d的前驱为%d\n", e, prior_e);
}
else {
cout << "该元素不存在" << endl;
}
}
else {
cout << "首元素无前驱" << endl;
}
}
//9.后继
Status NextElem(Sqlist& L, ElemType e, ElemType next_e) {
int i = 1;
if (L.length == 0) {
printf("线性表为空\n");
return false;
}
for (int i = 1;i <= L.length;i++) {
if (i < L.length && e == L.elem[i - 1]) {
next_e = L.elem[i];
printf("元素%d的后继为%d\n", e, next_e);
return OK;
}
else if (i == L.length && e != L.elem[i - 1]) {
cout << "该元素不存在" << endl;
return ERROR;
}
else if (i == L.length && e == L.elem[i - 1]) {
printf("尾元素无后继\n");
return ERROR;
}
}
}
//10.在指定位置插入元素
Status ListInsert(Sqlist& L, int i, ElemType e) {
ElemType* newbase;
int* q, * p;
if (i<1 || i>L.length + 1) {//i的合法位置为0<i<L.length+1
cout << "插入位置不合法" << endl;//判断插入位置是否合法
return ERROR;
}
if (L.length >= L.listsize) {//表示如果存储空间已满,增加内存
newbase = (ElemType*)realloc(L.elem, (L.listsize + LISTINCREMENT) * sizeof(ElemType));
if (!newbase) {//存储空间分配失败,异常退出
printf("存储空间分配失败\n");
exit(OVERFLOW);
}
L.elem = newbase;//新的存储空间基址
L.listsize += LISTINCREMENT;
}
q = &L.elem[i - 1];
p = &L.elem[L.length - 1];//L.elem[L.length - 1]为数组中的最后一个元素
for (p;p >= q;--p)
*(p + 1) = *p;//插入位置及以后位置向后移
*q = e;//将元素插入
++L.length;//插入后长度加1
cout << "插入成功" << endl;
return OK;
}
//11.删除指定位置的元素
Status DeleteList(Sqlist& L, int i) {
int* p, * q;
if (L.length == 0) {
cout << "线性表为空" << endl;
return ERROR;
}
//i的合法地址:0<i<L.length
if (i<1 || i>L.length) {//判断删除地址是否合法
printf("请输入一个有效的位置:\n");
return ERROR;
}
p = &L.elem[i - 1];//p为被删除元素的位置
ElemType e = *p;
q = &L.elem[L.length - 1];//q为表尾元素
for (p;p <= q;p++)
*p = *(p + 1);//将被删除元素之后的元素前移
cout << "删除成功" << endl;
--L.length;//表长减一
return OK;
}
//12.显示线性表
Status PrintList(Sqlist& L) {
if (L.length == 0) {
cout << "线性表为空" << endl;
}
for (int i = 0;i < L.length;i++) {
int x = L.elem[i];
cout << x << " ";
}
cout << "" << endl;
return OK;
}
// 为线性表赋值
void InputElem(Sqlist& LA, int i, Sqlist& LB, int j)//创建线性表LA,LB.
{
InitList(LA); //初始化LA
cout << "请为顺序表A赋值,输入负数退出!" << endl;
for (i = 0; i < LA.listsize; i++)
{
cin >> LA.elem[i];
if (LA.elem[i] < 0) //退出输入状态
{
break;
}
LA.length = i + 1;
}//for
//LA.listsize = sizeof(LA.elem);
InitList(LB); //初始化LB
cout << "请为顺序表B赋值,输入负数退出!" << endl;
for (j = 0; j < LB.listsize; j++)
{
cin >> LB.elem[j];
if (LB.elem[j] < 0)
{
break;
}
LB.length = j + 1;
}//for
//LB.listsize = sizeof(LB.elem);
}
//13--合并两个非递减有序的线性表
Status UnionList(Sqlist LA, Sqlist LB, Sqlist& LC)
{
int i = 1;
int j = 1;
int k = 1;
//赋值
InputElem(LA, i, LB, j);
int La_len = ListLength(LA);
int Lb_len = ListLength(LB);
while ((i <= La_len) && (j <= Lb_len))
{
if (LA.elem[i - 1] <= LB.elem[j - 1]) {
ListInsert(LC, k, LA.elem[i - 1]);
i++;
k++;
}
else {
ListInsert(LC, k, LB.elem[j - 1]);
j++;
k++;
}
}//while
//将较长的线性表剩余的元素插入
while (i <= LA.length)
{
ListInsert(LC, k, LA.elem[i - 1]);
i++;
k++;
}
while (j <= LB.length)
{
ListInsert(LC, k, LB.elem[j - 1]);
j++;
k++;
}
//去重
for (int a = 0; a < LC.length; a++)
{
for (int b = a + 1; b < LC.length; b++)
{
if (LC.elem[a] == LC.elem[b])
{
DeleteList(LC, b);
b--;
}
}
}
PrintList(LC);
return OK;
}
int main() {
Sqlist La, Lb, Lc;
bool initlist = false;
cout << "1----初始化一个线性表" << endl;
cout << "2----销毁线性表" << endl;
cout << "3----清空线性表" << endl;
cout << "4----判断线性表是否为空" << endl;
cout << "5----求线性表长度" << endl;
cout << "6----获取线性表中指定位置的元素" << endl;
cout << "7----获取线性表元素的位置" << endl;
cout << "8----求前驱" << endl;
cout << "9----求后继" << endl;
cout << "10---在线性表指定位置插入元素" << endl;
cout << "11---删除线性表指定位置的元素" << endl;
cout << "12---显示线性表" << endl;
cout << "13---合并两个非递减有序的线性表" << endl;
cout << "退出,输入一个负数!" << endl;
int n = 1;
while (n) {
int i;
cout << "请输入你选择的功能:";
scanf_s("%d", &i);
switch (i) {
case 1:
InitList(La);
initlist = true;
break;
case 2:
if (initlist != true) {
printf("请先进行初始化:\n");
break;
}
DestroyList(La);
initlist = false;
break;
case 3:
if (initlist != true) {
printf("请先进行初始化:\n");
break;
}
ClearList(La);
break;
case 4:
if (initlist != true) {
printf("请先进行初始化:\n");
break;
}
ListEmpty(La);
break;
case 5:
if (initlist != true) {
printf("请先进行初始化:\n");
break;
}
ListLength(La);
break;
case 6:
if (initlist != true) {
printf("请先进行初始化:\n");
break;
}
else {
ElemType e = 0;
int i = 0;
cout << "请输入要获取位置的元素:";
cin >> i;
GetElem(La, i, e);
}
break;
case 7:
if (initlist != true) {
printf("请先进行初始化:\n");
break;
}
{
ElemType e = 0;
cout << "请输入要获取位置的元素:";
cin >> e;
LocateElem(La, e);
}
break;
case 8:
if (initlist != true) {
printf("请先进行初始化:\n");
break;
}
{
ElemType e = 0;
ElemType prior_e = 0;
printf("请输入元素:");
cin >> e;
PriorElem(La, e, prior_e);
}
break;
case 9:
if (initlist != true) {
printf("请先进行初始化:\n");
break;
}
{
ElemType e = 0;
ElemType next_e = 0;
cout << "请输入元素:";
cin >> e;
NextElem(La, e, next_e);
}
break;
case 10:
if (initlist != true) {
printf("请先进行初始化:\n");
break;
}
{
int i = 0;
ElemType e = 0;
cout << "插入位置是:";
cin >> i;
cout << "插入元素为:";
cin >> e;
ListInsert(La, i, e);
}
break;
case 11:
if (initlist != true) {
printf("请先进行初始化:\n");
break;
}
{int i = 0;
cout << "请输入删除的位置:";
cin >> i;
DeleteList(La, i);
}
break;
case 12:
if (initlist != true) {
printf("请先进行初始化:\n");
break;
}
PrintList(La);
break;
case 13:
if (initlist != true) {
printf("请先进行初始化:\n");
break;
}
InitList(La);
InitList(Lb);
InitList(Lc);
UnionList(La, Lb, Lc);
break;
default:
if (i < 0) {
cout << "退出程序" << endl;
n = 0;
}
}
}
}