姓名: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
实验步骤及完成任务情况:
一、设计思想
- 采用模板实现泛型编程,可创建任意数据类型的顺序表;
- 采用动态内存分配的方式管理顺序表的容量,在顺序表内存空间不够时通过expend()函数扩容;
- 体会顺序表插入删除时间复杂度都是
#card=math&code=O%28n%29&id=I9Snm)的特点
二、主要源代码
#include <iostream>#define SEQUENCESIZE 1000#define SEQUENCEINCREMENT 500using 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;}
实验结果:


