堆和优先权队列

一、堆
1、定义:一颗包含n个节点的完全二叉树,每个节点的值大于等于父节点的值。堆顶为整棵树的最小值,则称为最小堆,反之,称为最大堆。

2、向下调整算法
从位置n/2的元素开始,设该节点为temp,若temp大于其左、右孩子中的较小者,则将该temp与较小者交换位置,调整后继续与其左右孩子比较,直至不再需要调整。从n/2的元素到堆顶元素,重复向下调整,则建堆完毕。

3、代码

public class Heap {
    int size = 0;
    int[] elements;

    public Heap() {

    }

    public Heap(int maxSize) {
        elements = new int[maxSize];
    }

    public void add(int x) {
        elements[size++] = x;
    }

    public void createHeap() {
        // 从中间节点开始,直至0节点
        for (int i = (size - 1) / 2; i >= 0; i--) {
            adjustDown(i);
        }
    }

    // 父节点为x,则左孩子:2x+1,右孩子:2x+2
    public void adjustDown(int start) {
        int n = size;
        int child = 2 * start + 1;
        int temp = elements[start];
        // 循环比较左、右孩子
        while (child < n) {
            // 取左、右孩子中的较小者,保证下标小于n
            if (child + 1 < n && elements[child] > elements[child + 1])
                child++;
            if (temp <= elements[child])
                break;
            if (child % 2 == 0) {
                elements[child / 2 - 1] = elements[child];
            } else {
                elements[child / 2] = elements[child];
            }
            // 指向左孩子
            child = 2 * child + 1;
        }
        if (child % 2 == 0) {
            elements[child / 2 - 1] = temp;
        } else {
            elements[child / 2] = temp;
        }
    }

}

二、优先权队列
1、堆顶元素具有最高优先权,借助堆结构,实现优先权队列。

2、插入操作
将新元素插入堆的最后,堆的大小加一,然后向上调整AdjustUp,与父节点比较,若父节点大于子节点,则交换位置,直至父节点不大于待插入元素,或到达堆顶。

3、删除操作
先取出堆顶元素,然后将堆底元素取代堆顶元素,同时让堆的大小减一,最后使用向下调整AdjustDown。

4、代码

public class PriorityQueue {

    int size = 0;
    int[] elements;

    public PriorityQueue() {

    }

    public PriorityQueue(int maxSize) {
        elements = new int[maxSize];
    }

    /**
     * 构造初始数据
     * 
     * @param x
     */
    public void add(int x) {
        elements[size++] = x;
    }

    public void createPriorityQueue() {
        for (int i = (size - 1) / 2; i >= 0; i--) {
            adjustDown(i, size);
        }
    }

    /**
     * 尾部插入之后向上调整
     * 
     * @param size
     */
    public void adjustUp(int size) {
        int i = size - 1;
        int temp = elements[i];
        System.out.println(temp);
        // 对于孩子节点x、y,则其父亲节点为(x-1)/2 = (y-1)/2
        while (i > 0 && temp < elements[(i - 1) / 2]) {
            elements[i] = elements[(i - 1) / 2];
            i = (i - 1) / 2;
        }
        elements[i] = temp;
    }

    /**
     * 删除之后向下调整
     * 
     * @param start
     * @param size
     */
    public void adjustDown(int start, int size) {
        int n = size;
        int child = 2 * start + 1;
        int temp = elements[start];
        // 循环比较左、右孩子
        while (child < n) {
            // 取左、右孩子中的较小者,保证下标小于n
            if (child + 1 < n && elements[child] > elements[child + 1])
                child++;
            if (temp <= elements[child])
                break;
            if (child % 2 == 0) {
                elements[child / 2 - 1] = elements[child];
            } else {
                elements[child / 2] = elements[child];
            }
            // 指向左孩子
            child = 2 * child + 1;
        }
        if (child % 2 == 0) {
            elements[child / 2 - 1] = temp;
        } else {
            elements[child / 2] = temp;
        }
    }

    /**
     * 插入一个新元素
     * 
     * @param x
     */
    public void append(int x) {
        // 堆底加入一个元素,堆的大小加一
        elements[size++] = x;
        // 从底部元素开始向上调整
        adjustUp(size);
    }

    /**
     * 删除头元素并返回
     * 
     * @return
     */
    public int serve() {
        // 头元素赋给x
        int x = elements[0];
        // 底元素赋给头元素,堆的大小减一
        elements[0] = elements[size--];
        // 只需头元素向下调整
        adjustDown(0, size);
        return x;
    }

    /**
     * 删除头元素但不返回
     */
    public void peek() {
        elements[0] = elements[size--];
        adjustDown(0, size);
    }

}
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值