入門級的三種排序算法(比較,冒泡,快排)詳講

1. 比較排序
  比較排序是小白最容易想到的排序方法,從第一個元素開始,和後面所有元素依次進行比較,比第一個元素小,就將這兩個元素交換,最後比完第一輪,第一個元素肯定是最小的了,然後從第二個元素開始,和後面所有元素比較,一輪比完,第二個元素是第二小的,同理,比完n-1(n爲數組元素個數)輪,數組全部變得有序。比較排序是穩定的,也就是遇到值一樣大的情況下不會發生交換,保持原來位置,其時間複雜度爲O(n^2),代碼如下:

#include <iostream>
using namespace std;

void swap(int* a,int* b){//交換 
	int temp=*a;
	*a=*b;
	*b=temp;
}

void Sort(int a[],int len){
	for(int i=0;i<len-1;i++){
		for(int j=i+1;j<len;j++){
			if(a[i]>a[j]){
				swap(a[i],a[j]);
			}
		}
	}
}

int main(){
	int a[10]={8,6,9,7,3,0,2,5,1,4};
	cout << "排序前的數組:" << endl;
	for(int i=0;i<10;i++){
		cout << a[i] << " ";
		if(i==9) cout << endl;
	}
	Sort(a,10);
	cout << "排序後的數組:" << endl;
	for(int i=0;i<10;i++){
		cout << a[i] << " ";
		if(i==9) cout << endl;
	}
	return 0;
}

2. 冒泡排序
  冒泡排序是很經典的一個排序算法,顧名思義,冒泡排序,就像水裏冒水泡一樣,從最底下慢慢升到最上面。冒泡排序是相鄰元素進行比較,這樣使最大值慢慢換到最後面去,所以,冒泡排序也得進行n-1趟,是穩定的,其時間複雜度爲O(N^2),代碼如下:

#include <iostream>
using namespace std;

void swap(int* a,int* b){//交換 
	int temp=*a;
	*a=*b;
	*b=temp;
}

void Sort(int a[],int len){
	for(int i=0;i<len-1;i++){
		for(int j=0;j<len-i-1;j++){
			if(a[j]>a[j+1]){
				swap(a[j],a[j+1]);
			}
		}
	}
}

int main(){
	int a[10]={8,6,9,7,3,0,2,5,1,4};
	cout << "排序前的數組:" << endl;
	for(int i=0;i<10;i++){
		cout << a[i] << " ";
		if(i==9) cout << endl;
	}
	Sort(a,10);
	cout << "排序後的數組:" << endl;
	for(int i=0;i<10;i++){
		cout << a[i] << " ";
		if(i==9) cout << endl;
	}
	return 0;
}

3. 快速排序
  快速排序簡稱快排,是最常用的排序方法,C++裏面STL庫中的sort()方法就是快排(進行了優化)。理解快速排序你首先得了解分治思想,即將一個大的複雜的問題分成幾個小的容易解決的問題,當你把所有小問題解決後,這個大問題也就被解決了。那麼說回快排,快排的思想就是:在待排序數組找到一個基準值,將待排序數組分成兩段,第一段的值全小於這個基準值,第二段的值全大於這個基準值。然後重複這個操作將這直到整個數組都變得有序。即 “整體有序,局部無序”。其中,基準值得選取關係到快排的效率,快排的平均複雜度爲 O(n*logn) 當數組完全逆序時,快排的複雜度會退化成 O(n^2)。關於基準值的選取(快排的優化)這裏不做展開,一般我們都選取區間最最左端的元素作爲基準值。
  那麼我們的問題轉化成,如何將區間分段?這也是快排的核心: 交叉掃描,將元素交換位置
舉個例子:待排序數組爲:8 6 9 7 3 0 2 5 1 4
此時,基準值flag=8,區間最左端下標left=0,最右端下標right=9;從右端right-9開始掃描(因爲我們基準值選取的是最左邊的元素值),4<8,代表4應該在8的左邊,所以我們將其交換位置,數組變成:4 6 9 7 3 0 2 5 1 8,left=0,right=9然後從左邊left=0開始掃,,4<=8,代表4應該在8的左邊,位置正確,那麼接着掃描,6<=8,代表6應該在8的左邊,位置正確,那麼接着掃描,9=>8,9應該在8的右邊,j進行交換,數組變成:4 6 8 7 3 0 2 5 1 9,left=2,right=9,然後重複此操作(沒交換,就繼續向前(後)掃描,交換了就從另一邊開始掃描),直到left>=right,就代表數組已經被分好段。分好段的數組爲:4 6 1 7 3 0 2 5 8 9,分成了4 6 1 7 3 0 2 5和9這兩個待排序區間,重複上面的操作,直至所有區間都排好序(每個元素的位置都正確),即排序完成。需要注意的是: 快排是不穩定的。根據上面的思路,我們可以寫出下面的代碼:
  代碼如下:(內含詳細註釋)

#include <iostream>
using namespace std;

void swap(int *a,int *b){//交換
	int temp=*a;
	*a=*b;
	*b=temp;
}

int partition(int left,int right,int a[]){//使基準值左邊全小於基準值,基準值右邊全大於基準值 
	int flag=a[left];//基準值,一般選取區間最左邊的元素 
	while(left<right){
		//先從後往前掃,如果比基準值小,將兩個值交換 
		while(left<right && a[right]>=flag) right--;
		swap(&a[left],&a[right]);
		//然後從前往後掃,如果比基準值大,將兩個值交換 
		while(left<right && a[left]<=flag) left++;
		swap(&a[left],&a[right]);
	}
	return left;//返回基準值的下標,以此爲分界線,將區間劃分成兩個小區間 
}

void quickSort(int start,int end,int a[]){//遞歸調用(分治思想),直至所有的元素 
	if(start<end){
		int flag=partition(start,end,a);
		quickSort(start,flag-1,a);
		quickSort(flag+1,end,a);
	}
}

int main(){
	int a[10]={8,6,9,7,3,0,2,5,1,4};
	cout << "排序前的數組:" << endl;
	for(int i=0;i<10;i++){
		cout << a[i] << " ";
		if(i==9) cout << endl;
	}
	quickSort(0,9,a);
	cout << "排序後的數組:" << endl;
	for(int i=0;i<10;i++){
		cout << a[i] << " ";
		if(i==9) cout << endl;
	}
	return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章