排序演算法總結

來源:互聯網
上載者:User

標籤:c   資料結構   排序   

本文原創,轉載請註明來自http://blog.csdn.net/j903829182/article/details/38018507


/*1.排序分為內排序和外排序2種。內排序是把待排資料元素全部調入記憶體中進行的排序。如果資料元素的數量太大,  需要分批匯入記憶體中。分批匯入記憶體的資料元素排好序後再分批匯出到磁碟或磁帶等外存介質中的排序方法稱作為  外部排序。 2.排序有:直接插入排序,希爾排序,直接選擇排序,堆排序,冒泡排序,快速排序,二路歸併排序和基數排序 3.排序的好壞標準:時間複雜度,空間複雜度,穩定性(當使用主關鍵字排序時,任何排序演算法的排序結果必定是相同的。   但當使用次關鍵字排序時,其排序結果有可能相同,也有可能不同。設待排序的資料元素共有n個,設ki和kj分別表示第   i個資料元素的關鍵字和第j個資料元素的關鍵字,設Ri和Rj分別表示第i個資料元素和第j個資料元素。若Ki=Kj,且在排序   之前資料元素Ri排在資料元素Rj之前,在排序之後資料元素Ri仍排在Rj前邊的排序演算法稱作穩定的排序演算法;否則,稱作不穩定的   拍戲演算法。穩定的排序演算法是通常是應用問題所希望的,因此,排序演算法的穩定性是衡量排序演算法好壞的一個重要標準。)*/#include<stdio.h>#include<malloc.h>typedef int KeyType;typedef struct{KeyType key;}DataType;/*1.插入排序的基本思想:從初始有序的子集合開始,不斷地把新的資料元素插入到已排列有序子集合的合適位置,使子集合中資料元素的個數不斷增多,當子集合等於集合時,插入排序演算法結束。常用的插入排序有直接插入排序和希爾排序2種。2.直接插入排序的基本思想:順序的把待排序的資料元素按其關鍵字值的大小插入到已排序資料元素子集合的合適位置。子集合的資料元素個數  從只有一個資料元素開始,逐次增大,當子集合大小最終和集合大小相同時,排序完畢。3直接插入排序演算法的時間複雜度: 最好:O(n) 最壞:O(n^2) 隨機:O(n^2) 未經處理資料越接近有序,直接插入排序演算法的時間效率越高,其時間效率在O(n)與O(n^2)之間4.直接插入排序的空間複雜度為O(1),直接插入排序是一種穩定的排序演算法*///直接插入排序演算法void InsertSort(DataType a[],int n){//用直接插入法對數組元素a[0]-a[n-1]進行排序int i,j;DataType temp;for(i=0;i<n-1;i++){temp=a[i+1];j=i;while(j>-1&&temp.key<a[j].key){a[j+1]=a[j];j--;}a[j+1]=temp;}}/*1.希爾排序的基本思想:把待排序的資料元素分成若干個小組,對同一小組內的資料元素用直接插入法排序;  小組的個數逐次減少;當完成所有資料元素都在一個組內的排序後,排序過程結束。希爾排序又稱作縮小增量排序。 2.希爾排序演算法的時間複雜度較直接插入排序演算法的時間複雜度改善很多 3.研究表明若增量取值較合理,則希爾排序演算法的時間複雜度約為O(n(lbn)^2) 4.希爾排序演算法的空間複雜度為O(1),由於希爾排序是增量分組排序,所以希爾排序演算法是一種不穩定的排序演算法*///希爾排序的演算法函數void ShellSort(DataType a[],int n,int d[],int numOfD){//用希爾排序法對元素a[0]到a[n-1]排序,d[0]--d[numOfD-1]為希爾增量值int i,j,k,m,span;DataType temp;for(m=0;m<numOfD;m++){//共numOfD次迴圈span=d[m];//取本次的增量值for(k=0;k<span;k++){//共span個小組//組內是直接插入排序,區別是,每次不是增加1而是spanfor(i=k;i<n-span;i=i+span){temp=a[i+span];j=i;while(j>-1&&temp.key<a[j].key){a[j+span]=a[j];j=j-span;}a[j+span]=temp;}}}}/*1.選擇排序的基本思想:每次從待排序的資料元素集合中選取關鍵字最小(或最大)的資料元素放到資料元素集合  的最前面(或最後面),資料元素集合不斷縮小,當資料元素集合為空白時,選擇排序結束。常用的選擇排序有直接選擇排序  和堆排序2種。堆排序是一種基於完全二叉樹的排序。*//*1.直接選擇排序的基本思想:從待排序的資料元素集合中選取關鍵字最小的資料元素並將它與未經處理資料元素集合中的第一個資料元素交換位置;  然後從不包含第一個位置上資料元素的集合中選取關鍵字最小的資料元素,並將它與未經處理資料元素集合中的第二個資料元素交換;如此重複,  直到資料元素集合中只剩下一個資料元素為止。2.直接選擇排序的演算法的時間複雜度為O(n^2),空間複雜度為O(1),直接選擇排序是不穩定的排序演算法。*///直接選擇排序的演算法如下void SelectSort(DataType a[],int n){//用直接選擇排序法對數組元素a[0]--a[n-1]進行排序int i,j,small;DataType temp;for(i=0;i<n-1;i++){small=i;//設第i個資料元素關鍵字最小for(j=i+1;j<n;j++){//尋找關鍵字最小的資料元素if(a[j].key<a[small].key){small=j;//記住最小的下標}}if(small!=i){//當最小元素的下標不為i時交換位置temp=a[i];a[i]=a[small];a[small]=temp;}}}/*1.堆排序分為最大堆(也稱大頂堆或大根堆)和最小堆(也稱小頂堆或小根堆)2.最大堆的定義:設數組a中存放了n個資料元素,數組下標從0開始,如果當數組下標2i+1<n時有  a[i].key>=a[2i+1].key,當數組下標2i+2<n時有a[i].key>=a[2i+2].key,則這樣的資料結構稱為最大堆3.最小堆的定義:設數組a中存放了n個資料元素,數組下標從0開始,如果當數組下標2i+1<n時有  a[i].key<=a[2i+1].key,當數組下標2i+2<n時有a[i].key<=a[2i+2].key,則這樣的資料結構稱為最小堆4.最大堆的根結點是堆中值最大的資料元素,最小堆的根節點是堆中值最小的資料元素。對於最大堆,從根結點到每個分葉節點  的路徑上,資料元素組成的序列都是遞減有序的;對於最小堆,從根結點到每個分葉節點的路徑上,資料元素組成的序列都是遞增有序的。5.堆排序的基本思想:首先把n元素的數組a初始化建立為最大堆,然後迴圈執行如下過程直到數組為空白為止:  a.把堆頂a[0]元素(為最大元素)和當前最大堆的最後一個元素交換;  b.最大堆元素個數減1;  c.由於第a步後根節點不再滿足最大堆的定義,所以調整根結點使之滿足最大隊的定義。6.堆排序演算法的時間複雜度為O(nlbn),堆排序的空間複雜度為O(1),堆排序是一種不穩定的排序演算法*/void CreateHeap(DataType a[],int n,int h){//調整非葉結點a[h]使之滿足最大堆,n為數組a的元素個數int i,j,flag;DataType temp;i=h;//i為要建立堆的二叉樹根節點j=2*i+1;//j為i的左孩子節點的下標temp=a[i];flag=0;//沿左右孩子中值較大者重複向下篩選while(j<n&&flag!=1){//尋找左右孩子節點中的較大者,j為其下標if(j<n-1&&a[j].key<a[j+1].key){j++;}if(temp.key>a[j].key){//a[i].key.key>a[j].keyflag=1;//標誌結束篩選條件}else{//否則把a[j]上移a[i]=a[j];i=j;j=2*i+1;}}a[i]=temp;}void InitCreatHeap(DataType a[],int n){//把數組元素a[0]--a[n-1]初始化建立為最大堆int i;for(i=(n-2)/2;i>=0;i--){CreateHeap(a,n,i);}}//堆排序演算法函數如下void HeapSort(DataType a[],int n){//用堆排序法對數組元素a[0]--a[n-1]進行排序int i;DataType temp;InitCreatHeap(a,n);//初始化建立最大堆for(i=n-1;i>0;i--){//當前最大堆個數每次遞減1//把堆頂a[0]元素和當前最大堆的最後一個元素交換temp=a[0];a[0]=a[i];a[i]=temp;CreateHeap(a,i,0);//調整根結點滿足最大堆//注意此時二叉樹根結點下標為0,子二叉樹結點個數為i}}/*1.利用交換資料元素的位置進行排序的方法稱作為交換排序。常用的交換排序方法有冒泡排序法和快速排序法。  快速排序法是一種分區交換排序方法2.冒泡排序的基本思想:設數組a中存放了n個資料元素,迴圈進行n-1趟如下的排序過程;第一趟時,依次比較相鄰兩個資料元素  a[i].key 和a[i+1].key(i=0,1,2,3....n-2),若為逆序,即a[i].key >a[i+1].key,則交換兩個資料元素,否則不交換,這樣數值最大  的資料元素將放置在a[n-1]中;第二趟時,資料元素減1,即資料元素個數為n-1,操作方法和第一趟的類似,這樣整個n個資料元素  集合中數值次大的資料元素將放置在a[n-2]中;當第n-1趟結束時,整個n個資料元素集合中次小資料元素放置在a[1]中,a[0]放置了  最小的資料元素。3.冒泡排序的最好時間複雜度為O(n),最壞時間複雜度為O(n^2),冒泡排序的空間複雜度為O(1),冒泡排序是一種穩定的排序演算法*///冒泡排序的演算法函數void BubbleSort(DataType a[],int n){//用冒泡排序法對數組元素a[0]--a[n-1]進行排序int i,j,flag=1;DataType temp;for(i=1;i<n&&flag==1;i++){flag=0;for(j=0;j<n-i;j++){if(a[j].key>a[j+1].key){flag=1;temp=a[j];a[j]=a[j+1];a[j+1]=temp;}}}}/*1.快速排序是一種二叉樹結構的交換排序方法2.快速排序演算法的基本思想:設數組a中存放了n個資料元素,low為數組的低端下標,high為數組  的高端下標,從數組a中任取一個元素(通常取a[low])作為標準,調整數組a中各個元素的位置,使  排在標準元素前面元素的關鍵字均小於標準元素的關鍵字,排在標準元素後面元素的關鍵字均大於或等於  標準元素的關鍵字。這樣一次過程結束後,一方面將標準元素放在未來排好序的數組中該標準元素應在的位置,  另一方面將數組中德元素以標準元素為中心分成了兩個子數組,位於標準元素左邊子數組中元素的關鍵字均  小於標準元素的關鍵字,位於標準元素右邊子數組中元素的關鍵字均大於或等於標準元素的關鍵字。對這兩個子數組  中的元素分別再進行方法類同的遞迴快速排序。遞迴演算法的結束條件是high<=low,即上界下標小於或等於下界下標。3.快速排序的最好情況下時間複雜度為O(nlbn),最壞情況下為O(n^2),快速排序的平均時間複雜度為O(nlbn);  快速排序演算法空間複雜度最壞為O(n),快速排序演算法是一種不穩定的排序演算法*///快速排序演算法函數void QuickSort(DataType a[],int low,int high){//對資料元素a[low]--a[high]進行快速排序int i=low,j=high;DataType temp=a[low];//取第一個元素為標準資料元素while(i<j){while(i<j&&temp.key<=a[j].key){j--;//在數組的右端掃描}if(i<j){a[i]=a[j];i++;}while(i<j&&a[i].key<temp.key){//在數組的左邊掃描i++;}if(i<j){a[j]=a[i];j--;}}a[i]=temp;if(low<i){QuickSort(a,low,i-1);//對左端子集合進行歸併}if(i<high){QuickSort(a,j+1,high);//對右端子集合進行歸併}}/*1.歸併排序主要是二路歸併排序2.二路歸併排序的基本思想:蛇數組a中存放了n個資料元素,初始時把他們看成是n個長度為1的有序子數組,然後  從第一個有序子數組開始,把相鄰的有序子數組兩兩合并,得到[n/2]個長度為2的新的有序子數組(當n為奇數時,  最後一個新的有序子數組的長度為1)。對這些新的有序子數組在進行兩兩歸併。如此反覆,直到得到一個長度為n  的有序數組為止。3.二路歸併排序的時間複雜度為O(nlbn),空間複雜度為O(n),是一種穩定的排序演算法,這是其他時間複雜度為O(nlbn)不穩定的  排序,這穩定是歸併排序的最大的特點*///一次二路歸併排序演算法void Merge(DataType a[],int n,DataType swap[],int k){//k為有序子數組的長度,一次二路歸併排序後的有序子序列存於數組swap中int m=0,u1,l2,i,j,u2;int low=0;//第一個有序子數組下界為0while(low+k<=n-1){l2=low+k;//計算第二個有序數組下界u1=l2-1;//計算第一個有序子數組上界u2=((l2+k-1)<=(n-1))?(l2+k-1):(n-1);//計算第二個有序子數組上界//兩個有序子數組合并for(i=low,j=l2;i<u1&&j<=u2;m++){if(a[i].key<=a[j].key){swap[m]=a[i];i++;}else{swap[m]=a[j];j++;}}//子數組2已經歸併完,將子數組1中剩餘的元素存放到數組swap中while(i<=u1){swap[m]=a[i];m++;i++;}//子數組1已經歸併完,將子數組2中剩餘的元素存放到數組swap中while(j<=u2){swap[m]=a[j];m++;j++;}low=u2+1;}//將原數組中只夠一組的資料元素順序存放到數組swap中for(i=low;i<n;i++,m++){swap[m]=a[i];}}//二路歸併排序演算法void MergeSort(DataType a[],int n){int i,k=1;//歸併長度從1開始DataType *swap;swap=(DataType *)malloc(sizeof(DataType)*n);//申請動態數組空間while(k<n){Merge(a,n,swap,k);//調用歸併函數Merge(DataType a[],int n,DataType swap[],int k)for(i=0;i<n;i++){a[i]=swap[i];//將元素從臨時數組swap放回數組a中}k=2*k;//歸併長度加倍}free(swap);//釋放動態數組空間}/*1.基數排序也稱作桶排序,是一種當關鍵字為整數類型時非常高效的排序演算法.2.基數排序的基本思想:設待排序的資料元素關鍵字是m位d進位整數(不足m位的關鍵字在高位補0),  設定d個桶,令其編號分別為0,1,2,3,4....d-1.首先按關鍵字最低位的數值依次把各資料元素放到相應的桶中  ,然後按照桶號從小到大和進入桶中資料元素的先後次序收集分配在各桶中的資料元素,這樣就形成了資料元素集合的一個新的  排列,稱這樣的一次排序過程為一次基數排序;再對一次基數排序得到的資料元素序列按關鍵字次低位的數值  依次把各資料元素放到相應的桶中,然後按照桶從小到大和進入桶中資料元素的先後次序收集分配在各桶中的資料元素;這樣的  過程重複進行,當完成了第m次基數排序後,就得到了排好序的資料元素序列。 //基於鏈式隊列的基數排序演算法的時間複雜度為O(2mn)或O(mn) //基於鏈式隊列的基數排序演算法的空間複雜度為O(n) //基於順序隊列的基數排序演算法時間複雜度為O(2mn)或O(mn),空間複雜度為O(mn) //基數排序是一種穩定的排序演算法*/typedef struct qnode{//鏈式隊列的結點DataType data;//資料部分struct qnode *next;//指向下一個結點}LQNode;typedef struct{LQNode *front;//隊頭指標    LQNode *rear;//對尾指標}LQueue;//初始化隊列void QueueInitiate(LQueue *q){//初始化鏈式隊列qq->front=NULL;//定義初始隊尾指標下標值q->rear=NULL;//定義初始對頭指標下標值}//非空否int QueueNotEmpty(LQueue q){//判斷鏈式隊列q非空否,非空則返回1,否則返回0if(q.front==NULL){return 0;}else{return 1;}}//入隊列void QueueAppend(LQueue *q,DataType x){//把資料元素值x插入鏈式隊列q的隊尾LQNode *p;p=(LQNode *)malloc(sizeof(LQNode));p->data=x;p->next=NULL;if(q->rear!=NULL){//隊列原來非空時隊尾加新結點q->rear->next=p;}q->rear=p;//修改隊尾指標if(q->front==NULL){//隊列原來為空白時修改對頭指標q->front=p;}}//出隊列int QueueDelete(LQueue *q,DataType *d){//刪除鏈式隊列q的對頭資料元素值d,出隊列成功返回1,否則返回0LQNode *p;if(q->front==NULL){printf("隊列已空無資料元素出隊列!!\n");return 0;}else{*d=q->front->data;p=q->front;q->front=q->front->next;//出隊列結點脫鏈if(q->front==NULL){q->rear=NULL;}free(p);return 1;}}//取對頭資料元素int QueueGet(LQueue q,DataType *d){//取鏈式隊列q的隊頭資料元素到d,成功返回1,否則返回0if(q.front==NULL){printf("隊列已空無資料元素出隊列!!\n");return 0;}else{*d=q.front->data;return 1;}}//撤銷動態申請空間void Destroy(LQueue q){LQNode *p,*p1;p=q.front;while(p!=NULL){p1=p;p=p->next;free(p1);}}//基數排序//基於鏈式隊列的基數排序演算法的時間複雜度為O(2mn)或O(mn)//基於鏈式隊列的基數排序演算法的空間複雜度為O(n)//基於順序隊列的基數排序演算法時間複雜度為O(2mn)或O(mn),空間複雜度為O(mn)//基數排序是一種穩定的排序演算法void RadixSort(DataType a[],int n,int m,int d){//對資料元素a[0]--a[n-1]進行關鍵字為m位d進位整形數值的基數排序//桶採用鏈式隊列int i,j,k,power=1;LQueue *tub;//把d個隊列定義為動態數組tub=(LQueue *)malloc(sizeof(LQueue)*d);for(i=0;i<d;i++){QueueInitiate(&tub[i]);//d的隊列分別初始化}//進行m次放和收for(i=0;i<m;i++){if(i==0){power=1;}else{power=power*d;}//將資料元素按關鍵字第k位的數值放到相應的隊列中for(j=0;j<n;j++){k=a[j].key/power-(a[j].key/(power*d))*d;//計算kQueueAppend(&tub[k],a[j]);//把a[j]放入第k個隊列中}//順序回收各隊列中的資料元素至數組a中k=0;for(j=0;j<d;j++){while(QueueNotEmpty(tub[j])!=0){QueueDelete(&tub[j],&a[k]);//從各隊列中回收k++;}}}}void main(){DataType test[6]={64,5,7,89,6,24};DataType b[]={65,34,25,87,12,38,56,46,14,77,92,23};DataType c[]={88,76,40,50,10,9,32,5};    int d[]={6,3,1};int i,n=6;//直接插入排序測試InsertSort(test,n);printf("直接插入排序: ");for(i=0;i<n;i++){printf("%d  ",test[i].key);}printf("\n");//希爾測試ShellSort(b,12,d,3);printf("希爾排序: ");for(i=0;i<12;i++){printf("%d  ",b[i].key);}printf("\n");//直接選擇排序    SelectSort(test,n);printf("直接選擇排序: ");for(i=0;i<n;i++){printf("%d  ",test[i].key);}printf("\n");//堆排序    HeapSort(c,8);printf("堆排序: ");for(i=0;i<8;i++){printf("%d  ",c[i].key);}printf("\n");//冒泡排序    BubbleSort(test,n);printf("冒泡排序: ");for(i=0;i<n;i++){printf("%d  ",test[i].key);}printf("\n");//快速排序    DataType quick[]={98,78,67,3,2,56,44,55,48,88};    QuickSort(quick,0,9);printf("快速排序: ");for(i=0;i<10;i++){printf("%d  ",quick[i].key);}printf("\n");   //歸併排序    DataType meger[]={72,73,71,23,94,16,5,68,64};//歸併排序有點bug一下沒找到    MergeSort(meger,9);printf("歸併排序: ");for(i=0;i<9;i++){printf("%d  ",meger[i].key);}printf("\n");//基數排序    DataType jishu[]={710,342,45,686,6,841,429,134,68,246};        RadixSort(jishu,10,3,10);printf("基數排序: ");for(i=0;i<10;i++){printf("%d  ",jishu[i].key);}printf("\n");}




排序結果:

  




排序演算法總結

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.