1、基數排序ios
基數排序的思想比較好理解,便是從各位數開始比較起,一直比較到最高位位置,每次比較都是在前一次比較的基礎上進行的。算法
代碼以下:數組
/* 基數排序,即爲按照每位數來將其分類,而後在前一次分類的順序基礎上,再次進行分類,直到全部分類標準都執行完畢 時間複雜度爲n */ #include <iostream> using namespace std; int GetNumByPos(int num,int dight){ int value=-1; while(dight>0){ value=num%10; num=num/10; dight--; } return value; } void RadixSort(int * s,int len,int dight){ int * buttet=new int[len]; int count[dight]; for(int i=1;i<=dight;i++){ for(int j=0;j<dight;j++){ count[j]=0; } for(int j=0;j<len;j++){ if(GetNumByPos(s[j],i)>=0){ count[GetNumByPos(s[j],i)]++; } } for(int j=1;j<dight;j++){ count[j]=count[j]+count[j-1]; } for(int j=len-1;j>=0;j--){ buttet[count[GetNumByPos(s[j],i)]-1]=s[j]; count[GetNumByPos(s[j],i)]--; } for(int j=0;j<len;j++){ s[j]=buttet[j]; } } } int main(){ int list[10]={278,109,63,930,589,184,505,269,8 ,83}; RadixSort(list,10,10); for(int i=0;i<10;i++){ cout<<list[i]<<" "; } cout<<endl; return 0; }
2、二路歸併排序ui
二路歸併排序的思想是開始就將數列劃分爲兩個部分,而後依次遞歸的對這兩部分執行二分操做,直到全部的部分都只包含一個元素位置,此時,再分別對這些部分執行歸併操做。直到整個數列都被歸併完畢。spa
代碼以下:code
/* 二路歸併排序,採用了遞歸的作法,它首先將整個隊列劃分爲兩個部分,再一次對這兩個部分進行二分操做, 直到每一個部分只包含一個元素爲止,而後再依次對這些只包含一個元素的部分開始進行歸併,而後遞歸操做會依次向上 進行回溯,最後返回已排好序的隊列,排序完成。 時間複雜度n*log2n */ #include <iostream> using namespace std; void Merge(int array[], int p, int q, int r) { int n1 = q - p + 1; int n2 = r - q; int *L; L = (int*)malloc(sizeof(int)*n1); int *R; R = (int*)malloc(sizeof(int)*n2); int i = 0; int j = 0; for(i; i < n1; i++) L[i] = array[i + p]; for(j; j < n2; j++) R[j] = array[j + q +1]; i = j = 0; int k = p; while(i!=n1 && j!= n2) { if(L[i] <= R[j]) array[k++] = L[i++]; else array[k++] = R[j++]; } while(i < n1) array[k++] = L[i++]; while(j < n2) array[k++] = R[j++]; free(L); free(R); } void merge(int * b,int s,int mid,int t){ int a[t-s+1]; int k=0;for(int i=s;i<=t;i++){ a[k++]=b[i]; }int i,j; int id=s; for(i=s,j=mid+1;i<=mid&&j<=t;){if(a[i-s]<a[j-s]){ b[id++]=a[i-s]; i++; }else{ b[id++]=a[j-s]; j++; } }while(i<=mid){ b[id++]=a[i-s]; i++; } while(j<=t){ b[id++]=a[j-s]; j++; } } void TwoGuiBing(int * a,int s,int e){ int * bb; if(s<e){ int mid=(s+e)/2; TwoGuiBing(a,s,mid); TwoGuiBing(a,mid+1,e); cout<<"before sort: "; for(int i=s;i<=e;i++){ cout<<a[i]<<" "; } cout<<endl; merge(a,s,mid,e); cout<<"after sort: "; for(int i=s;i<=e;i++){ cout<<a[i]<<" "; } cout<<endl; } } int main(){ int s[10]={4,1,5,2,4,3,98,6,65,1};//1 1 2 3 4 4 5 6 65 98 TwoGuiBing(s,0,9); for(int i=0;i<10;i++){ cout<<s[i]<<" "; } cout<<endl; return 0; }
3、快讀排序blog
快速排序的思想是每次都選擇一個標誌,將整個數列劃分爲兩個部分,而後在依次遞歸的對這兩個部分通用選取標誌進行劃分。直到每一個部分大小變爲1爲止。排序
代碼以下:遞歸
/* 快速排序就是首先將s[0]選定爲咱們的劃分標誌,而後,將隊列劃分爲兩個部分。而後再分別對這兩個部分進行劃分。 直到每一個部分只包含一個元素爲止。 時間複雜度n*log2n 不穩定排序,數列有序則退化爲冒泡排序。 */ #include <iostream> using namespace std; void swap(int & a,int & b){ int temp=a; a=b; b=temp; } int func(int * s,int b,int e){ int flag=s[b]; while(b<e){ while(b<e&&s[e]>=flag) e--;//必定要>=不然若是最後兩個數與flag相同,那麼整個while就會陷入死循環中。 swap(s[b],s[e]); while(b<e&&s[b]<=flag) b++; swap(s[b],s[e]); } return b; } void quickSort(int * s,int b,int e){ if(b<e){ int pos=func(s,b,e); quickSort(s,b,pos-1); quickSort(s,pos+1,e); } } int main(){ int s[10]={4,1,5,2,4,3,98,6,65,1};//1 1 2 3 4 4 5 6 65 98 quickSort(s,0,9); for(int i=0;i<10;i++){ cout<<s[i]<<" "; } cout<<endl; return 0; }
4、堆排序隊列
堆排序,經過每次構造一個大頂堆或者小頂堆,來查找出當前數列的最大值或最小值,而後交換堆頂與最後一個葉子節點,同時,將排序的範圍減一,直到排序的範圍減少到1,記住,初始時須要先將數列構造爲大頂堆或小頂堆。
代碼以下:
/* 時間複雜度n*log2n,咱們直到堆排序,須要首先構造一個大頂堆或者小頂堆,而後開始選出最大值或最小值,在這一過程當中,將其移動 到堆頂,而後交換堆頂和堆尾,縮小堆的大小,再次排序,直到堆的大小爲1爲止。 */ #include <iostream> using namespace std; int main(){ int s[10]={4,1,5,2,4,3,98,6,65,1};//1 1 2 3 4 4 5 6 65 98 for(int i=10;i>0;i--){//之因此將i設置爲從10開始,就是考慮了初始數列構造大頂堆或小頂堆的問題。 if(i<10){//初始時,無需交換堆頂和最後一個葉子結點。 int temp=s[i]; s[i]=s[0]; s[0]=temp; } for(int j=(i)/2;j>=0;j--){ int faV=s[j]; int fa=j; int child=2*j+1; while(child<i){ if(child+1<i&&s[child]<s[child+1]){ child++; } if(s[child]>s[fa]){//一直順着查找下去。 s[fa]=s[child]; fa=child; child=2*fa+1; }else{ break; } s[fa]=faV; } } } for(int i=0;i<10;i++){ cout<<s[i]<<" "; } cout<<endl; return 0; }
5、希爾排序
希爾排序經過設置間隔,來將數列進行分組,而後對於每組的數據使用直接插入排序。以後,在將間隔減少爲其的一半,直到間隔減少到0爲止。
代碼以下:
/* 經過設置間隔來實現,首先將間隔設置爲隊列大小的一半,對相同間隔內的元素執行直接插入排序。 時間複雜度n到n*n */ #include <iostream> using namespace std; int main(){ int s[10]={4,1,5,2,4,3,98,6,65,1}; int jianGe=10/2; while(jianGe>=1){ for(int i=jianGe;i<10;i++){ int j=i-jianGe; int val=s[i];//在後面的變換中,s[i]對應的值已經發生了變化。 while(s[j]>val&&j>=0){ s[j+jianGe]=s[j]; j=j-jianGe; } s[j+jianGe]=val; } jianGe=jianGe/2; } for(int i=0;i<10;i++){ cout<<s[i]<<" "; } cout<<endl; return 0; }
6、直接插入排序
直接插入排序的思想就是假設初始的有序序列大小爲1,而後依次擴大這個有序序列。
代碼以下:
/* 首先有序隊列只包含第一個元素,隨後逐漸擴充其大小,每次將新值與有序隊列末尾的值進行比較, 找到其位置。 時間複雜度爲n*n; */ #include <iostream> using namespace std; int main(){ int s[10]={4,1,5,2,4,3,98,6,65,1}; for(int i=1;i<10;i++){ if(s[i]>s[i-1]){ continue; }else{ int j=i-1; int val=s[i]; while(s[j]>val){ s[j+1]=s[j]; j--; } s[j+1]=val; } } for(int i=0;i<10;i++){ cout<<s[i]<<" "; } cout<<endl; return 0; }
7、冒泡排序
冒泡排序的每次遍歷都會比較臨近元素的大小,不知足要求就交換其順序,每次遍歷都會找到一個當前查找範圍的最大值或最小值。直到查找範圍縮小到1。
代碼以下:
#include <iostream> using namespace std; int main(){ int s[10]={4,1,5,2,4,3,98,6,65,1};//1 1 2 3 4 4 5 6 65 98 for(int i=0;i<10;i++){ for(int j=0;j<9-i;j++){ if(s[j]>s[j+1]){ int temp=s[j]; s[j]=s[j+1]; s[j+1]=temp; } } } for(int i=0;i<10;i++){ cout<<s[i]<<" "; } cout<<endl; return 0; }
8、簡單選擇排序
簡單選擇排序會在每次遍歷中找到它的最小值或最大值,而後縮小查找的範圍,直到查找範圍縮小到1.
代碼以下:
/* 每次找出最小值放置,時間複雜度n*n */ #include <iostream> using namespace std; int main(){ int s[10]={4,1,5,2,4,3,98,6,65,1}; for(int i=0;i<10;i++){ int min=i; for(int j=i+1;j<10;j++){ if(s[j]<s[min]){ min=j; } } if(min!=i){ int temp=s[i]; s[i]=s[min]; s[min]=temp; } } for(int i=0;i<10;i++){ cout<<s[i]<<" "; } cout<<endl; return 0; }
總結:
(1)平方階(O(n2))排序
各種簡單排序:直接插入、直接選擇和冒泡排序;
(2)線性對數階(O(nlog2n))排序
快速排序、堆排序和歸併排序;
(3)O(n1+§))排序,§是介於0和1之間的常數。
希爾排序
(4)線性階(O(n))排序
基數排序,此外還有桶、箱排序。
說明:
當原表有序或基本有序時,直接插入排序和冒泡排序將大大減小比較次數和移動記錄的次數,時間複雜度可降至O(n);
而快速排序則相反,當原表基本有序時,將蛻化爲冒泡排序,時間複雜度提升爲O(n2),每次劃分都會將數列劃分爲一個空數組和一個大小減一的數組,故比較次數爲n-1,n-2,n-2,.......1,故爲o(n2)。
原表是否有序,對簡單選擇排序、堆排序、歸併排序和基數排序的時間複雜度影響不大。
穩定性:
排序算法的穩定性:若待排序的序列中,存在多個具備相同關鍵字的記錄,通過排序, 這些記錄的相對次序保持不變,則稱該算法是穩定的;若經排序後,記錄的相對 次序發生了改變,則稱該算法是不穩定的。
穩定性的好處:排序算法若是是穩定的,那麼從一個鍵上排序,而後再從另外一個鍵上排序,第一個鍵排序的結果能夠爲第二個鍵排序所用。基數排序就是這樣,先按低位排序,逐次按高位排序,低位相同的元素其順序再高位也相同時是不會改變的。另外,若是排序算法穩定,能夠避免多餘的比較;
穩定的排序算法:冒泡排序、插入排序、歸併排序和基數排序
不是穩定的排序算法:選擇排序、快速排序、希爾排序、堆排序