【数据结构与算法】堆结构与堆排序

286 阅读2分钟

参考博客:www.cnblogs.com/lyw-hunnu/p…

上面这篇博文已经介绍的很详细了,就写一下实现过程中遇到的问题。

heapInsert

heapInsert:在一个已经存在的大根堆末尾追加一个元素,追加后调整其结构仍为大根堆。代码如下:

    public static void heapInsert(int[] array,int index){   
    //追加的数已经添加到了数组的末尾,需要做的是调整该数的位置
        while (array[index] > array[(index - 1)/2]) {
            // 停止条件1:新增结点不再比父节点大
            // 停止条件2:已经到达了整棵树的 根结点 0 
            swap(array, index, (index - 1) /2);
            index = (index - 1)/2 ;
        }
    }

需要注意的是,while循环的终止条件有两个。

1.新增结点不再比父节点大。

2.已经到达了整棵树的根结点0。

但当index=0时,(0-1)/2=0,所以arr[index] arr[(index-1)/2] 相等。也就是说关于商,表达式a/b的商会向0取整,即负数向上取整,正数向下取整,类似于四舍五入。

heapify

heapify:当将大根堆的最大值 pop 出去之后,对堆结构进行调整仍为大根堆。此时大根堆的根节点显然不是最大值,需要对该元素进行下沉,heapify就是某元素的下沉操作。代码如下:

    public static void heapify(int[] array, int index, int heapSize){
        int left = index * 2 + 1;
        while(left < heapSize){
            //左右孩子之间值比较:右孩子存在且右孩子的值大于左孩子的值,largest=右,否则largest=左
            int largest = left + 1 < heapSize && array[left + 1] > array[left] ? left + 1 : left;
            //父与子比较
            largest = array[largest] > array[index] ? largest : index;
            if (largest == index) {
                break;
            }
            swap(array, largest, index);
            index = largest;
            left = index * 2 + 1;
        }
    }

自己写感觉比上面的代码思路乱很多,还是采用上面的方法,习惯一下吧。

堆排序

有了上面的heapInsert和heapify,就可以进行堆排序了。堆排序的思路如下:

1.已知一数组array,先遍历数组,对数组中每个元素进行heapInsert操作,生成大根堆,得到size。

2.将生成的大根堆的根节点元素与末尾元素交换(因为根节点元素一定是最大值)。同时--size,把已经确定的最大值移出堆结构中。对交换到根节点位置的元素进行heapify。

2.重复2步骤直到堆结构为空。 代码如下:

	public static void heapSort(int[] arr) {
		if (arr == null || arr.length < 2) {
			return;
		}
		for (int i = 0; i < arr.length; i++) {
			heapInsert(arr, i);
		}
		int size = arr.length;
		swap(arr, 0, --size);
		while (size > 0) {
			heapify(arr, 0, size);
			swap(arr, 0, --size);
		}