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

Posted 叶卡捷琳堡

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了山东大学软件学院面向对象实验——排序相关的知识,希望对你有一定的参考价值。

一、写在最前面

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

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

基于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(); // 创建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面向对象方法及软件工程实验二

2018-2019-2 20175308实验二《面向对象程序设计》实验报告

项目架构——面向对象与软件工程实验五

VSCode自定义代码片段——JS中的面向对象编程

程序设计实践报告

VSCode自定义代码片段9——JS中的面向对象编程