topK问题解法之-堆排序

堆数据结构的介绍
堆是一种重要的数据结构,为一棵完全二叉树, 底层如果用数组存储数据的话,假设某个元素为序号为i(Java数组从0开始,i为0到n-1),如果它有左子树,那么左子树的位置是2i+1,如果有右子树,右子树的位置是2i+2,如果有父节点,父节点的位置是(n-1)/2取整。分为最大堆和最小堆,最大堆的任意子树根节点不小于任意子结点,最小堆的根节点不大于任意子结点。所谓堆排序就是利用堆这种数据结构来对数组排序,我们使用的是最大堆。处理的思想和冒泡排序,选择排序非常的类似,一层层封顶,只是最大元素的选取使用了最大堆。最大堆的最大元素一定在第0位置,构建好堆之后,交换0位置元素与顶即可。堆排序为原位排序(空间小), 且最坏运行时间是O(nlgn),是渐进最优的比较排序算法。

常见问题

1.最大的k个数:建立大小为k的最小堆,遍历原数组,依次与堆顶元素比较,若数组元素大于堆顶元素,则交换这两元素,并从堆顶调整元素

2.最小的k个数:建立大小为k的最大堆,遍历原数组,依次与堆顶元素比较,若数组元素小于堆顶元素,则交换这两元素,并从堆顶调整元素

代码样例

堆的调整算法:

/**
     * 堆的调整算法
     * 递归调整
     * 
     * @param arr
     *            :原数组
     * @param i
     *            :当前下标
     */
    public static void adjustMaxHeap(int[] arr, int i) {
        int lchild = lchild(i);
        int rchild = rchild(i);
        int largest;
        if (lchild < heapsize && arr[i] < arr[lchild]) {
            largest = lchild;
        } else {
            largest = i;
        }
        if (rchild < heapsize && arr[largest] < arr[rchild]) {
            largest = rchild;
        }
        if (largest == i || largest >= arr.length) {
            return;// 未与孩子节点交换,或者超出范围,直接return到上一级
        }
        // 将父节点与孩子节点交换
        int temp = arr[largest];
        arr[largest] = arr[i];
        arr[i] = temp;
        adjustMaxHeap(arr, largest);
    }

建立最大堆:

/**
 * 构建最大堆
 * @param arr
 */
    public static void buildMaxHeap(int[] arr) {
        for (int i = arr.length / 2 - 1; i >= 0; i--) {
            adjustMaxHeap(arr, i);
        }
    }

堆排序:

//对一个最大堆heap排序  
   public static void heapSort(List heap) {    

       for (int i = heap.size()-1; i > 0; i--) {    
       /*把根节点跟最后一个元素交换位置,调整剩下的n-1个节点,即可排好序*/    
           swap(heap,1, i);    
           adjust(heap,1, i - 1);    
       }    
   }    

你可能感兴趣的:(java面试常见算法)