快速排序
快速排序的思想是,先找一個基準(一般是最左邊的數),然後把比這個數小的移動到它的左邊,把比這個數大的移動到它的右邊,然後繼續對左子數組和右子數組進行同樣的操作,直到某個子數組只有一個元素爲止。
// 快速排序
#include <bits/stdc++.h>
using namespace std;
const int N = 1e5 + 5;
int n, a[N];
void quick_sort(int l, int r) {
if(l >= r) return ;
int tmp = a[l];
int i = l, j = r;
while(i != j) {
while(a[j] >= tmp && i < j) j--;
while(a[i] <= tmp && i < j) i++;
if(i < j) swap(a[i], a[j]);
}
swap(a[l], a[i]);
quick_sort(l, i - 1);
quick_sort(i + 1, r);
}
int main() {
scanf("%d", &n);
for(int i = 1; i <= n; i++)
scanf("%d", &a[i]);
quick_sort(1, n);
for(int i = 1; i <= n; i++)
printf("%d%s", a[i], i == n ? "\n" : " ");
return 0;
}
上面是一般做法,但是這樣會出現一個問題,假設給定的數組已經是排好序的,而基準又是第一個元素,那麼這些元素都會移動到右子數組中,而左子數組沒有元素,這樣的複雜度會是O(n^2)的,所以我們要隨機選擇基準。隨機數函數rand(),頭文件stdlib.h
// 快速排序
#include <bits/stdc++.h>
using namespace std;
const int N = 1e5 + 5;
int n, a[N];
void quick_sort(int l, int r) {
if(l >= r) return ;
int x = rand() % (r - l + 1) + l;
swap(a[x], a[l]);
int tmp = a[l];
int i = l, j = r;
while(i != j) {
while(a[j] >= tmp && i < j) j--;
while(a[i] <= tmp && i < j) i++;
if(i < j) swap(a[i], a[j]);
}
swap(a[l], a[i]);
quick_sort(l, i - 1);
quick_sort(i + 1, r);
}
int main() {
scanf("%d", &n);
for(int i = 1; i <= n; i++)
scanf("%d", &a[i]);
quick_sort(1, n);
for(int i = 1; i <= n; i++)
printf("%d%s", a[i], i == n ? "\n" : " ");
return 0;
}
插入排序
// 插入排序
#include <bits/stdc++.h>
using namespace std;
const int N = 1e5 + 5;
int n, a[N];
void insert_sort() {
for(int i = 2; i <= n; i++) {
int j, tmp = a[i];
for(j = i - 1; j >= 1; j--) {
if(a[j] <= a[i]) break;
}
for(int k = i; k > j + 1; k--)
a[k] = a[k - 1];
a[j + 1] = tmp;
}
}
int main() {
scanf("%d", &n);
for(int i = 1; i <= n; i++)
scanf("%d", &a[i]);
insert_sort();
for(int i = 1; i <= n; i++)
printf("%d%s", a[i], i == n ? "\n" : " ");
return 0;
}
歸併排序
先把數組分成兩個數組,把子數組排好序,再把兩個數組合並起來,對於子數組,執行同樣的操作,直到某個子數組只有一個元素。對於合併操作,我們已經把子數組排好序了,那麼就需要遍歷兩個子數組,比較兩個子數組當前的元素,把小的放到前面。
// 歸併排序
#include <bits/stdc++.h>
using namespace std;
const int N = 1e5 + 5;
int n, a[N], tmp[N];
void merge(int l, int r) {
if(l >= r) return ;
int mid = (l + r) >> 1;
merge(l, mid);
merge(mid + 1, r);
int pos = l;
int l1 = l, r1 = mid + 1;
while(l1 <= mid && r1 <= r) {
if(a[l1] <= a[r1]) {
tmp[pos++] = a[l1];
l1++;
} else {
tmp[pos++] = a[r1];
r1++;
}
}
while(l1 <= mid) {
tmp[pos++] = a[l1];
l1++;
}
while(r1 <= r) {
tmp[pos++] = a[r1];
r1++;
}
for(int i = l; i <= r; i++)
a[i] = tmp[i];
}
int main() {
scanf("%d", &n);
for(int i = 1; i <= n; i++)
scanf("%d", &a[i]);
merge(1, n);
for(int i = 1; i <= n; i++)
printf("%d%s", a[i], i == n ? "\n" : " ");
return 0;
}
堆排序
先把給定的數組建立一個最大堆,然後交換第一個元素和最後一個元素,繼續調整堆,執行n-1次就可以了。
// 堆排序
#include <bits/stdc++.h>
using namespace std;
const int N = 1e5 + 5;
int n, a[N];
void down(int x, int num) { // 當前父節點,堆中可操作的節點數
int tmp = a[x];
while(1) {
int i = x * 2;
if(i > num) break;
if((i < num) && a[i] < a[i + 1]) i++;
if(tmp >= a[i]) break;
a[x] = a[i];
x = i;
}
a[x] = tmp;
}
int main() {
scanf("%d", &n);
for(int i = 1; i <= n; i++)
scanf("%d", &a[i]);
for(int i = n / 2; i >= 1; i--) // 建立最大堆
down(i, n);
for(int i = n ; i > 1; i--) {
swap(a[i], a[1]);
down(1, i - 1);
}
for(int i = 1; i <= n; i++)
printf("%d%s", a[i], i == n ? "\n" : " ");
return 0;
}
桶排序
開一個num數組,某個數x每出現一次,那麼就把num[x]++,最後按從小到大的順序遍歷,把出現過的數輸出就可以了。但這只是簡單的桶排序,適用於整數且範圍較小的。
// 桶排序
#include <bits/stdc++.h>
using namespace std;
const int N = 1e5 + 5;
int n, a[N], num[N];
int main() {
scanf("%d", &n);
for(int i = 1; i <= n; i++) {
scanf("%d", &a[i]);
num[a[i]]++;
}
int cnt = 0;
for(int i = 0; i < N; i++) {
for(int j = 1; j <= num[i]; j++) {
if(cnt > 0) printf(" ");
printf("%d", i);
cnt++;
}
}
printf("\n");
return 0;
}