- 创建线性表顺序存储类MyArrayList
目的:通过对线性表顺序存储类的创建和应用,增强面向对象程序设计和顺序表的理解与应用实践。
内容:
(1)MyArrayList存储空间的大小以及存储数据类型根据用户需求自行确定。
(2) 提供初始化数据功能(即创建该对象时可以通过指定数组将初始参数传入该对象)
(3)提供插入一个元素功能;
(4)提供删除一个元素功能;
(5)提供根据指定关键字排序功能;(默认升序,也能降序,提供用户自己选择方式。)
(6)提供根据指定关键字查找功能,查找结果返回该元素位置,-1表示查找失败。
(7)提供两个有序顺序表合并功能;
(8)提供根据指定关键字,返回指定第K大的元素位置;
(9)提供显示顺序表中各元素功能;
(提示:顺序表中元素可能是简单数据类型,也可能是复合数据类型:比如自定义结构体类型,所以有指定关键字一说。)
(9)给出各个功能的测试样例。
报告要求:
(1)仔细观察设计中的各种现象及出现的问题。分析产生各种现象的原因。寻找解决问题的办法。
(2)报告应至少包括带注释的程序清单、输出的结果及对各种现象的分析意见。
下面附上
SqList.h文件代码与cpp文件代码:
注意:为了避免link2019等错误的出现,我们将类的头文件与实现文件全部写在了头文件。
以下代码在VS2019上完美运行!
运行截图:
#pragma once
#include <iostream>
using namespace std;
constexpr auto MAXSIZE = 500; //最大存储容量,便于批量操作
typedef int ElemType; //定义数据类型,便于批量操作
template <class T>
class SqList
{
public:
SqList(); //无参构造函数
SqList(T elems[], int n); //有参构造器,便于快速创建指定元素数量的线性表
~SqList(); //C //析构函数
void CreatList(); //新建一个顺序表
void UnionList1(SqList L1, SqList L2);//合并顺序表,不去重
void UnionList2(SqList L1, SqList L2);//合并顺序表,去重
void LocateElem(ElemType e);//L1 //按元素查找:成功则返回元素的序号(从1开始),失败则返回-1
int ListLength();//C //顺序表的长度
int GetElem(int i, T& e);//L1 //查找第i个位置的元素//按位置查找
void ListInsert(int i,T e);//L //在第i个位置插入元素
void ListDelete(int i, T& e);//L 1 //删除第i个位置的元素
void ListEmpty();//L1 //判空
void clearList();//C //清空顺序表
void display(); //C 1 //显示当前的顺序表
void Sort_Lead(); //排序选择引导函数
void QS( T E[],int m, int n); //快速排序(升序)
void R_Kth(int k);//C //返回第K大元素的值
void QST(T s[], int l, int r);//快速排序(降序)
T data[MAXSIZE];//由于在使用插入删除等功能时,需时时用到此数据域,故定为public
//下标从0开始,但是自然计数就是1,第1个元素其实就是下标为0的元素
private:
int length;
//所有的查找、删除、添加等功能全部基于length的大小,如果length不适当则操作无法进行
};
template<class T>
SqList<T>::SqList()//初始化
{
length = 0;
}
template<class T>
SqList<T>::SqList(T elems[], int n)//有参构造器,功能同CreateList
{
if (n > MAXSIZE)
{
cout << "传入的顺序表长度超出最大范围,只接收了前" << MAXSIZE << "个元素" << endl;
length = MAXSIZE;
}
else
length = n;
for (int i = 0; i < length; i++)
data[i] = elems[i];//将传入的T类型数组在有效长度范围内逐个赋值给data域
}
template<class T>
SqList<T>::~SqList()
{
clearList();
}
template<class T>
void SqList<T>::CreatList()
{
p3:
cout << "插入多少个元素(0-"<<MAXSIZE<<")?" << endl;
cin >> length;
cout << "进行初始化..." << endl;
if (length<0 || length>MAXSIZE)
{
length = 0;
cout << "创建失败,重新输入!" << endl;
goto p3;
}
int w;
p4:
cout << "请选择你想要创建的方式:1.数组自动赋值(升序赋值) 2.手动逐个输入" << endl;
cin >> w;
switch (w) {
case 1:
for (int i = 1; i <= length; i++)
{
data[i - 1] = i;
}
cout << "创建完成!" << endl;
break;
case 2:
for (int i = 1; i <= length; i++)
{
cout<<"请输入顺序线性表的第"<<i<<"个元素:";
cin >> data[i - 1];
}
cout << "创建完成!" << endl;
break;
default:
cout << "输入有误,请重新输入!" << endl;
goto p4;
break;
}
}
template<class T>
void SqList<T>::LocateElem(ElemType e)//成功则返回元素的序号(从1开始),失败则返回-1
{
int n = 0;
ElemType INST[MAXSIZE];
for (int i = 0; i < length; i++) {
if (data[i] == e)
{
INST[n] = i;
n++;
}
}
if (!n > 0)
cout << "查找失败!" << endl;
else
{
cout << "所查找元素元素共在线性表中发现" << n << "个" << endl
<< "在位置 ";
for (int j = 0; j < n; j++) {
cout << INST[j] +1<< " 、";//因为自然计数从1开始,而数组下标从0开始
}
cout << "找到" << e << endl;
}
}
template<class T>
void SqList<T>::UnionList1(SqList L1, SqList L2)
{
int i, j;
if ((L1.ListLength() == 0 && L2.ListLength() == 0))
{
cout << "双表为空!合并操作无效!" << endl;
return;
}
else if (L1.ListLength() + L2.ListLength() > MAXSIZE)
{
cout << "数据过大,合并后,顺序表的长度超过最大范围" << endl;
return;
}
for (i = 0; i < L1.length; i++)
{
data[i] = L1.data[i];
}
for (j = 0; j < L2.length; j++)
{
data[i] = L2.data[j];
i++;
}
length = i;
cout << "合并完成!" << endl;
}
template<class T>
inline void SqList<T>::UnionList2(SqList L1, SqList L2)
{
UnionList1(L1, L2);
ElemType elem;
cout << "开始去重" << endl;
QS(data, 0, length-1);
for (int i = 0; i < length-1; i++) {
if (data[i] == data[i + 1]) {
ListDelete(i + 1, elem);
}
}
}
template<class T>
int SqList<T>::ListLength()
{
return length;
}
template<class T>
int SqList<T>::GetElem(int i, T& e)
{
if (length == 0 || i<1 || i>length)
return -1;
e = data[i - 1];
cout << "已找到!位置" << i << "是" << e << endl;
return 0;
}
template<class T>
void SqList<T>::ListInsert(int i, T e)
{
if (length == MAXSIZE || i<1 || i>length + 1) {
//线性表满,或者i的范围不在合理范围内时返回错误
cout << "线性表满,或者i的范围不在合理范围内!" << endl;
return;//理论上我们认可空表的插入,所以不设置专门提示
}
if (i <= length) //不在表尾
{
//插入位置的后续元素后移一位
for (int k = length - 1; k >= i - 1; k--)
data[k + 1] = data[k]; // 倒序挪动位置,避免覆盖问题
}
data[i - 1] = e; //插入元素
length++;
cout << "插入成功!" << endl;
}
template<class T>
void SqList<T>::ListDelete(int i, T& e)
{
if (length == 0 || i<1 || i>length) {//线性表空,或者i的范围不在合理范围内时返回错误
cout << "线性表空,或者i的范围不在合理范围内!" << endl;
return;
}
e = data[i - 1]; //取出元素
if (i <= length) //不在表尾
{ //插入位置的后续元素前移一位
for (int k = i - 1; k < length - 1; k++)
data[k] = data[k + 1]; // 倒序挪动位置,避免覆盖问题
}
length--;
cout << e<<"删除成功!" << endl;
}
template<class T>
void SqList<T>::ListEmpty()
{
if (length == 0)
cout << "线性表为空!" << endl;
cout << "线性表不为空!" << endl;
}
template<class T>
void SqList<T>::clearList()
{
length = 0;
}
template<class T>
void SqList<T>::display()
{
for (int i = 0; i < length; i++)
cout << data[i] << " ";
cout << endl;
}
template<class T>
inline void SqList<T>::Sort_Lead()
{
p5:
cout << "请输入你的选择:1.升序2.降序";
int k;
cin >> k;
switch (k) {
case 1:QS(data, 0, length - 1);
cout << "排序完成,新顺序是:";
display();
break;
case 2:
QST(data, 0, length - 1);
cout << "排序完成,新顺序是:";
display();
break;
default:
cout << "输入有误,请重新选择!";
goto p5;
break;
}
}
template<class T>
void SqList<T>::QS(T s[], int l, int r)
{
if (l < r)
{
int i = l, j = r;
T x = s[l]; //自定类型参数
while (i < j)
{
while (i < j && s[j] >= x) // 从右向左找第一个小于x的数
j--;
if (i < j)
s[i++] = s[j];
while (i < j && s[i] < x) // 从左向右找第一个大于等于x的数
i++;
if (i < j)
s[j--] = s[i];
}
s[i] = x;
QS(s, l, i - 1); // 递归调用
QS(s, i + 1, r);
}
}
template<class T>
void SqList<T>::R_Kth(int k)
{
cout << "将会对data域进行排序..." << endl;
QS(data, 0, length - 1);
cout << "第"<<k<<"大元素是:" << data[length-k] << endl;
}
template<class T>
inline void SqList<T>::QST(T s[], int l, int r)
{
if (l < r)
{
int i = l, j = r;
T x = s[l];
while (i < j)
{
while (i < j && s[j] <= x) // 从右向左找第一个大于x的数
j--;
if (i < j)
s[i++] = s[j];
while (i < j && s[i] > x) // 从左向右找第一个小于等于x的数
i++;
if (i < j)
s[j--] = s[i];
}
s[i] = x;
QST(s, l, i - 1); // 递归调用
QST(s, i + 1, r);
}
}
以下为CPP文件代码:
#include <iostream>
#include<string>
#include<windows.h>
#include "SqList.h"
using namespace std;
int main()
{
SqList<ElemType> list;//使用自定类型可以实现批量切换
ElemType elem;
ElemType elems1[9] = { 5,11,23,32,4,27,6,7,777 };
ElemType elems2[10] = { 5,61,79,8,9,10,11,1,12,225 };
SqList<ElemType> list1(elems1, 9);
SqList<ElemType> list2(elems2, 10);//均是有参构造器的调用
SqList<ElemType> list3;
//string elems3[7] = { "while","if","else","do","for","switch","case" };
//SqList<string> list4(elems3, 7);
//list4.display();
//list4.Sort_Lead();
p1:
cout << "请选择你要操作的选项:" << endl << endl;
cout << "\t1.初始化线性表" <<"\t2.删除元素" << "\t3.插入元素"<<endl << endl;
cout << "\t4.按元素查找"<<"\t5.按位置查找" << "\t6.输出线性表"<<endl << endl;
cout << "\t7.获取当前表长" <<"\t8.清空顺序表"<< "\t9.快速排序线性表(升序/降序)"<<endl << endl;
cout << "\t9.快速排序线性表(升序/降序)" <<"\t10.返回第K大元素的值"<< endl << endl;
cout << "\t11.合并顺序表(另起:不去重/去重)" <<"\t12.退出"<< endl << endl;
int k;
ElemType ins;
cin >> k;
system("CLS");
switch (k)
{
case 1:
list.CreatList();
break;
case 2:
cout << "请输入要删除元素的序号:";
cin >> k;
list.ListDelete(k, elem);
break;
case 3:
cout << "请输入要插入的位置和要插入的元素:";
cin >> k>>ins;
list.ListInsert(k, ins);
break;
case 4:
cout << "请输入要查找的元素值:";
cin >> ins;
list.LocateElem(ins);
break;
case 5:
cout << "请输入要查找的位置序号:";
cin >> k;
k=list.GetElem(k, elem);
if(k==-1)
cout << "查找失败!" << endl;
break;
case 6:
list.display();
break;
case 7:
cout << "表长为:" << list.ListLength() << endl;
break;
case 8:
list.clearList();
cout << "清空完成!" << endl;
break;
case 9:
list.Sort_Lead();
break;
case 10:
cout << "请输入k值:";
cin >> k;
list.R_Kth(k);
break;
case 11:
system("CLS");
cout << "此功能不影响之前所创建的线性表!" << endl;
cout << "稍等,正在对线性表进行有参构造..." << endl;
Sleep(3000);
cout << "合并前的两个表为:" << endl;
list1.display();
list2.display();
p2:
cout << "请选择合并方式:1.不去重 2.去重" << endl;
cin >> k;
switch (k)
{
case 1:
list3.UnionList1(list1,list2);
cout << "该顺序表尚未有序化,不能保证数据有序性,是否进行有序化?(键入:Y / N )" << endl;
char C;
cin >> C;
if (C == 'Y' || C == 'y')
list3.Sort_Lead();
break;
case 2:
cout << "去重后的结果时有序数列!" << endl;
list3.UnionList2(list1, list2);
break;
default:
cout << "输入有误,请重新输入!" << endl;
goto p2;
break;
}
cout << "该表的长度为:" << list3.ListLength() << endl;
list3.display();
break;
//除此之外的输入全作无效处理
case 12:
cout << "执行退出" << endl;
return 0;
default:
cout << "输入有误!请重新输入!" << endl;
goto p1;
break;
}
goto p1;
return 0;
}