数据结构实验2 基于顺序表的非递减有序表的合并

姓名:Far_Rainbow
学号: 202505000X
专业: 软件工程
年级:2020级

实验名称:实验2 基于顺序表的非递减有序表的合并

实验内容

(1)实验目的
通过该实验,深入理解顺序表的逻辑结构、物理结构等概念,掌握顺序表基本操作的编程实现,注意顺序表插入、删除等操作过程中数据元素的移动现象,培养学生编写程序时,要考虑程序的健壮性,全面考虑问题,熟练掌握通过函数参数返回函数结果的办法。

(2)实验内容
编程实现顺序表下教材第二章定义的线性表的基本操作,并根据已经实现的基本操作,实现两个非递减有序的线性表的合并,注意,合并时,如果有重复的元素(一个表内部的重复元素和两个表之间的重复元素),请保留一个。

(3)实验要求

  • 求前驱是指,输入一个元素值(而不是位置),求该元素在顺序表中的直接前驱元素值。求后继是指:输入一个元素值(而不是位置),求该元素在顺序表中的直接后继元素值;
  • 为了方便修改数据元素的类型,请使用类型重定义,可以方便修改线性表中的数据元素的类型;
  • 大部分函数的返回结果应是函数执行是否成功的一种状态,执行成功了,才返回具体的结果值;
  • 对每个功能进行测试时,要求把不合法的情况也测试一下。具体见下面的测试用例;
  • 采用菜单形式对应各个操作,使其编成一个完整的小软件,参考界面如下。注意:程序运行过程中菜单不要做成刷屏的效果,测试过的数据不要清除,这样方便截图和查看。

(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),合并后的结果,请输出。

实验类型:验证性

实验的重难点:顺序表的定义和实现,销毁和清空的区别、 两个非递减有序表的去重合并

实验环境:TDM-GCC 4.9.2 64-bit

实验步骤及完成任务情况

一、设计思想

  1. 采用模板实现泛型编程,可创建任意数据类型的顺序表;
  2. 采用动态内存分配的方式管理顺序表的容量,在顺序表内存空间不够时通过expend()函数扩容;
  3. 体会顺序表插入删除时间复杂度都是 O ( n ) O(n) O(n)的特点

二、主要源代码

#include <iostream>
#define SEQUENCESIZE 1000
#define SEQUENCEINCREMENT 500
using std::cin;
using std::cout;
using std::endl;

template <typename T> class Sequence {
private:
	T* elem;
	int _length;
	int _capacity;
	void expand();
	
public:
	Sequence() {elem = NULL; _length = 0; }
	Sequence(T arr[], int size) 
	{init(); for (int i = 0; i < size; ++ i) elem[i] = arr[i]; _length = size; }
	~Sequence() {destroy(); }
	void init();
	void destroy();
	void clear() {_length = 0; }
	T operator[](int pos) {return elem[pos]; }
	bool isempty() const {return _length > 0 ? 0 : 1; }
	bool exist() const {return elem > 0 ? 1 : 0; }
	int getlength() const {return _length; }
	bool getelem(int pos, T& e) const 
	{if(pos > _length + 1 || pos < 1) return false; e = elem[pos-1]; return true; }
	int elemlocate(T const& e) const 
	{for(int i = 0; i < _length; ++ i) if(elem[i] == e) return i+1; return -1;}
	bool priorelem(T const& e, int& pos);
	bool nextelem(T const& e, int& pos);
	bool insert(T const& e, int pos);
	bool remove(T& e, int pos);
	void push(T const& e);
	T pop() {-- _length; return _length + 1; }
	void traverse() const 
	{for(int i = 0; i < _length; i ++) cout<<elem[i]<<' '; }
	void merge(Sequence<T>& Sa, Sequence<T>& Sb);
};

template <typename T> void Sequence<T>::init()
{
	elem = new T[SEQUENCESIZE];
	_capacity = SEQUENCESIZE; 
}

template <typename T> void Sequence<T>::destroy()
{
	if (!exist())	return;
	delete[] elem;
	elem = NULL;
	_length = 0;
	_capacity = 0;
}

template <typename T> void Sequence<T>::expand()
{
	T* newelem = new T[_capacity+SEQUENCEINCREMENT];
	for(int i = 0; i < _length; ++ i)	newelem[i] = elem[i];
	delete[] elem;
	elem = newelem;
}

