本文出自 “啊哈磊” 博客,请务必保留此出处http://ahalei.blog.51cto.com/4767671/1362789

(xuyangcao说:)啊哈磊老师的这篇文章用一个小例子说明了之前三个算法之间的比较,生动形象,最重要的是给我们提供了一种思考问题解决问题的方法,即如何根据不同的具体情况选择不同的算法;正如很多人所说,单纯的比较不同算法之间的优越性是没有意义的,只有结合了具体情况的比较才有说服力。话不多说,直接上啊哈磊老师的大作:

之前讲了三种常用的经典排序。排序算法还有很多,例如选择排序、计数排序、基数排序、插入排序、归并排序和堆排序等等。堆排序是基于二叉树的排序,以后再说吧。先分享一个超酷的排序算法的视频。

       再来看一个具体的例子《小哼买书》来看看三个排序在应用上的区别和局限性。 小哼的学校要建立一个图书角,老师派小哼去找一些同学做调查,看看同学们都喜欢读哪些书。小哼让每个同学写出一个自己最想读的书的ISBN号(你知道吗?每本书都有唯一的ISBN号,不信话你去找本书翻到背面看看)。当然有一些好书会有很多同学都喜欢,这样就会收集到很多重复的ISBN号。小哼需要去掉其中重复的ISBN号,即每个ISBN号只保留一个,也就说同样的书只买一本(学校真是够抠门的)。然后再把这些ISBN号从小到大排序,小哼将按照排序好的ISBN号去书店去买书。请你协助小哼完成“去重”与“排序”的工作。
       输入有2行,第1行为一个正整数,表示有n个同学参与调查(n<=100)。第2行有n个用空格隔开的正整数,为每本图书的ISBN号(假设图书的ISBN号在1~1000之间)。
       输出也是2行,第1行为一个正整数k,表示需要买多少本书。第2行为k个用空格隔开的正整数,为从小到大已排好序的需要购买的图书ISBN号。
       例如输入
102040326740208930040015
       则输出
8152032406789300400

最后,程序运行的时间限制为:1秒。

解决这个问题的方法大致有两种,第一种方法:先将这n个图书的ISBN号去重,再进行从小到大排序并输出。第二种方法:先从小到大排序,输出的时候再去重。这两种方法都可以。

       先来看第一种方法。通过第一节的学习我们发现桶排序稍加改动正好可以起到去重的效果,因此我们可以使用桶排序的方法来解决此问题。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#include <stdio.h>
int main()
{
    int a[1001],n,i,t;
    for(i=1;i<=1000;i++)
         a[i]=0; //初始化
                               
    scanf("%d",&n); //读入n
    for(i=1;i<=n;i++) //循环读入n个图书的ISBN号
    {
        scanf("%d",&t); //把每一个ISBN号读到变量t中
        a[t]=1; //标记出现过的ISBN号
    }
                               
    for(i=1;i<=1000;i++) //依次判断1~1000这个1000个桶
    {
          if(a[i]==1)//如果这个ISBN号出现过则打印出来
             printf("%d ",i);
    }
                             
    getchar();getchar();
    return 0;
}

这种方法的时间复杂度是就是桶排序的时间复杂度为O(N+M)。

第二种方法我们需要先排序再去重。排序我们可以用冒泡排序或者快速排序。

20 40 32 67 40 20 89 300 400 15

将这10个数从小到大排序之后为 15 20 20 32 40 40 67 89 300 400。

