最近看了些数据结构的书,为了便于以后复习,遂用Java实现了堆的构造与堆排序。
/**
* Created by cht on 2016/11/6.
*/
//堆:可以定义为一颗二叉树,树中的节点满足两个条件;a,树的形状要求,对于该树,要求树必须是基本完备的,即,除树的最后一层之外,其他层都是满的。
//b,父母优势,即,对于书中的任一父节点,该节点所对应的key不小于其孩子节点的key。叶子节点默认满足此要求。
//堆有如下的特性:
// 1,如果该堆得节点个数为n,则其所对应的树的高度为不大于log n的整数。
// 2,堆的根节点是堆中最大的元素,堆的左右子树也是一个堆。
// 3,可以用数组来实现一个堆,数组heap[n+1]的1<=index<=n,存储堆中的n个元素,heap[0]的位置可以存放一个0,也可以存放其他的值;父节点在数组中的前n/2个位置,叶子节点在后n/2个位置;父节点的位置为i(假设其有孩子节点),则其孩子节点的位置为2*i和2*i+1的位置
public class Heap {
//储存堆的数据结构,这里选择的是数组,为了简单。最理想的应该是动态数组,便于堆的插入与删除。
public int heap[];
/**
* 堆的构造函数。采用自底向上的方法构造堆
* @param heap
*/
public Heap(int heap[]) {
int n = heap.length - 1;
for (int i = n / 2; i >= 1; i--) {
int k = i;
int value = heap[k];
Boolean tagHeap = false;
while (!tagHeap && 2 * k <= n) {
int j=2*k; //k节点所对应的孩子节点
//k节点存在两个孩子,找到最大的一个孩子
if(j<n){
//如果右孩子大于左孩子,
if(heap[j]<heap[j+1]){
j=j+1;
}
}
if(value>heap[j]) {
tagHeap = true;
}else {
heap[k]=heap[j];
k=j;
}
}
heap[k]=value;
}
this.heap=heap;
}
/**
* 堆的构造函数。采用自底向上的方法构造堆
* n为堆中包含的元素。在数组中的位置对应的索引为1-n。
* @param heap
* @param n
*/
public Heap(int heap[],int n){
n=n-1;
for (int i = n / 2; i >= 1; i--) {
int k = i;
int value = heap[k];
Boolean tagHeap = false;
while (!tagHeap && 2 * k <= n) {
int j=2*k; //k节点所对应的孩子节点
//k节点存在两个孩子,找到最大的一个孩子
if(j<n){
//如果右孩子大于左孩子,
if(heap[j]<heap[j+1]){
j=j+1;
}
}
if(value>heap[j]) {
tagHeap = true;
}else {
heap[k]=heap[j];
k=j;
}
}
heap[k]=value;
}
this.heap=heap;
}
/**
* 打印堆
*/
public void printHeap(){
for (int i = 0; i < this.heap.length; i++) {
System.out.print(this.heap[i]+" ");
}
System.out.println();
}
/**
* 删除堆中最大的元素,即删除堆的根节点。
* 1.将堆的根节点与最后的一个元素(k)互换位置
* 2.堆的规模减一,并且重新进行堆化。
* 3.我在进行堆化的时候用的是方法是重新构建一个堆,不推荐这种方法,效率不高。应该对k采取沿着堆树向下进行筛选,以此进行堆化,对于此种方法,储存堆的数据结构应该选择动态数组。
*
*/
public void delRoot(){
int n=this.heap.length;
int temp=this.heap[n-1];
this.heap[n-1]=this.heap[1];
this.heap[1]=temp;
int tempArry[]=new int[n-1];
for (int i = 0; i <n-1 ; i++) {
tempArry[i]=this.heap[i];
}
Heap tempHeap=new Heap(tempArry);
this.heap=tempHeap.heap;
}
/**
* 删除堆中最大的元素,即删除堆的根节点,但是将该元素保留在储存堆的数组的最后一个位置。
* 该函数用于最大堆排序。
* 该函数的解析类似函数delRoot()。
* @param n
*/
public void delRoot(int n){
int temp=this.heap[n];
this.heap[n]=this.heap[1];
this.heap[1]=temp;
Heap tempHeap=new Heap(this.heap,n);
this.heap=tempHeap.heap;
}
/**
* 实现堆排序。
*/
public void sortHeap(){
int n=this.heap.length-1;
for (int i = n; i >1; i--) {
this.delRoot(i);
}
}
public static void main(String[] args) {
System.out.println("--------------测试(注:test[0]不是堆中的元素,是个占位数字,可以置零)------------");
int test[]={11,2,9,7,6,5,8};
System.out.println("--------------test[]------------");
for (int i = 0; i < test.length; i++) {
System.out.print(test[i]+" ");
}
System.out.println();
Heap heap=new Heap(test);
System.out.println("------------调用构造函数Heap(int heap[])---------");
System.out.println("------------heap.printHeap()---------");
heap.printHeap();
heap.delRoot();
System.out.println("------------heap.delRoot()---------");
heap.printHeap();
System.out.println("--------------test[]------------");
for (int i = 0; i < test.length; i++) {
System.out.print(test[i]+" ");
}
System.out.println();
Heap heap1=new Heap(test);
System.out.println("------------调用构造函数Heap(int heap[])---------");
System.out.println("------------heap1.printHeap()---------");
heap1.printHeap();
heap1.sortHeap();
System.out.println("------------heap1.sortHeap()---------");
heap1.printHeap();
}
}