堆排序
2015-11-23 11:36
211 查看
有什么不对的地方请指出。
花了大半天时间研究了下堆排序。总体来说堆排序是选择排序和分治思想的结合。每次选择堆顶元素,堆顶元素要么是最大,要么是最小的。分治是指堆进行调整时,每次调整都只会影响一个子树,都使得数据量减少一半。
堆排序的过程:
1.建立堆化数组:从最后一个非叶子节点开始调整,从后往前调整,每次调整后该子树为符合要求的堆,直到i=0的根节点调整完。调整的具体步骤下面介绍。
2.把堆顶和堆最后一个位置互换,堆大小减1,这样使堆顶出堆,并对剩余元素进行调整,使之成为大顶堆或者小顶堆。
3.重复2操作,直至堆中元素全部出堆。
其中最重要的是堆调整的方法,所有的堆操作都是这个基础上进行的。
堆调整的前提是,左右子树都是符合要求的堆。
以大顶堆为例。假设对根节点下标为i(i从0开始,既整个树的根节点下标为0)的子树进行调整,i的左子树根节点为2*i+1,右子树根节点为2*i+2。比较3个节点中值大小,记录最大的节点,若i不是最大节点,把i节点和最大节点互换,并对最大节点为根的子树进行调整(因为互换会破坏子树结构,使之成为非堆结构);若i为最大节点,那就退出该次调整(i节点最大,那么该子树也是大顶堆)。
/**
* 在左右子树都大顶堆的情况下,进行调整。使用递归调用。
*
* @param a
* 堆数组
* @param i
* 要调整的子树根节点号。(以0开始,子节点分别为2*i+1, 2*i+2)。
* @param size
* 整个堆的大小。
*/
public static void maxHeapAdjust(int[] a, int i, int size) {
int left = 2 * i + 1;
int right = 2 * i + 2;
int max = i; // 记录这次调整的最大数节点号。
if (i < size / 2) { // i是非叶子节点,就不要调整了。
if (left < size && a[max] < a[left])
max = left;
if (right < size && a[max] < a[right])
max = right;
if (max != i) {
swap(a, i, max);
maxHeapAdjust(a, max, size);
}
}
}
堆排序的完整代码如下:
public class HeapSort {
public static void main(String[] args) {
int[] a = new int[] { 3, 4, 5, 9, 10,2, 6, 7 };
print(a);
System.out.println("+++++++++排序前+++++++++++++");
minHeapSort(a);
System.out.println("+++++++++排序后+++++++++++++");
print(a);
}
public static void maxHeapSort(int[] a) {
int size = a.length;
if(size <= 1)
return ;
// 建立堆化数组
for (int i = (size-2)/2; i >= 0; i
4000
--) {
maxHeapAdjust(a, i, size);
}
// 进行堆排序
for (int i = size - 1; i >= 0; i--) {
swap(a, 0, i);
maxHeapAdjust(a, 0, i);
}
}
public static void minHeapSort(int[] a) {
int size = a.length;
if(size <= 1)
return ;
// 建立堆化数组
for (int i = (size-2)/2; i >= 0; i--) {
minHeapAdjust(a, i, size);
}
// 进行堆排序
for (int i = size - 1; i >= 0; i--) {
swap(a, 0, i);
minHeapAdjust(a, 0, i);
}
}
/**
* 在左右子树都大顶堆的情况下,进行调整。使用递归调用。
*
* @param a
* 堆数组
* @param i
* 要调整的子树根节点号。(以0开始,子节点分别为2*i+1, 2*i+2)。
* @param size
* 整个堆的大小。
*/
public static void maxHeapAdjust(int[] a, int i, int size) {
int left = 2 * i + 1;
int right = 2 * i + 2;
int max = i; // 记录这次调整的最大数节点号。
if (i < size / 2) { // i是非叶子节点,就不要调整了。
if (left < size && a[max] < a[left])
max = left;
if (right < size && a[max] < a[right])
max = right;
if (max != i) {
swap(a, i, max);
maxHeapAdjust(a, max, size);
}
}
}
/**
* 在左右子树都小顶堆的情况下,进行调整。使用递归调用。
*
* @param a
* 堆数组
* @param i
* 要调整的子树根节点号。(以0开始,子节点分别为2*i+1, 2*i+2)。
* @param size
* 整个堆的大小。
*/
public static void minHeapAdjust(int[] a, int i, int size) {
int left = 2 * i + 1;
int right = 2 * i + 2;
int min = i; // 记录这次调整的最大数节点号。
if (i < size / 2) { // i是非叶子节点,就不要调整了。
if (left < size && a[min] > a[left])
min = left;
if (right < size && a[min] > a[right])
min = right;
if (min != i) {
swap(a, i, min);
minHeapAdjust(a, min, size);
}
}
}
private static void swap(int[] a, int i, int j) {
int temp = a[j];
a[j] = a[i];
a[i] = temp;
}
private static void print(int[] a) {
for (int i : a) {
System.out.print(i + " , ");
}
System.out.println();
}
}
花了大半天时间研究了下堆排序。总体来说堆排序是选择排序和分治思想的结合。每次选择堆顶元素,堆顶元素要么是最大,要么是最小的。分治是指堆进行调整时,每次调整都只会影响一个子树,都使得数据量减少一半。
堆排序的过程:
1.建立堆化数组:从最后一个非叶子节点开始调整,从后往前调整,每次调整后该子树为符合要求的堆,直到i=0的根节点调整完。调整的具体步骤下面介绍。
2.把堆顶和堆最后一个位置互换,堆大小减1,这样使堆顶出堆,并对剩余元素进行调整,使之成为大顶堆或者小顶堆。
3.重复2操作,直至堆中元素全部出堆。
其中最重要的是堆调整的方法,所有的堆操作都是这个基础上进行的。
堆调整的前提是,左右子树都是符合要求的堆。
以大顶堆为例。假设对根节点下标为i(i从0开始,既整个树的根节点下标为0)的子树进行调整,i的左子树根节点为2*i+1,右子树根节点为2*i+2。比较3个节点中值大小,记录最大的节点,若i不是最大节点,把i节点和最大节点互换,并对最大节点为根的子树进行调整(因为互换会破坏子树结构,使之成为非堆结构);若i为最大节点,那就退出该次调整(i节点最大,那么该子树也是大顶堆)。
/**
* 在左右子树都大顶堆的情况下,进行调整。使用递归调用。
*
* @param a
* 堆数组
* @param i
* 要调整的子树根节点号。(以0开始,子节点分别为2*i+1, 2*i+2)。
* @param size
* 整个堆的大小。
*/
public static void maxHeapAdjust(int[] a, int i, int size) {
int left = 2 * i + 1;
int right = 2 * i + 2;
int max = i; // 记录这次调整的最大数节点号。
if (i < size / 2) { // i是非叶子节点,就不要调整了。
if (left < size && a[max] < a[left])
max = left;
if (right < size && a[max] < a[right])
max = right;
if (max != i) {
swap(a, i, max);
maxHeapAdjust(a, max, size);
}
}
}
堆排序的完整代码如下:
public class HeapSort {
public static void main(String[] args) {
int[] a = new int[] { 3, 4, 5, 9, 10,2, 6, 7 };
print(a);
System.out.println("+++++++++排序前+++++++++++++");
minHeapSort(a);
System.out.println("+++++++++排序后+++++++++++++");
print(a);
}
public static void maxHeapSort(int[] a) {
int size = a.length;
if(size <= 1)
return ;
// 建立堆化数组
for (int i = (size-2)/2; i >= 0; i
4000
--) {
maxHeapAdjust(a, i, size);
}
// 进行堆排序
for (int i = size - 1; i >= 0; i--) {
swap(a, 0, i);
maxHeapAdjust(a, 0, i);
}
}
public static void minHeapSort(int[] a) {
int size = a.length;
if(size <= 1)
return ;
// 建立堆化数组
for (int i = (size-2)/2; i >= 0; i--) {
minHeapAdjust(a, i, size);
}
// 进行堆排序
for (int i = size - 1; i >= 0; i--) {
swap(a, 0, i);
minHeapAdjust(a, 0, i);
}
}
/**
* 在左右子树都大顶堆的情况下,进行调整。使用递归调用。
*
* @param a
* 堆数组
* @param i
* 要调整的子树根节点号。(以0开始,子节点分别为2*i+1, 2*i+2)。
* @param size
* 整个堆的大小。
*/
public static void maxHeapAdjust(int[] a, int i, int size) {
int left = 2 * i + 1;
int right = 2 * i + 2;
int max = i; // 记录这次调整的最大数节点号。
if (i < size / 2) { // i是非叶子节点,就不要调整了。
if (left < size && a[max] < a[left])
max = left;
if (right < size && a[max] < a[right])
max = right;
if (max != i) {
swap(a, i, max);
maxHeapAdjust(a, max, size);
}
}
}
/**
* 在左右子树都小顶堆的情况下,进行调整。使用递归调用。
*
* @param a
* 堆数组
* @param i
* 要调整的子树根节点号。(以0开始,子节点分别为2*i+1, 2*i+2)。
* @param size
* 整个堆的大小。
*/
public static void minHeapAdjust(int[] a, int i, int size) {
int left = 2 * i + 1;
int right = 2 * i + 2;
int min = i; // 记录这次调整的最大数节点号。
if (i < size / 2) { // i是非叶子节点,就不要调整了。
if (left < size && a[min] > a[left])
min = left;
if (right < size && a[min] > a[right])
min = right;
if (min != i) {
swap(a, i, min);
minHeapAdjust(a, min, size);
}
}
}
private static void swap(int[] a, int i, int j) {
int temp = a[j];
a[j] = a[i];
a[i] = temp;
}
private static void print(int[] a) {
for (int i : a) {
System.out.print(i + " , ");
}
System.out.println();
}
}
相关文章推荐
- Xcode 插件管理
- Git 指令收集
- solr与ES 比较 Realtime Search: Solr vs Elasticsearch
- Memcached 及 Redis 架构分析和比较
- Android设计模式--适配器模式
- 使用BroadcastReceiver进行短信监控
- 安卓使用stickyGridHeader实现数据分组
- sql 获取最大的流水号
- 数据处理中使用的各种熵
- Windows10中“SQL Server 配置管理器”哪去了?
- 【leetcode】Spiral Matrix II
- java web实现用户权限管理
- git push用法和常见问题分析
- CSS简介
- <学习笔记> 安装Ionic
- 迭代删除
- MT7620原生SDK支持HUAWEI 4G dongle -- 2
- C# ——List<Enum> 转化为List<string>
- 去除Dialog的黑色背景
- 2、Zookeeper配置安装(Windows伪集群安装)