Empezando por el montón

1. Cola de prioridad

  • Concepto: La cola es una estructura de datos primero en entrar, primero en salir (FIFO), pero en algunos casos, los datos de la operación pueden tener prioridad. Por lo general, los elementos con mayor prioridad pueden necesitar salir primero de la cola. Es evidente que no es apropiado utilizar la cola. Por ejemplo, al jugar un juego en un teléfono móvil, si hay una llamada entrante, el sistema debe dar prioridad a la llamada entrante. En este caso, nuestra estructura de datos debe proporcionar las dos operaciones más básicas, una es devolver el objeto de mayor prioridad y la otra es agregar un nuevo objeto. Esta estructura de datos es la cola de prioridad.
import java.util.PriorityQueue;

public class TestDemo {
    
    
   
    public static void main(String[] args) {
    
    
        //优先级队列(最下面实现方法是堆),从小到大排列好的数据,
        PriorityQueue priorityQueue = new PriorityQueue();
        priorityQueue.offer(13);
        priorityQueue.offer(3);
        priorityQueue.offer(8);
        priorityQueue.offer(49);
        /*
        本来按照队列的先进先出原则,队头元素是13,但是对于优先级队列来说,内部已经排好序,因此是3
        */
        System.out.println(priorityQueue.peek());
        System.out.println(priorityQueue.poll());//弹出队头3
        System.out.println(priorityQueue.peek());//再次获取新队头就是8,这就是优先级队列
    }
}
  • Resultado de salida
    Inserte la descripción de la imagen aquí

2. Montón

  • Concepto: Si hay un conjunto de códigos clave K = {k0, k1, k2, ..., kn-1}, almacene todos sus elementos en una matriz unidimensional en el orden de un árbol binario completo y satisfaga: Ki <= K2i + 1 y Ki <= K2i + 2 (Ki> = K2i + 1 y Ki> = K2i + 2) i = 0, 1, 2 ..., se llama pila pequeña (o pila grande). El montón con el nodo raíz más grande se llama el montón más grande o el montón raíz grande, y el montón con el nodo raíz más pequeño se llama el montón más pequeño o el montón raíz pequeño.

  • Características :
    1. El montón es siempre un árbol binario completo,
    2. Para un montón raíz grande, el valor de la raíz de cualquier subárbol no es menor que sus nodos izquierdo y derecho;

    Inserte la descripción de la imagen aquí

    3 ... Para una pila de raíces pequeña, el valor de la raíz de cualquier subárbol no es mayor que sus nodos izquierdo y derecho;Inserte la descripción de la imagen aquí

  • El método de almacenamiento del montón: A partir del concepto del montón, se sabe que el montón es un árbol binario completo, por lo que se puede almacenar de forma eficiente de forma secuencial según las reglas de jerarquía.
    Inserte la descripción de la imagen aquí

  • Preste atención a los puntos importantes (diga tres cosas importantes)
    1. Si i es 0, el nodo representado por i es el nodo raíz; de lo contrario, el nodo padre del nodo i es (i-1) / 2;
    2. Sepa que el subíndice del nodo raíz es i, el nodo hijo izquierdo es 2 i + 1 (siempre que exista),
    3. El nodo hijo derecho es 2
    i + 2 (siempre que exista);

1. El método de construcción del pilote (el mismo principio para construir un pilote de raíces grande y un pilote de raíces pequeño)

-Método de ajuste a la baja

El ajuste hacia abajo significa que desde la perspectiva de cada subárbol, se ajusta hacia abajo desde su nodo principal, por lo que se denomina ajuste hacia abajo;

