(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>
#include <cstdlib>
#define LIST_INIT_SIZE 100
#define LISTINCREMENT 10
using namespace std;
typedef struct{
int *elem;
int length;
int listsize;
}SqList;
bool initList(SqList &L){
L.elem=(int * )malloc(LIST_INIT_SIZE*sizeof(int));
if(! L.elem)cout<<"分配失败"<<endl;
L.length=0;
L.listsize=LIST_INIT_SIZE;
cout<<"分配成功"<<endl;
return true;
}
/*这段代码是C++中用于初始化一个顺序列表(SqList)的函数。函数名为initList,输入参数是一个SqList类型的引用,也被 命名为L
在函数内部,首先通过调用malloc函数为L.elem分配内存,该内存的大小为LIST_INIT_SIZE(预定义的整数常量)乘以int类型的大小。将分配的内存地址赋给L.elem,如果内存分配失败(malloc返回NULL),则会输出 '分配失败'。
然后,将L.length(列表的当前长度)设置为0,表示列表为空。
接着,将L.listsize(列表的最大容量)设置为LIST_INIT_SIZE,表示列表的初始容量。
最后,输出 '分配成功',并返回true,表示函数执行成功。
这个函数的主要目的是初始化顺序列表,包括分配内存、设置列表长度和容量,并在必要时输出错误信息。*/
void destroy(SqList &L){
free(L.elem);
L.elem=NULL;
L.length=0;
L.listsize=0;
cout<<"销毁成功"<<endl;
}
//销毁链表
void clear(SqList &L){
if(!L.elem)cout<<"该链表已销毁"<<endl;
else{L.length=0;
cout<<"清空成功"<<endl;
}
}
//清空链表
bool jud(SqList &L){
if(!L.elem)cout<<"该表已销毁"<<endl;
else{
if(L.length==0) {
cout<<"线性表为空"<<endl;
return true ;
}else {cout<<"线性表不为空"<<endl;
return false;
}
}
}
int Listlength(SqList &L){
if(!L.elem)cout<<"该表已销毁"<<endl;
else return L.length;
}
int Getelem(SqList L,int i,int &e){
if(!L.elem)cout<<"该表已销毁"<<endl;
else{if(L.length>0){
if(i>0&&i<=L.length){
e=L.elem[i-1];
cout<<e<<endl;
}
else cout<<"输入错误"<<endl;
}
else cout<<"该线性表不存在,无法获取元素"<<endl;}
}
void Getload(SqList &L,int e){
if(!L.elem)cout<<"该表已销毁"<<endl;
else{cout<<"请输入想查找的元素"<<endl;
cin>>e;
int i;
for(i=0;i<L.length;i++){
if(L.elem[i]==e){
cout<<"位置为"<<i+1<<endl;
}
}
if(i=L.length&&L.elem[i-1]!=e){
cout<<"输入错误"<<endl;
}
}
}
int front(SqList *L,int i,int &e){
if(!L->elem)cout<<"该表已销毁"<<endl;
else{if(i>1&&i<=L->length){
cout<<"前驱为"<<endl;
e=L->elem[i-2];
cout<<e<<endl;
}else cout<<"输入错误"<<endl;}
}
int behind(SqList *L,int i,int &e){
if(!L->elem)cout<<"该表已销毁"<<endl;
else{if(i>0&&i<L->length){
cout<<"后继为"<<endl;
e=L->elem[i];
cout<<e<<endl;
}else cout<<"输入错误"<<endl;}
}
//前驱后缀
void insert(SqList *L,int i,int e){
if((i>0)&&(i<=L->listsize)){
if(L->length==L->listsize){
int *newbase=(int * )realloc(L->elem, (LIST_INIT_SIZE+LISTINCREMENT)*sizeof(int));
if(!newbase)cout<<"存储分配失败"<<endl;
int m;
for(m=0;m<i-1;m++){
newbase[m]=L->elem[m];
}
newbase[i-1]=e;
for(m=i;m<L->length+1;m++){
newbase[m]=L->elem[m-1];
}
L->elem=newbase;
L->listsize=LIST_INIT_SIZE+LISTINCREMENT;
L->length=L->length+1;
cout<<"插入成功"<<"\n";
}else {
int m;
for(m=L->listsize-1;m>=i;m--){
L->elem[m]=L->elem[m-1];
}
L->elem[i-1]=e;
L->length=L->length+1;
cout<<"插入成功"<<"\n";
}
}else cout<<"输入错误"<<"\n";
}
void delate(SqList &L,int i,int &e){
if(i>0&&i<=L.length){
int m;
if(i==L.length)
{
L.length=L.length-1;
cout<<"删除成功"<<endl;
}else {
for(m=i-1;m<L.length-1;m++){
L.elem[m]=L.elem[m+1];
}
cout<<"删除成功"<<endl;
L.length=L.length-1;
}
}else cout<<"输入错误"<<endl;
}
void display(SqList &L){
int m;
for(m=0;m<L.length;m++){
cout<<L.elem[m]<<" ";
}
}
bool merge(SqList L1,SqList L2,SqList &L){
int i=0;
int j=0;
int k=0;
while(i<L1.length&&j<L2.length){
if(L1.elem[i]>L2.elem[j]){
L.elem[k]=L1.elem[i];
++i;
}else{
L.elem[k]=L2.elem[j];
++j;
}
++k;
}
//这段 代码是用于合并两个有序列表L1和L2的函数,结果存储在列表L中。代码首先定义了三个指针(i, j, k),并设置它们都为0。然后,它进入一个循环,在这个循环中,它会比较L1和L2的当前元素(i和j索引的元素)。如果L1的当前元素大于L2的当前元素,它会将L1的当前元素添加到L中,然后增加i的值。否则,它会将L2的当前元素添加到L中,并增加j的值。一旦循环结束,任何剩余的元素(在L1或L2中)将被添加到结果列表L中。注意,这个函数假设列表L有足够的空间来存储合并后的元素。
if(i==L1.length){
for(int m=j;m<L2.length;m++,k++){
L.elem[k]=L2.elem[m];
}
}else if(j==L2.length){
for(int m=i;m<L1.length;m++,k++){
L.elem[k]=L1.elem[m];
}
}
cout<<"线性表为:";
for(int i=0;i<k;i++){
cout<<L.elem[i]<<" ";
}
}
int main(){
SqList L;
SqList L1;
SqList L2;
initList(L);
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<<"退出,输入一个负数!";
while(true){
int choice;
int e;
int i;
cin>>choice;
switch(choice) {
case 1:
initList(L);
break;
case 2:
destroy(L);
break;
case 3:
clear(L);
break;
case 4:
jud(L);
break;
case 5:
cout<<"长度是"<<Listlength(L);
break;
case 6:
cout<<"输入查找的位置"<<endl;
cin>>i;
Getelem(L,i,e);
break;
case 7:
int e;
Getload(L,e);
break;
case 8:
cout<<"输入第几个位置"<<endl;
cin>>i;
front(&L,i,e);
break;
case 9:
cout<<"输入第几个位置"<<endl;
cin>>i;
behind(&L,i,e);
break;
case 10:
cout<<"输入位置"<<endl;
cout<<"输入数字"<<endl;
cin>>i;
cin>>e;
insert(&L,i,e);
break;
case 11:
cout<<"输入删除元素的位置"<<endl;
cin>>i;
delate(L,i,e);
break;
case 12:
display(L);
break;
case 13:
int n;
cout<<"输入L1的元素个数"<<endl;
cin>>n;
initList(L1);
for(int k=0;k<n;k++){
cout<<"输入位置"<<endl;
cout<<"输入数值"<<endl;
cin>>i;
cin>>e;
insert(&L1,i,e);
}
cout<<"输入L2的元素个数"<<endl;
cin>>n;
initList(L2);
for(int k=0;k<n;k++){
cout<<"输入位置"<<endl;
cout<<"输入数值"<<endl;
cin>>i;
cin>>e;
insert(&L2,i,e);
}
merge(L1,L2,L);
break;
default:
if(choice<0){
cout<<"程序已结束";
break;
}
}
}
}