java写一个堆排序(大顶堆)
2017-08-28 12:22
381 查看
java写一个堆排序(大顶堆)
堆排序的时间复杂度,最好,最差,平均都是O(nlogn),空间复杂度O(1),是不稳定的排序堆(或二叉堆),类似于完全二叉树,除叶子节点外,每个节点均拥有左子树和右子树,同时左子树和右子树也是堆。
小顶堆:父节点的值 <= 左右孩子节点的值
大顶堆:父节点的值 >= 左右孩子节点的值
堆的存储:
用一个数组存储堆就可以了,如【19, 17, 20, 18, 16, 21】
对于数组中的第 i 个节点(从0开始),有如下规律:
如果父节点存在,则它的父节点是 (i - 1) / 2; 比如3的父亲是(3-1)/2=1
如果左孩子存在,则它的左孩子是 2 * i + 1; 比如1的左孩子是2*1+1=3
如果右孩子存在,则右孩子是 2 * i + 2;比如1的右孩子是2*1+2=4
假设当前要排序的数组是:arr = [19, 17, 20, 18, 16, 21],下面以大顶堆为例,介绍如何构建大顶堆。
1、由于叶子节点没有左孩子和右孩子,所以不必从叶子节点开始调整堆,即不从18、16、21开始调整,直接从20开始调整,直至堆顶。 用伪代码(Java)描述如下:
for(int i = arr.length / 2 - 1; i >= 0; i--) { // 调整(); fix_down(arr, i, arr.length-1); }
2、如果当前节点 小于 左右孩子的最大值【此处假设是右孩子】,则交换当前节点的值与右孩子的值,并从右孩子开始,继续向下调整。由于20不大于21,因此交换20和21。
接下来从17开始,因为17 < 18, 所以交换17与18的值。
接下来,由于19 < 21 ,所以交换19和21,又由于19 < 20,所以需要继续交换19和20。
3、 经过上一步,就得到了一个大顶堆,接下来就是堆排序的过程
在这个大顶堆中,堆顶元素是整个堆中的最大值,取出堆顶元素,并与堆中的最后一个元素交换位置,即21与19交换,然后调整堆(21不动)。不断重复这个过程,每一次取出堆顶元素,并与最后一个元素交换位置,直至最后一个元素就是堆顶,这样就可以得到一个自上而下的递增的堆。
public static void head_sort(int[] arr) { // 取出堆顶元素,与最后一个元素交换,调整堆 for(int i = arr.length - 1; i >= 0; i--) { int temp = arr[i]; // 最后一个元素 arr[i] = arr[0]; arr[0] = temp; fix_down(arr, 0, i-1); // 注意此处是i-1; 刚刚交换后的最后一个元素不参与调整,即21不参与调整 } }
堆排序完整代码如下:
/** * * @author lijialin * @since 2017/08/28 */ public class HeapSort { public static void print(int[] arr) { for(int i = 0; i < arr.length; i++) { System.out.print(arr[i] + " "); } System.out.println(); } public static void create_heap(int[] arr) { for(int i = arr.length / 2 - 1; i >= 0; i--) { fix_down(arr, i, arr.length-1); } } public static void fix_down(int[] arr, int i, int end) { int child = (i << 1) + 1; // 当前节点的左孩子 int temp = arr[i]; while(child <= end) { // 选出两个孩子较大的那个 if(child < end && arr[child+1] > arr[child]) { child++; } if(temp < arr[child]) { arr[i] = arr[child]; // 孩子节点与当前节点替换 i = child; child = (i << 1) + 1; }else { break; } } arr[i] = temp; } public static void head_sort(int[] arr) { // 取出堆顶元素,与最后一个元素交换,调整堆 for(int i = arr.length - 1; i >= 0; i--) { int temp = arr[i]; // 最后一个元素 arr[i] = arr[0]; arr[0] = temp; fix_down(arr, 0, i-1); } } public static void main(String[] args) { // TODO Auto-generated method stub // Test case 1 int[] arr = {19,17,20,18,16,21}; create_heap(arr); // 创建堆 head_sort(arr); print(arr); // 16 17 18 19 20 21 // Test case 2 int[] arr1 = {16,7,3,20,17,8}; create_heap(arr1); head_sort(arr1); print(arr1); // 3 7 8 16 17 20 // Test case 3 int[] arr2 = {5,4,3,2,1}; create_heap(arr2); head_sort(arr2); print(arr2); // 1 2 3 4 5 // Test case 4 int[] arr3 = {1,1,1,1}; create_heap(arr3); head_sort(arr3); print(arr3); // 1 1 1 1 } }
总结:
堆排序是不稳定的排序
在待排序的文件中,若存在多个关键字相同的记录,经过排序后,这些记录之间的相对次序保持不变,该排序方法是稳定的;反之,若相对次序变化,则排序不稳定。
堆排序的时间复杂度,最好最差平均都是O(nlogn),空间复杂度是O(n)。父节点与子节点交换时,需要使用一个中间变量,所以是O(1),当然创建堆的空间不计算在内。
大顶堆 | 小顶堆 |
---|---|
父节点大于左右孩子 | 父节点小于左右孩子 |
排序后从小到大 | 排序后从大到小 |
加油,再接再厉!
相关文章推荐
- 用java实现一个基于堆排序的优先队列
- 《排序算法》——堆排序(大顶堆,小顶堆,Java)
- Java 堆排序实例(大顶堆、小顶堆)
- 用Java实现一个堆排序
- Java 堆排序(大顶堆、小顶堆)
- 通过培训学到的一个java的基于线程,网络编程等的文件多线程断点下载器(断点功能还在操作实践中)
- Java程序设计(十二)----编写一个Teacher类负责给出算术题目
- 输入一个日期判断是星期几 java
- 使用网上流传的一个数据库连接池在Proxy.newProxyInstance处引起 java.lang.ClassCastException 问题的解决方法
- SpringMVC整合Shiro,Shiro是一个强大易用的Java安全框架,提供了认证、授权、加密和会话管理等功能
- 一个简单java布局管理器
- 初学java制作了一个绘图板
- java 生成一个永不重复的数字序列
- java 堆排序
- java将两个byte数组合为一个
- 项目中一个普通的Java类如何获取service接口(一)
- 一个经典例子让你彻彻底底理解java回调机制
- Java的char数据类型存储一个中文字符
- java extends & implements 一个一般不会注意到的重要区别
- 采用truelicense进行Java规划license控制 扩展可以验证后,license 开始结束日期,验证绑定一个给定的mac住址