Fila de prioridade (heap)

Índice

1. O conceito de pilha

2. Estrutura de armazenamento heap

3. Implementação de heap

3.1 shiftDown()

3.2 shiftUp()

3.3 Complexidade de tempo de shiftDown e shiftUp

4. Classificação de pilha


1. O conceito de pilha

Heaps são frequentemente usados ​​para implementar aplicações como Filas Prioritárias, onde elementos com prioridade mais alta (ou mais baixa) podem ser rapidamente encontrados e excluídos. As operações de heap incluem a inserção de novos elementos, a remoção do elemento superior do heap (ou seja, o valor mais alto) e o ajuste dos heaps existentes para satisfazer a propriedade de ordem de heap. As operações comuns de ajuste de heap são "float" (filtro superior) e "sink" (filtro inferior) .

O heap tem as duas características principais a seguir:

  1.  O heap é uma árvore binária completa
  2.  O valor de cada nó no heap deve ser maior ou igual (ou menor ou igual) ao valor de seu nó filho.

2. Estrutura de armazenamento heap

A partir do conceito de heap, podemos saber que o heap é uma árvore binária completa em sua estrutura lógica, portanto pode ser armazenado de forma eficiente e sequencial de acordo com as regras de ordem hierárquica, ou seja, o heap é armazenado usando um tabela de sequência. Faça um desenho para entender:

 Após armazenar os elementos em um array, a árvore pode ser restaurada de acordo com as propriedades de uma árvore binária completa. Supondo que i seja o subscrito do nó na matriz, então:

  • Se i = 0, então o nó representado por i é o nó raiz, caso contrário, o nó pai do nó i é (i - 1)/2
  • Se 2 * i + 1 for menor que o número de nós, o subscrito filho esquerdo do nó i será 2 * i + 1, caso contrário, não haverá filho esquerdo
  • Se 2 * i + 2 for menor que o número de nós, o índice filho certo do nó i será 2 * i + 2, caso contrário, não haverá filho certo

3. Implementação de heap

O que é implementado aqui é um grande heap raiz:

public class Heap {
    private int[] elem;
    private int usedSize;

    public Heap(int[] arr){
        elem = new int[arr.length];
        createHeap(arr);
    }

    //建堆
    public void createHeap(int[] arr){
        for (int i = 0; i < arr.length; i++) {
            elem[i] = arr[i];
            usedSize++;
        }
        for (int parent = (usedSize-2)/2; parent >= 0; parent--) {
            shiftDown(parent,usedSize);
        }
    }

    //向下调整
    public void shiftDown(int parent, int len){}

    public void swap(int i, int j){
        int tmp = elem[i];
        elem[i] = elem[j];
        elem[j] = tmp;
    }

    //入堆
    public void push(int val){}

    public boolean isFull(){
        return usedSize == elem.length;
    }

    //向上调整
    public void shiftUp(int child){}

    //出堆顶元素
    public int poll(){
        if(isEmpty()){
            System.out.println("堆中没有元素");
            return -1;
        }
        swap(0,usedSize-1);//将头尾交换
        usedSize--;//去掉堆顶元素
        shiftDown(0,usedSize);//重新排序
        return elem[usedSize];//返回堆顶元素
    }

    public boolean isEmpty(){
        return usedSize == 0;
    }

    //得到堆顶元素
    public int peek(){
        if(!isEmpty()){
            return elem[0];
        }
        System.out.println("堆中没有元素");
        return -1;
    }
}

O código principal no heap é a implementação dos métodos shiftDown() e shiftUp() . Você pode entender os outros métodos observando-os. Vamos falar sobre a implementação desses dois métodos em detalhes.

3.1 shiftDown()

Por exemplo, queremos transformar o array {27, 15, 19, 18, 28, 34, 65, 49, 25, 37} em um heap. Como implementamos isso? A ideia: primeiro encontre a última subárvore e vire em uma pilha. Depois de formar uma pilha, percorra outras subárvores em sequência até que o nó raiz da última subárvore seja o nó raiz de toda a árvore . Veja a figura abaixo: 

código mostrado abaixo:

    public void shiftDown(int parent, int len){
        int child = 2*parent + 1;
        while(child < len){
            if(child+1 < len && elem[child] < elem[child+1]){
                child++;
            }
            if(elem[parent] < elem[child]){
                swap(parent,child);
                parent = child;
                child = 2*parent + 1;
            }else{
                break;
            }
        }
    }

3.2 shiftUp()

Este método consiste em inserir um elemento na forma de um heap ao inseri-lo.Essencialmente, as ideias de shiftDown e shiftUp são semelhantes:

    public void shiftUp(int child){
        int parent = (child-1)/2;
        while(parent >= 0){
            if(elem[child] > elem[parent]){
                swap(child,parent);
                child = parent;
                parent = (child-1)/2;
            }else {
                break;
            }
        }
    }

3.3 Complexidade de tempo de shiftDown e shiftUp

 ​​​​​​​​​​​​​

 

4. Classificação de pilha

Por exemplo, se quisermos classificar em ordem crescente, primeiro precisamos criar um grande heap raiz e, em seguida, trocar o nó raiz pelo último nó.Neste momento, o último nó deve ser o maior, então execute shiftDown e em seguida, troque o nó raiz pelo penúltimo nó, troque e assim por diante. código mostrado abaixo:

/**
     * 堆排序
     * 时间复杂度:O(N*logN)
     * 空间复杂度:O(1)
     * 不稳定
     */
    public void heapSort(int[] arr){
        createHeap(arr);
        int end = arr.length-1;
        while(end > 0){
            swap(arr,0,end);
            shiftDown(arr,0,end);
            end--;
        }
    }
    private void shiftDown(int[] arr, int parent,int len) {
        int child = 2*parent+1;
        while(child < len){
            if(child+1 < len && arr[child] < arr[child+1]){
                child++;
            }
            if(arr[child] > arr[parent]){
                swap(arr,child,parent);
                parent = child;
                child = 2*parent+1;
            }else{
                break;
            }
        }
    }
    public void swap(int[] arr, int i, int j){
        int tmp = arr[i];
        arr[i] = arr[j];
        arr[j] = tmp;
    }
    public void createHeap(int[] array) {
        for (int parent = (array.length-2)/2; parent >= 0; parent--) {
            shiftDown(array,parent,array.length);
        }
    }

Acho que você gosta

Origin blog.csdn.net/m0_74859835/article/details/132024358
Recomendado
Clasificación