堆排序详解以及java实现
前言
临近毕业,开始找工作,近期一直在看算法导论(CLRS)同时各种刷题。希望以后有时间把所有学习心得和刷题心得记录下来。
堆
堆排序和合并排序一样,是一种时间复杂度为O(nlgn)的算法,同时和插入排序一样,是一种就地排序算法(不需要额外的存储空间)。堆排序需要用到一种被称为最大堆的数据结构,与java或者lisp的gc不一样,这里的堆是一种数据结构,他可以被视为一种完全二叉树,即树里面除了最后一层其他层都是填满的。也正是因为这样,树里面每个节点的子女和双亲节点的序号都可以根据当前节点的序号直接求出。
Parent(i)=i/2
Left(i)=2*i
Right(i)=2*i+1
如上图所示,1位置的子女节点分别为2,3 2节点的子女节点为4,5 2的双亲节点为1 考察其他节点也很容易发现上述关系。最大堆是一种特殊的堆,其特点是每个双亲节点的值都比子女节点大。他的这一特点使得他可以实现nlgn的就地排序。现在我们先来看看怎么构建和保持一个最大堆。
最大堆的构建和保持
我们现在有一个数组A,大小是n,假设其中元素按照完全二叉树的方式排列。如何将其构造成一个最大堆?首先我们知道最大堆的每个子树都符合最大堆的性质(根节点值大于所有子节点)。同时我们知道序号为(n/2+1)~n的元素都是叶子节点(因为其子女节点的序号都大于n,即说明没有子女节点),因此我们构建最大堆的操作就在序号为1~n/2的元素内进行(其他元素已满足最大堆性质)。我们定义如下操作maxify(i):将以i位置节点为根的子树改造成最大堆。其操作内容如下:对于每个节点i,我们考察他与子女节点的大小,如果他比某个子女节点小,则将他与子女节点中最大的那个互换位置,然后在相应的子女节点位置重复操作,直到到达堆的叶子节点或者考察的位置比子女节点的值都要大为止。由此可知我们构造最大堆buildmaxheap的过程就是在每个内部节点上调用maxify过程,依次到树的根部,此时其左右子树都是最大堆,现在在根节点调用maxify即完成了最大堆的构造。
堆排序的操作
有了最大堆的基础结构后,我们就可以利用最大堆的性质进行排序HeapSort,我们从根节点开始操作,因为根节点是这个数组中最大的元素,因此我们将其于数组中最后一个元素对换(排序后,最大元素应该在最后)将heapsize减1,然后再在根节点出调用maxify过程将新的堆重新最大堆化。依次循环,我们每次都能将现有堆中最大的元素放到堆末尾。最后就完成了整个排序过程。操作情况见下图(只列出了前4步)
代码及运行结果
public class MaxHeap {
int[] heap;
int heapsize;
public MaxHeap(int[] array)
{
this.heap=array;
this.heapsize=heap.length;
}
public void BuildMaxHeap()
{
for(int i=heapsize/2-1;i>=0;i--)
{
Maxify(i);//依次向上将当前子树最大堆化
}
}
public void HeapSort()
{
for(int i=0;i<heap.length;i++)
{
//执行n次,将每个当前最大的值放到堆末尾
int tmp=heap[0];
heap[0]=heap[heapsize-1];
heap[heapsize-1]=tmp;
heapsize--;
Maxify(0);
}
}
public void Maxify(int i)
{
int l=Left(i);
int r=Right(i);
int largest; if(l<heapsize&&heap[l]>heap[i])
largest=l;
else
largest=i;
if(r<heapsize&&heap[r]>heap[largest])
largest=r;
if(largest==i||largest>=heapsize)//如果largest等于i说明i是最大元素 largest超出heap范围说明不存在比i节点大的子女
return ;
int tmp=heap[i];//交换i与largest对应的元素位置,在largest位置递归调用maxify
heap[i]=heap[largest];
heap[largest]=tmp;
Maxify(largest);
}
public void IncreaseValue(int i,int val)
{
heap[i]=val;
if(i>=heapsize||i<=0||heap[i]>=val)
return;
int p=Parent(i);
if(heap[p]>=val)
return;
heap[i]=heap[p];
IncreaseValue(p, val);
} private int Parent(int i)
{
return (i-1)/2;
}
private int Left(int i)
{
return 2*(i+1)-1;
}
private int Right(int i)
{
return 2*(i+1);
}
}
public class Demo {
public static void main(String[] args)
{
int[] array=new int[]{1,2,3,4,7,8,9,10,14,16};
MaxHeap heap=new MaxHeap(array);
System.out.println("执行最大堆化前堆的结构:");
printHeapTree(heap.heap);
heap.BuildMaxHeap();
System.out.println("执行最大堆化后堆的结构:");
printHeapTree(heap.heap);
heap.HeapSort();
System.out.println("执行堆排序后数组的内容");
printHeap(heap.heap); }
private static void printHeapTree(int[] array)
{
for(int i=1;i<array.length;i=i*2)
{
for(int k=i-1;k<2*(i)-1&&k<array.length;k++)
{
System.out.print(array[k]+" ");
}
System.out.println();
}
}
private static void printHeap(int[] array)
{
for(int i=0;i<array.length;i++)
{
System.out.print(array[i]+" ");
}
} }
堆排序详解以及java实现的更多相关文章
- 事件驱动模型实例详解(Java篇)
或许每个软件从业者都有从学习控制台应用程序到学习可视化编程的转变过程,控制台应用程序的优点在于可以方便的练习某个语言的语法和开发习惯(如.net和java),而可视化编程的学习又可以非常方便开发出各类 ...
- Heapsort 堆排序算法详解(Java实现)
Heapsort (堆排序)是最经典的排序算法之一,在google或者百度中搜一下可以搜到很多非常详细的解析.同样好的排序算法还有quicksort(快速排序)和merge sort(归并排序),选择 ...
- Myeclipse Templates详解(一) —— Java模板基础
目录 Templates简介 MyEclipse自带Templates详解 新建Template 自定义Template 因为自己比较懒,尤其是对敲重复代码比较厌恶,所以经常喜欢用快捷键和模板,Mye ...
- 二叉搜索树详解(Java实现)
1.二叉搜索树定义 二叉搜索树,是指一棵空树或者具有下列性质的二叉树: 若任意节点的左子树不空,则左子树上所有节点的值均小于它的根节点的值: 若任意节点的右子树不空,则右子树上所有节点的值均大于它的根 ...
- Java AtomicInteger类的使用方法详解_java - JAVA
文章来源:嗨学网 敏而好学论坛www.piaodoo.com 欢迎大家相互学习 首先看两段代码,一段是Integer的,一段是AtomicInteger的,为以下: public class Samp ...
- java 流操作对文件的分割和合并的实例详解_java - JAVA
文章来源:嗨学网 敏而好学论坛www.piaodoo.com 欢迎大家相互学习 java 流操作对文件的分割和合并的实例详解 学习文件的输入输出流,自己做一个小的示例,对文件进行分割和合并. 下面是代 ...
- springboot扫描自定义的servlet和filter代码详解_java - JAVA
文章来源:嗨学网 敏而好学论坛www.piaodoo.com 欢迎大家相互学习 这几天使用spring boot编写公司一个应用,在编写了一个filter,用于指定编码的filter,如下: /** ...
- Java实现的二叉堆以及堆排序详解
一.前言 二叉堆是一个特殊的堆,其本质是一棵完全二叉树,可用数组来存储数据,如果根节点在数组的下标位置为1,那么当前节点n的左子节点为2n,有子节点在数组中的下标位置为2n+1.二叉堆类型分为最大堆( ...
- 【知识详解】JAVA基础(秋招总结)
JAVA基础 目录 JAVA基础 问:面向过程(POP)和面向对象(OOP)? 问:Python和Java的区别? 问:java的八大基本数据类型? 问:封装继承多态说一下? 问:方法和函数的区别? ...
随机推荐
- Postgresql 創建觸發器,刪除觸發器和 禁用觸發器
CREATE OR REPLACE FUNCTION XF_VIP_AFUPD_WX() RETURNS trigger AS $$ DECLARE i_count integer; s_wx_ope ...
- 世界各国货币,C#数字货币计算
货币 CCY(Currency)本质上是一种所有者与市场关于交换权的契约,根本上是所有者相互之间的约定.吾以吾之所有予市场,换吾之所需,货币就是这一过程的约定,它反映的是个体与社会的经济协作关系.货币 ...
- JAVA 从头开始<四>
一.switch 1.根据输入月份获取季节 import java.util.*; class Demo8{ public static void main(String[] args) { Syst ...
- Flask系列03--Flask的路由 app.route中的参数, 动态参数路由
Flask–路由 添加路由的两种方式 第一种 @app.route("/my_de") def detail() 第二种(了解即可) app.add_url_rule(" ...
- FreePascal - CodeTyphon交叉编译,在一个操作系统生成各个操作系统可以运行的程序!
致谢:[XE3]MN,让我加快完成了使用CodeTyphon进行交叉编译! CodeTyphon版本: 6.0 下载:http://www.pilotlogic.com/codetyphon/zips ...
- 面向对象进阶-item系列、__new__、__hash__、__eq__ (四)
item系列 dic = {'k':'v'}# 对象 : 存储属性 和调用方法dic['k'] = 'v'# class Foo:# def __init__(self,name,age,se ...
- 字符串写入txt文件
将字符串写入C盘txt文件里 File.AppendAllText(@"C:\" + DateTime.Now.ToString("HHmmss") + &qu ...
- Organising the Organisation(uva10766)(生成树计数)
Input Output Sample Input 5 5 2 3 1 3 4 4 5 1 4 5 3 4 1 1 1 4 3 0 2 Sample Output 3 8 3 题意: 有一张图上有\( ...
- Flask的WTforms
一.简单介绍 WTForms是一个支持多个web框架的form组件,主要用于对用户请求数据进行验证. 类似于Django中的modelform 安装: pip3 install wtforms 二.简 ...
- Java多线程实现异步调用
在Java平台,实现异步调用的角色有如下三个角色:调用者. 提货单 .真实数据,一个调用者在调用耗时操作,不能立即返回数据时,先返回一个提货单 .然后在过一断时间后凭提货单来获取真正的数据.去蛋糕店买 ...