接下来,要在输出的时候去掉重复的。因为我们已经排好序,因此相同的数都会紧挨在一起。只要在输出的时候,预先判断一下当前这个数a与前面一个数a[i-1]是否相同。如果相同则表示这个数之前已经输出过了,不同再次输出。不同则表示这个数是第一次出现需要,则需要输出这个数。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
#include <stdio.h>
int main()
{
    int a[101],n,i,j,t;
                        
    scanf("%d",&n);   //读入n
    for(i=1;i<=n;i++) //循环读入n个图书ISBN号
    {
        scanf("%d",&a[i]);
    }
                        
   //开始冒泡排序
    for(i=1;i<=n-1;i++)
    {
         for(j=1;j<=n-i;j++)
        {
             if(a[j]>a[j+1])
            {  t=a[j]; a[j]=a[j+1]; a[j+1]=t;  }
        }
    }
    printf("%d ",a[1]); //输出第1个数
    for(i=2;i<=n;i++) //从2循环到n
    {
         if( a[i] != a[i-1] ) //如果当前这个数是第一次出现则输出
             printf("%d ",a[i]);
    }
                      
    getchar();getchar();
    return 0;
}

这种方法的时间复杂度由两部分组成,一部分是冒泡排序时间复杂度是O(N2),另一部分是读入和输出都是O(N),因此整个算法的时间复杂度是O(2*N+N2)。相对于N2来说,2*N可以忽略(我们通常忽略低阶),最终该方法的时间复杂度是O(N2)。

接下来我们还需要看下数据范围。每个图书ISBN号都是1~1000之间的整数,并且参加调查的同学人数不超过100,即n<=100。之前已经说过,在粗略计算时间复杂度的时候,我们通常认为计算机每秒钟大约运行10亿次(当然实际情况要更快)。因此以上两种方法都可以在1秒钟内计算出解。如果题目图书ISBN号范围不是在1~1000之间,而是-2147483648~2147483647之间的话,那么第一种方法就不可行了,因为你无法申请出这么大数组来标记每一个ISBN号是否出现过。另外如果n的范围不是小于等于100而是小于等于10万,那么第二种方法的排序部分也不能使用冒泡排序。因为题目要求的时间限制是1秒,使用冒泡排序对10万个数的排序,计算机需要运行100亿次,需要10秒钟,需要替换为快速排序,快速排序只需要100000×log2100000≈100000×17≈170万次,这还不到0.0017秒。是不是很神奇,同样的问题使用不同的算法竟然有如此之大的时间差距,这就是算法的魅力!

       我们来回顾一下本章三种排序算法的时间复杂度。桶排序是最快的,它的时间复杂度是O(N+M);冒泡排序是O(N2);快速排序是O(NlogN)。

