数据结构堆heap(以小根堆为例,大根堆类似)

关于堆的介绍和操作可以参考:https://www.jianshu.com/p/6b526aa481b1

上面这篇文章写得非常详细。

堆的操作主要有:插入元素、删除堆顶元素两个操作。

以下代码都以小根堆为例。

插入元素代码:

    /**
     * 小根堆
     * 在堆中插入元素
     *
     * @param arr  堆数组
     * @param size 当前堆的大小
     * @param data 待插入的元素
     */
    public void heapInsert(int[] arr, final int size, int data) {
        //每个元素的父节点计算规则:parentIndex = (i-1)/2
        //现将元素插入到堆最后一个位置
        arr[size] = data;
        //开始shiftUp操作
        int curIndex = size;
        int parentIndex = (curIndex - 1) / 2;
        while (parentIndex >= 0) {
            if (arr[curIndex] < arr[parentIndex]) {
                //子节点要比父节点小,需要作交换
                int tmp = arr[parentIndex];
                arr[parentIndex] = arr[curIndex];
                arr[curIndex] = tmp;
                //进行下标上移
                curIndex = parentIndex;
                parentIndex = (curIndex - 1) / 2;
            } else {
                //没有发生交换,说明已经有序了,退出
                break;
            }
        }
    }

删除堆顶元素代码:

    /**
     * 小根堆
     * 删除堆顶元素
     *
     * @param arr  堆数组
     * @param size 当前堆的大小
     * @return 新堆的大小
     */
    public int heapDelete(int[] arr, final int size) {
        if (size == 1) {
            //只剩一个元素了,直接删除
            return size - 1;
        }
        //将根元素删除,将最后一个元素放置到根元素
        arr[0] = arr[size - 1];
        //开始shiftDown操作
        int parentIndex = 0;
        int leftChildIndex = parentIndex * 2 + 1;
        int rightChildIndex = parentIndex * 2 + 2;
        while (leftChildIndex < size) {
            int smallest = arr[parentIndex];
            int change = 0; //0表示不交换
            if (smallest > arr[leftChildIndex]) {
                change = leftChildIndex; //可能会交换左节点
                smallest = arr[leftChildIndex];
            }
            if (rightChildIndex < size && smallest > arr[rightChildIndex]) {
                //需要交换右节点
                change = rightChildIndex;
            }
            //如果change != 0,表示需要交换
            if (change != 0) {
                int tmp = arr[parentIndex];
                arr[parentIndex] = arr[change];
                arr[change] = tmp;
                //再交换坐标
                parentIndex = change;
                leftChildIndex = parentIndex * 2 + 1;
                rightChildIndex = parentIndex * 2 + 2;
            } else {
                //没有发生交换,直接退出循环
                break;
            }
        }
        return size - 1;
    }

测试代码(创建堆、删除堆顶元素):

    public void heapOps() {
        int[] arr = new int[]{100, 30, 3, 5, 80, 70, 200, 3000, 800, 10, 20, 50, 70};
        //开始构建小根堆
        for (int i = 1; i < arr.length; i++) {
            StringBuffer sb = new StringBuffer(); //仅用于输出
            heapInsert(arr, i, arr[i]);
            sb.append("[ ");
            for (int j = 0; j <= i; j++) {
                sb.append(arr[j]).append(" ");
            }
            sb.append("]");
            System.out.println(sb.toString());
            sb.setLength(0);
        }

        //开始删除小根堆
        for (int i = arr.length; i>0; i--){
            StringBuffer sb = new StringBuffer(); //仅用于输出
            sb.append("[ ");
            heapDelete(arr, i);
            for (int j = 0; j < i; j++) {
                sb.append(arr[j]).append(" ");
            }
            sb.append("]");
            System.out.println(sb.toString());
            sb.setLength(0);
        }
    }

输出结果:

[ 30 100 ]
[ 3 100 30 ]
[ 3 5 30 100 ]
[ 3 5 30 100 80 ]
[ 3 5 30 100 80 70 ]
[ 3 5 30 100 80 70 200 ]
[ 3 5 30 100 80 70 200 3000 ]
[ 3 5 30 100 80 70 200 3000 800 ]
[ 3 5 30 100 10 70 200 3000 800 80 ]
[ 3 5 30 100 10 70 200 3000 800 80 20 ]
[ 3 5 30 100 10 50 200 3000 800 80 20 70 ]
[ 3 5 30 100 10 50 200 3000 800 80 20 70 70 ]
[ 5 10 30 100 20 50 200 3000 800 80 70 70 ]
[ 10 20 30 100 70 50 200 3000 800 80 70 ]
[ 20 70 30 100 70 50 200 3000 800 80 ]
[ 30 70 50 100 70 80 200 3000 800 ]
[ 50 70 80 100 70 800 200 3000 ]
[ 70 70 80 100 3000 800 200 ]
[ 70 100 80 200 3000 800 ]
[ 80 100 800 200 3000 ]
[ 100 200 800 3000 ]
[ 200 3000 800 ]
[ 800 3000 ]
[ 3000 ]
[ ]

 

posted @ 2019-01-25 12:09  ronghantao  阅读(634)  评论(0编辑  收藏  举报