堆、堆排序及其应用


    堆是一种常见的数据结构,其结构类似树,以数组形式存储数据。

    下面来介绍两种堆,一种是最大堆,一种是最小堆。

    最大堆的性质是: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);
		}
		
		
	}
	
}
  上述代码并不是非常之严谨,还有些许纰漏的地方,应该结合实际应用来进行修改利用,对于堆的基本介绍就到这里。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值