原地堆排序

2021-09-26 16:34:30 字數 2303 閱讀 1807

堆排序

我之前使用的堆排序是要開 乙個長度為 n的陣列,事實上,我們可以把原陣列看成乙個堆,也就是說我們不用開乙個陣列,而是在原地排序

怎麼說呢…

還是給我乙個陣列,我對這個陣列進行heapify 操作,這樣就得到了乙個大根堆(腦袋是最大的),然後我們把最大的那個數和陣列的最後乙個元素交換,這樣一來,陣列末尾最大那個數就不用考慮了

至此,堆排序的乙個子過程已經完成,是不是覺得很迷

比如說氣泡排序吧

每一輪排序,我都會把最大的那個元素堆在陣列的末尾,也就是說下一次排序我就不看陣列末尾了,

因為已經排好序了

好,我們再回來看這個堆排序,也就是說我在heapify後,把陣列頭和陣列尾進行交換,那麼這個大根堆的結構就被破壞了,但是,只是0號元素的結構被破壞了而已,該元素的左右子樹還是大根堆

這個時候我們再對0 號元素進行shiftdown 操作,這樣一來,0號小的下去

下面大的上來,就又構建了乙個大根堆【注意:上一次heapify操作完了以後,我把最大的元素放在了 第 (arr.length -1)為,也就是說,在下一輪shiftdown後,我把第0位和 第(arr.length-2)位,也就是倒數第二位進行交換,這樣,我們就把最大的數和次大的數放在了倒數第一位和倒數第二位

也就是說:倒數兩位的數都被我排序好了,然後我們繼續shiftdown ,再交換0,和 (len-3)位

繼續shiftdown ,交換 0和(len-4)位

繼續shiftdown,交換0 和2位元素,這樣,整乙個堆排序也就完成了

繼續shiftdown ,然後交換0 和1 為元素,這樣這個陣列也就有序了

畫圖不易,望理解

每一次shiftdown 都在調整和維護乙個大根堆並且這個堆的size是上一次堆的(size-1),每一次swap就相當於一次 poll,也就是優先佇列的出隊操作

下面是**演示:

public class main 

public static void main(string args) ;

heapsort(arr);

for (int a:

arr)

}public static void heapsort(intarr)

for(int i=arr.length-1;i>0;i--)

}static void shiftdown(int arr,int heapsize,int i)

if(arr[i]>=arr[j])

swap(arr,i,j);

i=j;}}

static int parent(int i)

static int leftchild(int i)

static int rightchild(int i)

static int lastnodeforheapify(int n)

}

/**

* 堆排序工具類

*/private

static

class

heapsorthelper

private

static

void

heapify

(int

p,int cur,

int heapsize)

if(p[cur]

>=p[next]

)swap

(p,cur,next)

; cur = next;

next =1+

(next<<1)

;}}private

static

void

build

(int

p,int rightend)

}private

static

void

heapsort

(int

p)}}

原地堆排序

siwuxie095 原地堆排序 程式 1 原地堆排序的實現 sorttesthelper.h ifndef sorttesthelper h define sorttesthelper h include include include include include using namespac...

原地堆排序

上一節講的兩種堆排序都需要開闢o n 的輔助空間 建構函式中使用new分配的輔助空間 程式在開闢輔助空間和釋放空間的時候也會消耗一定的時間,若能多陣列進行原地堆排序,則省去了開闢和釋放空間的時間,時間效能會好一些。給定乙個大小為n的陣列,將這個陣列heapify,變為最大堆,此時陣列的第乙個元素就是...

實現原地堆排序(CPP)

堆是一種非常有用的資料結構,我們可以利用大頂堆或者小頂堆這種資料結構完成堆排序,但是這樣會增加o n 的輔助空間,其實,真正的堆排序是可以在原地進行的,我們稱之為原地堆排序,今天我們就來實現一下原地堆排序吧。原地堆排序主要分兩個步驟 1.對陣列進行堆化 2.將最大元素與陣列末端元素交換,然後對前n ...