JavaScript氣泡排序+Vue視覺化冒泡動畫

2022-12-19 12:02:04

氣泡排序(Bubble Sort)算是前端最簡單的演演算法,也是最經典的排序演演算法了。網上JavaScript版本的氣泡排序很多,今天用Vue實現一個動態的視覺化氣泡排序。

01、JavaScript氣泡排序

氣泡排序原理也比較簡單,就是相鄰元素兩兩比較排序,把大的元素氣泡排序到後面,遞迴所有相鄰元素組合完成排序。

1.1、原理

有一個無序陣列:let arr = [100, 5, 6, 17, 3, 1],長度為len=6

  • 、從第一位元素100(0索引)開始,比較相鄰arr[0]、arr[1]元素的大小,大的排後面,如果arr[0]>arr[1]則交換值位置。
  • 、如下圖,依次相鄰元素比較、交換,一輪完成後,最大元素就到了最右邊了。這個過程中,最大的元素(最大的泡泡)就像冒泡一樣到了末尾。

  • ③、然後繼續對剩下的前面len-1=5個元素重複上述步驟,直到只剩下一個元素。這是一個遞迴的過程,遞迴到第一個元素,就完成了氣泡排序。

氣泡排序的動畫過程如下圖,排序過程很直觀,一目瞭然,下一章節也實現一個跟好的。

1.2、JavaScript實現

經典氣泡排序演演算法,用兩個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]

02、Vue實現一個冒泡動畫

用Vue來實現一個視覺化的氣泡排序,用Vue就不用去操作Dom了,只需要要處理好排序過程即可,因此首先要對排序過程進行改造。

2.1、排序過程改造

上一章節的排序是連續執行,瞬間完成的。要實現視覺化的排序效果,每一個排序步驟之間得有間隔,給過渡動畫留時間。就需要把排序的每一個步驟拆開,可以單獨控制執行。

  • 定義一個排序物件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;
  }
}