文章目录

  • 一、写在最前面
  • 二、题目要求
  • 三、项目截图及录屏
  • 四、具体功能的实现
    • 4.1 动态演示功能
    • 4.2 对象排序功能
    • 4.3 单步回退功能
    • 4.4 二级下拉框的实现
    • 4.5 界面美化的实现
  • 五、不足和总结

一、写在最前面

在我的项目中,部分借鉴了往届学长的一个项目,在这里附上这个项目的链接,真的特别感谢

另外,本博客在发布之前也得到了学长的许可

基于QT实现九大排序的动态演示

二、题目要求

排序:设计一个负责排序的程序包,实现多种排序算法,至少包括插入排序、冒泡排序和快速排序算法。要求:可以对任何简单类型和任意对象进行排序;可以支持升序、降序、字典排序等多种顺序要求;可以随意增加排序算法和顺序要求,保证其他程序代码不修改;(选作,不属于基本要求)演示排序过程,演示速度可调整,可以单步、可以暂停、可以回退。

总结一下这个项目所需要的几个功能

  1. 实现多种排序的柱状图演示,要求实现升序排序,降序排序,排序速度可调整,可暂停
  2. 实现对象类型的排序,可支持升序和降序,可按不同对象的不同属性排序
  3. 实现多种排序的单步演示和回退

三、项目截图及录屏

主界面

录屏放在这里

面向对象实验录屏——排序

四、具体功能的实现

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(); // 创建chartchart->setTitle(tr("冒泡排序动态演示"));// 不设置动画效果,当数据较大时动画会出现卡顿、降低运行速度,并且显示效果不好chart->setAnimationOptions(QChart::NoAnimation);ui->chartView->setChart(chart); // 为chartViewBubble设置chartui->chartView->setRenderHint(QPainter::Antialiasing);
}
void MainWindow::buildBarChartBubble()
{QChart *chart =ui->chartView->chart(); // 获取chartViewBubble关联的chartQBarSet *barSet = new QBarSet(tr("随机数")); // 创建一个数据集QBarSetbuildBarCharts(chart, barSet); // 构建chartbarsets = 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(); // 创建一个柱状图序列QBarSeriesseries->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_OBJECTpublic: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 = falsewhile (!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;//用于呈现结果的TextEditQTextEdit* 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->at(index);temp2 = p->at(scan);p->replace(index,temp2);p->replace(scan,temp1);}}}}//将排序后的结果呈现到文本框中this->ObjectResult->append("Person类对象按Age属性排序后:");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("");}
}

4.3 单步回退功能

在本次面向对象实验中,单步和回退功能的实现思路是这样的
首先对QList进行相应的排序(比如冒泡排序),将排序每一步的QList变化都记录下来,保存在QVector<QList<int>>容器中,之后当用户选择前进或后退时,会指定一个索引,这个索引会锁定QVector的索引,找到对应的QList,之后再将QList添加到QBarSet中,再呈现到QChartView中

前进和回退按钮对应的槽函数

//前进
void MainWindow::front()
{allData.clear();//判断用户选择了哪个排序//用户选择了冒泡排序if(QString::compare(ui->sortTypeStep->currentText(),"冒泡排序") == 0){index++;bubbleSortStep(dataListStep,dataListStep.length());iniShowStepBar();buildShowStepBar();}//用户选择了插入排序else if(QString::compare(ui->sortTypeStep->currentText(),"插入排序") == 0){index++;insertSortStep(dataListStep,dataListStep.length());iniShowStepBar();buildShowStepBar();}//用户选择了快速排序else if(QString::compare(ui->sortTypeStep->currentText(),"快速排序") == 0){index++;quickSortStep(dataListStep,dataListStep.length());iniShowStepBar();buildShowStepBar();}//用户选择了选择排序else if(QString::compare(ui->sortTypeStep->currentText(),"选择排序") == 0){index++;selectSortStep(dataListStep,dataListStep.length());iniShowStepBar();buildShowStepBar();}
}

以冒泡排序为例,展示将排序的每一步添加到QVector<QList<int>>容器中
这里的allData就是这个容器