template <typename T> bool Sequence<T>::priorelem(T const& e, int& pos)
{
	int i = elemlocate(e);
	if (i < 2 || i > _length)	return false;
	pos = i - 1;
	return true;
}

template <typename T> bool Sequence<T>::nextelem(T const& e, int& pos)
{
	int i = elemlocate(e);
	if (i < 1 || i > _length - 1)	return false;
	pos = i + 1;
	return true;
}

template <typename T> bool Sequence<T>::insert(T const& e, int pos) 
{
	if (pos < 1 || pos > _length + 1)	return false;
	if (_capacity < _length + 1)	expand();
	for(int j = _length - 1; j >= pos - 1; -- j) // 最开始写成j>i-1了,debug了好几个小时,血的教训 
		elem[j+1] = elem[j];
	elem[pos-1] = e;
	++ _length;
	return true;
}

template <typename T> bool Sequence<T>::remove(T& e, int pos)
{
	if(pos < 1 || pos > _length)	return false;
	e = elem[pos-1];
	for(int j = pos - 1; j < _length - 1; ++ j)
		elem[j] = elem[j+1];
	-- _length;
	return true;
} 

template <typename T> void Sequence<T>::push(T const& e)
{
	if (_capacity < _length + 1)	expand();
	elem[_length] = e;
	++ _length;
} 

template <typename T> void Sequence<T>::merge(Sequence<T>& Sa, Sequence<T>& Sb)
{
	int i = 0, j = 0, k = 0;
	while(i < Sa._length && j < Sb._length) {  //不能 <= ,否则会数组下标越界 
		if (Sa[i] < Sb[j])	elem[k++] = Sa[i++]; 
		else if (Sa[i] > Sb[j])	elem[k++] = Sb[j++];
		else if (Sa[i] == Sb[j++])	elem[k++] = Sa[i++]; // 去重 
	} 
	while (i < Sa._length)	elem[k++] = Sa[i++];
	while (j < Sb._length) elem[k++] = Sb[j++];
	_length = k; 
}

