首先感谢朋友们对第一篇文章的鼎力支持,感动中....... 

今天说的是选择排序,包括“直接选择排序”和“堆排序”。

话说上次“冒泡排序”被快排虐了,而且“快排”赢得了内库的重用,众兄弟自然眼红,非要找快排一比高下。

这不今天就来了两兄弟找快排算账。

1.直接选择排序:

先上图:

说实话,直接选择排序最类似于人的本能思想,比如把大小不一的玩具让三岁小毛孩对大小排个序,

那小孩首先会在这么多玩具中找到最小的放在第一位,然后找到次小的放在第二位,以此类推。。。。。。

,小孩子多聪明啊,这么小就知道了直接选择排序。羡慕中........

对的,小孩子给我们上了一课,

第一步: 我们拿80作为参照物(base),在80后面找到一个最小数20,然后将80跟20交换。

第二步:  第一位数已经是最小数字了,然后我们推进一步在30后面找一位最小数,发现自己最小,不用交换。

第三步:........

最后我们排序完毕。大功告成。

既然是来挑战的,那就5局3胜制。

 1 using System; 2 using System.Collections.Generic; 3 using System.Linq; 4 using System.Text; 5 using System.Threading; 6 using System.Diagnostics; 7  8 namespace SelectionSort 9 {10     public class Program11     {12         static void Main(string[] args)13         {14             //5次比较15             for (int i = 1; i <= 5; i++)16             {17                 List<int> list = new List<int>();18 19                 //插入2w个随机数到数组中20                 for (int j = 0; j < 20000; j++)21                 {22                     Thread.Sleep(1);23                     list.Add(new Random((int)DateTime.Now.Ticks).Next(1000, 1000000));24                 }25 26                 Console.WriteLine("\n第" + i + "次比较:");27 28                 Stopwatch watch = new Stopwatch();29 30                 watch.Start();31                 var result = list.OrderBy(single => single).ToList();32                 watch.Stop();33 34                 Console.WriteLine("\n快速排序耗费时间:" + watch.ElapsedMilliseconds);35                 Console.WriteLine("输出前十个数:" + string.Join(",", result.Take(10).ToList()));36 37                 watch.Start();38                 result = SelectionSort(list);39                 watch.Stop();40 41                 Console.WriteLine("\n直接选择排序耗费时间:" + watch.ElapsedMilliseconds);42                 Console.WriteLine("输出前十个数:" + string.Join(",", list.Take(10).ToList()));43 44             }45         }46 47         //选择排序48         static List<int> SelectionSort(List<int> list)49         {50             //要遍历的次数51             for (int i = 0; i < list.Count - 1; i++)52             {53                 //假设tempIndex的下标的值最小54                 int tempIndex = i;55 56                 for (int j = i + 1; j < list.Count; j++)57                 {58                     //如果tempIndex下标的值大于j下标的值,则记录较小值下标j59                     if (list[tempIndex] > list[j])60                         tempIndex = j;61                 }62 63                 //最后将假想最小值跟真的最小值进行交换64                 var tempData = list[tempIndex];65                 list[tempIndex] = list[i];66                 list[i] = tempData;67             }68             return list;69         }70     }71 }

比赛结果公布:

堆排序:

要知道堆排序,首先要了解一下二叉树的模型。

下图就是一颗二叉树,具体的情况我后续会分享的。

那么堆排序中有两种情况(看上图理解):

大根堆:  就是说父节点要比左右孩子都要大。

小根堆:  就是说父节点要比左右孩子都要小。

那么要实现堆排序,必须要做两件事情:

第一:构建大根堆。

首先上图:

首先这是一个无序的堆,那么我们怎样才能构建大根堆呢?

第一步: 首先我们发现,这个堆中有2个父节点(2,,3);

第二步: 比较2这个父节点的两个孩子(4,5),发现5大。

第三步: 然后将较大的右孩子(5)跟父节点(2)进行交换,至此3的左孩子堆构建完毕,

如图:

第四步: 比较第二个父节点(3)下面的左右孩子(5,1),发现左孩子5大。

第五步: 然后父节点(3)与左孩子(5)进行交换,注意,交换后,堆可能会遭到破坏,

必须按照以上的步骤一,步骤二,步骤三进行重新构造堆。

最后构造的堆如下:

第二:输出大根堆。

至此,我们把大根堆构造出来了,那怎么输出呢?我们做大根堆的目的就是要找出最大值,

那么我们将堆顶(5)与堆尾(2)进行交换,然后将(5)剔除根堆,由于堆顶现在是(2),

所以破坏了根堆,必须重新构造,构造完之后又会出现最大值,再次交换和剔除,最后也就是俺们

要的效果了,

发现自己兄弟被别人狂殴,,堆排序再也坐不住了,决定要和快排干一场。

同样,快排也不甘示弱,谁怕谁?

  1 using System;  2 using System.Collections.Generic;  3 using System.Linq;  4 using System.Text;  5 using System.Threading;  6 using System.Diagnostics;  7   8 namespace HeapSort  9 { 10     public class Program 11     { 12         static void Main(string[] args) 13         { 14             //5次比较 15             for (int j = 1; j <= 5; j++) 16             { 17                 List<int> list = new List<int>(); 18  19                 //插入2w个数字 20                 for (int i = 0; i < 20000; i++) 21                 { 22                     Thread.Sleep(1); 23                     list.Add(new Random((int)DateTime.Now.Ticks).Next(1000, 100000)); 24                 } 25  26                 Console.WriteLine("\n第" + j + "次比较:"); 27  28                 Stopwatch watch = new Stopwatch(); 29                 watch.Start(); 30                 var result = list.OrderBy(single => single).ToList(); 31                 watch.Stop(); 32                 Console.WriteLine("\n快速排序耗费时间:" + watch.ElapsedMilliseconds); 33                 Console.WriteLine("输出前十个数" + string.Join(",", result.Take(10).ToList())); 34  35                 watch = new Stopwatch(); 36                 watch.Start(); 37                 HeapSort(list); 38                 watch.Stop(); 39                 Console.WriteLine("\n堆排序耗费时间:" + watch.ElapsedMilliseconds); 40                 Console.WriteLine("输出前十个数" + string.Join(",", list.Take(10).ToList())); 41             } 42  43         } 44  45         ///<summary> 46 /// 构建堆 47 ///</summary> 48 ///<param name="list">待排序的集合</param> 49 ///<param name="parent">父节点</param> 50 ///<param name="length">输出根堆时剔除最大值使用</param> 51         static void HeapAdjust(List<int> list, int parent, int length) 52         { 53             //temp保存当前父节点 54             int temp = list[parent]; 55  56             //得到左孩子(这可是二叉树的定义,大家看图也可知道) 57             int child = 2 * parent + 1; 58  59             while (child < length) 60             { 61                 //如果parent有右孩子,则要判断左孩子是否小于右孩子 62                 if (child + 1 < length && list[child] < list[child + 1]) 63                     child++; 64  65                 //父亲节点大于子节点,就不用做交换 66                 if (temp >= list[child]) 67                     break; 68  69                 //将较大子节点的值赋给父亲节点 70                 list[parent] = list[child]; 71  72                 //然后将子节点做为父亲节点,已防止是否破坏根堆时重新构造 73                 parent = child; 74  75                 //找到该父亲节点较小的左孩子节点 76                 child = 2 * parent + 1; 77             } 78             //最后将temp值赋给较大的子节点,以形成两值交换 79             list[parent] = temp; 80         } 81  82         ///<summary> 83 /// 堆排序 84 ///</summary> 85 ///<param name="list"></param> 86         public static void HeapSort(List<int> list) 87         { 88             //list.Count/2-1:就是堆中父节点的个数 89             for (int i = list.Count / 2 - 1; i >= 0; i--) 90             { 91                 HeapAdjust(list, i, list.Count); 92             } 93  94             //最后输出堆元素 95             for (int i = list.Count - 1; i > 0; i--) 96             { 97                 //堆顶与当前堆的第i个元素进行值对调 98                 int temp = list[0]; 99                 list[0] = list[i];100                 list[i] = temp;101 102                 //因为两值交换,可能破坏根堆,所以必须重新构造103                 HeapAdjust(list, 0, i);104             }105         }106     }107 }

结果公布:

堆排序此时心里很尴尬,双双被KO,心里想,一定要捞回面子,一定要赢,

于是堆排序提出了求“前K大问题”。(就是在海量数据中找出前几大的数据),

快排一口答应,小意思,没问题。

双方商定,在2w随机数中找出前10大的数:

  1 using System;  2 using System.Collections.Generic;  3 using System.Linq;  4 using System.Text;  5 using System.Threading;  6 using System.Diagnostics;  7   8 namespace QuickSort  9 { 10     public class Program 11     { 12         static void Main(string[] args) 13         { 14             //5此比较 15             for (int j = 1; j <= 5; j++) 16             { 17                 List<int> list = new List<int>(); 18  19                 for (int i = 0; i < 20000; i++) 20                 { 21                     Thread.Sleep(1); 22                     list.Add(new Random((int)DateTime.Now.Ticks).Next(1000, 100000)); 23                 } 24  25                 Console.WriteLine("\n第" + j + "次比较:"); 26  27                 Stopwatch watch = new Stopwatch(); 28                 watch.Start(); 29                 var result = list.OrderByDescending(single => single).Take(10).ToList(); 30                 watch.Stop(); 31                 Console.WriteLine("\n快速排序求前K大耗费时间:" + watch.ElapsedMilliseconds); 32                 Console.WriteLine("输出前十个数:" + string.Join(",", result.Take(10).ToList())); 33  34                 watch = new Stopwatch(); 35                 watch.Start(); 36                 result = HeapSort(list, 10); 37                 watch.Stop(); 38                 Console.WriteLine("\n堆排序求前K大耗费时间:" + watch.ElapsedMilliseconds); 39                 Console.WriteLine("输出前十个数:" + string.Join(",", list.Take(10).ToList())); 40             } 41  42         } 43  44         ///<summary> 45 /// 构建堆 46 ///</summary> 47 ///<param name="list">待排序的集合</param> 48 ///<param name="parent">父节点</param> 49 ///<param name="length">输出根堆时剔除最大值使用</param> 50         static void HeapAdjust(List<int> list, int parent, int length) 51         { 52             //temp保存当前父节点 53             int temp = list[parent]; 54  55             //得到左孩子(这可是二叉树的定义哇) 56             int child = 2 * parent + 1; 57  58             while (child < length) 59             { 60                 //如果parent有右孩子,则要判断左孩子是否小于右孩子 61                 if (child + 1 < length && list[child] < list[child + 1]) 62                     child++; 63  64                 //父节点大于子节点,不用做交换 65                 if (temp >= list[child]) 66                     break; 67  68                 //将较大子节点的值赋给父亲节点 69                 list[parent] = list[child]; 70  71                 //然后将子节点做为父亲节点,已防止是否破坏根堆时重新构造 72                 parent = child; 73  74                 //找到该父节点左孩子节点 75                 child = 2 * parent + 1; 76             } 77             //最后将temp值赋给较大的子节点,以形成两值交换 78             list[parent] = temp; 79         } 80  81         ///<summary> 82 /// 堆排序 83 ///</summary> 84 ///<param name="list">待排序的集合</param> 85 ///<param name="top">前K大</param> 86 ///<returns></returns> 87         public static List<int> HeapSort(List<int> list, int top) 88         { 89             List<int> topNode = new List<int>(); 90  91             //list.Count/2-1:就是堆中非叶子节点的个数 92             for (int i = list.Count / 2 - 1; i >= 0; i--) 93             { 94                 HeapAdjust(list, i, list.Count); 95             } 96  97             //最后输出堆元素(求前K大) 98             for (int i = list.Count - 1; i >= list.Count - top; i--) 99             {100                 //堆顶与当前堆的第i个元素进行值对调101                 int temp = list[0];102                 list[0] = list[i];103                 list[i] = temp;104 105                 //最大值加入集合106                 topNode.Add(temp);107 108                 //因为顺序被打乱,必须重新构造堆109                 HeapAdjust(list, 0, i);110             }111             return topNode;112         }113     }114 }

求前K大的输出结果:

最后堆排序赶紧拉着直接选择排序一路小跑了,因为求前K大问题已经不是他原本来的目的。

ps: 直接选择排序的时间复杂度为:O(n^2)

堆排序的时间复杂度:O(NlogN)

算法系列15天速成——第二天 七大经典排序【中】相关推荐

  1. 基本算法系列15天速成

    算法系列15天速成--第一天 七大经典排序[上] 算法系列15天速成--第二天 七大经典排序[中] 算法系列15天速成--第三天 七大经典排序[下] 算法系列15天速成--第四天 五大经典查找[上] ...

  2. 算法系列15天速成——第十天 栈

    原文:算法系列15天速成--第十天 栈 今天跟大家聊聊栈,在程序设计中,栈的使用还是非常广泛的,比如有"括号匹配问题","html结构匹配问题". 所以说掌握了 ...

  3. 算法系列15天速成——第三天 七大经典排序【下】

    今天跟大家聊聊最后三种排序: 直接插入排序,希尔排序和归并排序. 直接插入排序: 这种排序其实蛮好理解的,很现实的例子就是俺们斗地主,当我们抓到一手乱牌时,我们就要按照大小梳理扑克,30秒后, 扑克梳 ...

  4. 算法系列15天速成——第十三天 树操作【下】

    今天说下最后一种树,大家可否知道,文件压缩程序里面的核心结构,核心算法是什么?或许你知道,他就运用了赫夫曼树. 听说赫夫曼胜过了他的导师,被认为"青出于蓝而胜于蓝",这句话也是我比 ...

  5. 算法系列15天速成——第四天 五大经典查找【上】

    在我们的生活中,无处不存在着查找,比如找一下班里哪个mm最pl,猜一猜mm的芳龄....... 对的这些都是查找. 在我们的算法中,有一种叫做线性查找. 分为:顺序查找. 折半查找. 查找有两种形态: ...

  6. Algorithm:【Algorithm算法进阶之路】之十大经典排序算法

    Algorithm:[Algorithm算法进阶之路]之十大经典排序算法 相关文章 Algorithm:[Algorithm算法进阶之路]之数据结构二十多种算法演示 Algorithm:[Algori ...

  7. 常用七大经典排序算法总结(C语言描述)

    目录 一.交换排序 1.冒泡排序 2.快速排序 二.插入排序 1.直接插入排序 2.希尔(shell)排序 三.选择排序 1.直接选择排序 2.堆(Heap)排序 四.归并排序 正文 简介 其中排序算 ...

  8. 【算法入门】用Python手写五大经典排序算法,看完这篇终于懂了!

    算法作为程序员的必修课,是每位程序员必须掌握的基础.作为Python忠实爱好者,本篇将通过Python来手撕5大经典排序算法,结合例图剖析内部实现逻辑,对比每种算法各自的优缺点和应用点.相信我,耐心看 ...

  9. wcf系列5天速成——第二天 binding的使用(2)(转载)

    承接上一章,今天来讲MSMQ在实战项目中的应用.众所周知,放了防止订单丢失,我们都是采用Order过一下MSMQ. MSMQ的优点个人认为是:先天的异步消息发送和天生的自动负载均衡. 好了,看看MSM ...

最新文章

  1. 姚班代有才人出:清华本科生用“最简单的形式”,大幅提高少样本学习性能...
  2. 多媒体应用-swift
  3. Microsoft SQL Server SA权限最新入侵方法
  4. android IntentService
  5. centos Error: Cannot find a valid baseurl for repo: base 解决方法
  6. C/C++获取本地IP(适用于多种操作系统)
  7. python学习笔记(二)之列表
  8. 关于MDI窗体的那些问题
  9. 收藏!本、硕、博、程序员必备神器
  10. idea更换源_在Intelij IDEA中修改阿里Maven源
  11. Excel导入Sql Server出现Null的解决方法
  12. JavaScript中的关系运算符和逻辑运算符
  13. Leetcode|DFS|130. 被围绕的区域
  14. 20135202闫佳歆-期末总结
  15. 【Proteus仿真】L297驱动步进电机
  16. A Comprehensive Measurement Study of Domain Generating Malware 原文翻译
  17. 第11课:词句分布式表达——词建模工具
  18. Debian修改桌面系统
  19. 随机事件与概率术语与主题
  20. STM32——SPI通信实验

热门文章

  1. 高德地图POI搜索,附近地图搜索,类似附近的人搜索
  2. 《机器学习与数据科学(基于R的统计学习方法)》——2.11 R中的SQL等价表述...
  3. [转载]python optionparser1
  4. WTForms 小计1 forms
  5. 浅谈 MySQL 子查询及其优化
  6. Linux基础知识——常用shell命令介绍(三)
  7. 静茹docker容器的几种方法_Docker介绍及使用
  8. 如何使用create-react-app在本地设置HTTPS
  9. aws lambda使用_如何使用AWS Lambda和S3构建无服务器URL缩短器
  10. HBASE_API的应用