八種排序演算法原理及實現
一:氣泡排序
氣泡排序(Bubble Sort),是一種電腦科學領域的較簡單的排序演算法。它重複地走訪過要排序的數列,一次比較兩個元素,如果他們的順序錯誤就把他們交換過來。走訪數列的工作是重複地進行直到沒有再需要交換,也就是說該數列已經排序完成。氣泡排序演算法的運作如下:(從後往前)- 比較相鄰的元素。如果第一個比第二個大,就交換他們兩個。
- 對每一對相鄰元素作同樣的工作,從開始第一對到結尾的最後一對。在這一點,最後的元素應該會是最大的數。
- 針對所有的元素重複以上的步驟,除了最後一個。
- 持續每次對越來越少的元素重複上面的步驟,直到沒有任何一對數字需要比較。
void Bubblesort(int *a, int n) { int i, j, k; for (i = 1;i < n;i++) { for (j = 1;j <= n - i;j++) { if (a[j] > a[j + 1]) k = a[j], a[j] = a[j + 1], a[j + 1] = k; } } }
二:選擇排序
選擇排序(Selection sort)是一種簡單直觀的排序演算法。它的工作原理是每一次從待排序的資料元素中選出最小(或最大)的一個元素,存放在序列的起始位置,直到全部待排序的資料元素排完。
複雜度O(n^2)
void Selectionsort(int *a, int n)
{
int i, j, k;
for (i = 1;i <= n;i++)
{
for (j = i + 1;j <= n;j++)
{
if (a[i] > a[j])
k = a[i], a[i] = a[j], a[j] = k;
}
}
}
三:插入排序—直接插入排序
直接插入排序(Straight Insertion Sort)是一種最簡單的排序方法,其基本操作是將一條記錄插入到已排好的有序表中,從而得到一個新的、記錄數量增1的有序表。
void insertsort(int *a, int n) { int i, j, k, id; for (i = 2;i <= n;i++) { for (j = 1;j < i;j++) { if (a[j] > a[i]) { k=a[i],id = j; break; } } for (j = i;j > id;j--) a[j] = a[j - 1]; a[id] = k; } }
四:插入排序—希爾排序
希爾排序(Shell's Sort)是插入排序的一種又稱“縮小增量排序”(Diminishing Increment Sort),是直接插入排序演算法的一種更高效的改進版本。希爾排序是非穩定排序演算法。該方法因D.L.Shell於1959年提出而得名。希爾排序是把記錄按下標的一定增量分組,對每組使用直接插入排序演算法排序;隨著增量逐漸減少,每組包含的關鍵詞越來越多,當增量減至1時,整個檔案恰被分成一組,演算法便終止。希爾排序屬於插入類排序,是將整個有序序列分割成若干小的子序列分別進行插入排序。排序過程:先取一個正整數d1<n,把所有序號相隔d1的陣列元素放一組,組內進行直接插入排序;然後取d2<d1,重複上述分組和排序操作;直至di=1,即所有記錄放進一個組中排序為止。void shellsort(int *a, int n)
{
int i, j, k, id, gap;
for (gap = n / 2;gap;gap /= 2)
{
for (i = gap;i <= n;i++)
{
for (j = i - gap;j >= 0 && a[j] > a[j + gap];j -= gap)
k = a[j], a[j] = a[j + gap], a[j + gap] = k;
}
}
}
五:歸併排序
歸併排序(MERGE-SORT)是建立在歸併操作上的一種有效的排序演算法,該演算法是採用分治法(Divide and Conquer)的一個非常典型的應用。將已有序的子序列合併,得到完全有序的序列;即先使每個子序列有序,再使子序列段間有序。若將兩個有序表合併成一個有序表,稱為二路歸併。歸併過程為:比較a[i]和b[j]的大小,若a[i]≤b[j],則將第一個有序表中的元素a[i]複製到r[k]中,並令i和k分別加上1;否則將第二個有序表中的元素b[j]複製到r[k]中,並令j和k分別加上1,如此迴圈下去,直到其中一個有序表取完,然後再將另一個有序表中剩餘的元素複製到r中從下標k到下標t的單元。歸併排序的演算法我們通常用遞迴實現,先把待排序區間[s,t]以中點二分,接著把左邊子區間排序,再把右邊子區間排序,最後把左區間和右區間用一次歸併操作合併成有序的區間[s,t]。複雜度:O(nlogn)
void mergesort(int *a, int l, int r, int *b)
{
int mid = (l + r) / 2;
int i = l, j = mid + 1, n = mid, m = r, cnt = 0;
if (l != r)
{
mergesort(a, l, mid, b);
mergesort(a, mid + 1, r, b);
}
while (i <= n&&j <= m)
{
if (a[i] < a[j])
b[++cnt] = a[i++];
else
b[++cnt] = a[j++];
}
while (i <= n) b[++cnt] = a[i++];
while (j <= m) b[++cnt] = a[j++];
for (i = 1;i <= cnt;i++)
a[l + i - 1] = b[i];
}
六:計數排序
計數排序是一個非基於比較的排序演算法,該演算法於1954年由 Harold H. Seward 提出。它的優勢在於在對一定範圍內的整數排序時,它的複雜度為Ο(n+k)(其中k是整數的範圍),快於任何比較排序演算法。[1-2] 當然這是一種犧牲空間換取時間的做法,而且當O(k)>O(n*log(n))的時候其效率反而不如基於比較的排序(基於比較的排序的時間複雜度在理論上的下限是O(n*log(n)), 如歸併排序,堆排序)
void cntsort(int *a, int n, int *s,int *Rank)
{
int i, j;
for (i = 1;i <= n;i++)
s[a[i]]++;
for (i = 1;i <= 100;i++)
s[i] += s[i - 1];
for (i = n;i >= 1;i--)
Rank[s[a[i]]--] = a[i];
for (i = 1;i <= n;i++)
printf("%d ", Rank[i]);
printf("\n");
}
七:快速排序
快速排序由C. A. R. Hoare在1962年提出。它的基本思想是:通過一趟排序將要排序的資料分割成獨立的兩部分,其中一部分的所有資料都比另外一部分的所有資料都要小,然後再按此方法對這兩部分資料分別進行快速排序,整個排序過程可以遞迴進行,以此達到整個資料變成有序序列。
複雜度:O(nlogn)
void quicksort(int *a, int l, int r)
{
int i = l, j = r, k = a[l];
if (l < r)
{
while (i < j)
{
while (i < j&&a[j] >= k)
j--;
if (i < j) a[i++] = a[j];
while (i < j&&a[i] <= k)
i++;
if (i < j) a[j--] = a[i];
}
a[i] = k;
quicksort(a, l, i - 1);
quicksort(a, i + 1, r);
}
}
八:堆排序
堆排序(Heapsort)是指利用堆積樹(堆)這種資料結構所設計的一種排序演算法,它是選擇排序的一種。可以利用陣列的特點快速定位指定索引的元素。堆分為大根堆和小根堆,是完全二叉樹。大根堆的要求是每個節點的值都不大於其父節點的值,即A[PARENT[i]] >= A[i]。在陣列的非降序排序中,需要使用的就是大根堆,因為根據大根堆的要求可知,最大的值一定在堆頂。
#include<stdio.h>
#include<algorithm>
#include<string.h>
using namespace std;
const int maxm = 100005;
int a[maxm];
void max_heap(int a[], int x, int n)
{
int id = x, L = x * 2, R = x * 2 + 1;
if (L <= n&&a[L] > a[id]) id = L;
if (R <= n&&a[R] > a[id]) id = R;
if (id != x)
{
swap(a[id], a[x]);
max_heap(a, id, n);
}
}
void build_maxheap(int a[], int n)
{
for (int i = n / 2;i >= 1;i--)
max_heap(a, i, n);
}
void heapsort(int a[], int n)
{
int len = n, i;
build_maxheap(a, len);
for (i = n;i >= 2;i--)
{
swap(a[1], a[i]);
len--;
max_heap(a, 1, len);
}
}
int main()
{
int n, i, j;
scanf("%d", &n);
for (i = 1;i <= n;i++)
scanf("%d", &a[i]);
heapsort(a, n);
for (i = 1;i <= n;i++)
printf("%d ", a[i]);
printf("\n");
return 0;
}