int main()
{
	cout<<"\n   基于顺序表的非递减有序表的合并\n\n";
	cout<<"1---初始化一个线性表\n";
	cout<<"2---销毁线性表\n";
	cout<<"3---清空线性表\n";
	cout<<"4---判断线性表是否为空\n";
	cout<<"5---求线性表长度\n";
	cout<<"6---获取线性表中指定位置的元素\n";
	cout<<"7---获取线性表元素的位置\n";
	cout<<"8---求前驱\n";
	cout<<"9---求后继\n";
	cout<<"10--在线性表指定位置插入元素\n";
	cout<<"11--删除线性表指定位置的元素\n";
	cout<<"12--显示线性表\n";
	cout<<"13--合并两个非递减有序线性表\n"; 
	cout<<"\n\t退出,输入一个负数!\n\n";
	Sequence<int> Se;
	while(true)
	{
		int myOption;
		cout<<"\n请输入操作序号:";
		cin>>myOption;
		switch(myOption){
			case 1:{
				if(Se.exist()){
					cout<<"初始化失败,顺序表已存在!\n";
					break; 
				}
				Se.init();
				cout<<"初始化成功!\n";
				break;
			}
			case 2:{
				if (!Se.exist()){
					cout<<"销毁失败,顺序表不存在\n";
					break; 
				}
				Se.destroy();
				cout<<"销毁成功!\n";
				break;
			} 
			case 3:{
				if (!Se.exist()){
					cout<<"清空失败,顺序表不存在\n";
					break; 
				}
				if (Se.isempty()) ; 
				else	Se.clear();
				cout<<"清空成功!\n"; 
				break;
			}
			case 4:{
				if (!Se.exist()){
					cout<<"判空失败,顺序表不存在\n";
					break; 
				}
				if (Se.isempty())	cout<<"顺序表为空!\n";
				else	cout<<"顺序表非空!\n"; 
				break;
			}
			case 5:{
				if (!Se.exist()){
					cout<<"请先创建顺序表!\n";
					break; 
				}
				cout<<"顺序表的长度是"<<Se.getlength()<<endl; 
				break;
			}
			case 6:{
				if (!Se.exist()){
					cout<<"顺序表不存在,请先创建顺序表!\n";
					break; 
				}
				if (Se.isempty()){
					cout<<"顺序表为空,请先插入元素!\n";
					break;
				}
				cout<<"请输入你要获取元素的位置:";
				int pos, e;
				cin>>pos;
				if (!Se.getelem(pos, e)) {
					cout<<"不存在该位置的元素\n";
					break;
				}
				cout<<"第"<<pos<<"位元素是 "<<e<<endl; 
				break;
			}
			case 7:{
				if (!Se.exist()){
					cout<<"顺序表不存在,请先创建顺序表!\n";
					break; 
				}
				if (Se.isempty()){
					cout<<"顺序表为空,请先插入元素!\n";
					break;
				}
				cout<<"请输入您要获取位置的元素:";
				int e;
				cin>>e;
				if (!Se.elemlocate(e)){
					cout<<"顺序表中不存在该元素!\n";
					break;
				}
				cout<<"元素"<<e<<"的位置是"<<Se.elemlocate(e)<<endl; 
				break;
			}
			case 8:{
				if (!Se.exist()){
					cout<<"顺序表不存在,请先创建顺序表!\n";
					break; 
				}
				if (Se.isempty()){
					cout<<"顺序表为空,请先插入元素!\n";
					break;
				}
				cout<<"请输入您要获取前驱的元素:";
				int pos, e;
				cin>>e;
				if (!Se.priorelem(e, pos)){
					cout<<"获取失败,该元素不存在或无前驱!";
					break; 
				}
				cout<<"元素"<<e<<"的前驱元素是"<<Se[pos-1]<<endl;
				break;
			}
			case 9:{
				if (!Se.exist()){
					cout<<"顺序表不存在,请先创建顺序表!\n";
					break; 
				}
				if (Se.isempty()){
					cout<<"顺序表为空,请先插入元素!\n";
					break;
				}
				cout<<"请输入您要获取后继的元素:";
				int pos, e;
				cin>>e;
				if (!Se.nextelem(e, pos)){
					cout<<"获取失败,该元素不存在或无后继!";
					break; 
				}
				cout<<"元素"<<e<<"的后继元素是"<<Se[pos-1]<<endl;
				break;
			}
			case 10:{
				if (!Se.exist()){
					cout<<"顺序表不存在,请先创建顺序表!\n";
					break; 
				}
				cout<<"请输入指定位置:";
				int pos;
				cin>>pos;
				cout<<"请输入想要插入的值:";
				int e;
				cin>>e;
				if (!Se.insert(e, pos)){
					cout<<"插入失败,请重新尝试!\n";
					break;
				}
				else	cout<<"插入完毕!\n";
				break;
			}
			case 11:{
				if (!Se.exist()){
					cout<<"顺序表不存在,请先创建顺序表!\n";
					break; 
				}
				if (Se.isempty()){
					cout<<"顺序表为空!\n";
					break;
				}
				cout<<"请输入你要删除的元素的位置:";
				int pos;
				cin>>pos;
				int e;
				if (!Se.remove(e, pos)){
					cout<<"删除失败,请重新尝试!\n";
					break;
				}
				else	cout<<"删除完毕!"<<"被删除的元素是"<<e<<endl;;
				break;
			}
			case 12:{
				if (!Se.exist()){
					cout<<"顺序表不存在,请先创建顺序表!\n";
					break; 
				}
				if (Se.isempty()){
					cout<<"顺序表为空!\n";
					break;
				}
				cout<<"顺序表的所有元素是:";
				Se.traverse();
				cout<<endl;
				break;
			} 
			case 13:{
				int a[5] = {17, 21, 39, 40, 56};
				int b[8] = {10, 20, 30, 40, 50, 60, 70, 80};
				Sequence<int> Sa(a, 5);
				Sequence<int> Sb(b, 8);
				cout<<"顺序表Sa的所有元素是:";
				Sa.traverse();
				cout<<endl;
				cout<<"顺序表Sb的所有元素是:";
				Sb.traverse();
				cout<<endl;
				Sequence<int> Sc;
				Sc.init();
				Sc.merge(Sa, Sb);
				cout<<"\n合并Sa和Sb为Sc";
				cout<<"顺序表Sa的所有元素是:";
				Sc.traverse();
				cout<<endl;
				break;
			}
		}
		if(myOption >13)	cout<<"\n请输入小于13的正整数\n\n";
		if(myOption < 0){
			cout<<"\n退出程序!\n";
			break;
		}
	} 
	return 0;
}

实验结果
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

  • 2
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值