数据结构和算法 – 11.高级排序算法(下)
三、选择类排序
3.1.简单选择排序
http://www.cnblogs.com/tangge/p/5338734.html#XuanZe
3.2 堆排序
要知道堆排序,首先要了解一下二叉树的模型。
下图就是一颗二叉树
那么堆排序中有两种情况(看上图理解):
大根堆: 就是说父节点要比左右孩子都要大。
小根堆: 就是说父节点要比左右孩子都要小。
那么要实现堆排序,必须要做两件事情:
第一:构建大根堆。
首先这是一个无序的堆,那么我们怎样才能构建大根堆呢?
第一步: 首先我们发现,这个堆中有2个父节点(2,3);
第二步: 比较2这个父节点的两个孩子(4,5),发现5大。
第三步: 然后将较大的右孩子(5)跟父节点(2)进行交换,至此3的左孩子堆构建完毕,
第四步: 比较第二个父节点(3)下面的左右孩子(5,1),发现左孩子5大。
第五步: 然后父节点(3)与左孩子(5)进行交换,注意,交换后,堆可能会遭到破坏,
必须按照以上的步骤一,步骤二,步骤三进行重新构造堆。
最后构造:
第二:输出大根堆。
至此,我们把大根堆构造出来了,那怎么输出呢?我们做大根堆的目的就是要找出最大值,
那么我们将堆顶(5)与堆尾(2)进行交换,然后将(5)剔除根堆,由于堆顶现在是(2),
所以破坏了根堆,必须重新构造,构造完之后又会出现最大值,再次交换和剔除,最后也就是俺们
要的效果了。
///<summary>
/// 构建堆
///</summary>
///<param name="list">待排序的集合</param>
///<param name="parent">父节点</param>
///<param name="length">输出根堆时剔除最大值使用</param>
public static void HeapAdjust(List<int> list, int parent, int length)
{
//temp保存当前父节点
int temp = list[parent]; //得到左孩子(这可是二叉树的定义哇)
int child = 2 * parent + 1; while (child < length)
{
//如果parent有右孩子,则要判断左孩子是否小于右孩子
if (child + 1 < length && list[child] < list[child + 1])
child++; //父节点大于子节点,不用做交换
if (temp >= list[child])
break; //将较大子节点的值赋给父亲节点
list[parent] = list[child]; //然后将子节点做为父亲节点,已防止是否破坏根堆时重新构造
parent = child; //找到该父节点左孩子节点
child = 2 * parent + 1;
}
//最后将temp值赋给较大的子节点,以形成两值交换
list[parent] = temp;
} ///<summary>
/// 堆排序
///</summary>
///<param name="list">待排序的集合</param>
///<param name="top">前K大</param>
///<returns></returns>
public List<int> HeapSort(List<int> list, int top)
{
//string joinlist = string.Join(",", list.ToList());
List<int> topNode = new List<int>(); //list.Count/2-1:就是堆中非叶子节点的个数
for (int i = list.Count / 2 - 1; i >= 0; i--)
{
HeapAdjust(list, i, list.Count);
//joinlist = string.Join(",", list.ToList());
} //最后输出堆元素(求前K大)
for (int i = list.Count - 1; i >= list.Count - top; i--)
{
//堆顶与当前堆的第i个元素进行值对调
int temp = list[0];
list[0] = list[i];
list[i] = temp;
//joinlist = string.Join(",", list.ToList());
//最大值加入集合
topNode.Add(temp); //因为顺序被打乱,必须重新构造堆
HeapAdjust(list, 0, i);
//joinlist = string.Join(",", list.ToList());
}
return topNode;
}
List<int> list1 = new List<int>();
int[] array1 = new int[] { 20, 40, 50, 10, 60 };
list1.AddRange(array1);
new QuickSortClass().HeapSort(list1, 5); Console.WriteLine("堆排序:");
Console.Write(string.Join(",", list1.ToList()));
总结:堆排序的执行时间主要由建立初始堆和反复调整堆这两个部分的时间开销组成,由于堆排序对原始记录的排序状态并不敏感,因此它无论是最好、最坏和平均时间复杂度均为O(nlog2n)。这在性能上显然要远远好过于冒泡、简单选择、直接插入的O(n2)的时间复杂度了。另外,由于初始构建堆所需的比较次数较多,因此,它并不适合待排序序列个数较少的情况。
四、归并类排序
4.1 二路归并排序介绍
4.2 二路归并排序实现
总结:
(1)当待排序序列的记录数n较小的时候(一般n<=50),可以采用直接插入排序、直接选择排序或冒泡排序:
若序列初始状态基本为正序,则应选用直接插入排序、冒泡排序。
如果单条记录本身信息量较大,由于直接插入排序所需的记录移动操作较直接选择排序多,因此用直接选择排序较好。
(2)当待排序序列的记录数n较大的时候,则应采用时间复杂度为O(nlog2n)的排序方法,如:快速排序、堆排序或归并排序。
快速排序时目前基于比较的内部排序中被认为是最好的方法,当待排序的关键字随机分布时,快速排序的平均时间最短,.NET中集合类的内置排序方法(例如:Array.Sort())也是使用了快速排序实现的。
堆排序需要的辅助空间少于快速排序,并且不会出现快速排序可能出现的最坏情况O(n2)。
归并排序需要大量的辅助空间,因此不值得提倡使用,但是如果要将两个有序序列组合成一个新的有序序列,最好的方法就是归并排序。
数据结构和算法 – 11.高级排序算法(下)的更多相关文章
- 数据结构和算法 – 11.高级排序算法(上)
对现实中的排序问题,算法有七把利剑可以助你马道成功. 首先排序分为四种: 交换排序: 包括冒泡排序,快速排序. 选择排序: 包括直接选择排序,堆排序. 插入排序 ...
- javascript数据结构与算法--高级排序算法
javascript数据结构与算法--高级排序算法 高级排序算法是处理大型数据集的最高效排序算法,它是处理的数据集可以达到上百万个元素,而不仅仅是几百个或者几千个.现在我们来学习下2种高级排序算法-- ...
- javascript数据结构与算法--高级排序算法(快速排序法,希尔排序法)
javascript数据结构与算法--高级排序算法(快速排序法,希尔排序法) 一.快速排序算法 /* * 这个函数首先检查数组的长度是否为0.如果是,那么这个数组就不需要任何排序,函数直接返回. * ...
- javascript高级排序算法之快速排序(快排)
javascript高级排序算法之快速排序(快排)我们之前讨论了javascript基本排序算法 冒泡排序 选择排序 插入排序 简单复习: 冒泡排序: 比较相邻的两个元素,如果前一个比后一个大,则交换 ...
- 【高级排序算法】1、归并排序法 - Merge Sort
归并排序法 - Merge Sort 文章目录 归并排序法 - Merge Sort nlogn 比 n^2 快多少? 归并排序设计思想 时间.空间复杂度 归并排序图解 归并排序描述 归并排序小结 参 ...
- 【高级排序算法】2、归并排序法的实现-Merge Sort
简单记录 - bobo老师的玩转算法系列–玩转算法 -高级排序算法 Merge Sort 归并排序 Java实现归并排序 SortTestHelper 排序测试辅助类 package algo; im ...
- 插入排序算法--直接插入算法,折半排序算法,希尔排序算法(C#实现)
插入排序算法主要分为:直接插入算法,折半排序算法(二分插入算法),希尔排序算法,后两种是直接插入算法的改良.因此直接插入算法是基础,这里先进行直接插入算法的分析与编码. 直接插入算法的排序思想:假设有 ...
- 数据结构与算法之--高级排序:shell排序和快速排序
高级排序比简单排序要快的多,简单排序的时间复杂度是O(N^2),希尔(shell)排序大约是O(N*(logN)^2),而快速排序是O(N*logN). 说明:下面以int数组的从小到大排序为例. 希 ...
- 数据结构和算法 – 12.高级查找算法(下)
哈希(散列)技术既是一种存储方法,也是一种查找方法.然而它与线性表.树.图等结构不同的是,前面几种结构,数据元素之间都存在某种逻辑关系,可以用连线图示表示出来,而哈希技术的记录之间不存在什么逻辑关系, ...
随机推荐
- 简单易懂的crontab设置工具集
导读 在上一篇文章中,我介绍了crontab的配置文件以及如何设置定时任务,对于偶尔用一次crontab的同学而言,可能遗忘配置语法会很快,这里我向大家推荐几个在线设置crontab任务的网站. ge ...
- 总结六条对我们学习Linux系统有用的忠告
接触linux需要的是端正自己的态度,这个玩意可不是一天两天就能拿得下的.学习个基础,能装系统.能装常见服务.能编译.能配置存储空间.能配置系统参数.能简单查看系统负载等基本够用.但这些只保证能做机房 ...
- Java实现读取文件夹下(包括子目录)所有文件的文件名
在编程的过程中,经常会用到对文件的读写操作等.比如,找出某一个文件夹下的所有文件名等. 下面的程序给出了,获取某一给定文件夹下所有文件的绝对路径的程序.可以作为某一个模块,在需要的时候直接使用. pa ...
- Codeforces Gym 100114 D. Selection
Description 问选择一个序列上的所有数的最少操作次数,跟电脑上选择文件一样,输出操作方案. Sol 贪心. 用Shift一段文件只能使用一次,之后必须一直按Ctrl了. 然后就是看用Shif ...
- JDBC的应用
JDBC的开发步骤: 1. 引入JDBC驱动架包 2. 程序中引入JDBC驱动类 3. 创建java与数据库的连接 4. 跟数据库交互:发送sql语句,接收数据库对sql语句的执行结果 ...
- 3.2---最小栈(CC150)
//思路:入栈时不是最小值,永远都没机会成为最小值. import java.util.Stack; class MinStack { private Stack<Integer> sta ...
- 3. Android程序生成步骤
主要流程如下图所示: 所需要的工具列表 名称 功能介绍 在操作系统中的路径 aapt Android资源打包工具 ${ANDROID_SDK_HOME}/platform-tools/ ...
- Objective C 快速入门学习五
<一>继承和多态 @class Complex 声明类(同C++) 子类函数成员 super 访问父类 同C++类似 .通过继承 在子类中添加新方法 .通过继承 在子类中添加新成员 .通过 ...
- MySQL客户端Workbench
MySQL客户端除了Navicat之外,还有官方推出的MySQL Workbench,能看到数据库包含的存储过程,而Navicate不能. 下载链接: 32位:http://cdn.mysql.com ...
- oracle 存储过程中调用存储过程
create procedure sp_name() begin ……… end 比如: create procedure pro_showdbs() show datebase; end //用ex ...