实验二、顺序表的基本操作【简单易懂,代码可以直接运行】

实验二、顺序表的基本操作

(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;
}

制作不易,看到这里点个赞吧。留个赞好吗?秋梨膏!!
在这里插入图片描述

  • 15
    点赞
  • 27
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

henu-于笨笨

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值