排序杂谈

最近正好计导和c语言都讲到排序问题,以前都是了解概念之后直接用sort,这次把各种排序算法都代码实现一下。

 

题目传送门

 

插入排序

把序列分成两部分,前一部分为已排好序部分,后一部分未排序。(初始1~1为已排序部分,2~n为未排序部分)

然后从未排序部分中取一个数,将其加入已排序部分的对应位置中。

 

代码实现:

 1 // 插入排序  升序 
 2 #include<iostream>
 3 #include<cstdio>
 4 #include<cstring>
 5 #include<algorithm>
 6 #include<queue>
 7 using namespace std ;
 8 const int N = 100000 + 10 ;
 9 
10 inline int read() {
11     int k = 0, f = 1 ; char c = getchar() ;
12     for( ; !isdigit(c) ; c = getchar())
13       if(c == '-') f = -1 ;
14     for( ; isdigit(c) ; c = getchar())
15       k = k*10 + c-'0' ;
16     return k*f ;
17 } 
18 
19 int n ;
20 int hh[N] ;
21 
22 int main() {
23     n = read() ;
24     for(int i=1;i<=n;i++) hh[i] = read() ;
25     for(int i=2;i<=n;i++) {
26         int t = hh[i] ;
27         for(int j=1;j<i;j++) {    // 新加入一个未排序的数 
28             if(hh[j] > t) {   // 在已经排好序的数据中找到第一个比它大的数 
29                 for(int k=i;k>j;k--) hh[k] = hh[k-1] ;  // 比它大的数都后移一位
30                 hh[j] = t ; 
31                 break ;
32             }
33         }
34     }
35     for(int i=1;i<=n;i++) printf("%d ",hh[i]) ;
36     return 0 ;
37 }

 

复杂度:O(n^2)  (严格)

 

选择排序

每次从未排序序列中找到最小的数,加入已排序序列的末尾

 

代码实现:

 

 1 // 选择排序  升序 
 2 #include<iostream>
 3 #include<cstdio>
 4 #include<cstring>
 5 #include<algorithm>
 6 #include<queue>
 7 using namespace std ;
 8 const int N = 100000 + 10 ;
 9 const int INF = 0x7ffffff ;
10 
11 inline int read() {
12     int k = 0, f = 1 ; char c = getchar() ;
13     for( ; !isdigit(c) ; c = getchar())
14       if(c == '-') f = -1 ;
15     for( ; isdigit(c) ; c = getchar())
16       k = k*10 + c-'0' ;
17     return k*f ;
18 } 
19 
20 int n ;
21 int hh[N] ;
22 
23 int main() {
24     n = read() ;
25     for(int i=1;i<=n;i++) hh[i] = read() ;
26     for(int i=1;i<=n;i++) {  
27         int minn = INF, pp ;   // pp记录最小值位置 
28         for(int j=i;j<=n;j++) {   
29             if(hh[j] < minn) {
30                 minn = hh[j] ;  pp = j ;
31             }
32         }
33         for(int j=pp;j>i;j--) hh[j] = hh[j-1] ;   // 元素后移 
34         hh[i] = minn ;
35     }
36     for(int i=1;i<=n;i++) printf("%d ",hh[i]) ;
37     return 0 ;
38 }

 

 

复杂度:O(n^2)(严格) (比插入排序常数更大些)

 

冒泡排序:

执行n轮,对于每轮:

扫一遍数组,如果发现一个元素比它的后继元素大,就交换它们

 

代码:

 

 1 // 冒泡排序  升序 
 2 #include<iostream>
 3 #include<cstdio>
 4 #include<cstring>
 5 #include<algorithm>
 6 #include<queue>
 7 using namespace std ;
 8 const int N = 100000 + 10 ;
 9 const int INF = 0x7ffffff ;
10 
11 inline int read() {
12     int k = 0, f = 1 ; char c = getchar() ;
13     for( ; !isdigit(c) ; c = getchar())
14       if(c == '-') f = -1 ;
15     for( ; isdigit(c) ; c = getchar())
16       k = k*10 + c-'0' ;
17     return k*f ;
18 } 
19 
20 int n ;
21 int hh[N] ;
22 
23 int main() {
24     n = read() ;
25     for(int i=1;i<=n;i++) hh[i] = read() ;
26     for(int i=1;i<n;i++) {
27         for(int j=1;j<=n-i;j++)
28           if(hh[j] > hh[j+1]) swap(hh[j],hh[j+1]) ;
29     }
30     for(int i=1;i<=n;i++) printf("%d ",hh[i]) ;
31     return 0 ;
32 }

 

 

 

复杂度:O(n^2) (严格) 

不过可以优化一下,就是对于每一轮做一个标记,如果发现该轮中一次swap都没有做,就说明数组已排序完毕,就可以break了。

 

桶排序:

假如数据为0~500000内的整数,那我们就假设有500001个桶,编号分别为0~500000。

对于数组中的每一个数,将其放到对应的桶中。

最后从小到大遍历每个桶,将其中的数输出出来即可。

 

