排序 | 堆排序

先用一段 C++ 代码来看看推排序的过程:

 模拟 sort_heap 的过程
1
#include <iostream> 2 #include <algorithm> 3 using namespace std; 4 5 bool cmp(const int lhs, const int rhs) 6 { 7 return lhs > rhs; 8 } 9 10 int main() 11 { 12 int arr[] = {4, 2, 10, 9, 5, 6, 8, 6, 7, 1, 3}; 13 make_heap(arr, arr+10);      // 构造堆 14 for(int i = 11; i >= 0; --i) {  // 不断 pop_heap 15 pop_heap(arr, arr+i);     // heap 的 pop 非真正意义上的 pop,其实是 swap(arr, arr+i-1),然后再 percolate_down(下溯) 16 for(int i = 0; i < 11; ++i) cout << arr[i] << ' '; 17 cout << endl; 18 } 19 20 return 0; 21 }


 

主要就是 make_heap、pop_heap

make_heap:建堆,默认最大堆-》得到递增数组(因为pop_heap是把堆顶取出依次放到后面)

pop_heap:arr[0]和arr[i]交换,并维护arr[0]到arr[i-1]的堆结构。

 

meke_heap 里面可以细分为从下往上建堆,递归的来说就是要维护 i,就得维护 i.left 和 i.right。

而 pop_heap 就是 n 次维护 root 节点。

所以,实际上,只需要写一个 perlocateDown 来维护以 i 为 root 的子堆。

// perlocate_down
1
void perlocateDown(int arr[], int n, int i) 2 { 3 int l = 2*i + 1; 4 int r = 2*i + 2; 5 int largest = i; 6 if(l < n && arr[l] > arr[largest]) 7 largest = l
9
if(r < n && arr[r] > arr[largest]) 10 largest = r; 11 12 if(largest == i) return; 13 swap(arr[i], arr[largest]); 14 perlocateDown(arr, n, largest); 15 }

维护堆的过程简单来说就是不断往下沉。

后面的的 meke_heap 和 pop_heap 也就不难写了。

makeHeap(arr, n) :

  for i = n/2 downto 1 :  // 所有非叶子节点

    perlocateDown(arr, n, i)

popHeap(arr, n) :

  swap(arr[0], arr[n-1])

  perlocateDown(arr, n, 0)

然后 sortHeap 也容易写出来了:

sortHeap(arr, n) :

  makeHeap(arr, n)

  for i = n downto 0 :

    popHeap(arr, i)

 另外,还有个push_heap,加入一个元素至数组尾部,即作为堆的叶子。然后再上溯。

 上溯过程比较简单:

 perlocateUp(arr, i) :

  parent = (i-1)/2

  if i==0 or arr[i] < arr[parent] : return

  swap(arr[parent], arr[i])

  perlocate(arr, parent)

 

posted on 2015-09-27 13:52  Excavator  阅读(277)  评论(0编辑  收藏  举报

导航