//将数组先放入堆中,然后调用向下调整方法(adjustDown),构造堆
    public void initHeap(int[] arr){
    
    
        for (int i = 0;i < arr.length;i++){
    
    
            elem[i] = arr[i];
            usedSize++;
        }
        //建堆时间复杂度O(n*log2n),一棵子树完成后,j就减减,这样就能够找到下一棵子树的双亲下标了
        for (int j = (usedSize-1-1)/2;j >= 0;j--){
    
    
            adjustDown(j,usedSize);
        }
    }

    //向下调整的方法构造堆(大根堆)(时间复杂度log2n)
    //参数传入的parent是最后一棵子树双亲下标,len就是usedSize,堆中节点的个数
    public void adjustDown(int parent,int len){
    
    
        int child = 2*parent+1;//左孩子下标
        //1.首先判断是不是有左孩子
        while(child < len){
    
    
            //是否有右孩子,如果有的话,child保存的是左右孩子中最大值的下标;
            if (child+1 < len && elem[child] < elem[child+1]){
    
    
                child++;
            }
            //到这步,说明已经确定左右孩子中最大值的下标了,则和双亲节点开始进行比较
            if(elem[child] > elem[parent]){
    
    
                int tmp = elem[child];
                elem[child] = elem[parent];
                elem[parent] = tmp;
                //下面这俩个式子用来进行判断子树,是否已经构造完毕
                parent = child;
                child = 2*parent+1;
            }else{
    
    //否则直接跳出循环,因为只要双亲节点大于孩子中最大值,那么子树一定已经构造成为一棵大根堆
                break;
            }
        }
    }
-Método de ajuste al alza

El ajuste ascendente consiste en ajustar cada subárbol desde el nodo secundario al principal;

//用向上调整的方法构造堆(向上调整就是从孩子节点向上,向双亲节点调整)
    public void adjustUp(int child){
    
    
        //知道孩子节点,根据孩子节点下标和双亲节点下标的关系,得到双亲节点下标
       int parent = (child-1)/2;
        /*
       因为是向上走,因此下标肯定是从小到大,最后到根节点是0,
       所以这里是大于0;child等于0;这个堆就已经走完了;
       */
       while(child > 0){
    
    
            if(elem[child] > elem[parent]){
    
      //如果大于双亲节点,就交换; 
                int tmp = elem[child];
                elem[child] = elem[parent];
                elem[parent] = tmp;
                //检查子树是否已经完成
                child = parent;
                parent = (child-1)/2;
            }else{
    
    
                break;
            }
        }
    }

2. Agrega nuevos elementos al montón

  • Idea : agregue directamente después del montón más grande, como se muestra en la figura a continuación, agréguelo directamente en la posición del nodo correcto de 37, y luego llame hacia arriba o hacia abajo, y simplemente reconstruya el montón directamente;
    Inserte la descripción de la imagen aquí
//模拟队列形式,给堆添加新元素
    public void push(int val){
    
    
        //1.首先判断该堆的存储大小是否已经满了,如果满了要进行扩容
        if (isFull()){
    
    
            this.elem = Arrays.copyOf(this.elem,elem.length*2);//空间扩展为原来的二倍
        }
        elem[usedSize] = val;//将新的值,直接加到堆的最后面
        usedSize++;//进行加加,说明堆中元素又多了一个;
        adjustUp(this.usedSize-1);//然后从孩子开始,向上进行调整
    }
//判断堆是否已经满了
    public boolean isFull(){
    
    
        return this.usedSize == this.elem.length;
    }

3. Fuera del montón

  • Idea : intercambie el elemento fijo del montón con el último elemento del montón, luego sáquelo y ajuste el montón de nuevo
 //出堆(弹出堆顶元素)
    public void pop(){
    
    
        /*
        思路:将堆定元素和堆最后一个元素进行交换,然后弹出,并且将堆重新进行调整
         */
        //判断是否为空
        if (isEmpty()){
    
    
            return;
        }
        // 1.交换
        int tmp = elem[0];
        this.elem[0] = this.elem[this.usedSize-1];
        this.elem[this.usedSize-1] = tmp;
        this.usedSize--;//数据个数减少
        //2.调用向下调整方法
        adjustDown(0,usedSize);
        System.out.println("=====");
    }
    //判断是否为空
    public boolean isEmpty(){
    
    
        return usedSize == 0;
    }
}

Código completo

import java.util.Arrays;

public class MyHeap {
    
    
    int[] elem;
    int usedSize;
    public MyHeap(){
    
    
        this.elem = new int[10];
    }