//单步冒泡排序
void MainWindow::bubbleSortStep(QList<int> dataList, int dataNum)
{allData.append(dataList);// 冒泡排序循环for (int i = dataNum; i > 1; i--){for (int j = 0; j < i-1; j++){//upDown = 0 为升序排序if(QString::compare(ui->upDownStep->currentText(),"升序排序") == 0){if (dataList.at(j) > dataList.at(j+1)){// 将两个bar的值交换int temp1 = dataList.at(j);int temp2 = dataList.at(j+1);dataList.replace(j, temp2);dataList.replace(j+1, temp1);}allData.append(dataList);}//upDown = 1 为降序排序else if(QString::compare(ui->upDownStep->currentText(),"降序排序") == 0){if (dataList.at(j) < dataList.at(j+1)){// 将两个bar的值交换int temp1 = dataList.at(j);int temp2 = dataList.at(j+1);dataList.replace(j, temp2);dataList.replace(j+1, temp1);}allData.append(dataList);}}}
}

将排序的一步显示到柱状图上

void MainWindow::showStepBar(QChart *chart, QVector<QList<int>> allData, int index, QBarSet* barSet)
{if(index < 0){alertError("不能再回退了");index++;return;}else if(index >= allData.length()){alertError("不能再前进了");index--;return;}chart->removeAllSeries(); // 删除所有序列chart->removeAxis(chart->axisX()); // 删除坐标轴chart->removeAxis(chart->axisY()); // 删除坐标轴// 从dataList中获取数据for (int i = 0; i < n; i++){barSet->append(allData.at(index).at(i));}QBarSeries *series = new QBarSeries(); // 创建一个柱状图序列QBarSeriesseries->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 二级下拉框的实现

当选择Person类时,二级下拉框的属性为name和age
当选择Student类时,二级下拉框的属性为name和score

具体的图如下

通过绑定槽函数的方法,使用switch语句,通过第一个下拉框的值改变第二个下拉框的值

//实现二级下拉框
void MainWindow::on_ObjectType_currentIndexChanged(const QString &arg1)
{switch (ui->ObjectType->currentIndex()){//第一个下拉框选中Personcase 0:ui->TypeName->clear();ui->TypeName->insertItem(0,"name");ui->TypeName->insertItem(1,"age");break;//第一个下拉框选中Studentcase 1:ui->TypeName->clear();ui->TypeName->insertItem(0,"name");ui->TypeName->insertItem(1,"score");break;}
}

4.5 界面美化的实现

这一部分内容和我之前的数据结构课设是一样的,这里就不再赘述了,可以参考我的数据结构课设的文章,里面有具体的描述

山东大学软件学院大二下数据结构课程设计—排序算法的性能分析

五、不足和总结

在这次面向对象的实验中,由于题目要求有些模糊,再加上每个人的理解不同,不同人做出来的效果很不一样。总体来说,由于有了之前数据结构课设的经验,这个项目显得容易一些。最后实现出来的效果个人感觉基本满意,但还有一些不足的地方,比如

  1. 对象排序仅支持两种对象的排序,并且直接显示结果,没有呈现排序过程,显得很单薄
  2. 单步和回退没有和动态演示结合在一起,单独弄了一个单步演示区
  3. 单步回退部分在快速排序部分依然有小bug尚未解决,其它的都正常
  4. 功能还不够丰富,可以再拓展字典排序或其它的功能

山东大学软件学院面向对象实验——排序相关推荐

  1. 山东大学软件学院数据结构实验报告及实验代码(全)

    实验大纲: https://pan.baidu.com/s/16X4z9vbJzR7D-UlTyMLjgg 提取码:g29t 内容为2019级的实验大纲,每年基本不变.平台具有查重功能,所以建议大家自 ...

  2. 山东大学软件学院数据库实验1-9

    SDU 数据库系统实验 实验一 1-1创建test1_student表 1-2创建test1_course表 1-3创建teset1_student_course表 1-4表test1_student ...

  3. 山东大学软件学院 - 面向对象开发技术 - 期末复习知识点总结

    前言 这篇文章里的总结大部分来自老师的PPT,然后还有一些自己对概念的补充(也就是网上扒的很多知识讲解和自己对于一些概念的理解),希望能对后面的学弟学妹们在复习的时候有点帮助φ(゜▽゜*)♪ 这里是总 ...

  4. 山东大学软件学院操作系统实验1(关于环境)

    目录 1.写在前面 2.关于环境 3.关于函数和操作 4.具体代码 1.写在前面 2023年山东大学操作系统实验,第一次实验肥肠简单,压缩以后代码仅仅几行罢了 实验要求只是:创建一个父进程,然后创建子 ...

  5. 山东大学软件学院数据库系统实验五

    文章目录 一.实验时间 二.实验题目 一.实验时间 2021年5月4日星期二,第10周 二.实验题目 1. 在学生表pub.student中统计名字(姓名的第一位是姓氏,其余为名字,不考虑复姓)的使用 ...

  6. 山东大学软件学院面向对象编程导论期末考试回忆版

    文章目录 一.考试时间 二.考试范围 三.考试题目 3.1 简答题(4*5 = 20分) 3.2 设计题 (10+20+10+20 = 60分) 3.3 综合题(20分) 四.后记 一.考试时间 20 ...

  7. 山东大学软件学院数据挖掘实验五(2)的坑

    一. 实验目的   掌握数据导入Hive表的方式   理解三种数据导入Hive表的原理 二. 实验内容   1.启动Hadoop和Hive服务并创建数据表   2.将Hive表中的数据导出 三. 实验 ...

  8. 山东大学软件学院数据库系统实验四

    文章目录 一.实验时间 二.实验题目 一.实验时间 2021年4月25日星期六,第8周,补周二的课 二.实验题目 1.将pub用户下表student_41及数据复制到主用户的表test4_01中,使用 ...

  9. 山东大学软件学院数据库系统实验八、九

    文章目录 一.实验时间 二.实验题目 一.实验时间 2021年5月25日星期二,13周 二.实验题目 实验八.数据修改的提交和回退.实体授权 一. 实验内容 启动两个不同浏览器,firefox登录主账 ...

最新文章

  1. mono+jexus 部署之CompilationException
  2. 未解决oracle错误12505、01034、27101
  3. ORACLE+RAC+ASM环境下添加redo日志组
  4. Cs231n课堂内容记录-Lecture2-Part2 线性分类
  5. java 输入流关闭顺序_JAVA的节点流和处理流以及流的关闭顺序
  6. 浏览器崩溃_字节跳动程序员28岁身价上亿,财务自由宣布退休;微软最新系统再迎“喜报”:更多用户的浏览器开始崩溃...
  7. 求职招聘系统中的观察者模式的应用和分析
  8. 移动端使用的WebKit私有属性(转)
  9. vue对象属性为null_如何避免在Vue中使用null作为class的空值
  10. 仿QQ音乐(HTML+CSS)
  11. 如何下载河南省卫星地图高清版大图
  12. 概率论的V=max{X,Y},U=min{X,Y},W=X+Y的求解分布律解法——笔记
  13. 小成开发日记----python爬虫利用selenium实现无限刷不背单词app的酷币
  14. Element组件--Upload文件/图片上传
  15. Java递归求全排列详解
  16. Linux常见的压缩工具
  17. JSP设置Excel表格换行_Excel表格技巧—如何调整工作表打印页面设置
  18. 物联网协议之一:MQTT协议和kafka
  19. 二项分布均值,方差推导
  20. 一步步教你新电脑如何分区教程

热门文章

  1. Java面向事件编程_Java面向事件编程
  2. 揭秘黑暗力量:AMD黑盒5400处理器详测(AMDCPU超频)
  3. 中关村软件园机房项目进度汇报
  4. KindEditor插件的使用(一招教你搞定)
  5. 【评职好刊】国自然新动态?中科院2区TOP正刊,一篇顶三篇
  6. mac安装ios应用程序_如何在Mac上安装应用程序:您需要知道的一切
  7. html重复复制粘贴,cad使用复制粘贴的时候弹出忽略块的重复定义怎么解决
  8. 雷军眼中的下一个风口,为什么是它?
  9. Excel导入导出源码分析
  10. 工作日志-Opyrator进展