堆排序Heapsort的Java和C代码
Heapsort排序思路
将整个数组看作一个二叉树heap, 下标0为堆顶层, 下标1, 2为次顶层, 然后每层就是"3,4,5,6", "7, 8, 9, 10, 11, 12, 13, 14", ..., 对于其中的每一个非叶子节点, 其子节点的下标为 2 * pos + 1 和 2 * pos + 2
循环进行以下工作:
- 标记当前堆的右边界
- 将堆初始化为大顶堆
- 将堆顶置换到右边界, 同时将右边界左移一位(即将堆缩小一格)
将堆初始化为大顶堆的处理
- 从最后一个非叶子节点开始, 其下标为 length / 2 - 1, length为当前的堆大小, 往前挨个处理
- 检查节点值, 对节点与其子节点的值大小i进行比较, 如果子节点值比当前节点大, 将最大值的那个子节点换上来
- 如果发生了交换, 那么要对发生交换的这个子节点位置也进行检查, 如果还有交换, 则继续往下查, 直到达到叶子节点
public class DemoHeapSort {
// 待排序的数组
private int[] ints;
// 当前堆的右边界(下标)
private int limit;
public DemoHeapSort(int ... ints) {
this.ints = ints;
this.limit = ints.length - 1;
}
public void sortAll() {
while (limit > 0) {
resort();
swap(0, limit);
limit--;
}
}
public void resort() {
// 起点pos为当前堆length / 2 - 1
for (int i = (limit + 1) / 2 - 1; i >= 0; i--) {
int pos = i;
while (true) {
pos = check(pos);
if (pos == 0) {
break;
}
}
}
}
/**
* 检查pos位置, 自上而下判断是否都满足大顶堆的要求
* 其左右子节点的下标为 2*pos+1 和 2*pos+2
*
* @param pos 当前要检查的下标
* @return 如果无调整, 则返回0, 如果有调整, 则返回被调整的子节点下标
*/
private int check(int pos) {
int posLeft = 2 * pos + 1;
int posRight = 2 * pos + 2;
if (posLeft > limit) { // 没有子节点
return 0;
}
if (posRight > limit) { // 仅有左节点
if (ints[pos] < ints[posLeft]) {
swap(pos, posLeft);
return posLeft;
} else {
return 0;
}
}
// 左右节点都有
if (ints[posLeft] > ints[posRight]) {
if (ints[pos] < ints[posLeft]) {
swap(pos, posLeft);
return posLeft;
} else {
return 0;
}
} else {
if (ints[pos] < ints[posRight]) {
swap(pos, posRight);
return posRight;
} else {
return 0;
}
}
}
public void print() {
for (int a : ints) {
System.out.printf("%3d", a);
}
System.out.print("\n");
}
private void swap(int a, int b) {
int tmp = ints[a];
ints[a] = ints[b];
ints[b] = tmp;
}
public static void main(String[] args) {
DemoHeapSort hs = new DemoHeapSort(10, 97, 9, 1,63, 64, 8, 17, 33, 7, 21, 0, 7, 75, 13, 18, 2, 99, 87);
hs.sortAll();
hs.print();
}
}
C代码, 在原数组上排序
void heap_sort(int *nums, int size) {
for (int i = 0; i < size; i++) {
int num = *(nums + i);
printf("%d ", num);
}
printf("\n");
for (int i = 0; i < size; i++) {
int length = size - i;
for (int pos = length / 2 - 1; pos >= 0; pos-- ) {
int p = pos;
do {
p = check(nums + i, length - 1, p);
} while (p != 0);
}
for (int j = 0; j < size; j++) {
int num = *(nums + j);
printf("%d ", num);
}
printf(" %d\n", i);
}
}
int check(int *nums, int limit, int pos) {
int ls = pos * 2 + 1;
int rs = pos * 2 + 2;
if (ls > limit) {
return 0;
}
int p = *(nums + pos);
if (rs > limit) {
int l = *(nums + ls);
if (l > p) {
swap(nums + ls, nums + pos);
return ls;
} else {
return 0;
}
} else {
int l = *(nums + ls);
int r = *(nums + rs);
if (l > r) {
if (l > p) {
swap(nums + ls, nums + pos);
return ls;
} else {
return 0;
}
} else {
if (r > p) {
swap(nums + rs, nums + pos);
return rs;
} else {
return 0;
}
}
}
}
void swap(int *a, int *b) {
int t = *a;
*a = *b;
*b = t;
}
堆排序Heapsort的Java和C代码的更多相关文章
- 数据结构 - 堆排序(heap sort) 具体解释 及 代码(C++)
堆排序(heap sort) 具体解释 及 代码(C++) 本文地址: http://blog.csdn.net/caroline_wendy 堆排序包括两个步骤: 第一步: 是建立大顶堆(从大到小排 ...
- 正则表达式学习笔记(附:Java版示例代码)
具体学习推荐:正则表达式30分钟入门教程 . 除换行符以外的任意字符\w word,正常字符,可以当做变量名的,字母.数字.下划线.汉字\s space,空白符 ...
- java俄罗斯方块游戏代码
java俄罗斯方块游戏代码: package com; import java.awt.Color; import java.awt.Graphics; import java.awt.event.K ...
- java常用用代码
/** *Java获取IP代码 */ import java.awt.GridLayout; import java.awt.event.ActionEvent; import java.awt.ev ...
- java学用代码
/** *Java获取IP代码 */ import java.awt.GridLayout; import java.awt.event.ActionEvent; import java.awt.ev ...
- 分享非常有用的Java程序(关键代码)(七)---抓屏程序
原文:分享非常有用的Java程序(关键代码)(七)---抓屏程序 import java.awt.Dimension; import java.awt.Rectangle; import java.a ...
- 分享非常有用的Java程序 (关键代码)(六)---解析/读取XML 文件(重要)
原文:分享非常有用的Java程序 (关键代码)(六)---解析/读取XML 文件(重要) XML文件 <?xml version="1.0"?> <student ...
- 分享非常有用的Java程序 (关键代码)(五)---把 Array 转换成 Map
原文:分享非常有用的Java程序 (关键代码)(五)---把 Array 转换成 Map import java.util.Map; import org.apache.commons.lang.Ar ...
- 分享非常有用的Java程序 (关键代码)(四)---动态改变数组的大小
原文:分享非常有用的Java程序 (关键代码)(四)---动态改变数组的大小 /** * Reallocates an array with a new size, and copies the co ...
随机推荐
- [LeetCode] 543. 二叉树的直径 ☆(递归、数最大深度)
描述 给定一棵二叉树,你需要计算它的直径长度.一棵二叉树的直径长度是任意两个结点路径长度中的最大值.这条路径可能穿过根结点. 示例 :给定二叉树 1 / \ 2 3 / \ 4 5 返回 3, 它的长 ...
- Oracle 11g新特性direct path read引发的系统停运故障诊断处理
黎俊杰 | 2016-07-28 14:37 声明:部分表名为了脱敏而用XX代替 1.故障现象 (1)一个业务系统输入用户名与密码后无法进入首页,表现为一直在运行等待,运行缓慢 (2)整个系统无法正常 ...
- Spring IOC 总结
IOC 简介 IOC是(Inversion of Control,控制反转)的简写.Spring提供IOC容器,将对象间的依赖关系交由Spring进行控制,避免硬编码所造成的的过度程序耦合.它由DI( ...
- GreenPlum数据库搭建原原则
1.平衡: 性能 容量 成本 2.高可用(主节点高可用): 节点 网络 磁盘 3.部署方案: Master和Standby Master分机部署 primaty segment 与miiror Seg ...
- window安装gcc、g++、make等编译环境
1. MinGW官网下载:http://www.mingw.org 点击右上角Downloads 点击下载 mingw-get-setup.exe 2. 百度网盘(2019年4月从官网下 ...
- JSON.stringify(),JSON.parse(),toJSON()使用方法总结
今天在看<你不知道的javascript-中>第四章‘强制类型转换’的时候,发现JSON.stringify(),JSON.parse(),toJSON()有很多细节,自己也就总结测试了一 ...
- QA流程
一.测试人员的介入时间 1.当产品经理与业务人员制定需求的时候,测试人员不宜介入: 2.当下一期的需求原型出来以后,这个时候就进入了需求评审.需求分析阶段,此时,测试人员应该介入: 3.当开发人员在编 ...
- 2019安徽省程序设计竞赛 I.你的名字(序列自动机)
这题和今年南昌邀请网络预选赛M题很像啊,不过主串数量不是一个了 都是在主串中判断子串是不是属于主串的一个子序列 #include <iostream> #include <cstri ...
- MySQL——时间戳和时间的转化
前言 Mysql中时间戳和时间的转化 时间转时间戳 select unix_timestamp('2019-7-29 14:23:25'); 时间戳转时间 select from_unixtime(1 ...
- vue饿了么UI库-笔记
1. :rules="{required: true, message: '有效期不能为空'}" :rules="{type:'date',required: true, ...