问题描述

用基于变治法的堆排序算法对任意一组给定的数据进行排序

2.1 堆排序原理简介

堆可以定义为一颗二叉树,树的节点中包含键(每个节点是一个键),并且满足下面两个条件:

(1)树的形状要求——这颗二叉树是基本完备的(或者简称为完成二叉树),这意味着,树的每一层都是满的,除了最后一层最右边的元素有可能缺位。

(2)父母优势要求,又称为堆特性——每一个节点的键都要大于或等于它子女的键(对于任何孩子节点也要自动满足父母优势要求)。

2.2 变治法原理简介

变治法:首先,在“变”的阶段,出于这一或者那样的原因,把问题的实例变得更容易求解(PS:类似本文求解问题,在排序前先把数组中数进行成堆处理);然后,在第二阶段或者说“治”的阶段,对实例进行求解。

根据我们对问题实例的变换方式,变治思想有3种主要的类型:

(1)变换为同样问题的一个更简单或者更方便的实例——我们称之为实例化简;

(2)变换为同样实例的不同表现——我们称之为改变表现;

(3)变换为另一个问题的实例,这种问题的算法是已知的——我们称之为问题的化简。

package com.liuzhen.heapsort;

public class HeapSort {
/*将array[a]和array[b]、array[c]中最大值进行比较,如果较小则将array[a]与array[b]、array[c]中最大值
进行交换,否则直接返回数组array*/
public static int[] getMaxA(int[] array,int a,int b ,int c){
int temp = 0;
if(array[b] >= array[c]){
if(array[a] < array[b]){
temp = array[a];
array[a] = array[b];
array[b] = temp;
}
}
else{
if(array[a] < array[c]){
temp = array[a];
array[a] = array[c];
array[c] = temp;
}
}
return array;
} //根据堆排序父母优势规则,返回一个给定长度的数组的成堆结果
public static int[] getHeapSort(int[] array , int len){
boolean judge = true;
while(judge){
//根据堆排序父母优先规则,对数组array进行排序
for(int i = 1;i <= len/2;i++){
if((2*i+1) < len)
array = getMaxA(array,i,(2*i),(2*i+1));
if((2*i) == len-1){ //当2*i == len-1时,说明array[i]只有一个左孩子节点a[2*i]
int temp = 0;
if(array[i] < array[2*i]){
temp = array[i];
array[i] = array[2*i];
array[2*i] = temp;
}
}
} //遍历数组array,一旦出现根节点小于其叶子节点时,跳出for循环
int j;
for(j = 1;j < len/2;j++){
if((2*j+1) < len){
if(array[j] < array[2*j])
break;
if(array[j] < array[2*j+1])
break;
}
if((2*j) == len-1){
if(array[j] < array[2*j])
break;
}
} if(j == len/2) //如果j==len/2,说明遍历结果符合堆排序规则,直接结束while循环
judge = false;
}
return array;
} //使用数组成堆,对一个数组元素进行从小到大排序,并返回排序后的结果
public static int[] getResultSort(int[] array , int len){
array = getHeapSort(array , len); //首先对数组进行堆排序处理
int temp = 0; //数组值交换中间变量
int sortLen = len; //排序过程中,需要重新进行堆排序的数组长度,并初始化为array的总长度
while(sortLen > 2){
// for(int i = 1;i < len;i++)
// System.out.print(array[i]+"\t");
// System.out.println();
temp = array[1]; //交换array[0]和array[sortLen-1]的值,即把最大的值放在未排序的数组最后一位
array[1] = array[sortLen-1];
array[sortLen-1] = temp;
sortLen = sortLen - 1; //交换成功后,未排序的数组长度自动减1
array = getHeapSort(array,sortLen); //对未排序的数组,重新进行堆排序
}
return array;
} //初始化一个长度为n的随机数组
public static int[] initArray(int n){
int[] result = new int[n];
result[0] = 0;
for(int i = 1;i < n;i++)
result[i] = (int)(Math.random()*1000); //采用随机函数随机生成0~1000之间的数
return result;
} public static void main(String args[]){
int[] array = {0,1,4,5,3,5,23,45,12,23,34,56,78,23,24,25}; //此处定义数组,对array[1]到array[len-1]进行排序
int len = array.length;
int[] result = getResultSort(array,len);
System.out.println("手动输入数组,使用堆排序,最终排序结果:");
for(int i = 1;i < len;i++){
System.out.print(result[i]+"\t");
} System.out.println();
System.out.println();
int[] oneArray = initArray(1000);
int len1 = 1000;
int[] result1 = getResultSort(oneArray,len1);
System.out.println("系统随机生成的长度为1000的数组(其值均在0~1000之间),使用堆排序,最终排序结果:");
for(int j = 1;j < len1;j++){
System.out.print(result1[j]+"\t");
if(j%15 == 0)
System.out.println();
}
}
}

