數據結構與算法-學習筆記(20)

什麼是堆?

① 對是一個徹底二叉樹 ; ② 堆中的每一個節點的值都必須 >=(或者<=)其子樹中每一個節點。算法

如何實現一個堆

  1. 如何存儲一個堆:徹底二叉樹,用數組最好了。

2. 插入

插入徹底二叉樹中,也就是插入到數組的最後一個位置。 api

此時破壞了堆的特性,須要調整(也叫堆化):

① 從下往上 比較交換直到符合規則數組

② 從上往下比較交換直到符合規則緩存

  1. 刪除

堆的插入刪除操做都是順着節點路徑比較交換,徹底二叉樹的高度log2n,所以時間複雜度O(logn)bash

堆排序

藉助堆結構的特色,把數組中數據位置對應到堆上對應位置,經過調整堆來對數組中數據進行排序。ui

對一組數據進行堆排序(以大頂堆爲例)。spa

  1. 一組數據能夠對應成一個徹底二叉樹。
  2. 對徹底二叉樹進行調整(也就是堆化)成堆。這一步相似插入操做,插入後的數據最終是在葉子節點上的。所以從最後一個節點開始從上往下進行堆化。節點n是葉子節點沒有子節點所以從他的父節點開始。
private static void buildHeap(int[] a, int n) {
  for (int i = n/2; i >= 1; --i) {// 它是徹底二叉樹,所以有子節點的父節點i向上確定都是父節點
    heapify(a, n, i);
  }
}

private static void heapify(int[] a, int n, int i) {
  while (true) { // 交換後節點下邊的子樹又須要從新刷新位置
    int maxPos = i;
    if (i*2 <= n && a[i] < a[i*2]) maxPos = i*2;
    if (i*2+1 <= n && a[maxPos] < a[i*2+1]) maxPos = i*2+1;
    if (maxPos == i) break;
    swap(a, i, maxPos);
    i = maxPos;
  }
}

複製代碼
  1. 排序 大頂堆已經排序好了,如今堆頂的元素確定是數組中最大值,由於要原地排序且不能破壞堆的結構所以將堆頂元素與尾節點交換(相似刪除操做),以後對新頂節點進行自上向下堆化(堆的範圍1~n-1),完成後,堆頂又是最大元素。以此類推,每次將堆頂拿出,也就是每次找到剩餘元素的最大值。重複n次全部元素就都排好了。
// n 表示數據的個數,數組 a 中的數據從下標 1 到 n 的位置。
public static void sort(int[] a, int n) {
  buildHeap(a, n);
  int k = n;
  while (k > 1) {
    swap(a, 1, k);
    --k;
    heapify(a, k, 1);
  }
}
複製代碼

堆排序的測評

空間複雜度O(n)code

時間複雜度O(nlogn)cdn

不穩定排序blog

爲何實際開發中快速排序好於堆排序?

  1. 堆排序數據訪問方式沒有快速排序友好:快:順序(CPU緩存友好);堆:跳着
  2. 對於一樣數據,在排序過程當中,堆排序算法的數據交換次數多於快排。

應用

堆的排序過程當中,每次都會找出剩餘元素中最大的元素,所以能夠應用於求topN

相關文章
相關標籤/搜索