Heap Java e fila de prioridade (ativado)

contente

1. Armazenamento sequencial de árvore binária

1.1 Método de armazenamento

1.2 Relação de subscrito

2. Pilha

2.1 Conceito

2.2 Operação - (sink & float) Este exemplo é um heap máximo

2.3 Construir heap - código completo (heap máximo)

3. Fila de prioridade


1. Armazenamento sequencial de árvore binária

1.1 Método de armazenamento

Use o array para salvar a estrutura da árvore binária, o método é colocar a árvore binária no array por camada de ordem de travessia .
Geralmente, é adequado apenas para representar árvores binárias completas, e o principal uso desse método é a representação de heaps .
Porque as árvores binárias não completas desperdiçarão espaço (todas as árvores binárias não completas são armazenadas em cadeias).

1.2 Relação de subscrito

Dados os subscritos dos pais , então:
subscrito filho esquerdo (esquerdo) = 2 * pai + 1;
subscrito filho direito (direito) = 2 * pai + 2;
Conhecendo o subscrito filho (sem distinguir esquerda e direita) (filho) , então:
pai (pai) subscrito = (filho - 1) / 2;

2. Pilha _

2.1 Conceito

1. O heap é logicamente uma árvore binária completa
2. O heap é armazenado fisicamente em uma matriz
3. Certifique-se de que o valor de qualquer nó é maior que o valor do nó em sua subárvore, que é chamada de heap grande, heap raiz grande ou heap máximo
4. Pelo contrário, é um heap pequeno, ou um heap de raiz pequeno, ou um heap mínimo
5. A função básica do heap é encontrar rapidamente o maior valor no conjunto

2.2 Operação - (afundar e flutuar) Este exemplo é o heap máximo

Elementos dissipadores:
     /**
     * 下沉操作
     */
    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;
            }
        }
    }

Elementos flutuam para cima:

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

O método de troca é uma operação de troca:

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

Matriz empilhada:

    /**
     * 将任意数组堆化
     * @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);
        }
    }
Ícone:
Tome esta matriz como exemplo:
// 调整前
int[] array = { 27,15,19,18,28,34,65,49,25,37 };
// 调整后
int[] array = { 15,18,19,25,28,34,65,49,27,37 };

Análise de complexidade de tempo:
O pior caso é o caso mostrado na figura, da raiz à folha, o número de comparações é a altura da árvore binária completa
Ou seja, a complexidade de tempo é O(log(n))

2.3 Construir heap - código completo (heap máximo)

/**
 * 基于整形最大堆实现
 * 时根节点从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: operação de números aleatórios

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

3. Fila de prioridade

Consulte a próxima seção para obter detalhes: "Java Heap & Priority Queue (Parte 2) "

Acho que você gosta

Origin blog.csdn.net/m0_62218217/article/details/123279819
Recomendado
Clasificación