实验二、顺序表的基本操作
(1)实验目的
通过该实验,深入理解顺序表的逻辑结构、物理结构等概念,掌握顺序表基本操作的编程实现,注意顺序表插入、删除等操作过程中数据元素的移动现象,培养学生编写程序时,要考虑程序的强壮性,熟练掌握通过函数参数返回函数结果的办法。
(2)实验内容
编程实现顺序表下教材第二章定义的线性表的基本操作,最好用菜单形式对应各个操作,使其编程一个完整的小软件。
(3)参考界面:
(4)验收/测试用例
通过菜单调用各个操作,测试点:
没有初始化前进行其他操作,程序是否能控制住;
初始化一个顺序表;
插入数据(位置, 数据),要测插入位置不合法的情况(0,1)、(2,1),正确插入4个数据(1,2)、(1,1)、(3,3);
显示顺序表中的数据,屏幕输出1, 2, 3;
判空,屏幕输出顺便表非空;
顺便表长度,屏幕输出3;
获取指定位置元素,要测指定位置在【1,3】范围之外的情况和之内的情况;
定位,输入:4, 输出:不存在,输入2,输出位置为2;
求直接前驱,要测求第一个元素的前驱、不存在顺序表中的元素的直接前驱,其他元素的直接前驱;
求直接后继,要测最后一个元素的后继、不存在顺序表中的元素的直接后继,其他元素的直接后继;
删除,要测位置在【1,3】范围之外的情况和之内的情况;
清空操作后再测长度;
销毁顺序表
从这个实验开始,数据结构的实验就变得困难了,会大量用到函数与指针,这个实验是我当时写了4天左右才写出来(运行起来,对于我来说运行起来就是写出来了,嘿嘿),但是第一次找老师检查程序的时候里面的bug非常多,换一换数据程序就会卡死,后来和同学进行了很多讨论,也画了很多顺序表的图,想着你们会不想画图,后面我留了一张顺序表合并的图通俗易懂嗷。最后成功做出来了这个程序。很不容易,点个赞吧,秋梨膏!!
小Tip:自己写出来的程序,让老师检查,平时分会更高哦!!
先读懂程序,按照程序写一边,能运行出来,搞懂每一步,能可以在老师的问题下回答出来,就算是自己写出来的。
这个程序算是比较困难的程序了,坚持下去,每一次都能自己做出来程序的话,对于一个对自己变成不自信的人来说还是挺有成就感到,我是自己写出来的程序能够跑起来我就有成就感,hhh。
此外,我当时比较喜欢C艹里面的cin和cout我觉得比scanf和printf更加简单和方便(主要是好敲和不用考虑数据类型)
代码如下:
#include<stdio.h>
#include<stdlib.h>
#include<iostream>
using namespace std;
#define ok 1
#define false 0
#define overflow -2
#define maxsize 200
typedef int Status;
typedef int ElemType;
typedef struct{ //给结构体起名:SqList
ElemType *elem; //存储空间基址
int length; //当前长度
int listsize; //当前分配的存储容量
}SqList;
Status InitList(SqList &L);
Status DestoryList(SqList &L);
Status ClearList(SqList &L);
Status ListEmpty(SqList L);
Status ListLength(SqList L);
Status GetElemt(SqList L,int i);
Status LocateElemt(SqList L,int cur_e);//Status PriorElemt(SqList L,int cur_e,int * pri_e)
Status PriorElemt(SqList L,int i,int *pri_e);
Status NextElemt(SqList L,int i,int *next_e);
Status InsertElem(SqList &L,int i,int e);
Status DeleteElem(SqList &L,int i);
Status ListTraver(SqList &L);
void MergeLsit(SqList LA,SqList LB,SqList &LC);
int main()
{
int i,j,m,n,inser,dizhi,cur_e,pri_e,next_e;
//int *e;
SqList L;
SqList LA;
SqList LB;
SqList LC;
L.elem = NULL;
cout<<"*********************"<<endl;
cout<<"自己可以单独运行一下试试"<<endl;
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.初始化线性表LA,LB,LC"<<endl;
cout<<"13.插入构建线性表LA"<<endl;
cout<<"14.插入构建线性表LB"<<endl;
cout<<"15.合并两个非递减顺序表"<<endl;
cout<<"16.查找元素位置"<<endl;
cout<<"输入一个负数退出"<<endl;
cout<<"**********************"<<endl;
do{
cout<<"请输入你的选择: "<<endl;
cin>>n;
cout<<endl;
switch(n)
{
case 1:InitList(L);
break;
case 2:DestoryList(L);
break;
case 3:ClearList(L);
break;
case 4:ListEmpty(L);
break;
case 5:ListLength(L);
break;
case 6:
cout<<"输入指定位置:"<<endl;
cin>>i;
GetElemt(L,i);
break;
case 7:
cout<<"输入要求前驱的元素:"<<endl;
cin>>cur_e;
PriorElemt(L,cur_e,&pri_e);//修改去掉了地址引用符
break;
case 8:
cout<<"输入要求后继的元素:"<<endl;
cin>>cur_e;
//cout<<""<<endl;
NextElemt(L,cur_e,&next_e);
break;
case 9:
cout<<"输入线性表指定位置:"<<endl;
cin>>i;
cout<<"输入要插入的元素:"<<endl;
cin>>inser;
InsertElem(L,i,inser);
break;
case 10:
cout<<"输入要删除元素的位置:"<<endl;
cin>>i;
DeleteElem(L,i);
break;
case 11:
ListTraver(L);
break;
case 12:
InitList(LA);
InitList(LB);
InitList(LC);
break;
case 13:
cout<<"输入线性表LA指定位置:"<<endl;
cin>>i;
cout<<"输入要插入的元素:"<<endl;
cin>>inser;
InsertElem(LA,i,inser);
break;
case 14:
cout<<"输入线性表LB指定位置:"<<endl;
cin>>i;
cout<<"输入要插入的元素:"<<endl;
cin>>inser;
InsertElem(LB,i,inser);
break;
case 15:
MergeLsit(LA,LB, LC);
break;
case 16:
cout<<"输入该元素的位置:"<<endl;
cin>>cur_e;
LocateElemt(L,cur_e);
break;
default :cout<<"请输入1~16内的数字!!"<<endl;
break;
}
}while(n > 0);
}
Status InitList(SqList &L){
L.elem = (ElemType *)malloc(maxsize*sizeof(ElemType));//申请地址空间,书上有他的伪代码,之后整个语句用到的非常多,一般都是这样用,不要因为这行代码的函数多感到害怕,(ElemType)括号里面加*,这个顺序表就是链表,不加*就是数组
if(! L.elem) exit(overflow);
L.length = 0;
L.listsize = maxsize;
cout<<"线性表初始化成功!"<<endl;
return ok;
}
Status DestoryList(SqList &L){
if(L.elem == NULL)
{
cout<<"请先初始化线性表"<<endl;
return false;
}
free(L.elem);
L.elem = NULL;
cout<<"线性表销毁成功"<<endl;
}
Status ClearList(SqList &L){
//if(L.length == 0)
if(L.elem == NULL)
{
cout<<"请先初始化线性表"<<endl;
return false;
}
L.length = 0;
cout<<"线性表清除成功"<<endl;
}
Status ListEmpty(SqList L){
//if(L.length == 0)
if(L.length == 0)
{
cout<<"线性表为空"<<endl;
return ok;
}
else
{
cout<<"该线性表不为空"<<endl;
return false;
}
}
Status ListLength(SqList L){
//if(L.length == 0)
if(L.elem == NULL)
{
cout<<"请先初始化线性表"<<endl;
return false;
}
cout<<"线性表长度为:"<<L.length<<endl;
return ok;
//return (L.length);
}
Status GetElemt(SqList L,int i){
//if(L.length == 0)
if(L.elem == NULL)
{
cout<<"请先初始化线性表"<<endl;
return false;
}
if(i < 1||i > L.length)
{
cout<<"不存在,请输入线性表长度范围内的数"<<endl;
return false;
}
//*e = L.elem[i - 1];
cout<<"该元素为:"<<L.elem[i - 1]<<endl;
return ok;
}
Status PriorElemt(SqList L,int cur_e,int * pri_e){//求解前驱
int i = 0;
//if(L.length == 0)
if(L.elem == NULL)
{
cout<<"请先初始化线性表"<<endl;
return false;
}
while((L.elem[i] != cur_e) && (i < L.length))
{i++;}
if(i < L.length)
{
if(i == 0)
{
cout<<"该元素位于元首,没有前驱!"<<endl;
return false;
}
*pri_e = L.elem[i - 1];
cout<<"该元素的前驱:"<<*pri_e<<endl;
return ok;
}
else
{
cout<<"该线性表中没有该元素!"<<endl;
return ok;
}
}
Status NextElemt(SqList L,int cur_e,int * next_e){
if(L.elem == NULL)
{
cout<<"请先初始化线性表"<<endl;
return false;
}
int i = 0;
while((L.elem[i] != cur_e) && (i < L.length))
{i++;}
if(i < L.length)
{
if(i == L.length - 1)
{
cout<<"该元素没有后继!"<<endl;
return false;
}
*next_e = L.elem[i + 1];
cout<<"该元素的后继:"<<*next_e<<endl;
return ok;
}
else
{
cout<<"该线性表中没有该元素!"<<endl;
return false;
}
}
Status InsertElem(SqList &L,int i,int e){
int j;
//if(L.length == 0)
if(L.elem == NULL)
{
cout<<"请先初始化线性表"<<endl;
return false;
}
if(i < 1||i > L.length + 1)//循序表的第一个元素位置记为1了
{
cout<<"请输入线性表长度以内的数"<<endl;
return false;
}
if(L.length == maxsize) //线性表已经存满
{return false;}
for(j = L.length;j >= i - 1;j--)
{
L.elem[j + 1] = L.elem[j];
}
L.elem[i - 1] = e;
L.length++;
cout<<"元素插入成功"<<endl;
return ok;
}
Status DeleteElem(SqList &L,int i){
int j;
//if(L.length == 0)
if(L.elem == NULL)
{
cout<<"请先初始化线性表"<<endl;
return false;
}
if(i < 1||i > L.length + 1)
{
cout<<"请输入线性表长度以内的数"<<endl;
return false;
}
for(j = i - 1;j <= L.length;j++)
{
L.elem[j] = L.elem[j + 1];
}
L.length--;
cout<<"删除元素成功!"<<endl;
return ok;
}
Status ListTraver(SqList &L){
int i;
//if(L.length == 0)
if(L.elem == NULL)
{
cout<<"请先初始化线性表"<<endl;
return false;
}
cout<<"输出该线性表:"<<endl;
for(i = 0;i < L.length;i++)
{
cout<<L.elem[i]<<" ";
}
cout<<endl;
return ok;
}
void MergeLsit(SqList LA,SqList LB,SqList &LC){
int i,j;
cout<<"输出线性表LA:"<<endl;
ListTraver(LA);
cout<<"输出线性表LB:"<<endl;
ListTraver(LB);
int *pa,*pb,*pc,*pa_last,*pb_last;
pa = LA.elem;
pb = LB.elem;
LC.length = LA.length + LB.length;
pc = LC.elem;
pa_last = LA.elem + LA.length - 1;
pb_last = LB.elem + LB.length - 1;
while((pa <= pa_last) && (pb <= pb_last)){
if(*pa < *pb)
{
*pc = *pa;
*pc++;
*pa++;
}
else
{
*pc = *pb;
*pc++;
*pb++;
}
}
while(pa <= pa_last)
{
*pc = *pa;
*pc++;
*pa++;
}
while(pb <= pb_last)
{
*pc = *pb;
*pc++;
*pb++;
}
//新合并的顺序表进行查重
for(i = 0;i < LC.length;i++)
{
for(j = 0;j < i;j++)
{
if(LC.elem[i] == LC.elem[j])
{
cout<<"重复的元素为:"<<LC.elem[i]<<endl;
cout<<"请输入一个新元素:"<<endl;
cin>>LC.elem[i];
j = -1;
}
}
}
cout<<"输出此时的数组LC:"<<endl;
ListTraver(LC);
}
Status LocateElemt(SqList L,int cur_e){
if(L.elem == NULL)
{
cout<<"请先初始化线性表"<<endl;
return false;
}
int i = 0;
int m = 0;
for(i = 0;i < L.length;i++)
{
if(L.elem[i] == cur_e)
{
cout<<"该元素的位置为"<<i + 1<<endl;
m = -1;
return ok;
}
}
if(m == 0)
{
cout<<"该元素不在线性表中"<<endl;
return false;
}
}
这个程序相对来说还是挺大的,特别是整个小程序该如何构建顺序表,怎么向初始化后的顺序表里面填充数据,下面将手把手演示如何进行数据操作。除此之外,整个程序难的地方还有一个就是两个顺序表合并的问题。里面主要涉及到的是两个顺序表合并的话,如何剔除两个顺序表中的相同元素,我当时实现这个功能的时候一直干到迷惑,后来我单独写了一个小的代码程序,把这个功能给实现了,放在文章后面会贴出来:
小 Tip:画图会让你的视野豁然开朗,不要凭空想象
程序如何运行:
接下来是合并两个顺序表的代码,它里面主要是指针的所指向的位置不断改变:知道你们可能不想画图,我就给你们画一下吧!
不要嫌弃字不好看,再合并两个顺序表之后,会有算法去剔除重复的元素的,和实验一那个从集合里面剔除重复元素的算法一样。
代码如下:这个代码的数据,我就不掩饰了,和大程序的12,13,14,15的过程是一样的。
#include<stdio.h>
#include<stdlib.h>
#include<iostream>
using namespace std;
#define ok 1
#define false 0
#define overflow -2
#define maxsize 200
typedef int Status;
typedef int ElemType;
typedef struct{ //给结构体起名:SqList
ElemType *elem; //存储空间基址
int length; //当前长度
int listsize; //当前分配的存储容量
}SqList;
Status InitList(SqList &L);
Status InsertElem(SqList &L,int i,int e);
Status ListTraver(SqList &L);
void MergeLsit(SqList &LA,SqList &LB,SqList &LC);
int main()
{
int i,j,m,n,inser,dizhi,cur_e,e;
SqList LA;
SqList LB;
SqList LC;
LA.elem = NULL;
LB.elem = NULL;
LC.elem = NULL;
cout<<"****************"<<endl;
cout<<"1.初始化线性表LA,LB,LC"<<endl;
cout<<"2.插入LA构建线性表A"<<endl;
cout<<"3.插入LB构建线性表B"<<endl;
cout<<"4.合并线性表LA与LB"<<endl;
cout<<"****************"<<endl;
do{
cout<<"请输入你的选择: "<<endl;
cin>>n;
switch(n){
case 1:
InitList(LA);
InitList(LB);
InitList(LC);
break;
case 2:
cout<<"输入此时插入LA的位置: "<<endl;
cin>>i;
cout<<"输入要插入的元素: "<<endl;
cin>>e;
InsertElem(LA,i,e);
break;
case 3:
cout<<" 输入此时插入LB的位置:"<<endl;
cin>>i;
cout<<" 输入要插入的元素:"<<endl;
cin>>e;
InsertElem(LB,i,e);
break;
case 4:
/*cout<<"此时的线性表LA"<<endl;
ListTraver(LA);
cout<<"此时的线性表LB"<<endl;
ListTraver(LB);
cout<<"输出此时的线性表LC"<<endl;*/
MergeLsit(LA,LB,LC);
break;
default:
cout<<"请输入1~4内的数"<<endl;
break;
}
}while(n > 0);
}
Status InitList(SqList &L){
L.elem = (ElemType *)malloc(maxsize*sizeof(ElemType));
if(L.elem == NULL)
{exit(overflow);}
L.listsize = maxsize;
L.length = 0;
cout<<"线性表初始化成功!!"<<endl;
return ok;
}
Status InsertElem(SqList &L,int i,int e){
int j;
if(L.elem == NULL){
cout<<"请先初始化线性表"<<endl;
return false;
}
if(L.length == maxsize)
{
cout<<"线性表已满!"<<endl;
return false;
}
if(i < 1||i > L.length + 1)
{
cout<<"请输入正确位置"<<endl;
return false;
}
for(j = i;j < L.length;j++)
{
L.elem[j + 1] = L.elem[j];
}
L.elem[i - 1] = e;
L.length++;
//L.length++;
cout<<"元素插入成功"<<endl;
return ok;
}
Status ListTraver(SqList &L){
int i;
if(L.elem == NULL)
{
cout<<"请先初始化线性表"<<endl;
return false;
}
for(i = 0;i < L.length;i++)
{
cout<<L.elem[i]<<" ";
}
return ok;
}
void MergeLsit(SqList &LA,SqList &LB,SqList &LC){
int i,j;
cout<<"此时的线性表LA:"<<endl;
ListTraver(LA);
cout<<endl;
cout<<"此时的线性表LB:"<<endl;
ListTraver(LB);
cout<<endl;
int *pa,*pb,*pc,*pa_last,*pb_last;
pa = LA.elem;
pb = LB.elem;
pc = LC.elem;
pa_last = pa + LA.length - 1;
pb_last = pb + LB.length - 1;
LC.length = LA.length + LB.length;
while((pa <= pa_last) && (pb <= pb_last))
{
if(*pa < *pb)
{
*pc = *pa;
pc++;
pa++;
}
else
{
*pc = *pb;
pc++;
pb++;
}
}
while(pa <= pa_last)
{
*pc = *pa;
pc++;
pa++;
}
while(pb <= pb_last)
{
*pc = *pb;
pc++;
pb++;
}
for(i = 0;i < LC.length;i++)
{
for(j = 0;j < i;j++)
{
if(LC.elem[i] == LC.elem[j])
{
cout<<"线性表中重复的元素为:"<<LC.elem[i]<<endl;
cout<<"请输入一个新元素:";
cin>>LC.elem[i];
j = -1;
}
}
}
//cout<<"输出此时的数组LC:"<<endl;
ListTraver(LC);
cout<<endl;
}
制作不易,看到这里点个赞吧。留个赞好吗?秋梨膏!!