在计算机科学与数学中,一个排序算法(英语:Sorting algorithm)是一种能将一串资料依照特定排序方式排列的算法。最常用到的排序方式是数值顺序以及字典顺序。有效的排序算法在一些算法(例如搜索算法与合并算法)中是重要的,如此这些算法才能得到正确解答。排序算法也用在处理文字资料以及产生人类可读的输出结果。基本上,排序算法的输出必须遵守下列两个原则:
——Wiki百科
在计算机科学中,排序算法是一种常见的算法任务,它的目标是将一组数据按照一定的顺序排列,通常是升序或降序。不同的排序算法可以根据不同的性能指标(例如执行时间、内存使用等)在不同的情况下表现出不同的性能特点。因此,我们需要一个程序来比较多种排序算法在给定数据集上的性能。
解决方案:我们将创建一个多种排序算法的比较程序,该程序具有以下功能:
以下是项目目录结构图:
SortAlgorithms/
├── include/
│ ├── SortAlgorithm.h
│ ├── BubbleSort.h
│ ├── InsertionSort.h
│ ├── SelectionSort.h
│ ├── QuickSort.h
│ ├── MergeSort.h
│ ├── ShellSort.h
│ ├── HeapSort.h
│ └── STLsort.h
├── src/
│ ├── BubbleSort.cpp
│ ├── InsertionSort.cpp
│ ├── SelectionSort.cpp
│ ├── QuickSort.cpp
│ ├── MergeSort.cpp
│ ├── ShellSort.cpp
│ ├── HeapSort.cpp
│ └── STLsort.cpp
├── mainwindow.h
├── mainwindow.ui
├── mainwindow.cpp
└── main.cpp
排序算法抽象类(SortAlgorithm):
这是一个抽象基类,包含了所有排序算法的共同接口。其中,最重要的函数是 sort,用于对输入的数据进行排序。
排序算法子类:
对于每一种排序算法(例如冒泡排序、插入排序、选择排序、快速排序、归并排序、希尔排序、),都创建一个子类,继承自抽象类 SortAlgorithm,并实现 sort 函数。每个子类将包含算法的具体实现逻辑。
冒泡排序 (Bubble Sort):
冒泡排序是一种简单的比较排序算法,它通过不断交换相邻的元素将最大(或最小)的元素逐步移动到数组的末尾。
插入排序 (Insertion Sort):
插入排序是一种逐步构建有序序列的排序算法,它从未排序的元素中逐个取出元素并将其插入已排序的部分。
选择排序 (Selection Sort):
选择排序是一种简单的排序算法,它每次选择未排序部分中的最小(或最大)元素,并将其交换到已排序部分的末尾。
快速排序 (Quick Sort):
快速排序是一种分治排序算法,它通过选择一个元素作为基准,将数组分为两个子数组,然后递归地对子数组进行排序。
归并排序 (Merge Sort):
归并排序也是一种分治排序算法,它将数组递归分为两个子数组,然后将这些子数组合并成一个有序数组。
希尔排序 (Shell Sort):
希尔排序是一种改进的插入排序,它通过对数组的多个子序列进行排序,逐渐减小子序列的间隔,最终得到一个有序序列。
堆排序 (Heap Sort):
堆排序使用堆数据结构来排序数组,它首先将数组转换为一个最大堆或最小堆,然后逐个取出堆顶元素。
主程序(main):
主程序用于初始化排序算法的实例、性能比较器类,创建测试数据,然后调用比较函数,对不同排序算法进行性能比较。最后,展示比较结果供用户分析。
// main.cpp
#include "mainwindow.h"
#include <QApplication>
int main(int argc, char *argv[]) {
QApplication a(argc, argv);
MainWindow w;
w.setWindowTitle("DS 课程设计 zdy229074447");
w.show();
return a.exec();
}
// mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
QT_BEGIN_NAMESPACE
namespace Ui {
class MainWindow;
}
QT_END_NAMESPACE
class MainWindow: public QMainWindow {
Q_OBJECT
public:
MainWindow(QWidget *parent = nullptr);
~MainWindow();
void onButtonConfirmClicked();
private:
Ui::MainWindow *ui;
};
#endif // MAINWINDOW_H
// mainwindow.cpp
#include <QtWidgets>
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include "include/SortAlgorithm.h"
#include "include/BubbleSort.h"
#include "include/InsertionSort.h"
#include "include/SelectionSort.h"
#include "include/QuickSort.h"
#include "include/MergeSort.h"
#include "include/ShellSort.h"
#include "include/HeapSort.h"
#include "include/STLsort.h"
#include <cstdlib>
#include <ctime>
// 产生随机数据
vector<int> generateRandomArray(int size, int minValue, int maxValue) {
vector<int> arr;
for (int i = 0; i < size; i++) {
int randomNum = rand() % (maxValue - minValue + 1) + minValue;
arr.push_back(randomNum);
}
return arr;
}
MainWindow::MainWindow(QWidget *parent): QMainWindow(parent), ui(new Ui::MainWindow) {
ui->setupUi(this);
// 查找输入框和按钮,并进行相应的设置或连接信号槽
QLineEdit *inputDataSize = this->findChild<QLineEdit *>("Input_DataSize");
QPushButton *buttonConfirm = this->findChild<QPushButton *>("Button_Confirm");
if (inputDataSize) {
inputDataSize->setPlaceholderText("请输入");
}
if (buttonConfirm) {
// 连接按钮的点击信号到适当的槽函数
connect(buttonConfirm, &QPushButton::clicked, this, &MainWindow::onButtonConfirmClicked);
}
}
// 槽函数,用于处理按钮点击事件
void MainWindow::onButtonConfirmClicked() {
QLineEdit *inputDataSize = this->findChild<QLineEdit *>("Input_DataSize");
if (inputDataSize) {
QString dataSize = inputDataSize->text();
if (dataSize.length() == 0) {
QMessageBox warningBox;
warningBox.setIcon(QMessageBox::Warning);
warningBox.setWindowTitle("警告");
warningBox.setText("未输入任何数据");
warningBox.exec(); // 显示对话框并等待用户关闭
return;
}
vector<SortAlgorithm*> sortAlgorithms; // 使用的排序算法
if (dataSize.length() >= 8 || dataSize.toInt() > 2e6) {
QMessageBox warningBox;
warningBox.setIcon(QMessageBox::Warning);
warningBox.setWindowTitle("警告");
warningBox.setText("数据量过大,无法在短时间内完成计算");
warningBox.exec(); // 显示对话框并等待用户关闭
return;
} else if (dataSize.toInt() <= 50000) {
sortAlgorithms.push_back(new BubbleSort());
sortAlgorithms.push_back(new InsertionSort());
sortAlgorithms.push_back(new SelectionSort);
}
sortAlgorithms.push_back(new QuickSort);
sortAlgorithms.push_back(new MergeSort);
sortAlgorithms.push_back(new ShellSort);
sortAlgorithms.push_back(new HeapSort);
sortAlgorithms.push_back(new STLsort);
srand(time(NULL));
int minValue = -0x3f3f3f3f;
int maxValue = 0x3f3f3f3f;
vector<int> Data = generateRandomArray(dataSize.toInt(), minValue, maxValue);
QTableWidget *tableResult = this->findChild<QTableWidget *>("Table_Result");
if (tableResult) {
tableResult->setRowCount(sortAlgorithms.size()); // 设置表格的行数
tableResult->setColumnCount(2); // 设置表格的列数
tableResult->setHorizontalHeaderLabels(QStringList() << "排序算法" << "执行用时/s");
int row = 0;
for (auto sortAlgorithm : sortAlgorithms) {
vector<int> data(Data);
clock_t startTime = clock(); // 打时间戳计时
sortAlgorithm->sort(data);
clock_t endTime = clock();
double executionTime = double(endTime - startTime) / CLOCKS_PER_SEC;
QTableWidgetItem *algorithmItem = new QTableWidgetItem(QString::fromStdString(sortAlgorithm->getName()));
QTableWidgetItem *timeItem = new QTableWidgetItem(QString::number(executionTime, 'f', 3));
tableResult->setItem(row, 0, algorithmItem);
tableResult->setItem(row, 1, timeItem);
row ++;
}
}
}
}
MainWindow::~MainWindow() {
delete ui;
}
// BubbleSort.h
#ifndef BUBBLE_SORT_H
#define BUBBLE_SORT_H
#include "SortAlgorithm.h"
class BubbleSort: public SortAlgorithm {
public:
void sort(vector<int>& arr) override;
string getName() const override;
};
#endif // BUBBLE_SORT_H
// HeapSort.h
#ifndef HEAPSORT_H
#define HEAPSORT_H
#include "SortAlgorithm.h"
class HeapSort: public SortAlgorithm {
private:
void heapify(vector<int>& arr, int n, int i);
public:
void sort(vector<int>& arr) override;
string getName() const override;
};
#endif // HEAPSORT_H
// InsertionSort.h
#ifndef INSERTION_SORT_H
#define INSERTION_SORT_H
#include "SortAlgorithm.h"
class InsertionSort: public SortAlgorithm {
public:
void sort(vector<int>& arr) override;
string getName() const override;
};
#endif // NSERTION_SORT_H
// MergeSort.h
#ifndef MERGE_SORT_H
#define MERGE_SORT_H
#include "SortAlgorithm.h"
class MergeSort: public SortAlgorithm {
private:
void merge(vector<int>& arr, int l, int mid, int r);
void mergeSort(vector<int>& arr, int l, int r);
public:
void sort(vector<int>& arr) override;
string getName() const override;
};
#endif // MERGE_SORT_H
// QuickSort.h
#ifndef QUICK_SORT_H
#define QUICK_SORT_H
#include "SortAlgorithm.h"
class QuickSort: public SortAlgorithm {
private:
void quickSort(vector<int>& arr, int l, int r);
public:
void sort(vector<int>& arr) override;
string getName() const override;
};
#endif // QUICK_SORT_H
// STLsort.h
#ifndef STLSORT_H
#define STLSORT_H
#include "SortAlgorithm.h"
class STLsort: public SortAlgorithm {
public:
void sort(vector<int>& arr) override;
string getName() const override;
};
#endif // STLSORT_H
// SelectionSort.h
#ifndef SELECTION_SORT_H
#define SELECTION_SORT_H
#include "SortAlgorithm.h"
class SelectionSort: public SortAlgorithm {
public:
void sort(vector<int>& arr) override;
string getName() const override;
};
#endif // SELECTION_SORT_H
// ShellSort.h
#ifndef SHELLSORT_H
#define SHELLSORT_H
#include "SortAlgorithm.h"
class ShellSort: public SortAlgorithm {
public:
void sort(vector<int>& arr) override;
string getName() const override;
};
#endif // SHELLSORT_H
// SortAlgorithm.h
#ifndef SORT_ALGORITHM_H
#define SORT_ALGORITHM_H
#include <vector>
#include <string>
using namespace std;
class SortAlgorithm {
public:
virtual void sort(vector<int>& arr) = 0;
virtual string getName() const = 0;
};
#endif // SORT_ALGORITHM_H
// BubbleSort.cpp
#include "../include/BubbleSort.h"
void BubbleSort::sort(vector<int>& arr) {
int n = arr.size();
for (int i = 0; i < n - 1; i ++)
for (int j = 0; j < n - i - 1; j ++)
if (arr[j] > arr[j + 1])
swap(arr[j], arr[j + 1]);
}
string BubbleSort::getName() const {
return "Bubble Sort";
}
// HeapSort.cpp
#include "../include/HeapSort.h"
void HeapSort::sort(vector<int>& arr) {
int n = arr.size();
// 建堆
for (int i = n / 2 - 1; i >= 0; i --)
heapify(arr, n, i);
for (int i = n - 1; i >= 0; i --) {
// 从堆顶取出元素
swap(arr[0], arr[i]);
heapify(arr, i, 0);
}
}
void HeapSort::heapify(vector<int>& arr, int n, int i) {
int maxIndex = i;
int l = i * 2 + 1;
int r = i * 2 + 2;
if (l < n && arr[l] > arr[maxIndex])
maxIndex = l;
if (r < n && arr[r] > arr[maxIndex])
maxIndex = r;
if (maxIndex != i) {
swap(arr[i], arr[maxIndex]);
heapify(arr, n, maxIndex);
}
}
string HeapSort::getName() const {
return "Heap Sort";
}
// InsertionSort.cpp
#include "../include/InsertionSort.h"
void InsertionSort::sort(vector<int>& arr) {
int n = arr.size();
for (int i = 1; i < n; i ++) {
int key = arr[i];
int j = i - 1;
while (j >= 0 && arr[j] > key) {
arr[j + 1] = arr[j];
j --;
}
arr[j + 1] = key;
}
}
string InsertionSort::getName() const {
return "Insertion Sort";
}
// MergeSort.cpp
#include "../include/MergeSort.h"
void MergeSort::sort(vector<int>& arr) {
int l = 0, r = arr.size() - 1;
mergeSort(arr, l, r);
}
void MergeSort::merge(vector<int>& arr, int l, int mid, int r) {
int n1 = mid - l + 1;
int n2 = r - mid;
vector<int> L(n1), R(n2);
for (int i = 0; i < n1; i ++) L[i] = arr[l + i];
for (int i = 0; i < n2; i ++) R[i] = arr[mid + 1 + i];
int i = 0, j = 0, k = l;
while (i < n1 && j < n2) {
if (L[i] <= R[j]) arr[k ++] = L[i ++];
else arr[k ++] = R[i ++];
}
while (i < n1) arr[k ++] = L[i ++];
while (j < n2) arr[k ++] = R[j ++];
}
void MergeSort::mergeSort(vector<int>& arr, int l, int r) {
if (l >= r) return;
int mid = l + r >> 1; // 位运算
mergeSort(arr, l, mid);
mergeSort(arr, mid + 1, r);
merge(arr, l, mid, r);
}
string MergeSort::getName() const {
return "Merge Sort";
}
// QuickSort.cpp
#include "../include/QuickSort.h"
void QuickSort::sort(vector<int>& arr) {
int l = 0, r = arr.size() - 1;
quickSort(arr, l, r);
}
void QuickSort::quickSort(vector<int>& arr, int l, int r) {
if (l >= r) return;
int pivot = arr[r]; // 取 arr[r] 为分界点
int i = l - 1;
for (int j = l; j <= r - 1; j ++)
if (arr[j] <= pivot) {
i ++;
swap(arr[i], arr[j]);
}
swap(arr[i + 1], arr[r]);
int inter = i + 1;
quickSort(arr, l, inter - 1);
quickSort(arr, inter + 1, r);
}
string QuickSort::getName() const {
return "Quick Sort";
}
// STLsort.cpp
#include "../include/STLsort.h"
#include <algorithm>
void STLsort::sort(vector<int>& arr) {
std::sort(arr.begin(), arr.end());
}
string STLsort::getName() const {
return "STLsort";
}
// SelectionSort.cpp
#include "../include/SelectionSort.h"
void SelectionSort::sort(vector<int>& arr) {
int n = arr.size();
for (int i = 0; i < n - 1; i ++) {
int minIndex = i;
for (int j = i + 1; j < n; j ++)
if (arr[j] < arr[minIndex])
minIndex = j;
swap(arr[i], arr[minIndex]);
}
}
string SelectionSort::getName() const {
return "Selecton Sort";
}
// ShellSort.cpp
#include "../include/ShellSort.h"
void ShellSort::sort(vector<int>& arr) {
int n = arr.size();
for (int gap = n / 2; gap > 0; gap >>= 1)
for (int i = gap; i < n; i ++) {
int tmp = arr[i];
int j;
for (j = i; j >= gap && arr[j - gap] > tmp; j -= gap)
arr[j] = arr[j - gap];
arr[j] = tmp;
}
}
string ShellSort::getName() const {
return "Shell Sort";
}
// mainwindows.ui
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>MainWindow</class>
<widget class="QMainWindow" name="MainWindow">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>363</width>
<height>435</height>
</rect>
</property>
<property name="windowTitle">
<string>MainWindow</string>
</property>
<widget class="QWidget" name="centralwidget">
<widget class="QPushButton" name="Button_Confirm">
<property name="geometry">
<rect>
<x>230</x>
<y>10</y>
<width>111</width>
<height>31</height>
</rect>
</property>
<property name="styleSheet">
<string notr="true">font: 12pt "Microsoft YaHei UI";</string>
</property>
<property name="text">
<string>确定</string>
</property>
</widget>
<widget class="QLineEdit" name="Input_DataSize">
<property name="geometry">
<rect>
<x>110</x>
<y>10</y>
<width>111</width>
<height>31</height>
</rect>
</property>
<property name="styleSheet">
<string notr="true">font: 10pt "Microsoft YaHei UI";</string>
</property>
</widget>
<widget class="QLabel" name="label">
<property name="geometry">
<rect>
<x>20</x>
<y>10</y>
<width>91</width>
<height>31</height>
</rect>
</property>
<property name="text">
<string><html><head/><body><p><span style=" font-size:12pt;">数据量大小</span></p></body></html></string>
</property>
</widget>
<widget class="QTableWidget" name="Table_Result">
<property name="geometry">
<rect>
<x>20</x>
<y>50</y>
<width>321</width>
<height>331</height>
</rect>
</property>
<property name="styleSheet">
<string notr="true">font: 10pt "Microsoft YaHei UI";</string>
</property>
</widget>
</widget>
<widget class="QStatusBar" name="statusbar"/>
<widget class="QMenuBar" name="menubar">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>363</width>
<height>24</height>
</rect>
</property>
<widget class="QMenu" name="menu">
<property name="title">
<string>排序算法比较</string>
</property>
</widget>
<addaction name="menu"/>
</widget>
</widget>
<resources/>
<connections/>
</ui>
未输入内容时
dataSize = 20000 时
dataSize = 2000000 时
dataSize > 2000000 时
排序简介 OI Wiki (oiwiki.org) https://oi-wiki.org/basic/sort-intro/
排序算法 维基百科,自由的百科全书 (wikipedia.org) https://zh.wikipedia.org/wiki/%E6%8E%92%E5%BA%8F%E7%AE%97%E6%B3%95