    //向下调整的方法构造堆(大根堆)(时间复杂度log2n)
    //向下调整的意思就是,从每一棵子树的视角来看是从它的双亲节点往下调整的所以叫向下调整的
    //参数传入的parent是最后一棵子树双亲下标,len就是usedSize,堆中节点的个数
    public void adjustDown(int parent,int len){
    
    
        int child = 2*parent+1;//左孩子下标
        //1.首先判断是不是有左孩子
        while(child < len){
    
    
            //是否有右孩子,如果有的话,child保存的是左右孩子中最大值的下标;
            if (child+1 < len && elem[child] < elem[child+1]){
    
    
                child++;
            }
            //到这步,说明已经确定左右孩子中最大值的下标了,则和双亲节点开始进行比较
            if(elem[child] > elem[parent]){
    
    
                int tmp = elem[child];
                elem[child] = elem[parent];
                elem[parent] = tmp;
                //下面这俩个式子用来进行判断子树,是否已经构造完毕
                parent = child;
                child = 2*parent+1;
            }else{
    
    //否则直接跳出循环,因为只要双亲节点大于孩子中最大值,那么子树一定已经构造成为一棵大根堆
                break;
            }
        }
    }
    //将数组先放入堆中,然后调用向下调整方法(adjustDown),构造堆
    public void initHeap(int[] arr){
    
    
        for (int i = 0;i < arr.length;i++){
    
    
            elem[i] = arr[i];
            usedSize++;
        }
        //建堆时间复杂度O(n*log2n),一棵子树完成后,j就减减,这样就能够找到下一棵子树的双亲下标了
        for (int j = (usedSize-1-1)/2;j >= 0;j--){
    
    
            adjustDown(j,usedSize);
        }
    }

    //用向上调整的方法构造堆(向上调整就是从孩子节点向上,向双亲节点调整)
    public void adjustUp(int child){
    
    
        int parent = (child-1)/2;
        /*
       因为是向上走,因此下标肯定是从小到大,最后到根节点是0,所以这里是大于0;child等于0;这个堆就已经走完了
       */
        while(child > 0){
    
    
            if(elem[child] > elem[parent]){
    
    
                int tmp = elem[child];
                elem[child] = elem[parent];
                elem[parent] = tmp;
                child = parent;
                parent = (child-1)/2;
            }else{
    
    
                break;
            }
        }
    }

    //模拟队列形式,给堆添加新元素
    public void push(int val){
    
    
        //1.首先判断该堆的存储大小是否已经满了,如果满了要进行扩容
        if (isFull()){
    
    
            this.elem = Arrays.copyOf(this.elem,elem.length*2);//空间扩展为原来的二倍
        }
        elem[usedSize] = val;//将新的值,直接加到堆的最后面
        usedSize++;//进行加加,说明堆中元素又多了一个;
        adjustUp(this.usedSize-1);//然后从孩子开始,向上进行调整
    }

    //判断堆是否已经满了
    public boolean isFull(){
    
    
        return this.usedSize == this.elem.length;
    }
    //出堆(弹出堆顶元素)
    public void pop(){
    
    
        /*
        思路:将堆定元素和堆最后一个元素进行交换,然后弹出,并且将堆重新进行调整
         */
        //判断是否为空
        if (isEmpty()){
    
    
            return;
        }
        // 1.交换
        int tmp = elem[0];
        this.elem[0] = this.elem[this.usedSize-1];
        this.elem[this.usedSize-1] = tmp;
        this.usedSize--;//数据个数减少
        //2.调用向下调整方法
        adjustDown(0,usedSize);
        System.out.println("=====");
    }
    //判断是否为空
    public boolean isEmpty(){
    
    
        return usedSize == 0;
    }
}


//测试类,用来给堆里面传递元素
public class TestDemo {
    
    
    public static void main(String[] args) {
    
    
        int[] arr = {
    
    27, 15, 19, 18, 28, 34, 65, 49, 25, 37};
        MyHeap heap = new MyHeap();
        heap.initHeap(arr);
    }
}

Supongo que te gusta

Origin blog.csdn.net/qq_45665172/article/details/109604225
Recomendado
Clasificación