Java heap & priority queue (on)

content

1. Sequential storage of binary tree

1.1 Storage method

1.2 Subscript relationship

2. Heap

2.1 Concept

2.2 Operation - (sink & float) This example is a max heap

2.3 Build heap - complete code (maximum heap)

3. Priority queue


1. Sequential storage of binary tree

1.1 Storage method

Use the array to save the binary tree structure, the method is to put the binary tree into the array by layer order traversal .
It is generally only suitable for representing complete binary trees, and the main usage of this method is the representation of heaps .
Because non-complete binary trees will waste space (all non-complete binary trees are stored in chains).

1.2 Subscript relationship

Given the subscripts of the parents , then:
left child (left) subscript = 2 * parent + 1;
right child (right) subscript = 2 * parent + 2;
Knowing the child (without distinguishing left and right) (child) subscript, then:
parent (parent) subscript = (child - 1) / 2;

2. Heap _

2.1 Concept

1. The heap is logically a complete binary tree
2. The heap is physically stored in an array
3. Satisfy that the value of any node is greater than the value of the node in its subtree, which is called a large heap, or a large root heap, or a maximum heap
4. On the contrary, it is a small heap, or a small root heap, or a minimum heap
5. The basic function of the heap is to quickly find the most value in the set

2.2 Operation - (sinking & floating) This example is the max heap

Element sinks:
     /**
     * 下沉操作
     */
    public void siftDown(int k){
        //还存在子树
        while (leftChild(k) < data.size()){
            int j = leftChild(k);
            //判断是否存在右子树且大于左子树的值
            if(j+1 < data.size() && data.get(j+1) > data.get(j)){
                j=j+1;
            }
            //此时j为左右子树最大值
            //和当前节点比较大小
            if(data.get(j) <= data.get(k)){
                break;
            }else {
                swap(k,j);
                k=j;
            }
        }
    }

Elements float up:

    /**
     * 上浮操作
     */
    // 上浮操作的终止条件: 已经走到根节点 || 当前节点值 <= 父节点值
    // 循环的迭代条件 : 还存在父节点并且当前节点值 > 父节点值
    private void siftUp(int k) {
        while (k>0 && data.get(k)>data.get(parent(k))){
            swap(k,parent(k));
            k=parent(k);
        }
    }

The swap method is a swap operation:

    //交换三连
    private void swap(int i,int j) {
        int temp = data.get(j);
        data.set(j,data.get(i));
        data.set(i,temp);
    }

Heaped array:

    /**
     * 将任意数组堆化
     * @param arr
     */
    public MaxHeap(int[] arr){
        data = new ArrayList<>(arr.length);
        // 1.先将arr的所有元素复制到data数组中
        for(int i : arr){
            data.add(i);
        }
        // 2.从最后一个非叶子结点开始进行siftDown
        for (int i = parent(data.size()-1); i >=0 ; i--) {
            siftDown(i);
        }
    }
Icon:
Take this array as an example:
// 调整前
int[] array = { 27,15,19,18,28,34,65,49,25,37 };
// 调整后
int[] array = { 15,18,19,25,28,34,65,49,27,37 };

Time complexity analysis:
The worst case is the case shown in the figure, from the root to the leaf, the number of comparisons is the height of the complete binary tree
That is, the time complexity is O(log(n))

2.3 Build heap - complete code (maximum heap)

/**
 * 基于整形最大堆实现
 * 时根节点从0开始编号,若此时节点编号为k
 * 左孩子为2k+1
 * 右孩子为2k+2
 * 父节点为(k-1)/2
 */

import java.util.ArrayList;
import java.util.List;
import java.util.NoSuchElementException;

public class MaxHeap {
    // 使用JDK的动态数组(ArrayList)来存储一个最大堆
    List<Integer> data;

    // 构造方法的this调用
    public MaxHeap(){
        this(10);
    }
    
    // 初始化的堆大小
    public MaxHeap(int size){
        data = new ArrayList<>(size);
    }

    /**
     * 将任意数组堆化
     * @param arr
     */
    public MaxHeap(int[] arr){
        data = new ArrayList<>(arr.length);
        // 1.先将arr的所有元素复制到data数组中
        for(int i : arr){
            data.add(i);
        }
        // 2.从最后一个非叶子结点开始进行siftDown
        for (int i = parent(data.size()-1); i >=0 ; i--) {
            siftDown(i);
        }
    }

    /**
     * 向最大堆中增加值为Value的元素
     * @param value
     */
    public void add(int value){
        //1.先直接加到堆的末尾
        data.add(value);
        //2.元素上浮操作
        siftUp(data.size()-1);
    }

    /**
     * 只找到堆顶元素值
     * @return
     */
    public int peekMax (){
        if(isEmpty()){
            throw new NoSuchElementException("heap is empty!connot peek");
        }
        return data.get(0);
    }

    /**
     * 取出当前最大堆的最大值
     */
    public int extractMax(){
        // 取值一定注意判空
        if(isEmpty()){
            throw new NoSuchElementException("heap is empty!connot extract");
        }
        int max = data.get(0);
        // 1.将数组末尾元素顶到堆顶
        int lastValue =data.get(data.size()-1);
        data.set(0,lastValue);
        // 2.将数组末尾的元素删除
        data.remove(data.size()-1);
        // 3.进行元素的下沉操作
        siftDown(0);
        return max;
    }

    /**
     * 下沉操作
     */
    public void siftDown(int k){
        //还存在子树
        while (leftChild(k) < data.size()){
            int j = leftChild(k);
            //判断是否存在右子树且大于左子树的值
            if(j+1 < data.size() && data.get(j+1) > data.get(j)){
                j=j+1;
            }
            //此时j为左右子树最大值
            //和当前节点比较大小
            if(data.get(j) <= data.get(k)){
                break;
            }else {
                swap(k,j);
                k=j;
            }
        }
    }

    /**
     * 上浮操作
     */
    // 上浮操作的终止条件: 已经走到根节点 || 当前节点值 <= 父节点值
    // 循环的迭代条件 : 还存在父节点并且当前节点值 > 父节点值
    private void siftUp(int k) {
        while (k>0 && data.get(k)>data.get(parent(k))){
            swap(k,parent(k));
            k=parent(k);
        }
    }

    //交换三连
    private void swap(int i,int j) {
        int temp = data.get(j);
        data.set(j,data.get(i));
        data.set(i,temp);
    }

    //判读堆为空
    public boolean isEmpty(){
        return data.size() == 0;
    }
    //根据索引找父节点
    public int parent(int k){
        return (k-1)>>1;
    }
    //根据索引找左孩子
    public int leftChild(int k){
        return k<<2+1;
    }
    //根据索引找右孩子
    public int rightChild(int k){
        return k<<2+2;
    }

    @Override
    public String toString() {
        return data.toString();
    }
}

ps: random number operation

        int[] data=new int[10000];
        //随机数
        ThreadLocalRandom random = ThreadLocalRandom.current();
        for (int i = 0; i < data.length; i++) {
            data[i] = random.nextInt();
        }

3. Priority queue

See the next section for details: "Java Heap & Priority Queue (Part 2) "

Guess you like

Origin blog.csdn.net/m0_62218217/article/details/123279819