氣泡排序(Bubble Sort)算是前端最簡單的演演算法,也是最經典的排序演演算法了。網上JavaScript版本的氣泡排序很多,今天用Vue實現一個動態的視覺化氣泡排序。
氣泡排序原理也比較簡單,就是相鄰元素兩兩比較排序,把大的元素氣泡排序到後面,遞迴所有相鄰元素組合完成排序。
有一個無序陣列:let arr = [100, 5, 6, 17, 3, 1]
,長度為len=6
。
arr[0]、arr[1]
元素的大小,大的排後面,如果arr[0]>arr[1]
則交換值位置。len-1=5
個元素重複上述步驟,直到只剩下一個元素。這是一個遞迴的過程,遞迴到第一個元素,就完成了氣泡排序。氣泡排序的動畫過程如下圖,排序過程很直觀,一目瞭然,下一章節也實現一個跟好的。
經典氣泡排序演演算法,用兩個for
迴圈來實現所有元素的兩兩對比排序。統計了一下排序次數,一共比較了15次。氣泡排序的時間複雜度是O(n^2),這是最大值,最小為O(n)。
//經典氣泡排序演演算法
//從小到大氣泡排序
let arr = [100, 5, 6, 17, 3, 1];
let count=0; //計數器
function bubbleSort(arr) {
const len = arr.length;
let t;count=0;
for (let i = 0; i < len - 1; i++) {
for (let j = 0; j < len - i - 1; j++) {
count++;
//比較相鄰兩個元素
if (arr[j] > arr[j + 1]) {
//交換兩個元素,大的往後排列
t = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = t;
}
}
}
return arr;
}
console.log(bubbleSort(arr),"比較次數:",count);
//[1, 3, 5, 6, 17, 100] '比較次數:' 15
上面程式碼中交換兩個元素位置的時候,用了一箇中間變數(t),可以改進一下。用一個解構賦值來交換值,就不用額外的一箇中間變數(t)了。
let arr = [100, 5, 6, 17, 3, 1];
function bubbleSort(arr) {
const len = arr.length;
for (let i = 0; i < len - 1; i++) {
for (let j = 0; j < len - i - 1; j++) {
//比較相鄰兩個元素
if (arr[j] > arr[j + 1]) {
//用結構賦值進行交換
[arr[j], arr[j + 1]] = [arr[j+1], arr[j]];
}
}
}
return arr;
}
console.log(bubbleSort(arr));
//[1, 3, 5, 6, 17, 100]
用Vue來實現一個視覺化的氣泡排序,用Vue就不用去操作Dom了,只需要要處理好排序過程即可,因此首先要對排序過程進行改造。
上一章節的排序是連續執行,瞬間完成的。要實現視覺化的排序效果,每一個排序步驟之間得有間隔,給過渡動畫留時間。就需要把排序的每一個步驟拆開,可以單獨控制執行。
SortItem
,包裝待排序元素,用於視覺化展示,屬性包括排序值、泡泡大小、泡泡顏色。SortItem
,生成排序物件集合,正式排序步驟中用該集合。方法的引數為排序元素字串,空格隔開,如「9 100 6 17 3 1」。//定義一個排序物件,包裝待排序元素
function SortItem(n) {
this.value = n;
this.size = 30 + n + 'px'; //泡泡大小,初試大小30px
this.color = bubbleColor.default;
}
//生成排序物件集合,引數為排序元素字串,如「9 100 6 17 3 1」
function generateSortItems(arrStr) {
let arrItems = [];
let arr = arrStr.trim().split(' ');
for (let i = 0; i < arr.length; i++) {
arrItems[i] = new SortItem(window.parseInt(arr[i]));
}
return arrItems;
}
泡泡列表展示效果如下:
Generator
更優雅,馬上重構,上迭代器!每次迭代yield
返回排序的函數。//迭代器實現排序步驟的拆分
function* generateSortFunc(items) {
const len = items.length;
for (let i = 0; i < len - 1; i++) {
for (let j = 0; j < len - i - 1; j++) {
//迭代器返回的是一個(閉包)函數,為每一個排序步驟
yield () => {
//執行排序前重置泡泡顏色
resetColor(items);
//正在排序的泡泡元素高亮
items[j].color = bubbleColor.inprocess;
items[j + 1].color = bubbleColor.inprocess;
if (items[j].value > items[j + 1].value) {
[items[j], items[j + 1]] = [items[j + 1], items[j]];
}
}
}
//完成一輪排序,末尾泡泡元素標記為完成態顏色
items[len - i - 1].color = bubbleColor.completed;
}
}