常見排序演算法(描述與實現)
阿新 • • 發佈:2018-12-17
常見排序演算法
效率比較
演算法實現
◎氣泡排序
氣泡排序(英語:Bubble Sort)是一種簡單的排序演算法。它重複地遍歷要排序的數列,一次比較兩個元素,如果他們的順序錯誤就把他們交換過來。遍歷數列的工作是重複地進行直到沒有再需要交換,也就是說該數列已經排序完成。這個演算法的名字由來是因為越小的元素會經由交換慢慢“浮”到數列的頂端。
氣泡排序演算法流程如下:
- 比較相鄰的元素。如果第一個比第二個大(升序),就交換他們兩個。
- 對每一對相鄰元素作同樣的工作,從開始第一對到結尾的最後一對。這步做完後,最後的元素會是最大的數。
- 針對所有的元素重複以上的步驟,除了最後一個。
- 持續每次對越來越少的元素重複上面的步驟,直到沒有任何一對數字需要比較。
程式碼實現
void bubbleSort(int a[],int len)
{
int i, j, temp;
for (j=0; j<len; j++)
{
for (i=0; i<len-j; i++)
{
if (a[i] > a[i+1])
{
temp = a[i];
a[i] = a[i+1];
a[i+1] = temp;
}
}
}
}
◎快速排序
快速排序(英語:Quicksort),又稱劃分交換排序(partition-exchange sort),快速排序是對氣泡排序的一種改進,由C. A. R. Hoare在1962年提出。
快速排序演算法流程如下:
- 從數列中挑出一個元素,稱為"基準"(pivot)。
- 重新排序數列,所有元素比基準值小的擺放在基準前面,所有元素比基準值大的擺在基準的後面(相同的數可以到任一邊)。在這個分割槽結束之後,該基準就處於數列的中間位置。這個稱為分割槽(partition)操作。
- 遞迴地(recursive)把小於基準值元素的子數列和大於基準值元素的子數列排序。
程式碼實現
/* * 函式引數: * a[]: 待排序陣列 * start:陣列起始下標 * end:陣列末位下標 */ void quickSort(int a[], int start, int end) { if(start >= end) { return ; } int low = start; int high = end; int key = a[start]; // 基準 while(low < high) { while(low < high && key <= a[high]) { high--; } a[low] = a[high]; while(low < high && key >= a[low]) { low++; } a[high] = a[low]; } a[low] = key; quickSort(a, start, low-1); quickSort(a, low+1, end); }
◎插入排序
插入排序(英語:Insertion Sort)是一種簡單直觀的排序演算法。它的工作原理是通過構建有序序列,對於未排序資料,在已排序序列中從後向前掃描,找到相應位置並插入。插入排序在實現上,在從後向前掃描過程中,需要反覆把已排序元素逐步向後挪位,為最新元素提供插入空間。
程式碼實現
void InsertSort(int a[],int len)
{
int i, j, temp;
for (i=0; i<len; i++)
{
j = i-1;
temp = a[i];
while (j>=0 && temp<a[j])
{
a[j+1] = a[j];
j--;
}
a[j+1] = temp;
}
}
◎希爾排序
希爾排序(Shell Sort)是插入排序的一種。也稱縮小增量排序,是直接插入排序演算法的一種更高效的改進版本。希爾排序是非穩定排序演算法。該方法因DL.Shell於1959年提出而得名。
希爾排序演算法流程如下:
- 希爾排序是把記錄按下標的一定增量分組,對每組使用直接插入排序演算法排序。
- 隨著增量逐漸減小,每組包含的關鍵詞越來越多,當增量減至1時,整個檔案恰被分成一組,演算法便終止。
程式碼實現
void shellSort(int a[], int len)
{
int i, j, temp;
int gap=0;
while (gap <= len) // 生成初始增量
{
gap = 3*gap + 1;
}
while (gap >= 1)
{
for (i=gap; i<len; i++)
{
j = i-gap;
temp = a[i];
while (j>=0 && a[j]>temp)
{
a[j+gap] = a[j];
j = j-gap;
}
a[j+gap] = temp;
}
gap = (gap-1) / 3; // 遞減增量
}
}
◎選擇排序
選擇排序(Selection sort)是一種簡單直觀的排序演算法。
選擇排序演算法流程如下:
- 在未排序序列中找到最小(大)元素,存放到排序序列的起始位置。
- 再從剩餘未排序元素中繼續尋找最小(大)元素,然後放到已排序序列的末尾。
- 以此類推,直到所有元素均排序完畢。
程式碼實現
void selectSort(int a[], int len)
{
int i; // 有序區的末尾位置
int j; // 無序區的起始位置
int min; // 無序區中最小元素位置
int temp;
for (i=0; i<len; i++)
{
min=i;
for (j=i+1; j<len; j++)
{
if(a[j] < a[min])
min=j;
}
if (min != i)
{
temp = a[i];
a[i] = a[min];
a[min] = temp;
}
}
}
◎堆排序
堆排序(Heapsort)是指利用堆積樹(堆)這種資料結構所設計的一種排序演算法,它是選擇排序的一種。
堆排序演算法流程如下:
- 將待排序的序列構造成一個大頂堆(或小頂堆)。
- 此時,整個序列的最大值就是堆頂的根結點。將它移走(就是將其與堆陣列的末尾元素交換,此時末尾元素就是最大值)。
- 然後將剩餘的n-1個序列重新構造成一個堆,這樣就會得到n個元素中的次大值。
- 如此反覆執行,便能得到一個有序序列了。
程式碼實現
/*
* parentIndex:父結點下標
* leftIndex: 左孩子結點下標
*/
// 調整大根堆
void adjustHeap(int a[], int parentIndex, int len)
{
int leftIndex, temp;
temp = a[parentIndex];
for (leftIndex=2*parentIndex; leftIndex<=len; leftIndex*=2)
{
if (leftIndex<len && a[leftIndex] < a[leftIndex+1])
{
leftIndex++;
}
if (temp > a[leftIndex])
{
break;
}
a[parentIndex] = a[leftIndex];
parentIndex = leftIndex;
}
a[parentIndex] = temp;
}
// 交換元素
void swap(int arr[], int i, int j)
{
int temp;
temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
// 堆排序
void heapSort(int arr[],int len)
{
int index;
for (index=len/2 ; index>0; index--)
{
adjustHeap(arr, index, len);
}
for (index=len; index>1; index--)
{
// 交換堆頂元素與末尾元素
swap(arr, 1, index);
adjustHeap(arr, 1, index-1);
}
}
◎歸併排序
歸併排序(MERGE-SORT)是建立在歸併操作上的一種有效的排序演算法,該演算法是採用分治法(Divide and Conquer)的一個非常典型的應用。
歸併排序演算法流程如下:
- 將待排序陣列遞迴的分解至最小,分成許多個左右子序列。
- 對每個子序列分別進行排序。
- 將已有序的子序列合併排序,使子序列段間有序,得到完全有序的序列。
程式碼實現
#include <stdio.h>
// 合併陣列
void Merge(int sourceArr[],int tempArr[], int start, int mid, int end)
{
int i = start, j=mid+1, k = start;
while (i!=mid+1 && j!=end+1)
{
if (sourceArr[i] > sourceArr[j])
tempArr[k++] = sourceArr[j++];
else
tempArr[k++] = sourceArr[i++];
}
// 追加剩餘元素
while (i != mid+1)
tempArr[k++] = sourceArr[i++];
while (j != end+1)
tempArr[k++] = sourceArr[j++];
for (i=start; i<=end; i++)
sourceArr[i] = tempArr[i];
}
// 歸併排序
void MergeSort(int sourceArr[], int tempArr[], int start, int end)
{
int mid;
if(start < end)
{
mid = start + (end-start) / 2;
MergeSort(sourceArr, tempArr, start, mid);
MergeSort(sourceArr, tempArr, mid+1, end);
Merge(sourceArr, tempArr, start, mid, end);
}
}
// 列印陣列
void printArray(int a[], int n)
{
int i;
for (i=0; i<n; i++)
{
printf("%3d", a[i]);
}
printf("\n");
}
void main()
{
int sourceArr[9] = {44,33,11,22,66,88,77,55,99};
int n = sizeof(sourceArr) / sizeof(int);
int tempArr[9];
printArray(sourceArr, n);
MergeSort(sourceArr, tempArr, 0, n-1);
printArray(tempArr, n);
}