1. 程式人生 > >考研數據結構筆記—堆排序

考研數據結構筆記—堆排序

pre 最大 str 時間復雜度 時間 左右 OS wap -s

完全二叉樹是效率很高的數據結構,堆是一種完全二叉樹或者近似完全二叉樹,所以效率同樣極高。目前十分常用的排序算法、Dijkstra算法、Prim算法等都要用堆才能優化。

堆排序是一種選擇排序算法,與原序列的初始排列次序無關,即最好、最壞和一般情況排序的時間復雜度不變,均為O(nlgn)。而且,堆排序只需要一個記錄記錄元素大小的輔助空間(供交換使用),故空間復雜度為O(1)。正由於堆排序不僅時間復雜度小,而且空間復雜度O(1)也是最小,所以是用於排序的最佳選擇。

堆的定義

n個元素序列 { k0,k1,..., kn } 當且僅當滿足下列條件之一時,稱之為堆(其中 i = 0, 1, ..., n/2 向下取整)。

  • ki <= k2i+1 且 ki <= k2i+2(最小堆)
  • ki >= k2i+1 且 ki >= k2i+2(最大堆)

堆排序實現

方法1:

利用最小堆性質實現堆排序

/*交換數組中兩個元素的值*/
void swap(int *arr, int a, int b)
{
    int temp = arr[a];
    arr[a] = arr[b];
    arr[b] = temp;
}

/*(小根)堆調整*/
void minHeapify(int *arr, int heapSize, int curNode)
{
    /*找出當前節點和其左右節點三者的最小值
*/ int minNode = curNode; int left = curNode * 2 + 1; int right = curNode * 2 + 2; if(left < heapSize && arr[left] < arr[minNode]) //左孩子存在且較小 minNode = left; if(right < heapSize && arr[right] < arr[minNode]) //右孩子存在且較小 minNode = right;
if(minNode != curNode) //當前節點不是最小則需要交換 { swap(arr, minNode, curNode); minHeapify(arr, heapSize, minNode); //子節點需重新調整 } } /*構建堆*/ void createHeap(int *arr, int heapSize) { for(int i = heapSize/2 - 1; i >= 0; i--) //從最後一個非葉節點開始 { minHeapify(arr, heapSize, i); } } /*(最小)堆排序 *思想: *1、構建最小堆 *2、從最後一個元素開始只第二個元素將依次與首元素交換 *3、全局調整堆
*上面步驟2和步驟3將所有元素都與首元素交換,然後進行全局範圍的堆調整,利用最小堆的性質實現將所有元素按從小到大的方式排序
*/ void heapSort(int *arr, int length) { createHeap(arr, length); //構建堆 for(int i = length-1; i > 0; i--) { swap(arr, 0, i); //與首元素交換 minHeapify(arr, length, 0); //調整堆 } }

方法2

利用最大堆性質實現堆排序

/*交換數組中兩個元素的值*/
void swap(int *arr, int a, int b)
{
    int temp = arr[a];
    arr[a] = arr[b];
    arr[b] = temp;
}

/*(大根)堆調整*/
void maxHeapify(int *arr, int heapSize, int curNode)
{
    /*找出當前節點和其左右節點三者的最小值*/
    int maxNode = curNode;  
    int left  = curNode * 2 + 1;
    int right = curNode * 2 + 2;
    if(left < heapSize && arr[left] > arr[maxNode]) //左孩子存在且較小
        maxNode = left;
    if(right < heapSize && arr[right] > arr[maxNode]) //右孩子存在且較小
        maxNode = right;

    if(maxNode != curNode)    //當前節點不是最小則需要交換
    {   
        swap(arr, maxNode, curNode);
        maxHeapify(arr, heapSize, maxNode);  //子節點需重新調整
    }
}

/*構建堆*/
void createHeap(int *arr, int heapSize)
{
    for(int i = heapSize/2 - 1; i >= 0; i--)  //從最後一個非葉節點開始
    {
        maxHeapify(arr, heapSize, i);
    }
}

/*(最大)堆排序
*思想:
*1、構建最大堆
*2、從最後一個元素開始只第二個元素將依次與首元素交換
*3、進行數組中當前元素前面的所有元素的局部調整堆
*上面步驟2和步驟3將所有元素都與首元素交換,將局部範圍內的最大值沈到後面,然後進行當前元素前面所有元素的局部範圍內的堆調整
*即在數組A中,當前元素索引為i,將A[i]與A[0]交換,將A[0,1,...,i]中最大的值放到A[i],然後進行A[0,1,...,i-1]堆調整,
*將A[0,1,...,i-1]內的最大值放到A[0]中,待下一次交換使用,實現將局部的最大值依次沈到數組後面,完成排序
*/
void heapSort(int *arr, int length)
{
    createHeap(arr, length);  //構建堆
    for(int i = length-1; i > 0; i--)
    {   
        swap(arr, 0, i);  //與首元素交換
        maxHeapify(arr, i, 0);  //調整堆
    }
}

考研數據結構筆記—堆排序