Java实现堆排序问题(变治法)的更多相关文章

  1. Java中的逆变与协变

    看下面一段代码 Number num = new Integer(1); ArrayList<Number> list = new ArrayList<Integer>(); ...

  2. Java中的逆变与协变(转)

    看下面一段代码 Number num = new Integer(1); ArrayList<Number> list = new ArrayList<Integer>(); ...

  3. Java泛型的逆变

    在上篇<Java泛型的协变>这篇文章中遗留以下问题——协变不能解决将子类型添加到父类型的泛型列表中.本篇将用逆变来解决这个问题. 实验准备 我们首先增加以下方法,见代码清单1所示. 代码清 ...

  4. Java中的逆变与协变 专题

    结论先行: PECS总结: 要从泛型类取数据时,用extends: 协变 要往泛型类写数据时,用super: 逆变 既要取又要写,就不用通配符(即extends与super都不用) 不变 List&l ...

  5. [改善Java代码]覆写变长方法也循规蹈矩

    建议6:覆写变长方法也循规蹈矩 在Java中,子类覆写父类中的方法很常见,这样做既可以修正Bug也可以提供扩展的业务功能支持,同时还符合开闭原则(Open-Closed Principle),我们来看 ...

  6. Java实现堆排序

    import java.util.Scanner; /*堆是一种数据结构,类似于一棵完整的二叉树. * 思想:堆的根节点值最大(最小),将无序序列调整成一个堆,就能找出这个序列的最大值(最小值),将找 ...

  7. 蓝桥杯比赛java 练习《立方变自身》

    立方变自身 观察下面的现象,某个数字的立方,按位累加仍然等于自身.1^3 = 1 8^3  = 512    5+1+2=817^3 = 4913   4+9+1+3=17... 请你计算包括1,8, ...

  8. Java实现堆排序和计数排序

    堆排序代码: 思想:每次都取堆顶的元素,将其放在序列最后面,然后将剩余的元素重新调整为最小堆,依次类推,最终得到排序的序列. import java.util.Arrays; /** * 思路:首先要 ...

  9. Java中的逆变与协变 很直接不饶弯的讲出来了

    ```java 协变 extends只能new 辈分比自己低的家伙 List<? extends Number> list001 = new ArrayList<Integer> ...

随机推荐

  1. [hdu5225]逆序对统计

    题目:给定一个1到n的排列,求字典序小于这个排列的所有排列的逆序对数之和. 思路:既然是求字典序小于这个排列的,不妨将排列根据和它前k位相同来分类,然后枚举第k+1位的数(小于原序列第k+1位的数), ...

  2. Mac 安装实用开发软件和日常软件清单

    软件安装 开发需要安装软件 HomeBrew 这个是 mac 的软件包管理软件,类似于 yum 安装 rpm 包会帮我们处理软件包之间的依赖关系一样,或者 apt-get 安装 deb 包,最开始接触 ...

  3. 掌握这10种方法帮你快速在Linux上分析二进制文件

    我们每天都使用二进制文件,但对二进制文件知之甚少.二进制是指您每天运行的可执行文件,从命令行工具到成熟的应用程序.Linux提供了丰富的工具集,可轻松进行二进制分析!无论您的工作角色是什么,如果您在L ...

  4. SD实现原理学习,以及SD失效的问题解决

    SD失效的问题可能解决方案: 1.有可能是图片的url地址不对,有可能浏览器可以打开,但是这个地址浏览器是做了处理的,所以浏览器能打开. 2.如果图片地址是Http,那么就需要关闭ATS. ATS ( ...

  5. 复变函数-MINDMAPS-continuous updating

  6. ⚠ | 不要再使用 markdown 主题了!

    前置 我在很久之前就发现了使用第三方 markdown 主题将产生一个的问题,今日在社区发现依然有人写文章来推荐这种做法.接下来我告诉你为什么最好不要这样做以及分享一些 markdown 技巧.若有不 ...

  7. firefox的fq设置图文教程- 【windows,mac通用】

    不能像下图一样全部设置socket代理,这样会把所以请求都转发到ss ! 应该使用系统设置,这里不能用pac ,因为pac 链接每次都是变化的. 搞定.

  8. ORACLE重做日志小结

    1.Redo log特点 重做日志以磁盘I/O为主,将数据库操作记录到日志文件.(磁盘I\O性能有可能成为瓶颈) 每个实例只有一个活动的LGWR(log writer)进程,至少有两个日志组(logf ...

  9. DPDK IP分片及重组库(学习笔记)

    1 前置知识学习 1.1 MTU MTU是最大传输单元( Maximum Transmission Unit)的缩写,指一个接口无需分片所能发送的数据包的最大字节数.  MTU范围在46 ~ 1500 ...

  10. 为什么我不建议你通过 Python 去找工作?

    二哥,你好,我是一名大专生,学校把 Python 做为主语言教给我们,但是我也去了解过,其实 Python 门槛挺高的,所以我在自学 Java,但是我现在并不清楚到底要不要全心的去学 Java,学校里 ...