堆排序--java

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_27790011/article/details/84530524

堆是一种完全二叉树,每个结点的值都大于或等于其左右孩子结点的值,称为大顶堆;或者每个结点的值都小于或等于其左右孩子结点的值,称为小顶堆。
先引入一下完全二叉树的概念。

完全二叉树
定义:完全二叉树是由满二叉树而引出来的。对于深度为K的,有n个结点的二叉树,当且仅当其每一个结点都与深度为K的满二叉树中编号从1至n的结点一一对应时称之为完全二叉树。
具有性质:
1) 深度为k的完全二叉树,至少有2^(k-1)个节点,至多有2^k-1个节点。
2)树高h=log2n + 1。

满二叉树
一棵深度为k,且有2^k-1个节点的树是满二叉树。
另一种定义:除了叶结点外每一个结点都有左右子叶且叶子结点都处在	最底层的二叉树。
这两种定义是等价的
性质:
1) 如果一颗树深度为h,最大层数为k,且深度与最大层数相同,即k=h;
2)它的叶子数是: 2^(h-1)
3)  第k层的结点数是: 2^(k-1)
4) 总结点数是: 2^k-1 (2的k次方减一)
5)总节点数一定是奇数。
6)树高:h=log2(n+1)。

通俗的讲:满二叉树,就是每一个父节点都有两个叶子节点,每一层要不全是叶子节点,要不全是父节点(也即是说每一层都是满节点的)。二完全二叉树则是除了最后一层外,其他的层都是满的,最后一层的叶子节点可以不满,且最后一层的叶子节点从左到右,左边没满,右边不能有子节点(最后一层的叶子节点都靠左排列)。

堆排序(Heapsort)是指利用堆这种数据结构所设计的一种排序算法。堆积是一个近似完全二叉树的结构,并同时满足堆积的性质:即子结点的键值或索引总是小于(或者大于)它的父节点。堆排序可以说是一种利用堆的概念来排序的选择排序。分为两种方法:大顶堆的生序排序,小顶堆的降序排序。
代码实现:

import java.util.Arrays;
public class HeapSort {
	public int[] sort(int[] sourceArray) throws Exception {
        // 对 arr 进行拷贝,不改变参数内容
        int[] arr = Arrays.copyOf(sourceArray, sourceArray.length);
        int len = arr.length;
        buildMaxHeap(arr, len);//构建大顶堆
        for (int i = len - 1; i > 0; i--) {
            swap(arr, 0, i);//使得数组的最后一定为最大的数
            len--;
            heapify(arr, 0, len);//刷新大顶堆
        }
        return arr;
    }
	/**
	 * 构建大顶堆
	 * @param arr 数据数组
	 * @param len 数组长度
	 */
    private void buildMaxHeap(int[] arr, int len) {
    	//(int) Math.floor(len / 2) 向下取整,但是Math.floor()返回的类型是double,所以要强转成int
        for (int i = (int) Math.floor(len / 2); i >= 0; i--) {
            heapify(arr, i, len);
        }
    }
    
    /**
     * 使得父节点大于等于左右子节点
     * @param arr 数组
     * @param i  父节点位置
     * @param len 数组长度
     */
    private void heapify(int[] arr, int i, int len) {
        int left = 2 * i + 1; //左子节点位置
        int right = 2 * i + 2;//右子节点位置
        int largest = i;

        if (left < len && arr[left] > arr[largest]) {
            largest = left;//如果左子节点的值大于父节点位置的值,则替换largest
        }

        if (right < len && arr[right] > arr[largest]) {
            largest = right;//如果右子节点的值大于父节点位置的值,则替换largest
        }

        if (largest != i) {
            swap(arr, i, largest);//交换使得父节点的值比左右子节点的值都大。
            heapify(arr, largest, len);
        }
    }
  
/**
 * 交换函数
 */
    private void swap(int[] arr, int i, int j) {
        int temp = arr[i];
        arr[i] = arr[j];
        arr[j] = temp;
    }

}

代码都写有注释,看懂应该不难,但是让自己手写一个,还真是得思路比较清晰才行,heapify()方法看着很简单,确实很关键。细细品味。

测试main函数:


public class MainTest {
public static void main(String[] args) throws Exception {
	HeapSort heap=new HeapSort();
        int[] array={5,2,7,3,6,1,4};
        array=heap.sort(array);
        for (int i=0;i<array.length;i++){
            System.out.print(array[i]+",");
        }
	}
}

结果:

1,2,3,4,5,6,7,

猜你喜欢

转载自blog.csdn.net/qq_27790011/article/details/84530524