排序杂谈

最近正好计导和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)  (严格)

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

不正经系列待更新~

原文地址:https://www.cnblogs.com/zub23333/p/11656601.html

时间: 2024-11-08 18:21:27

排序杂谈的相关文章

排序算法杂谈(五) —— 关于快速排序的优化策略分析

1. 前提 排序算法(六) -- 归并排序 排序算法(七) -- 快速排序 排序算法杂谈(四) -- 快速排序的非递归实现 2. 优化策略1:主元(Pivot)的选取 归并排序(Merge Sort)有一个很大的优势,就是每一次的递归都能够将数组平均二分,从而大大减少了总递归的次数. 而快速排序(Quick Sort)在这一点上就做的很不好. 快速排序是通过选择一个主元,将整个数组划分(Partition)成两个部分,小于等于主元 and 大于等于主元. 这个过程对于数组的划分完全就是随机的,俗

数据结构杂谈(一)浅谈基本排序算法

0.基本概念 记录:待排序的项目 关键词:决定排序结果 稳定性:相同关键词的记录保持原来的相对次序 1.1插入排序(Insertion Sort) 算法思想 一种简单直观的排序算法,工作原理是通过构建有序序列:对于未排序数据,在已排序序列中从后向前扫描,找到相应位置并插入. 算法描述 具体算法描述如下: 从第一个元素开始,该元素可以认为已经被排序 取出下一个元素,在已经排序的元素序列中从后向前扫描 如果该元素(已排序)大于新元素,将该元素移到下一位置 重复步骤3,直到找到已排序的元素小于或者等于

数据结构杂谈(二)简单有趣的地精排序Gnome sort

很早之前便听说过地精排序的名字,今天自己看来一下,发现这是一种非常简单而且有趣的排序算法. 为什么叫地精排序? 地精排序在2000年由Dr. Hamid Sarbazi-Azad 提出的时候被称作 stupid sort,可见其思想的简单性.后来,这个算法被Dick Grune 描述成地精排序Gnome sort. 故事背景: Here is how a garden gnome sorts a line of flower pots.  Basically, he looks at the f

排序算法杂谈(一) —— 量化数组的有序程度

1. 基本有序 在众多排序算法中,有一个概念被多次提及:数组基本有序. 例如: 直接插入排序(Insertion Sort)在面对数组基本有序时,体现出良好的性能. 平滑排序(Smooth Sort)在数组趋向有序时,其时间复杂度趋向于 O(n). 快速排序(Quick Sort)和堆排序(Heap Sort),在面对基本有序的数组时,并不会对其排序的速度有所增长. 正是由于这个性质,使得直接插入排序,相比于时间复杂度同为 O(n^2) 的冒泡排序(Bubble Sort),拥有了更多的使用场景

排序算法杂谈(二) —— 冒泡排序的递归实现

众所周知,循环和递归,在很多情况下是可以互相转换的. 那么,冒泡排序(Bubble Sort),作为典型的双重循环结构,也可以将其转化成递归形式. 但是,将递归转化为循环,对于程序的运行是有益的,因为它避免了不可预知的"方法压栈"的现象出现. 而将循环化为递归,多数情况下,不推荐这么做,即使递归的代码可能实现地非常漂亮.漂亮与高效往往是冲突的. 所以,以下的冒泡排序仅作参考,读者可以用它来拓宽思维.但是,永远不要这样写冒泡排序! public final class BubbleSor

杂谈之SolrCloud这个坑货

杂谈之SolrCloud这个坑货 看<Solr In Action>时候看到对Solr不足的介绍有这么一段话:“One final limitation of Solr worth mentioning is its elastic scalability: the ability to automatically add and remove servers and redistribute content to handle load. While Solr scales well acr

[python爬虫] Selenium定向爬取海量精美图片及搜索引擎杂谈

我自认为这是自己写过博客中一篇比较优秀的文章,同时也是在深夜凌晨2点满怀着激情和愉悦之心完成的.首先通过这篇文章,你能学到以下几点:        1.可以了解Python简单爬取图片的一些思路和方法        2.学习Selenium自动.测试分析动态网页和正则表达式的区别和共同点        3.了解作者最近学习得比较多的搜索引擎和知识图谱的整体框架        4.同时作者最近找工作,里面的一些杂谈和建议也许对即将成为应届生的你有所帮助        5.当然,最重要的是你也可以尝

Java杂谈之数组

数组在编程过程中用的频率较高,所以熟练掌握数组的各种方法尤为重要. 主要方法: 1.Arrays.toString()--主要用于输出 (此方法是不需要用for循环遍历数组显示出来,用这个方法直接能输出数组的全部数据) 2.System.arraycopy()--数组复制 将一个数组的一部分或者全部复制给另一个数组 3.Arrays.sort()--数组排序 将一个数组进行排序,默认从小到大 4.Arrays.binarySearch()--数组折半查找 注意这个函数之前必须对数组进行排序 以下

看数据结构写代码(67) 置换 _ 选择排序(完结篇)

杂谈: 严蔚敏版<数据结构(C语言版)> 一书 终于看完了.这是 一个完结,也是 一个新的开端.<算法导论> 已到手. 置换选择排序的思想 是 将 归并段 尽量 变的 更大,而不是根据 内存 大小 限制在 固定的 大小. 这样 可以 利用赫夫曼树 来 进行 最优归并树,从而 使 外存 读写次数 最少. 下面给出 具体 代码:欢迎指出代码不足. // Replace_Selcetion.cpp : 定义控制台应用程序的入口点. // #include "stdafx.h&q