歸并排序
歸并排序采用分治的思想:
- Divide: 將n個元素平均劃分為各含n/2個元素的子序列。
- Conquer:遞歸解決兩個規模為n/2的子問題。
- Combine:合并倆個已排序的子序列。
性能:時間復雜度為O(nlogn),空間復雜度為O(N),算法與初始序列無關,排序是穩定的。
void mergeSort(int arr[], int len) {
int* a = arr;
int* b = (int*) malloc(len * sizeof(int));
for (int size = 1; size < len; size += size) {
for (int start = 0; start < len; start += size + size) {
int k = start;
int left = start, right = min(left + size + size, len), mid = min(left + size, len);
int start1 = left, end1 = mid;
int start2 = mid, end2 = right;
while (start1 < end1 && start2 < end2) {
b[k++] = a[start1] > a[start2] ? a[start2++] : a[start1++];
}
while (start1 < end1) {
b[k++] = a[start1++];
}
while (start2 < end2) {
b[k++] = a[start2++];
}
}
int* temp = a;
a = b;
b = temp;
}
if (a != arr) {
for (int i = 0; i < len; ++i) {
b[i] = a[i];
}
b = a;
}
free(b);
}
基數排序
對于有d個關鍵字時,可以分別按關鍵字進行排序。有兩種方法:
- MSD:先從高位開始進行排序,在每個關鍵字上,可采用基數排序。
- LSD:先人低位開始進行排序,在每個關鍵字上,可采用桶排序。
即通過每個數的每位數字的大小來比較
//找出最大數字的位數
int maxNum(int arr[], int len) {
int _max = 0;
for (int i = 0; i < len; ++i) {
int d = 0;
int a = arr[i];
while (a) {
a /= 10;
d++;
}
if (_max < d) {
_max = d;
}
}
return _max;
}
void radixSort(int *arr, int len) {
int d = maxNum(arr, len);
int *temp = new int[len];
int count[10];
int radix = 1;
for (int i = 0; i < d; ++i) {
for (int j = 0; j < 10; ++j) {
count[j] = 0;
}
for (int k = 0; k < len; ++k) {
count[(arr[k] / radix) % 10]++;
}
for (int l = 1; l < 10; ++l) {
count[l] += count[l - 1];
}
for (int m = 0; m < len; ++m) {
int index = (arr[m] / radix) % 10;
temp[count[index] - 1] = arr[m];
count[index]--;
}
for (int n = 0; n < len; ++n) {
arr[n] = temp[n];
}
radix *= 10;
}
delete (temp);
}
拓撲排序
在有向圖中找拓撲序列的過程,就是排外排序。 ** 拓撲序列常常用于判定圖是否有環 **。
- 從有向圖中選擇一個入度為0的結點,輸出它。
- 將這個結點以及該結點出發的所有邊從圖中刪除。
- 重復前兩步,直到沒有入度為0的點。
如果 所有的點都被輸出,即存在一個拓撲序列,則圖沒有環。