算法设计之堆排序

1. 堆

堆,也叫做优先队列。而其实质上是一颗完全二叉树,而且其每个非叶节点的值都大于或等于它左右孩子的值(大根堆),或者小于等于它左右孩子的值(小根堆)。而之所以称之为优先队列,是因为在队列中我们按存入队列的先后顺序取出元素,而在堆中我们按照节点的优先级别取出元素(显然,根节点具有最大优先级)。

以大根堆为例,堆的主要操作是插入和删除最大元素(元素值本身为优先级键值,大元素享有高优先级)。在插入或者删除操作之后,我们必须保持该实现应有的性质: 1. 完全二叉树 2. 每个节点值都大于或等于它的子节点。

所以堆的插入步骤(上滤):

    1.将新元素增加到堆的末尾
    2.按照优先顺序,将新元素与其父节点比较,如果新元素小于父节点则将两者交换位置。
    3.不断进行第2步操作,直到不需要交换新元素和父节点,或者达到堆顶
    4.最后通过得到一个最小堆

堆的删除步骤(下滤):
    1.删除堆顶元素(通常是将堆顶元素放置在数组的末尾)
    2.比较左右子节点,将小的元素上调。
    3.不断进行步骤2,直到不需要调整或者调整到堆底

2.堆排序

排序的过程:首先将待排序系列的记录构造成一个大根堆,然后将堆定记录移走,继续将剩下的记录再调整成大根堆,如此循环,直到堆中只有一个记录为止。

package heap_sort;

import java.util.Arrays;
import java.util.Scanner;

public class HeapSort {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		
		Scanner sc = new Scanner(System.in);
		int[] arr = new int[8];
		for(int i = 0; i < arr.length; i++)
			arr[i] = sc.nextInt();
		Heapsort(arr);
		System.out.println(Arrays.toString(arr));
		sc.close();

	}
	
	private static void Heapsort(int[] arr) {
		for(int i = 0; i < arr.length; i++) {
			CreateMaxHeap(arr,arr.length-1-i);
			Swap(arr,0,arr.length-1-i);
		}
	}
	
	private static void CreateMaxHeap(int[] arr, int LastIndex) {
		for(int i = (LastIndex - 1) / 2; i >= 0; i--) {
			int k = i;
			while(k * 2 + 1 <= LastIndex) {
				int leftChild = k * 2 +1;
				if(leftChild < LastIndex) {
					if(arr[leftChild] < arr[leftChild + 1])
						leftChild++;
				}
				if(arr[k] < arr[leftChild])
					Swap(arr, k, leftChild);
				else
					break;
			}
			
		}
	}
	
	private static void Swap(int[] arr, int a, int b) {
		int temp = arr[a];
		arr[a] = arr[b];
		arr[b] = temp;
	}
}

要注意的是完全二叉树中,设最后节点的键值为lastIndex,其父节点为(lastIndex-1)/2.也就是说从最后一个有孩子节点的父节点开始比较,逐步构建大根堆,这样会比较节省效率。

参考文献:

1. http://www.cnblogs.com/vamei/archive/2013/03/20/2966612.html

2.https://www.jianshu.com/p/b1ea662bc91f

猜你喜欢

转载自blog.csdn.net/wannuoge4766/article/details/84308006