原地堆排序

2021-08-08 07:57:02 字數 3288 閱讀 4002

上一節講的兩種堆排序都需要開闢o(n)的輔助空間(建構函式中使用new分配的輔助空間),程式在開闢輔助空間和釋放空間的時候也會消耗一定的時間,若能多陣列進行原地堆排序,則省去了開闢和釋放空間的時間,時間效能會好一些。

給定乙個大小為n的陣列,將這個陣列heapify,變為最大堆,此時陣列的第乙個元素就是最大值,將該值與陣列最後乙個元素交換位置後,對前n-1個元素進行heapify,變成最大堆,將第乙個元素與陣列倒數第二個元素交換位置...以此類推,最後得到的陣列就是從小到大排序的。

注意,上一節中堆排序堆的實現是從1開始,所以當前元素(下標 i)的雙親下標為 i/2,左孩子下標為 2i,右孩子下標為 2i+1;而原地堆排序中直接對陣列進行操作,陣列的下標是從0開始,所以當前元素(下標i)的雙親為 (i-1)/2,左孩子下標為 2i+1,右孩子下標為 2i+2。

原地堆排序的c++實現如下:

sorttesthelper.h檔案(包含輔助函式)

#include #include #include //clock()、clocks_per_sec

#include //包含函式assert()

using namespace std;

namespace sorttesthelper

return arr;

}//輔助函式 - 產生乙個近乎有序的隨機數組

int* generatenearlyorderedarray(int n, int swaptime)

//然後交換幾組元素,使之變成無序但近乎有序的陣列

srand(time(0));

for(int j = 0; j < swaptime; j++)

return arr;

}//輔助陣列 - 產生乙個完全有序陣列

int* generatetotallyorderedarray(int n)

return arr;

}//輔助函式 - 列印陣列

templatevoid printarray(t arr, int n)

cout << endl;

}//輔助函式 - 判斷陣列是否有序(公升序)

templatebool issorted(t arr, int n)

}return true;

}//輔助函式 - 測試演算法的時間

templatevoid testsort(string sortname, void(*sort)(t, int), t arr, int n) //arr和n是函式指標需要的引數

//輔助函式 - 拷貝陣列

int* copyintarray(int a, int n)

}

heapsort.h檔案(包含上一節所講的兩種空間複雜度為o(n)的堆排序演算法)

#include #include #include #include #include using namespace std;

templateclass maxheap

*/ //優化:用賦值取代交換

item item = data[k];

while( k>1 && data[k/2] < item )

data[k] = item;

}void shiftdown(int k)

if(data[k] >= data[j])

swap(data[k], data[j]);

k = j;

}*///優化:用賦值取代交換

item item = data[k];

while( 2*k <= count )

if(data[j] <= item)

data[k] = data[j];

k = j;

}data[k] = item;

}public:

maxheap(int capacity)

maxheap(item arr, int n)

//將傳入的陣列整合成堆的樣子

for(int i = count / 2; i >= 1; i--)

}~maxheap()

//返回堆現在的大小

int size() const

//判斷堆是否為空堆

bool isempty() const

//向堆中插入乙個元素

void insert(item item)

//取出堆中的乙個元素(只能取出根結點)

item extractmax()

//列印堆中內容

void printdata() const

cout << endl;

}};templatevoid heapsort1(t arr, int n)

//從小到大排序

for(int i = n - 1; i >= 0; i--)

}templatevoid heapsort2(t arr, int n)

}

main.cpp檔案(包含這一節所講的原地堆排序演算法)

#include #include "heapsort.h"

#include "sorttesthelper.h"

using namespace std;

//對arr[0...n-1]中的下標為k的元素進行shiftdown操作

templatevoid __shiftdown(t arr, int n, int k)

if(arr[j] < v)

arr[k] = arr[j];

k = j;

}arr[k] = v;

}//原地堆排序

templatevoid heapsort3(t arr, int n)

for(int i = n-1; i > 0; i--)

}int main()

測試結果:

heapsort1 needs 0.3s.

heapsort2 needs 0.293s.

heapsort3 needs 0.288s.

heapsort1 needs 0.26s.

heapsort2 needs 0.173s.

heapsort3 needs 0.169s.

heapsort1 needs 0.186s.

heapsort2 needs 0.181s.

heapsort3 needs 0.179s.

從測試結果中可以看出,不同測試用例中,原地堆排序都比heapsort1和heapsort2快一些,這正是由於省去了開闢堆空間和釋放堆空間的時間。

原地堆排序

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

原地堆排序

堆排序 我之前使用的堆排序是要開 乙個長度為 n的陣列,事實上,我們可以把原陣列看成乙個堆,也就是說我們不用開乙個陣列,而是在原地排序 怎麼說呢 還是給我乙個陣列,我對這個陣列進行heapify 操作,這樣就得到了乙個大根堆 腦袋是最大的 然後我們把最大的那個數和陣列的最後乙個元素交換,這樣一來,陣...

實現原地堆排序(CPP)

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