桶排序,冒泡排序,快速排序三者比较(例子说名)相关推荐

  1. 数据结构与算法 第八天常见排序+冒泡排序+快速排序+文件IO+大数据排序+文件合并

    数据结构与算法 第八天常见排序+冒泡排序+快速排序+文件IO+大数据排序+文件合并 第一章 冒泡排序 [1]Bubble_Sort.c 第二章 快速排序 [1]quick_sort.c 第三章 大数据 ...

  2. 数据结构(八):排序 | 插入排序 | 希尔排序 | 冒泡排序 | 快速排序 | 简单选择排序 | 堆排序 | 归并排序 | 基数排序 | 外部排序 | 败者树 | 置换-选择排序 | 最佳归并树

    文章目录 第八章 排序 一.排序的基本概念 (一)什么是排序 (二)排序的应用 (三)排序算法的评价指标 (四)排序算法的分类 (五)总结 二.插入排序 (一)算法思想 (二)算法实现 (三)算法效率 ...

  3. iOS swift 选择排序 冒泡排序 快速排序

    返回上级目录:iOS 算法题 三大经典排序 | 冒泡排序,选择排序,快速排序 - 知乎 文章目录 1.选择排序 2.冒泡排序 3.快速排序 1.选择排序 //选择排序 func rankSelect( ...

  4. 直接插入排序 希尔排序 冒泡排序 快速排序 直接选择排序 堆排序 归并排序 基数排序的算法分析和具体实现 ...

    排序分为内部排序和外部排序 内部排序是把待排数据元素全部调入内存中进行的排序. 外部排序是因数量太大,把数据元素分批导入内存,排好序后再分批导出到磁盘和磁带外存介质上的排序方法. 比较排序算法优劣的标 ...

  5. 王道八大排序:直接插入排序 折半插入排序 希尔排序 冒泡排序 快速排序 归并排序 基数排序

    文章目录 1.插入排序 1.1直接插入排序 1.2折半插入排序 1.3希尔排序 2.交换排序 2.1冒泡排序 2.2快速排序 3.选择排序 3.1简单选择排序 3.2堆排序 4.归并排序 5.基数排序 ...

  6. python快速排序算法详细图解_Python实现桶排序与快速排序算法结合应用示例

    说明: FreeNAS是一个基于FreeBSD的开源网络存储系统,支持iSCSI.NFS等共享协议, 通过Web页面进行管理,安装FreeNAS最小需要2G硬盘. 最新版本下载: http://iso ...

  7. c语言排序(快速排序,冒泡排序,选择排序,插入排序,桶排序)

    快速排序,冒泡排序,选择排序,插入排序,桶排序 文章目录 什么是排序 快速排序 实现流程 代码 改进版快速排序代码 注意点 冒泡排序 实现流程 实现代码 选择排序 实现代码 插入排序 实现代码 桶排序 ...

  8. 归并排序,快速排序,冒泡排序,选择排序,基数排序,桶排序,堆排序(c++实现)

    一.归并排序 #include<iostream> using namespace std; void Merge(int arr[],int low,int mid,int high); ...

  9. 【完整可运行源码+GIF动画演示】十大经典排序算法系列——冒泡排序、选择排序、插入排序、希尔排序、归并排序、快速排序、堆排序、计数排序、桶排序、基数排序

    以前也零零碎碎发过一些排序算法,但总是不系统, 这次彻底的对排序系列做了一个整体的规划, 小伙伴们快快mark哦~ [GIF动画+完整可运行源代码]C++实现 冒泡排序--十大经典排序算法之一 [GI ...

  10. C语言排序(桶排序,冒泡排序,选择排序,插入排序,快速排序)

    参考:C语言五大排序(桶排序,冒泡排序,选择排序,插入排序,快速排序)动态演示 作者:一只青木呀 发布时间: 2020-09-09 20:18:43 网址:https://blog.csdn.net/ ...

最新文章

  1. PAT甲级题目翻译+答案 AcWing(动态规划)
  2. [CCF] 201612-2 工资计算
  3. 技术与商业到底啥关系?我们从业务角度聊一聊
  4. android activity 被notification启动,Android通知Notification全面剖析
  5. Centos7安装时提示,没有可用的网络设备
  6. Java秘技之Json数据解析与转换 -- Java使用示例
  7. Struts2.3接收post方式提交的表单参数的方式
  8. C#中几种数据库的大数据批量插入
  9. wangeditor 不识别html_前端知识(一)认识HTML
  10. Linux内核中断引入用户空间(异步通知机制)【转】
  11. microbiomeViz:绘制lefse结果中Cladogram
  12. Linux之用户和组账户管理命令
  13. layui 横向表单_fwr-layui-formdesigner
  14. Open3D 渐进式形态学滤波
  15. Mega软件操作教程
  16. 经验正交分解EOF的Matlab的实现示例
  17. 干货!如何在训练中自动识别数据中潜在的不同分布并自适应?——以空间数据为例,应用不限于空间数据...
  18. 阅读笔记-DACE随机模型(计算实验设计与分析)
  19. 【龙讯module小课堂】“光”怪陆离:PWmat计算光学性质(三)
  20. 文科生学python,可能吗?

热门文章

  1. Linux学习——Makefile
  2. [转]老婆还是自己好
  3. [转]安装完成后机器重新启动运行 JBuilder 时却每次只是看到 L
  4. 分享一个高清壁纸网站
  5. zstuoj 4245 KI的斐波那契
  6. spring security原理图及其解释
  7. VS2008使用技巧及快捷键大全
  8. 创建xhr对象实现浏览器全兼容
  9. heart ultrasound from american society of echocardiography
  10. 把业务逻辑变成数据结构和SQL语句的例子。自然架构改成自然框架