二叉堆与堆排序

二叉堆是一棵完全二叉树,分为大/小根堆,大根堆每个节点的值都不大于其父节点的值,所以最大值一定在堆顶。在堆排序中和优先队列中可以发挥作用

建堆:堆排序,要先建立一个堆,在建堆的过程中要根据每个节点的值都不大于其父节点的值而建立。由于所有叶子节点都已经是堆了,所以调整堆的过程从最后一个非叶子节点开始,假设数组a[n]表示此堆,那么要从n/2-1节点开始,依次向上直到根节点。在一个节点时,如果此节点的孩子节点没有此节点大,不用调换,否则和左右孩子节点中比较大的那一个调换,直到满足堆的要求。

假设有一组数组{4,1,3,2,16,9,10,14,8,7},那么调堆将会从16开始

 

二叉堆

二叉堆

 

排序:由于建好的堆顶就是最大值,因此只要把堆顶的元素和最后一个元素调换,然后再把a[n-1]的元素按照建堆的思路重新调整为一个新堆,重复此步骤就可以了

二叉堆排序过程

二叉堆排序过程

hdu 1040  As Easy As A+B

import java.io.BufferedInputStream;
import java.util.Scanner;
import static java.lang.System.out;

public class Main {
	private Scanner sc = new Scanner(new BufferedInputStream(System.in));
	private int[] a;

	private int max(int m, int n) {
		return a[m] > a[n] ? m : n;
	}

	private void swap(int m, int n) {
		int t = a[m];
		a[m] = a[n];
		a[n] = t;
	}

	public void init() {
		int nCase = sc.nextInt();
		while (nCase-- > 0) {
			int n = sc.nextInt();
			a = new int[n];

			for (int i = 0; i < n; i++)
				a[i] = sc.nextInt();

			buildHeap(n);// **********建堆
			heapSort(n);// ********排序

			for (int i = 0; i < n - 1; i++)
				out.printf("%d ", a[i]);
			out.println(a[n - 1]);
		}
	}

	private void buildHeap(int n) { // ******** 建堆
		int id = ((n >> 1) - 1);
		for (int i = id; i >= 0; i--) {
			int k = i;

			int p = 0;
			if (((i << 1) + 2 < n)) {
				p = max((i << 1) + 1, (i << 1) + 2);
			} else if ((i << 1) + 1 < n && (i << 1) + 2 >= n) {
				p = (k << 1) + 1;
			} else
				break;
			while (a[k] < a[p]) {
				swap(k, p);

				if (((p << 1) + 1 < n) && ((p << 1) + 2 < n)) {
					k = p;
					p = max((k << 1) + 1, (k << 1) + 2);
				} else if ((p << 1) + 1 < n && (p << 1) + 2 >= n) {
					k = p;
					p = (k << 1) + 1;
				} else
					break;
			}
		}
	}

	private void heapSort(int n) {
		int num = n - 1;
		for (int i = 0; i < n - 1; i++) {
			swap(0, num);
			buildHeap((num));
			num--;
		}
	}

	public static void main(String[] args) {
		new Main().init();
	}
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值