JavaScript數據結構與算法(十一)二叉堆

二叉堆數據結構是一種特殊的二叉樹,他能高效、快速的找出最大值和最小值,常應用於優先隊列和著名的堆排序算法中。

二叉堆

二叉堆有以下兩個特性:

  1. 是一顆完全二叉樹,表示數的每一層都有左側和右側子節點(除最後一層的葉節點),並且最後一層的葉節點儘可能是左側子節點
  2. 二叉堆不是最小堆就是最大堆,所有節點都大於等於(最大堆)或者小於等於(最小堆)每個他的子節點。

創建最小堆類

class MinHeap {
  constructor(compareFn = defaultCompare) {
    this.compareFn = compareFn;
    this.heap = [];
  }
}

二叉堆的數組表示


    static getLeftIndex(index) {
    return (2 * index) + 1;
  }

  static getRightIndex(index) {
    return (2 * index) + 2;
  }

  static getParentIndex(index) {
    if (index === 0) {
      return undefined;
    }
    return Math.floor((index - 1) / 2);
  }

  size() {
    return this.heap.length;
  }

  isEmpty() {
    return this.size() <= 0;
  }

  clear() {
    this.heap = [];
  }

查找二叉堆最小值或者最大值

 findMinimum() {
    return this.isEmpty() ? undefined : this.heap[0];
  }

交換函數實現

function swap(array, a, b) {
  /* const temp = array[a];
  array[a] = array[b];
  array[b] = temp; */
  [array[a], array[b]] = [array[b], array[a]];
}

向堆中插入新值

insert(value) {
    if (value != null) {
      const index = this.heap.length;
      this.heap.push(value);
      this.siftUp(index);
      return true;
    }
    return false;
  };
//上移操作
siftUp(index) {
    let parent = this.getParentIndex(index);
    while (
      index > 0
      && this.compareFn(this.heap[parent], this.heap[index]) === Compare.BIGGER_THAN
    ) {
      swap(this.heap, parent, index);
      index = parent;
      parent = this.getParentIndex(index);
    }
  }

二叉堆中導出最大值或最小值

extract() {
    if (this.isEmpty()) {
      return undefined;
    }
    if (this.size() === 1) {
      return this.heap.shift();
    }
    const removedValue = this.heap[0];
    this.heap[0] = this.heap.pop();
    this.siftDown(0);
    return removedValue;
  };
//下移操作
 siftDown(index) {
    let element = index;
    const left = MinHeap.getLeftIndex(index);
    const right = this.getRightIndex(index);
    const size = this.size();
    if (
      left < size
      && this.compareFn(this.heap[element], this.heap[left]) === Compare.BIGGER_THAN
    ) {
      element = left;
    }
    if (
      right < size
      && this.compareFn(this.heap[element], this.heap[right]) === Compare.BIGGER_THAN
    ) {
      element = right;
    }
    if (index !== element) {
      swap(this.heap, index, element);
      this.siftDown(element);
    }
  }

創建最大堆類

class MaxHeap extends MinHeap {
  constructor(compareFn = defaultCompare) {
    super(compareFn);
    this.compareFn = compareFn;
    this.compareFn = reverseCompare(compareFn);
  }
}

其他操作跟最小堆類一樣,這裏就不多加贅述。

堆排序算法

heapify(array) {
    if (array) {
      this.heap = array;
    }
    const maxIndex = Math.floor(this.size() / 2) - 1;
    for (let i = 0; i <= maxIndex; i++) {
      this.siftDown(i);
    }
    return this.heap;
  };
 getAsArray() {
    return this.heap;
  };
//構建最大堆函數
function buildMaxHeap(array, compareFn) {
    for (let i = Math.floor(array.length / 2);i >= 0; i -= 1){
      heapify(array, i, array.length, compareFn);
      return array;
    }
  }
//堆排序算法實現
function heapSort(array, compareFn = defaultCompare) {
  let heapSize = array.length;
  //用數組創建一個最大堆用作源數據
  buildMaxHeap(array, compareFn);
  while(heapSize > 1){
    //創建最大堆後,最大的值會被存儲在堆的第一個位置,我們將它替換爲堆的最後一個值,將堆的大小-1
    swap(array, 0, --heapSize);
    //將堆的根節點下移並重復步驟2直到堆的大小爲1
    heapify(array, 0, heapSize, compareFn);
  }
  return array;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章