選擇排序的基本方法是:每步從帶排序的元素中選出關鍵詞最小(或最大)的元素,順序放在已排序的元素的最後,直到全部排序完爲止。這裏介紹簡單選擇排序和堆排序。
簡單選擇排序
1.算法思想
每次從無序區中挑選出一個最小的值,將其與無序區的第一個元素交換,初始有序區爲空,無序區包含所有待排序元素。
2.性能分析
簡單選擇排序算法的效率與初始數據的順序無關。
3.完整代碼
#include<iostream>
using namespace std;
void select_sort(int a[], int n) {
int k,temp=0;
//每次從無序區中選出最小的元素與無序區的第一個元素交換
for(int i=0;i<n;++i) {
//k標記無序區最小元素
k=i;
for(int j=i+1;j<n;++j)
if(a[j]<a[k])
k = j;
if(k!=i) {
temp = a[i];
a[i] = a[k];
a[k] = temp;
}
}
}
//輸出數組
void print_array(int a[],int n) {
for(int i=0;i<n;++i){
cout<<a[i]<<" ";
}
cout<<endl;
}
int main() {
//簡單選擇排序測試數據
int a[] = {7,3,1,12,5,9};
int n = 6;
cout<<"Before sort:";
print_array(a,n);
cout<<"After binary insertion:";
select_sort(a,n);
print_array(a,n);
return 0;
}
測試結果如下:
堆排序
1.算法思想
首先按照大根推的定義將數組調整爲堆(初始建堆),交換根結點a[0]和最後一個結點a[n-1](將最大元素a[0]歸位);然後將a[0]~a[n-2]重新調整爲堆,交換a[0]和a[n-2];如此反覆,直到交換了a[0]和a[1]。
2.算法過程
(1)維護堆的性質
AMX-HEAPIFY是用於維護最大堆性質的重要過程。它的輸入爲一個數組a和一個下標i。在調用MAX-HEAPIFY的時候,我們假定根結點爲LEFT(i)和RIGHT(i)的二叉樹都是最大堆,但這時a[i]有可能小於其孩子,這樣就違背了最大堆的性質。MAX-HEAPIFY通過讓a[i]在最大堆中“逐級下降”,從而使得以下標i爲根結點的字數重新遵循最大堆的性質。
//假設以index爲結點的左右子樹Left(index)和Right(index)都爲最大堆
//這時a[index]可能小於其孩子
//maxHeapify通過讓a[index]在最大堆中“逐級下降”來維持最大堆的性質
void maxHeapify(int a[], int index) {
int l = Left(index);
int r = Right(index);
int largest = 0;
if(l<heapSize && a[l]>a[index])
largest = l;
else largest = index;
if(r<heapSize && a[r]>a[largest])
largest = r;
if(largest != index) {
swap(&a[largest],&a[index]);
maxHeapify(a,largest);
}
}
(2)建堆
我們可以用自底向上的方法利用過程MAX-HEAPIFY把一個大小爲n=A.length的數組a[0]~a[n-1]轉換爲最大堆。我們知道,每個葉子節點都可以堪稱只包含一個元素的堆,通過過程BUILD-MAX-HEAP對樹中非葉子結點從下標最大的開始都調用一次MAX-HEAPIFY來建堆。
void buildMaxHeap(int a[],int length) {
heapSize = length;
//含有n個結點的堆的下標最大的非葉子結點的標號爲(n-2)/2
for(int i=(length-2)>>1;i>=0;--i)
maxHeapify(a,i);
}
(3)堆排序算法
調用過程BUILD-MAX-HEAP初始化堆,交換a[0]與堆中最後一個結點,調用MAX-HEAPIFY(a,0),重複這一過程直到堆的大小爲1。
void heap_sort(int a[], int length) {
//初始化堆
buildMaxHeap(a,length);
//選擇堆的根結點與最後一個結點交換
for(int i=length-1;i>=1;--i){
swap(&a[i],&a[0]);
--heapSize;
maxHeapify(a,0);
}
}
3.性能分析
堆排序的時間效率與帶排序數據的順序無關。
4.完整代碼
#include<iostream>
using namespace std;
int heapSize = 0;
int Left(int index) {
return (index<<1)+1;
}
int Right(int index) {
return (index<<1)+2;
}
void swap(int *a, int *b) {
int temp = *a;
*a = *b;
*b = temp;
}
//假設以index爲結點的左右子樹Left(index)和Right(index)都爲最大堆
//這時a[index]可能小於其孩子
//maxHeapify通過讓a[index]在最大堆中“逐級下降”來維持最大堆的性質
void maxHeapify(int a[], int index) {
int l = Left(index);
int r = Right(index);
int largest = 0;
if(l<heapSize && a[l]>a[index])
largest = l;
else largest = index;
if(r<heapSize && a[r]>a[largest])
largest = r;
if(largest != index) {
swap(&a[largest],&a[index]);
maxHeapify(a,largest);
}
}
void buildMaxHeap(int a[],int length) {
heapSize = length;
for(int i=(length-2)>>1;i>=0;--i)
maxHeapify(a,i);
}
void heap_sort(int a[], int length) {
buildMaxHeap(a,length);
for(int i=length-1;i>=1;--i){
swap(&a[i],&a[0]);
--heapSize;
maxHeapify(a,0);
}
}
//輸出數組
void print_array(int a[],int n) {
for(int i=0;i<n;++i){
cout<<a[i]<<" ";
}
cout<<endl;
}
int main() {
//直接插入測試數據
int a[] = {4,10,16,2,12,9,7};
int n = 7;
cout<<"Before sort:";
print_array(a,n);
cout<<"After heap-sort:";
heap_sort(a,n);
print_array(a,n);
cout<<endl;
return 0;
}
測試結果如下: