HeapSort

在程序设计相关领域,堆(Heap)的概念主要涉及到两个方面:

·        一种数据结构,逻辑上是一颗完全二叉树,存储上是一个数组对象(二叉堆)。

·        垃圾收集存储区,是软件系统可以编程的内存区域。

本文所说的堆,指的是前者。

堆排序的时间复杂度是O(nlgN),与快速排序达到相同的时间复杂度。但是在实际应用中,我们往往采用快速排序而不是堆排序。这是因为快速排序的一个好的实现,往往比堆排序具有更好的表现。堆排序的主要用途,是在形成和处理优先级队列方面。另外,如果计算要求是类优先级队列(比如,只要返回最大或者最小元素,只有有限的插入要求等),堆同样是很适合的数据结构。

基础知

堆一般用数组表示,比如数组A数组的长度Length(A),堆在数组中的元素个数HeapSize(A)。一般说来,HeapSize(A) <= Length(A),因为数组A当中可能有一些元素不在堆中。

假设节点I是数组A中下标为i的节点。

·        Parent(i) : return Floor(i/2); //I的父节点下标,Floor(i)表示比i小的最大整数

·        Left(i) : return 2*i; //I的左子节

·        Right(i) : return 2*i+1; //I的右子节

含有n个元素的堆A的高度是: Floor(lgn)

堆的基本操

·        MaxHeapify( A, i ):

保持堆的性质。假设数组A和下标i,假定以Left(i)Right(i)为根结点的左右两棵子树都已经是最大堆,节点i的值可能小于其子节点。调整节点i的位置。

·        BuildMaxHeap( A ):

从一个给定的数组建立最大堆。子数组A[ floor(n/2)+1 .... ... n]中的元素都是树的叶节点(完全二叉树的基本性质)。从索引 ceiling(n/2)开始一直到1,对每一个元素都执行MaxHeapify,最终得到一个最大堆。

·        堆排序HeapSort( A ):

堆排序算法的基本思想是,将数组A创建为一个最大堆,然后交换堆的根(最大元素)和最后一个叶节点x,将x从堆中去掉形成新的堆A1,然后重复以上动作,直到堆中只有一个节点。

·        优先级队列算法-增加某元素的值(优先级) : HeapIncreaseKey( A,i, key )

增加某一个元素的优先级后(元素的值),该元素应该向上移动,才能保持堆的性质。

·        优先级队列算法-插入一个元素:Insert( S, x )x元素插入到优先级队列S

主要思路是,将堆的最后一个叶节点之后,扩展一个为无穷小的新叶节点,然后增大它的值为x的值。

堆排序实现原
package com.citi.byteman.test.arithmatic;

public class HeapSort {

	HeapSort() {
	}

	/**
	 * 对该数进行下滤操作,直到该数比左右节点都小就停止下滤
	 * 
	 * @param num
	 * @param index
	 * @param size
	 */
	public void percolateDown(int num[], int index, int size) {
		int min;// 设置最小指向下标
		while (index * 2 + 1 < size) {// 如果该数有左节点,则假设左节点最小
			min = index * 2 + 1;// 获取左节点的下标
			if (index * 2 + 2 < size) {// 如果该数还有右节点
				if (num[min] > num[index * 2 + 2]) {// 就和左节点分出最小者
					min = index * 2 + 2;// 此时右节点更小,则更新min的指向下标
				}
			}
			// 此时进行该数和最小者进行比较,
			if (num[index] < num[min]) {// 如果index最小,
				break;// 停止下滤操作
			} else {
				swap(num, index, min);// 交换两个数,让大数往下沉
				index = min;// 更新index的指向
			}
		}
	}

	// 建堆方法,只需线性时间建好
	public void buildHeap(int num[], int size) {
		for (int i = size / 2 - 1; i >= 0; i--) {
                     //对前一半的节点(解释为“从最后一个非叶子节点开始,将每个父节点都调整为最小堆”更合理一些)
			percolateDown(num, i, size);// 进行下滤操作
		}
	}

	public void heapSort(int num[]) {
		int size = num.length;
		buildHeap(num, size);// 建立小顶堆
		for (int i = num.length - 1; i >= 1; i--) {
			swap(num, 0, i);
			size--;// 每交换一次让规模减少一次
			percolateDown(num, 0, size);// 将新的首元素下滤操作
		}
	}

	/**
	 * swap two number in the array
	 * 
	 * @param num
	 * @param v
	 * @param u
	 */
	public void swap(int num[], int v, int u) {
		int temp = num[v];
		num[v] = num[u];
		num[u] = temp;
	}

	public void printArray(int[] array) {
		for (int i = 0; i < array.length; i++) {
			System.out.print(array[i] + "\t");
		}
		System.out.println("");
	}

	public static void main(String[] args) {
		HeapSort heapSort = new HeapSort();
		int[] data = { 8, 5, 4, 6, 13, 7, 1, 9, 12, 11, 3, 10, 2 };
		System.out.println("before sort:");
		heapSort.printArray(data);
		heapSort.heapSort(data);
		System.out.println("after sort:");
		heapSort.printArray(data);
	}
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值