代码:

 

 1 // 桶排序  升序 
 2 #include<iostream>
 3 #include<cstdio>
 4 #include<cstring>
 5 #include<algorithm>
 6 #include<queue>
 7 using namespace std ;
 8 const int N = 100000 + 10 ;
 9 const int M = 500000 + 10 ; 
10 const int INF = 0x7ffffff ;
11 
12 inline int read() {
13     int k = 0, f = 1 ; char c = getchar() ;
14     for( ; !isdigit(c) ; c = getchar())
15       if(c == '-') f = -1 ;
16     for( ; isdigit(c) ; c = getchar())
17       k = k*10 + c-'0' ;
18     return k*f ;
19 } 
20 
21 int n ;
22 int buc[M] ;
23 
24 int main() {
25     n = read() ;
26     for(int i=1;i<=n;i++) buc[read()]++ ;
27     for(int i=0;i<=500000;i++) {
28         while(buc[i]--) printf("%d ",i) ;
29     }
30     return 0 ;
31 }

 

 

 

复杂度:O(n+m) m表示数据范围

桶排序只适用于数据范围较小,且数据均为整数(或类似)的情况。不过对于非整形数据,我们有时可以将其离散化,然后适用桶排序。

桶排序较其他排序方式较为特殊,有些情况下会起到出人意料的效果!

 

快速排序:

对于一段未排序的序列,选取一个sdd(标准数),将小于标准数的放入一个序列,大于等于标准数的放入另一个序列,然后再递归处理两个子序列。

 

代码:

 

// 快速排序  升序 
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
using namespace std ;
const int N = 100000 + 10 ;
const int M = 500000 + 10 ; 
const int INF = 0x7ffffff ;

inline int read() {
    int k = 0, f = 1 ; char c = getchar() ;
    for( ; !isdigit(c) ; c = getchar())
      if(c == '-') f = -1 ;
    for( ; isdigit(c) ; c = getchar())
      k = k*10 + c-'0' ;
    return k*f ;
} 

int n ;  int hh[N] ;

void q_sort(int l,int r) {
    
//    int mid = (l+r)>>1 ;
//    printf("\nl,r:%d,%d",l,r) ;
    
    if(l >= r) return ;
    int ll = l, rr = r ;  int sdd = hh[ll] ;
    while(ll < rr) {
        while(hh[ll] < sdd && ll < r) ll++ ;
        while(hh[rr] >= sdd && rr > l) rr-- ;
        if(ll >= rr) break ;
        swap(hh[ll],hh[rr]) ;
    }
    int mm = rr ;
    
//    for(int i=1;i<=3;i++) printf("%d ",hh[i]) ;  printf("\n") ;
//    printf("\nmm:%d\n",mm) ;
    
    q_sort(l,mm) ; q_sort(mm+1,r) ;
}

int main() {
    n = read() ;
    for(int i=1;i<=n;i++) hh[i] = read() ;
    q_sort(1,n) ;
    for(int i=1;i<=n;i++) printf("%d ",hh[i]) ;
    return 0 ;
}

 

复杂度:O(nlogn)   (理想) 

 

归并排序:

先将待排序序列平均分成两个序列,递归处理。

待两个子序列排好序后,依次比较两个子序列中最小的数,将其提取出来,放入新的序列中。

 

代码:

 1 // 归并排序 升序 
 2 #include<iostream>
 3 #include<cstdio>
 4 #include<cstring>
 5 #include<cmath>
 6 using namespace std ;
 7 const int N = 100000 + 10 ;
 8 
 9 inline int read() {
10     int k = 0, f = 1 ; char c = getchar() ;
11     for( ; !isdigit(c) ; c = getchar())
12       if(c == '-') f = -1 ;
13     for( ; isdigit(c) ; c = getchar())
14       k = k*10 + c-'0' ;
15     return k*f ;
16 }
17 
18 int n ;  int hh[N], gg[N] ;
19 
20 void m_sort(int l,int r) {
21     if(l == r) return ;
22     int mid = (l+r)>>1 ;
23     m_sort(l,mid) ; m_sort(mid+1,r) ;
24     int l1 = l, l2 = mid+1 ;
25     int now = l ;
26     for(int i=l;i<=r;i++) {
27         if(l1 > mid) {
28             gg[now++] = hh[l2++] ;
29         } else if(l2 > r) {
30             gg[now++] = hh[l1++] ;
31         } else {
32             if(hh[l1] < hh[l2]) {
33                 gg[now++] = hh[l1++] ;
34             } else gg[now++] = hh[l2++] ;
35         }
36     }
37     for(int i=l;i<=r;i++) hh[i] = gg[i] ;
38 }
39 
40 int main() {
41     n = read() ;
42     for(int i=1;i<=n;i++) hh[i] = read() ;
43     m_sort(1,n) ;
44     for(int i=1;i<=n;i++) printf("%d ",hh[i]) ;
45     return 0 ;
46 }

 

复杂度:O(nlogn)  (严格)

上述代码为二路归并,其实也可以多路归并。

 

不正经系列待更新~

 

posted @ 2019-10-12 19:18  zubizakeli  阅读(105)  评论(0编辑  收藏  举报