先引用Wiki的介紹(鏈接在這):
冒泡排序,有時也稱爲沉沒排序,是一種簡單的排序算法,它重複遍歷列表,比較相鄰的對,如果它們的順序錯誤則交換它們。重複傳遞列表,直到列表排序。該算法是一種比較排序,以較小或較大元素“冒泡”到列表頂部的方式命名。雖然算法很簡單,但即使與插入排序相比,它對於大多數問題來說太慢而且不切實際。如果輸入大多是按順序排列的,並且一些無序元素幾乎就位,則冒泡排序可以是實用的。
這是我大學接觸的第一個排序算法,原理比較簡單,就是通過不斷的循環交換不符合規則的相鄰倆個數。接下來用在Qt上實現,並可視化的展現出來。
1.新建工程,加入下列頭文件,用來實現繪圖和多線程
#include <QVector>
#include <QTime> //方便產生隨機數
#include <QThread> //多線程
#include <QDebug> //方便調試打印
#include <QPainter> //繪圖
2.在這裏將使用多線程,主線程負責繪圖,輔線程負責排序計算,所以得再新建一個class並繼承於QObject,具體可以參考我之前寫過的有關Qt5多線程簡單使用的那篇博客。
#ifndef BUBBLE_H
#define BUBBLE_H
#include <QObject>
#include <QThread>
#include <QTime>
class Bubble : public QObject
{
Q_OBJECT
public:
explicit Bubble(int l,int m,int mD,int *data,QObject *parent = nullptr);
void goBubble(); //處理排序算法
void rand(); //隨機產生數據
signals:
void bubbleSignal(int cur); //發送當前排序的位子
private:
int length; //數組的長度
int *data; //數組
int max; //單個數據的最大值
int cur; //排序當前處理的位置
int mDelay; //延時時間,方便動態展示
public slots:
};
#endif // BUBBLE_H
#include "bubble.h"
Bubble::Bubble(int l, int m, int mD, int *data, QObject *parent) : QObject(parent)
{
qsrand(static_cast<uint>(QTime::currentTime().msec())); //初始化隨機種子
length = l;
max = m;
mDelay = mD;
this->data = data;
rand();
}
void Bubble::goBubble()
{
bool flag = false; //供判斷是否已經完成
for(int i = 1; i < length && !flag; i ++){
flag = true;
for(int j = 0; j < length-i; j++){
if(data[j] > data[j+1]){
int t = data[j];
data[j] = data[j+1];
data[j+1] = t;
flag = false;
}
bubbleSignal(j);
QThread::msleep(static_cast<unsigned int>(mDelay));
}
}
for(int i = 0; i < length; i++){
bubbleSignal(i);
QThread::msleep(static_cast<unsigned int>(mDelay));
}
}
void Bubble::rand()
{
if(data == nullptr)
throw "數據不合理";
for(int i = 0; i < length ; i++){
data[i] = qrand()%max;
}
}
3.繼續來實現Widget類
#ifndef WIDGET_H
#define WIDGET_H
#include <QWidget>
#include "bubble.h"
#include <QPainter>
namespace Ui {
class Widget;
}
class Widget : public QWidget
{
Q_OBJECT
public:
explicit Widget(QWidget *parent = nullptr);
~Widget();
void paintEvent(QPaintEvent *e);
signals:
void start(); //開啓子線程
public slots:
void deal(int c); //處理來自子線程的消息
private:
Ui::Widget *ui;
int blockH; //繪圖方塊的高
int blockW; //繪圖方塊的寬
int length; //數組長度
int *data; //數組
int cur; //當前排序的位子
QThread *thread;
Bubble *bubble;
};
#endif // WIDGET_H
#include "widget.h"
#include "ui_widget.h"
Widget::Widget(QWidget *parent) :
QWidget(parent),
ui(new Ui::Widget)
{
ui->setupUi(this);
length = 120;
blockH = 4;
blockW = 8;
data = new int [length];
cur = 0;
bubble = new Bubble(length,length,5,data);
setGeometry(0,0,length*blockW,length*blockH);//設置當前窗口的長寬,方便觀察
thread = new QThread(this);
bubble->moveToThread(thread);
//進行信號與槽的綁定
connect(bubble,&Bubble::bubbleSignal,this,&Widget::deal);
connect(this,&Widget::start,bubble,&Bubble::goBubble);
thread->start(); //開啓子線程
emit start(); //運行子線程的goBubble函數
}
void Widget::paintEvent(QPaintEvent *){
QPainter painter;
if(data == nullptr)
return ;
painter.begin(this);
for(int i = 0; i< length;i++){
QRect rect(i*blockW,height()-data[i]*blockH,
blockW - 1,data[i]*blockH);
if(i == cur){
painter.fillRect(rect,Qt::blue);
}else {
painter.fillRect(rect,Qt::red);
}
}
painter.end();
}
void Widget::deal(int c)
{
cur = c;
repaint(); //進行重繪
}
Widget::~Widget()
{
delete [] data;
thread->quit(); //結束子線程
thread->wait(); //回收子線程資源
delete ui;
}
4.運行結果(gif不好弄呀),勉強能看,還請見諒。由動畫可非常方便的觀察冒泡排序是不斷的通過將所遇到的最大值往後挪實現的。
5.總結,整體比較簡單,以至於關於冒泡算法的複雜度的問題,我就不重複囉嗦了,具體你們可以看百度百科或者Wiki。後續排序算法將建立在此基礎上,避免重複。