山东大学软件学院面向对象实验——排序
Posted 叶卡捷琳堡
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了山东大学软件学院面向对象实验——排序相关的知识,希望对你有一定的参考价值。
一、写在最前面
在我的项目中,部分借鉴了往届学长的一个项目,在这里附上这个项目的链接,真的特别感谢
另外,本博客在发布之前也得到了学长的许可
二、题目要求
排序:设计一个负责排序的程序包,实现多种排序算法,至少包括插入排序、冒泡排序和快速排序算法。要求:可以对任何简单类型和任意对象进行排序;可以支持升序、降序、字典排序等多种顺序要求;可以随意增加排序算法和顺序要求,保证其他程序代码不修改;(选作,不属于基本要求)演示排序过程,演示速度可调整,可以单步、可以暂停、可以回退。
总结一下这个项目所需要的几个功能
- 实现多种排序的柱状图演示,要求实现升序排序,降序排序,排序速度可调整,可暂停
- 实现对象类型的排序,可支持升序和降序,可按不同对象的不同属性排序
- 实现多种排序的单步演示和回退
三、项目截图及录屏
主界面
录屏放在这里
面向对象实验录屏——排序
四、具体功能的实现
4.1 动态演示功能
4.4.1 显示柱状图的功能
首先,要实现排序,需要有排序的数。在界面上需要输入要排序的数的最大值,以及排序的数量,之后随机生成随机数,将随机数添加到QList里,之后再将QList里的数添加到QBarSet中,之后将QBarSet呈现到QChartView中。
实现显示柱状图总共调用了4个方法,具体的代码如下:
代码执行顺序为:start()->iniBarChartBubble()->buildBarChartBubble()->buildBarCharts()
void MainWindow::start()
{
//获取最大值
max = ui->max->text().toInt();
//获取数量
n = ui->n->text().toInt();
//如果用户输入为空,就弹出提示对话框
if(QString::compare(ui->n->text(),"") == 0 || QString::compare(ui->max->text(),"") == 0)
{
alertError("您未指定初始数据,请重新输入!");
return;
}
//判断是否为纯数字,如果不是,就弹出提示对话框
if(!isNumber(ui->max->text()) || !isNumber(ui->n->text()))
{
alertError("您输入的不是纯数字,请重新输入!");
return;
}
//初始化要排序的数组
//清空原有的数据
dataList.clear();
srand((unsigned)time(NULL));
for(int i = 0;i < n;i++)
{
int temp = rand() % (max + 1);
dataList.append(temp);
}
//判断用户选择了哪个排序
//用户选择了冒泡排序
if(QString::compare(ui->sortType->currentText(),"冒泡排序") == 0)
{
iniBarChartBubble();
buildBarChartBubble();
}
//用户选择了插入排序
else if(QString::compare(ui->sortType->currentText(),"插入排序") == 0)
{
iniBarChartInsert();
buildBarChartInsert();
}
//用户选择了快速排序
else if(QString::compare(ui->sortType->currentText(),"快速排序") == 0)
{
iniBarChartQuick();
buildBarChartQuick();
}
//用户选择了选择排序
else if(QString::compare(ui->sortType->currentText(),"选择排序") == 0)
{
iniBarChartSelect();
buildBarChartSelect();
}
}
void MainWindow::iniBarChartBubble()
{
QChart *chart = new QChart(); // 创建chart
chart->setTitle(tr("冒泡排序动态演示"));
// 不设置动画效果,当数据较大时动画会出现卡顿、降低运行速度,并且显示效果不好
chart->setAnimationOptions(QChart::NoAnimation);
ui->chartView->setChart(chart); // 为chartViewBubble设置chart
ui->chartView->setRenderHint(QPainter::Antialiasing);
}
void MainWindow::buildBarChartBubble()
{
QChart *chart =ui->chartView->chart(); // 获取chartViewBubble关联的chart
QBarSet *barSet = new QBarSet(tr("随机数")); // 创建一个数据集QBarSet
buildBarCharts(chart, barSet); // 构建chart
barsets = barSet;
}
//排序算法构造柱状图的最后一步
void MainWindow::buildBarCharts(QChart *chart, QBarSet *barSet)
{
chart->removeAllSeries(); // 删除所有序列
chart->removeAxis(chart->axisX()); // 删除坐标轴
chart->removeAxis(chart->axisY()); // 删除坐标轴
for (int i = 0; i < n; i++) // 从dataList中获取数据
barSet->append(dataList.at(i));
QBarSeries *series = new QBarSeries(); // 创建一个柱状图序列QBarSeries
series->append(barSet); // 添加数据集
chart->addSeries(series); // 添加柱状图序列
// 设置横坐标
QStringList categories;
for (int i = 1; i <= 5; i++)
categories << QString::number(i);
QBarCategoryAxis *axisX = new QBarCategoryAxis();
axisX->setRange(categories.at(0), categories.at(4)); // 这是坐标轴范围
axisX->setTitleText("位置");
chart->setAxisX(axisX, series); // 设置横坐标
int minNum = 0;
int maxNum = max;
// 设置纵坐标
QValueAxis *axisY = new QValueAxis;
axisY->setRange(minNum, maxNum);
axisY->setTitleText("数值");
axisY->setTickCount(11);
chart->setAxisY(axisY, series);
//设置暗黑背景
chart->setTheme(QChart::QChart::ChartThemeDark);
chart->legend()->setVisible(true); //显示图例
chart->legend()->setAlignment(Qt::AlignBottom); //图例显示在下方
}
4.4.2 动态排序和排序暂停功能
为了实现动态排序,我使用了QBarSet中的replace方法,这个方法可以重置柱状图的内容。此外,为了实现排序暂停的功能,我专门设置了一个bool变量,用于控制是否执行for循环。外层while循环一直运行,但for循环的运行取决于是否处于暂停状态
在动态演示中,所有的排序算法都继承了QThread类,并重写run方法,以实现多线程的排序
下面的代码演示的是冒泡排序类的头文件和源文件
冒泡排序头文件
class BubbleSortThread: public QThread
{
Q_OBJECT
public:
BubbleSortThread(QBarSet *barSet);
BubbleSortThread();
void beginThread(); // 开始线程
void pauseThread(); // 暂停线程
int sleepTime;// 排序速度
int upDown;// 排序类型:升序或降序
protected:
void run() override; // 线程任务
private:
QBarSet *barSet; // 柱状图数据
bool paused = true; // 暂停
bool stop = false; // 停止
int dataNum; // barSet->count() 数据数量
};
冒泡排序源文件
//冒泡排序
BubbleSortThread::BubbleSortThread(QBarSet *barSet)
{
this->barSet = barSet;
dataNum = barSet->count();
}
BubbleSortThread::BubbleSortThread()
{
}
void BubbleSortThread::beginThread()
{
paused = false;
}
void BubbleSortThread::pauseThread()
{
paused = true;
}
void BubbleSortThread::run()
{
stop = false; // 启动线程时令 m_stop = false
while (!stop) // 事件主循环
{
// 冒泡排序循环
for (int i = dataNum; i > 1 && !paused && !stop; i--)
{
for (int j = 0; j < i-1 && !paused && !stop; j++)
{
//upDown = 0 为升序排序
if(upDown == 0)
{
if (barSet->at(j) > barSet->at(j+1))
{
// 将两个bar的值交换
int temp1 = barSet->at(j);
int temp2 = barSet->at(j+1);
barSet->replace(j, temp2);
barSet->replace(j+1, temp1);
}
}
//upDown = 1 为降序排序
else if(upDown == 1)
{
if (barSet->at(j) < barSet->at(j+1))
{
// 将两个bar的值交换
int temp1 = barSet->at(j);
int temp2 = barSet->at(j+1);
barSet->replace(j, temp2);
barSet->replace(j+1, temp1);
}
}
msleep(sleepTime); // 停留sleepTimes
}
}
}
quit();
}
4.2 对象排序功能
在对象排序中,我一共准备了两种类型的对象,一个是Person对象,另一个是Student对象,为了演示方便,Person和Student的name,age和score都是随机生成的,不需要让用户再次输入了。age和score由随机数产生,姓名存放在一个数组中,数组的索引随机生成,因此可以给定随机的姓名
此外,还准备了一个专门的ObjectSort类,专门用于对象排序,由于本次实验使用的是C++Qt,在Qt中不推荐使用对象数组,而推荐使用QVector容器进行排序,所以我将所有对象放入QVector容器中,使用泛型技术,进行排序
排序同样支持升序排序和降序排序
下面是具体的Person类,Student类,ObjectSort类的头文件及源文件
头文件
//**********************待排序的Person类******************
class Person
{
public:
Person();
Person(QString name, int age);
//姓名
QString name;
//年龄
int age;
};
//**********************待排序的Student类******************
class Student
{
public:
Student();
Student(QString name, int score);
//姓名
QString name;
//分数
int score;
};
//**********************为对象排序准备的类******************
class ObjectSort
{
public:
ObjectSort();
//保存名字的数组
QVector<QString> nameSet;
//用于呈现结果的TextEdit
QTextEdit* ObjectResult;
//判断升序or降序,0为升序,1为降序
int sortType;
//按名字对Person数组排序
void sortPersonByName(QVector<Person>* p);
//按年龄对Person数组排序
void sortPersonByAge(QVector<Person>* p);
//按名字对学生排序
void sortStudentByName(QVector<Student>* s);
//按年龄对学生排序
void sortStudentByScore(QVector<Student>* s);
//打印输出所有的名字
void printAllNames();
};
源文件
按name属性进行排序
void ObjectSort::sortPersonByName(QVector<Person>* p)
{
//使用选择排序,按Person的名字排序
for(int index = 0;index < p->length();index++)
{
Person temp1;
Person temp2;
for(int scan = index + 1;scan < p->length();scan++)
{
//升序排序
if(sortType == 0)
{
//使用大小写不敏感方式匹配
if(QString::compare(p->at(index).name,p->at(scan).name,Qt::CaseInsensitive) > 0)
{
temp1 = p->at(index);
temp2 = p->at(scan);
p->replace(index,temp2);
p->replace(scan,temp1);
}
}
else if(sortType == 1)
{
//使用大小写不敏感方式匹配
if(QString::compare(p->at(index).name,p->at(scan).name,Qt::CaseInsensitive) < 0)
{
temp1 = p->at(index);
temp2 = p->at(scan);
p->replace(index,temp2);
p->replace(scan,temp1);
}
}
}
}
//将排序后的结果呈现到文本框中
this->ObjectResult->append("Person类对象按Name属性排序后:");
this->ObjectResult->append("");
for(int index = 0;index < p->length();index++)
{
this->ObjectResult->insertPlainText("name = ");
this->ObjectResult->insertPlainText(p->at(index).name);
this->ObjectResult->insertPlainText(", age = ");
this->ObjectResult->insertPlainText(QString::number(p->at(index).age));
//换行
this->ObjectResult->append("");
}
}
按age属性进行排序
void ObjectSort::sortPersonByAge(QVector<Person>* p)
{
//使用选择排序,按Person的年龄排序
for(int index = 0;index < p->length();index++)
{
Person temp1;
Person temp2;
for(int scan = index + 1;scan < p->length();scan++)
{
//升序排序
if(this->sortType == 0)
{
if(p->at(index).age > p->at(scan).age)
{
temp1 = p->at(index);
temp2 = p->at(scan);
p->replace(index,temp2);
p->replace(scan,temp1);
}
}
else if(sortType == 1)
{
if(p->at(index).age < p->at(scan).age)
{
temp1 = p面向对象方法及软件工程实验二