[C#] 用菜鸟的思维学习算法 -- 马桶排序、冒泡排序和快速排序

用菜鸟的思维学习算法 -- 马桶排序、冒泡排序和快速排序

【博主】反骨仔    【来源】http://www.cnblogs.com/liqingwen/p/4994261.html   

马桶排序

  一、场景:期末考试完了,老师要将同学们的分数从高到低排序。假设班上有 5 名同学,分别考了 5 分、3 分、5 分、2 分和 8 分【满分:10 分】,排序后的结果就是 8 5 5 3 2,现在,让我们先思考 10 分钟吧!

  二、思路:

    (1)先创建一个数组 int scores[11],就有 scores[0]~scores[10] 共 11 个变量。我们用变量值为 0 表示没有人得到该分数,即 scores [0]=0 表示没有人得 0 分,scores [10]=0 表示没有人得 10 分,而 scores [8]=1 表示有一个人得到 8 分。

    (2)第 1 个数为 5,所以在 scores[5]=0 的基础上+1,即 scores[5]=1 表示有 1 人得到 5 分

    (3)第 2 个数为 3,所以在 scores[3]=0 的基础上+1,即 scores[3]=1 表示有 1 人得到 3 分

    (4)第 3 个数为 5,所以在 scores[5]=1 的基础上+1,即 scores[5]=2 表示有 2 人得到 5 分

    ... ...

    (5)依此类推,处理第 4 和第 5 个数,最终的结果图如下:

    (6)我们发现,scores[0]~scores[10] 内对应的值就是 0~10 分中每个分数所出现的次数。现在,只需将结果打印即可,出现几次就打印机次。

我们暂且称它为“马桶排序”,这个算法就相当于有 11 个马桶,编号从 0~10。每出现一个数,就在对应编号的马桶中放一个旗子。

   三、思考:现在分别有 5 个人的名字和分数:小A 5、小二 3、小三 5、小妞 2 和王大锤 8,请按照分数从高到低,输出他们的名字?

  【特点】

    假设需要排序的范围 0~20000000,则需要 new int[20000001],非常浪费空间,即便只给 2 个数排序(1,19999999 );

    如果排序的数是小数也不行,如:3.141 5926 5358 9793 2384 6264 3383 2795 0238;

冒泡排序

  一、基本思想:每次比较相邻的两个 元素,按需调整顺序

  二、题目:要求将 12 35 99 18 76 这 5 个数进行从大到小排序

  三、思路:

    (1)先比较第 1 位和第 2 位的大小,12<35,因为希望越小越靠后,所以要调整两者顺序,交换后的结果:35 12 99 18 76

    (2)现在比较第 2 位和第 3 位的大小,12<99,所以需要交换位置,交换后的结果为:35 99 12 18 76

    (3)接着比较第 3 位和第 4 位的大小,12<18,交换后的结果为:35 99 18 12 76

    (4)最后比较第 4 位和第 5 位的大小,12<76,交换后的结果为:35 99 18 76 12

    (5)经过 4 次后我们发现 5 个数中最小的一个数已经就位,每将一个数归位我们称其为“一趟”;

    (6)现在我们开始第二趟,目标将第 2 小的数归位,根据之前逻辑,还是从第 1 个数和第 2 个数开始比较上:

  35 99 18 76 12 --①--> 99 35 18 76 12 --②--> 99 35 18 76 12 --③--> 99 35 76 18 12

   在第一趟比较就知道第 5 位是最小的,所以第 4 位不用和第 5 位比较,这一趟只需比较 3 次

    (7)第3趟:99 35 76 18 12 --> 99 35 76 18 12 --> 99 76 35 18 12 (比较 2 次)

    (8)第4趟:99 76 35 18 12 --> 99 76 35 18 12 ,有4个数已经就位,那么最后一个数无须比较,它就是最大的

  【总结】如果有 n 个数进行排序,只需将 n-1 个数归位,即要进行 n-1 趟操作,而每一趟开始都从第 1 位进行相邻的两个数 进行比较,将小的那个数放在后面,已经归位的就不用进行比较。

  【特点】冒泡算法的核心部分是双重嵌套循环,可以看出时间复杂度是 O(N²),这是一个非常高的时间复杂度。

快速排序

  一、场景:对 6 1 2 7 9 3 4 5 10 8 这 10 个数进行排序

  二、思路:

    先找一个基准数(一个用来参照的数),为了方便,我们选最左边的 6,希望将 >6 的放到 6 的右边,<6 的放到 6 左边。如:3 1 2 5 4 6 9 7 10 8

    先假设需要将 6 挪到的位置为 k,k 左边的数 <6,右边的数 >6

    (1)我们先从初始数列“6 1 2 7 9 3 4 5 10 8 ”的两端开始“探测 ”,先从右边往左找一个 <6 的数,再从左往右找一个 >6 的数,然后交换。我们用变量 i 和变量 j 指向序列的最左边和最右边。刚开始时最左边 i=0 指向 6,最右边 j=9 指向 8

    (2)现在设置的基准数是最左边的数,所以序列先右往左移动(j--),当找到一个 <6 的数(5)就停下来。接着序列从左往右移动(i++),直到找到一个 >6 的数又停下来(7);

    (3)两者交换,结果:6 1 2 5 9 3 4 7 10 8;

    (4)j 的位置继续向左移动(友情提示:每次都必须先从 j 的位置出发),发现 4 满足要求,接着 i++ 发现 9 满足要求,交换后的结果:6 1 2 5 4 3 9 7 10 8;

    (5)目前 j 指向的值为 9,i 指向的值为 4,j-- 发现 3 符合要求,接着 i++ 发现 i=j,说明这一轮移动结束啦。现在将基准数 6 和 3 进行交换,结果:3 1 2 5 4 6 9 7 10 8;现在 6 左边的数都是 <6 的,而右边的数都是 >6 的,但游戏还没结束

    

    (6)我们将 6 左边的数拿出来先:3 1 2 5 4,这次以 3 为基准数进行调整,使得 3 左边的数 <3,右边的数 >3,根据之前的模拟,这次的结果:2 1 3 5 4

    (7)再将 2 1 抠出来重新整理,得到的结果: 1 2

    (8)剩下右边的序列:9 7 10 8 也是这样来搞,最终的结果: 1 2 3 4 5 6 7 8 9 10

    【总结】快速排序的每一轮处理其实就是将这一轮的基准数归位,当所有的基准数归位,排序就结束啦


  【参考】文字与插图来源《啊哈!算法》

时间: 2024-11-06 19:38:58

[C#] 用菜鸟的思维学习算法 -- 马桶排序、冒泡排序和快速排序的相关文章

学习算法 -- 马桶排序、冒泡排序和快速排序

目录 马桶排序(令人作呕的排序) 冒泡排序(面试都要问的算法) 快速排序(见证亚当和夏娃的爱情之旅) 马桶排序(令人作呕的排序) 一.场景:期末考试完了,老师要将同学们的分数从高到低排序.假设班上有 5 名同学,分别考了 5 分.3 分.5 分.2 分和 8 分[满分:10 分],排序后的结果就是 8 5 5 3 2,现在,让我们先思考 10 分钟吧! 二.思路: (1)先创建一个数组 int scores[11],就有 scores[0]~scores[10] 共 11 个变量.我们用变量值为

数据结构和算法之排序二:快速排序

上一篇文章我们讲完了归并排序,对于分而治之和递归思想应该都有了一定的理解,这篇文章我们将介绍道被认为是排序算法中最容易出错,但是又是最喜欢使用的一中排序方式,快速排序.对于快速排序而言我们必须抓住几个关键点就是基准值的选取,以及它在递归思想的运用过程中需要注意的事项.我们先看下面的图片了解一下快速排序的过程. 我们可以看出每一次排序过程中都是选取第一个数据作为基准值,然后在前段和末端设置两个指针,指针对应的数据和基准值进行比较,如果大于基准值我们将它放在右边,如果小于基准值,我们就将它放在左边.

【PHP面试题】通俗易懂的两个面试必问的排序算法讲解:冒泡排序和快速排序

又到了金三银四找工作的时间,相信很多开发者都在找工作或者准备着找工作了.一般应对面试,我们无可厚非的去刷下面试题.对于PHPer来说,除了要熟悉自己所做的项目,还有懂的基本的算法.下面来分享下PHP面试中常会问到的算法:冒泡排序和快速排序 冒泡排序:一一对比排序 基本思想: 重复地走访过要排序的元素列,依次比较两个相邻的元素,如果他们的顺序(如从大到小)错误就把他们交换过来.走访元素的工作是重复地进行直到没有相邻元素需要交换,也就是说该元素已经排序完成. 图解: 1.第一次:拿着数组的第一个元素

在Object-C中学习数据结构与算法之排序算法

笔者在学习数据结构与算法时,尝试着将排序算法以动画的形式呈现出来更加方便理解记忆,本文配合Demo 在Object-C中学习数据结构与算法之排序算法阅读更佳. 目录 选择排序 冒泡排序 插入排序 快速排序 双路快速排序 三路快速排序 堆排序 总结与收获 参考与阅读 选择排序 选择排序是一种简单直观的排序算法,无论什么数据进去都是 O(n2) 的时间复杂度.所以用到它的时候,数据规模越小越好.唯一的好处可能就是不占用额外的内存空间了吧. 1.算法步骤 首先在未排序序列中找到最小(大)元素,存放到排

写在前面:21天学习算法

最近打算找一份新的工作,感到自己在算法环节还很疲弱.由于时间还算充裕,就决定将LeetCode上面的算法题学一遍,找出自己的薄弱,锻炼算法思维,吸收他人长处.个人觉得,刷题只是学习算法中的一个环节,主要的作用是用来反馈错误和增加熟练度.相比较刷题,更加重要的是对比和总结,对比自己的代码和他人的代码,对比不同的解法,总结一类算法或一类问题,总结一些tips,这两步是提升自己的关键.另外,为了不让自己的视野过于局限,让得到的碎片化学习成果体系化,可以在刷题的时候,就某方面的算法或数据结构,多参考其他

产品思维学习(二)--获取用户需求

上篇产品思维学习(一)–浅显的整体认识记录了我这个2年的菜鸟程序员对产品的一些浅显认识.下面记录下开发产品的第一步:获取用户需求,分析用户需求,转化产品功能. 之前做的一个产品,是直接面向市场,当时开发周期很紧张,基本是两个星期一个迭代.产品人手不足,基本都是BD去采集需求或者老板根据经验说用户想要什么.于是,我们的产品看着做了很多的功能,但是用户量一直没有上来.这其中就陷入了一个误区,什么才是用户的真正需求. 在产品圈有一个经典的例子(大致意思),用户想去一个地方,说我想要一匹更快的马,福特却

菱形打印程序——谈如何学习算法

菱形打印程序——谈如何学习算法 1.菱形打印 很多人,打印菱形在控制台的思路是,把菱形上下拆分,分两段很接近的代码来打印,其实这样代码很不好看,并且不好阅读.    我们知道,要打印的图案是这种:                            *                          *** *****      ***    * 满足上下对称,左右对称,那么,你能不能也弄一个二重循环,同样是对称的?      很简单,首先我们要抛开习惯性思维,for循环不一定要在0开始或者

如何学习算法

目前浅显地看过<数据结构与算法分析> <算法设计与分析基础>两本涉及到算法的书. 简单认为,学习算法的重点和难点都不在代码实现上,而在: 1.数学逻辑式    这个是写出伪代码的关键 2.算法正确性证明     证明该算法能得到最优解还是比较优解 数学逻辑式,从两方面考虑:一种是迭代,另一种是递归. 迭代思维相对容易理解,它的要求是:一.可以明确知道循环次数:二.每次循环中操作对象可以用变量表示,如: for i=0 to i=n-1 do: a[i] .... 递归思想其实本质上

什么是算法,学习算法有什么用

什么是算法 任何一个问题的解决方案都并非是凭空出现的,解决一个问题都需要选择一个合适的方法,并在此方法的引导下完成一系列的解答步骤,最终将问题转换为结果状态,对于计算机来说,这样的方法就是算法. 算法有很多种分类,可以是一系列的数学计算,也可以是一系列的操作步骤,总之,它存在的意义就是为了有针对性地解决问题,之所以强调针对性解决问题,是因为这个世界上还没有一种可以解决一切的万能算法,每个问题都有它独特的一面. 而对于这些特殊的需求,于是在这行业中出现了新的一批人,他们负责设计解决各种问题的算法.