堆是一种常见的数据结构,其结构类似树,以数组形式存储数据。
下面来介绍两种堆,一种是最大堆,一种是最小堆。
最大堆的性质是:A[parent(i)]>=A[i];父节点必须比子节点大。
最小堆的性质是:A[parent(i)]<=A[i];父节点必须比子节点小。
接下来我们来一步步的看:
首先我们如何来维护堆的性质
上代码:
/**
* 类:维护堆的性质 最大堆 最小堆 两种方法 一种是递归 一种是循环
*
* @author mazip
*
*/
public class MaxHeapify {
int largest;
public static void main(String[] args) {
MaxHeapify maxHeap = new MaxHeapify();
// 这里需要在前面加上一个0 数组下标是0开始的 而堆是1 所以加上一个0
int[] m = { 0, 16, 4, 10, 14, 7, 9, 3, 2, 8, 1 };
int[] n = { 0, 16, 4, 10, 14, 7, 9, 3, 2, 8, 1 };
maxHeap.MaxHeap1(m, 2);
for (int j = 0; j < m.length; j++) {
System.out.print(m[j] + " ");
}
maxHeap.MaxHeap2(n, 2);
System.out.println();
for (int j = 0; j < n.length; j++) {
System.out.print(n[j] + " ");
}
}
/**
* method 1 递归的方法
*/
public void MaxHeap1(int[] i, int node) {
int left = leftNode(node);
int right = rightNode(node);
if (left < i.length && i[left] > i[node]) {
largest = left;
} else {
largest = node;
}
if (right < i.length && i[right] > i[largest]) {
largest = right;
}
if (largest != node) {
int temp = i[node];
i[node] = i[largest];
i[largest] = temp;
MaxHeap1(i, largest);
}
}
/**
* 用于排序的一个改造方法
*
* @param i
* @param node
*/
public void MaxHeapForSort(int[] i, int node,int flag) {
int left = leftNode(node);
int right = rightNode(node);
if (left < flag && i[left] > i[node]) {
largest = left;
} else {
largest = node;
}
if (right < flag && i[right] > i[largest]) {
largest = right;
}
if (largest != node) {
int temp = i[node];
i[node] = i[largest];
i[largest] = temp;
MaxHeapForSort(i, largest,flag);
}
}
/**
* method 2 递归的方法
*/
public void MaxHeap2(int[] i, int node) {
for (int m = node; m < i.length;) {
int left = leftNode(m);
int right = rightNode(m);
if (left < i.length && i[left] > i[m]) {
largest = left;
} else {
largest = m;
}
if (right < i.length && i[right] > i[largest]) {
largest = right;
}
if (largest != m) {
int temp = i[m];
i[m] = i[largest];
i[largest] = temp;
m = largest;
} else {
m++;
}
}
}
/**
*
* @param m
* 参数是某结点的位置
* @return int 返回左子节点的位置
*/
public int leftNode(int m) {
return 2 * m;
}
/**
*
* @param n
* 参数是某节点的位置
* @return int 返回右子节点的位置
*/
public int rightNode(int n) {
return 2 * n + 1;
}
}
至此堆的性质的维护已经完成。接下来我们来构造最大堆,相应的最小堆就是一个反例。
上代码:
/**
* 将一个普通的数组构造成一个堆
* @author mazip
*
*/
public class BuildMaxHeap {
public static void main(String[] args) {
BuildMaxHeap build = new BuildMaxHeap();
int [] array={0,4,1,3,2,16,9,10,14,8,7};
build.buildHeap(array);
for (int i = 0; i < array.length; i++) {
System.out.print(array[i]+" ");
}
System.out.println("");
System.out.println("-----------------");
int [] array1={0,4,1,3,2,16,9,10,14,8,7};
build.buildHeap1(array1);
for (int i = 0; i < array1.length; i++) {
System.out.print(array1[i]+" ");
}
}
/**
* 使用循环的方式
* 这里for循环从j.length/2开始,因为可知从j.length/2+1到n都是叶子节点
* 可以看做一个独立的堆,其它的树有可能破坏了最大堆的性质,
* 要维护最大堆的性质,所以对其它的树进行一个MaxHeapify
* @param j
*/
public void buildHeap(int[] j){
MaxHeapify maxHeapiey = new MaxHeapify();
for (int i = j.length/2; i > 0; i--) {
maxHeapiey.MaxHeap2(j, i);
}
}
/**
* 使用递归的方式
* @param j
*/
public void buildHeap1(int[] j){
MaxHeapify maxHeapiey = new MaxHeapify();
for (int i = j.length/2; i > 0; i--) {
maxHeapiey.MaxHeap1(j, i);
}
}
}
构造完了堆,我们就要开始排序了。
上代码:
public class HeapSort {
public static void main(String[] args) {
int [] array={0,4,1,3,2,16,9,10,14,8,7};
BuildMaxHeap build = new BuildMaxHeap();
build.buildHeap(array);
MaxHeapify maxHeap = new MaxHeapify();
for(int i=array.length-1;i>1;i--){
int temp = array[1];
array[1] = array[i];
array[i] = temp;
maxHeap.MaxHeapForSort(array, 1, i);
}
for(int j=0;j<array.length;j++){
System.out.print(array[j]+" ");
}
}
}
排序完成了,在这个过程中使用了为排序而改造的构建最大堆的方法。
那么,堆这种数据结构的好处在哪里呢,首先是保证了数据原址性,然后是有其重要的应用,其中之一就是优先队列,常见应用就是操作系统中的作业调度。
上代码:
/**
* 优先级队列
* 优先级队列有以下四个操作
* 1.Insert 插入一个元素
* 2.Maximum 返回最大的元素
* 3.ExtractMax 剔除最大的元素并且返回这个元素
* 4.Increasekey key增长
* 优先级队列主要应用于作业调度中
* @author mazip
*
*/
public class PriorityQueue {
//返回最大的元素
public int maximum(int[] array){
//最大堆的第一层就是最大的元素
return array[1];
}
//剔除最大的元素并且返回这个元素
public int extractMax(int[] array){
int max=array[1];
array[1]=array[array.length];
MaxHeapify maxHeap = new MaxHeapify();
maxHeap.MaxHeapForSort(array, 1, array.length-1);
return max;
}
//key增长
public void increaseKey(int[] array,int i,int key){
//当key比所希望增加的数小的时候不会进行操作
//当key大于所希望增加的数时,将该树变成key并且将堆变成最大堆
if(key<array[i]){
System.out.println("不能完成增加操作");
}else{
array[i]=key;
MaxHeapify maxHeapify= new MaxHeapify();
maxHeapify.MaxHeap1(array,i);
}
}
}
上述代码并不是非常之严谨,还有些许纰漏的地方,应该结合实际应用来进行修改利用,对于堆的基本介绍就到这里。