幾種排序整理

快速排序

快速排序的思想是,先找一個基準(一般是最左邊的數),然後把比這個數小的移動到它的左邊,把比這個數大的移動到它的右邊,然後繼續對左子數組和右子數組進行同樣的操作,直到某個子數組只有一個元素爲止。

// 快速排序 
#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;
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章