這篇文章將會介紹常見的排序算法(使用 C++ 實現)
1、冒泡排序
將數組分爲有序區(左邊)和無序區(右邊),在初始化時有序區爲空,無序區包含數組所有元素
每次從無序區的最後一個元素開始,一直向前冒泡到無序區的第一個位置,使其變成有序
template<typename E>
void swap(E A[], int i, int j) {
E temp = A[i];
A[i] = A[j];
A[j] = temp;
}
template<typename E>
void bubbleSort(E A[], int n) {
for (int i = 0; i < n - 1; i++) {
for (int j = n - 1; j > i; j--) {
if (A[j] < A[j - 1]) {
swap(A, j, j - 1);
}
}
}
}
2、選擇排序
將數組分爲有序區(左邊)和無序區(右邊),在初始化時有序區爲空,無序區包含數組所有元素
每次從無序區中選擇一個合適的元素,並將其交換到無序區的第一個位置,使其變成有序
template<typename E>
void swap(E A[], int i, int j) {
E temp = A[i];
A[i] = A[j];
A[j] = temp;
}
template<typename E>
void selectionSort(E A[], int n) {
for (int i = 0; i < n - 1; i++) {
int minIdx = i;
for (int j = i; j <= n - 1; j++) {
if (A[j] < A[minIdx]) minIdx = j;
}
swap(A, i, minIdx);
}
}
3、插入排序
將數組分爲有序區(左邊)和無序區(右邊),在初始化時有序區包含數組的第一個元素,無序區包含其餘的元素
每次將無序區中的第一個元素,一直向前交換到有序區中的合適位置,使其變成有序
template<typename E>
void swap(E A[], int i, int j) {
E temp = A[i];
A[i] = A[j];
A[j] = temp;
}
template<typename E>
void insertionSort(E A[], int n) {
for (int i = 1; i < n; i++) {
for (int j = i; j > 0; j--) {
if (A[j] < A[j - 1]) {
swap(A, j, j - 1);
}
}
}
}
4、歸併排序
遞歸進行,每次將數組一分爲二,然後對兩個數組分別排序後,合併兩個數組
template<typename E>
void mergeSort(E A[], E T[], int l, int r) {
if (l == r) return;
int m = (l + r) / 2;
mergeSort<E>(A, T, l, m);
mergeSort<E>(A, T, m + 1, r);
// merge
for (int k = l; k <= r; k++) T[k] = A[k];
int i = l, j = m + 1;
for (int c = l; c <= r; c++) {
if (i > m) A[c] = T[j++];
else if (j > r) A[c] = T[i++];
else if (T[i] < T[j]) A[c] = T[i++];
else A[c] = T[j++];
}
}
優化:臨時數組後半部分反向插入,這樣可以不用檢測邊界情況
template<typename E>
void mergeSort(E A[], E T[], int l, int r) {
if (l == r) return;
int m = (l + r) / 2;
mergeSort<E>(A, T, l, m);
mergeSort<E>(A, T, m + 1, r);
// merge
for (int k = l; k <= m; k++) T[k] = A[k];
for (int k = 1; k <= r - m; k++) T[r - k + 1] = A[k + m];
int i = l, j = r;
for (int c = l; c <= r; c++) {
if (T[i] < T[j]) A[c] = T[i++];
else A[c] = T[j--];
}
}
5、快速排序
遞歸進行,每次在數組中選擇一個基準,根據基準將數組一分爲二,然後對兩個數組分別排序後,拼接兩個數組
template<typename E>
void swap(E A[], int i, int j) {
E temp = A[i];
A[i] = A[j];
A[j] = temp;
}
template<typename E>
void quickSort(E A[], int l, int r) {
if (r <= l) return;
// find pivot
int pivotIndex = (l + r) / 2;
E pivot = A[pivotIndex];
// put pivot at last
swap(A, pivotIndex, r);
// partition
int i = l - 1;
int j = r;
do {
while (A[++i] < pivot) {}
while (i < j && pivot < A[--j]) {}
swap(A, i, j);
} while (i < j);
// put pivot in place
swap(A, r, i);
// recursive
quickSort(A, l, i - 1);
quickSort(A, i + 1, r);
}
優化:使用棧替代遞歸
template<typename E>
void swap(E A[], int i, int j) {
E temp = A[i];
A[i] = A[j];
A[j] = temp;
}
template<typename E>
void quickSort(E A[], int l, int r) {
int stack[200];
int top = -1;
stack[++top] = l;
stack[++top] = r;
while (top > 0) {
// pop the stack
r = stack[top--];
l = stack[top--];
// find pivot
int pivotIndex = (l + r) / 2;
E pivot = A[pivotIndex];
// put pivot at last
swap(A, pivotIndex, r);
// partition
int i = l - 1;
int j = r;
do {
while (A[++i] < pivot) {}
while (i < j && pivot < A[--j]) {}
swap(A, i, j);
} while (i < j);
// undo the last swap
swap(A, i, j);
// put pivot in place
swap(A, r, i);
// load up stack
if (i - 1 > l) {
stack[++top] = l;
stack[++top] = i - 1;
}
if (r > i + 1) {
stack[++top] = i + 1;
stack[++top] = r;
}
}
}
6、測試
測試程序
#include <iostream>
#include <time.h>
using namespace std;
int main() {
const int num = 1000;
const int minVal = 0;
const int maxVal = 1000;
int* arr = new int[num];
for (int i = 0; i < num; i++)
arr[i] = rand() % (maxVal - minVal + 1) + minVal;
int* a4b = new int[num];
int* a4s = new int[num];
int* a4i = new int[num];
int* a4m = new int[num];
int* a4q = new int[num];
int* t = new int[num];
for (int i = 0; i < num; i++) a4b[i] = arr[i];
for (int i = 0; i < num; i++) a4s[i] = arr[i];
for (int i = 0; i < num; i++) a4i[i] = arr[i];
for (int i = 0; i < num; i++) a4m[i] = arr[i];
for (int i = 0; i < num; i++) a4q[i] = arr[i];
clock_t start, end;
start = clock();
bubbleSort(a4b, num);
end = clock();
cout << "bubbleSort: " << (double)(end-start)/CLOCKS_PER_SEC << endl;
start = clock();
selectionSort(a4s, num);
end = clock();
cout << "selectionSort: " << (double)(end-start)/CLOCKS_PER_SEC << endl;
start = clock();
insertionSort(a4i, num);
end = clock();
cout << "insertionSort: " << (double)(end-start)/CLOCKS_PER_SEC << endl;
start = clock();
mergeSort(a4m, t, 0, num - 1);
end = clock();
cout << "mergeSort: " << (double)(end-start)/CLOCKS_PER_SEC << endl;
start = clock();
quickSort(a4q, 0, num - 1);
end = clock();
cout << "quickSort: " << (double)(end-start)/CLOCKS_PER_SEC << endl;
return 0;
}
測試結果
數據規模 | 1000 | 10000 | 100000 | 1000000 | 10000000 | 100000000 |
---|---|---|---|---|---|---|
bubble sort | 0.003 s | 0.355 s | 41.414 s | / | / | / |
selection sort | 0.001 s | 0.123 s | 12.151 s | / | / | / |
insertion sort | 0.002 s | 0.224 s | 22.881 s | / | / | / |
merge sort | 0 s | 0.002 s | 0.021 s | 0.212 s | 2.285 s | 24.352 s |
quick sort | 0 s | 0.002 s | 0.017 s | 0.175 s | 1.826 s | 19.498 s |
【 閱讀更多數據結構與算法系列文章,請看 數據結構與算法複習 】