所謂選擇嘛就是從待排序的元素中先選個最大的或最小的出來放一邊,然後重複同樣的操作.
簡單選擇排序就是遍曆那些未排序的元素,而堆排序則是利用大堆或小堆從中選擇最大或最小值,因為大堆堆頂值就是最大值(小堆堆頂是最小值).
簡單選擇排序:
void SimpleSelectSort(int* arr, int len)
{
int tmp;
int maxValIndex;
for(int i = len - 1; i >0; i--)
{
maxValIndex = i;
for(int j = 0; j < i; j++)
{
if(arr[j] > arr[maxValIndex])
maxValIndex = j;
}
tmp = arr[maxValIndex];
arr[maxValIndex] = arr[i];
arr[i] = tmp;
}
}
簡單選擇排序實際上跟冒泡排序蠻像,每遍曆一次選出個最大的來,只不過選擇排序不用去交換相鄰的元素,直到找到了最大值,交換那一個元素就行.
堆排序
堆是一棵完全二叉樹,如果父結點大於等於子結點則叫大堆,父結點小於等於子結點叫小堆.這裡我們使用大堆來進行堆排序(用小堆也是可以的).
堆的邏輯結構雖然是樹結構,但物理結構可以是一個數組.各結點索引間的關係是:假如父結點索引為index,則左孩子索引為index*2 + 1;右孩子索引為index*2 + 2;
根結點自然是第一個,索引為0.
首先把待排序的數組建成一個大堆,則索引為0的元素是最大值,然後把它與最後一個元素交換.使數組縮短1,然後重建立堆,則索引為0的元素又是最大值.所以堆排序的思想跟簡單選擇排序是一樣的,就是從未排序的元素中挑出最大的,只不這裡是利用建立一個大堆來得到最大值.
//調整堆,假如堆中只有一個元素變動,則通過調整又產生一個堆
//通過父結點與孩子結點比較如果小於子結點則交換位置.這裡說的調整實際上指的是調整父結點
void LargeHeapAdjust(int* arr, int index, int len)
{
int lChild = index*2 + 1;
int rChild = index*2 + 1;
int fatherIndex = index;
int tmp;
//如果索引大於len/2 - 1則必是孩子結點了.因為假如有這樣的父結點(len/2)的話.則它的左孩子是len + 1.已經超出了數組範圍
if(index <= len/2 - 1) {
if(lChild < len && arr[lChild] > arr[max])
fatherIndex= lChild;
if(rChild < len && arr[rChild] > arr[max])
fatherIndex= rChild;
if(fatherIndex!= index)
{
tmp = arr[index];
arr[index] = arr[max];
arr[max] = tmp;
LargeHeapAdjust(arr, max, len);
}
}
}
//建立大堆
void CreateLargeHeap(int* arr, int len)
{
for(int i = len/2 - 1; i >= 0; i--)
LargeHeapAdjust(arr, i, len); //針對每一個非葉子結點做一次調整
}
void HeapSort(int* arr, int len)
{
int i;
int tmp;
CreateLargeHeap(arr, len); //排序前最建立一個大堆
for( i = len - 1; i >= 1; i --) //這裡跟簡單選擇排序一樣,從後往前遍曆,找個最大值出來.堆根結點arr[0]就是最大值
{
tmp = arr[i];
arr[i] = arr[0];
arr[0] = tmp;
LargeHeapAdjust(arr, 0, i); //索引為0的根結點變動了,需要調整重建堆.
}
}