Montón y estructura de árbol

Montón y estructura de árbol

Puede mejorar el rendimiento operativo de las colas prioritarias.

1. Estructura lineal y de árbol

Primero analice las razones de la baja eficiencia:

  • La operación de inserción secuencial es ineficaz, cuya raíz es la necesidad de recuperar la posición de inserción a lo largo del orden de la tabla., Para la tabla de secuencia, es necesario mover O (n) elementos, y para la lista vinculada, es necesario rastrear O (n) pasos a lo largo del enlace.

  • Si no se cambia el método de almacenamiento de orden lineal de los datos, es imposible romper el límite de complejidad O (n). Para hacer una cola de prioridad con mayor eficiencia operativa, se deben considerar otros métodos de organización de la estructura de datos.

  • Usando la secuencia ancestro / descendiente de la estructura del árbol, es posible obtener una mejor eficiencia operativa

En términos generales, para determinar el elemento de mayor prioridad no es necesario compararlo con todos los demás elementos. Tome el nocaut en una competencia deportiva como ejemplo. Suponiendo que hay n jugadores participando, se deben jugar los primeros juegos N-1 para determinar el campeón, y cada jugador solo necesita jugar Acerca de log 2 n juegos, después de que se determina el campeón, para determinar el segundo lugar real, solo el subcampeón debe competir con todas las personas que perdieron ante el campeón, y solo necesita siga la ruta de la victoria del campeonato, no más de log 2 n veces

2. Montón y su naturaleza

Una tecnología eficaz para implementar colas de prioridad con una estructura de árbol se llama montón. Desde un punto de vista estructural, el montón esÁrbol binario completo de datos almacenados en el nodo, Pero el almacenamiento de datos en el montón debe cumplir con un orden de montón especial: los datos almacenados en cualquier nodo (en el orden considerado) son anteriores o iguales a los datos en sus nodos secundarios (si los hay)

  • En la ruta desde la raíz del árbol hasta cualquier nodo hoja en un montón, los datos almacenados en cada nodo disminuyen de acuerdo con la relación de prioridad especificada (no estricta)
  • El elemento de mayor prioridad en el montón debe estar ubicado en el nodo raíz del árbol binario (parte superior del montón), y se puede obtener en O (1) tiempo
  • Elementos ubicados en diferentes caminos en el árbol, no se preocupan por su relación de orden aquí

Si el orden requerido es el elemento más pequeño primero, el montón construido es un montón superior pequeño; de lo contrario, es un montón superior grande.

[Error en la transferencia de la imagen del enlace externo. El sitio de origen puede tener un mecanismo anti-hotlinking. Se recomienda guardar la imagen y subirla directamente (img-5bcZhPc0-1612257238795) (C: \ Users \ 93623 \ AppData \ Roaming \ Typora \ typora-user-images \ image-20210114152155871.png)]

La imagen de arriba muestra la forma de una pila (es decir, la forma de un árbol binario completo) y un camino en la pila. Excepto por la falta del lado derecho de la capa inferior, todos los nodos de la pila están llenos. la imagen, de la raíz a la hoja. Cuanto más pequeño sea el círculo en el camino

Un árbol binario completo puede almacenar información de forma natural y completa en una estructura lineal continua (como una tabla continua), un montón también se puede almacenar de forma natural en una tabla continua, y el padre de cualquier nodo en el árbol se puede encontrar fácilmente a través de la subíndice. Nodo / subnodo

Los montones y los árboles binarios tienen las siguientes propiedades:

P1: Agregue un elemento al final de un montón (agregue un elemento al final de la tabla continua correspondiente), toda la estructura aún se puede considerar como un árbol binario completo, pero puede que no sea un montón (el último elemento puede no satisface la orden del montón)

P2: Un montón elimina la parte superior del montón (el elemento en la posición 0 en la tabla) y los elementos restantes forman dos "montones secundarios". Las reglas de cálculo de subíndices del nodo secundario / nodo principal del árbol binario completo siguen siendo aplicable, y el orden del montón todavía se establece en la ruta

P3: Agregue un elemento raíz (almacenado en la posición 0) a la tabla (dos sub-montones) obtenida por Q2, y la secuencia de nodos obtenida puede considerarse como un árbol binario completo, pero puede que no sea un montón (el nodo raíz puede que no satisfaga la orden del montón)

P4: Elimine el último elemento en un montón (el nodo más a la derecha en el nivel inferior, que es el último elemento en la tabla continua correspondiente), y los elementos restantes todavía forman un montón

[Error en la transferencia de la imagen del enlace externo. El sitio de origen puede tener un mecanismo anti-hotlinking. Se recomienda guardar la imagen y subirla directamente (img-ddnvulHP-1612257238798) (C: \ Users \ 93623 \ AppData \ Roaming \ Typora \ typora-user-images \ image-20210115140627664.png)]

Cola de prioridad de implementación de montón

  • Usando el montón como una cola de prioridad, puede obtener directamente el elemento de mayor prioridad en el montón, O (1)
  • La operación de insertar elementos (cribado ascendente): para agregar un nuevo elemento al montón (cola de prioridad), debe poder obtener un montón que contenga todos los elementos originales y el nuevo elemento que acaba de agregar, O (logn)
  • Saque el elemento más pequeño del montón (selección hacia abajo). Después de sacar el elemento más pequeño del montón, debe poder rehacer los elementos restantes en un montón, O (logn)

Tres. Implementación del montón de la cola de prioridad

(1) Insertar elementos y filtrar hacia arriba

Según Q1, al agregar un elemento al final de un montón, el resultado sigue siendo un árbol binario completo, pero no necesariamente un montón. Para restaurar un árbol binario tan completo en un montón, solo se necesita un filtro ascendente.

Método de cribado ascendente:

Compare constantemente el elemento recién agregado (establecido en e) con los datos de su nodo principal e intercambie las posiciones de los dos elementos si e es más pequeño, A través de esta comparación e intercambio, el elemento e continúa subiendo. Esta operación se ha logrado cuando los datos del nodo padre de e son menores o iguales que e, o cuando e ha llegado al nodo raíz, se detiene y luego todas las rutas a través de e Los elementos de satisfacen el orden requerido, y el resto de las rutas permanecen en orden, por lo que este árbol binario completo satisface el orden del montón

  • Coloque el elemento recién agregado (en la lista continua) después del elemento existente y realice una operación de filtrado ascendente
  • El número de comparaciones e intercambios en la operación de filtrado ascendente no excederá la longitud de la ruta más larga en el árbol binario, por lo que la operación de inserción del elemento se puede completar en tiempo O (logn)

(2) Elementos emergentes y filtro hacia abajo

Haga estallar el elemento superior del montón, elimine un elemento del final del montón original y colóquelo en la parte superior del montón para obtener un árbol binario completo. Ahora, excepto el elemento en la parte superior del montón, que puede no cumplen con el orden del montón, el resto de los elementos cumplen con el orden del montón. Ahora tenemos que intentar cambiar La estructura se restaura a un montón

[Error en la transferencia de la imagen del enlace externo. El sitio de origen puede tener un mecanismo de enlace anti-sanguijuela. Se recomienda guardar la imagen y subirla directamente (img-0xl9bU8Z-1612257238801) (C: \ Users \ 93623 \ AppData \ Roaming \ Typora \ typora-user-images \ image-20210115143047139.png)]

  • Compare e con el elemento superior (raíz) de los dos "submontones" de A y B, y el más pequeño se usa como la parte superior de todo el montón
    • Si e no es el más pequeño, la relación más pequeña es la raíz de A o B. Establezca la raíz de A como la más pequeña y muévala a la parte superior del montón, lo que equivale a eliminar el elemento superior de A
    • Ponga e en A sin la parte superior del montón, que es el mismo problema en una escala más pequeña
    • Lo mismo se aplica al caso donde la raíz de B es la más pequeña
  • Si un cierto tiempo es más pesado y e es el más pequeño, el árbol local con él como la parte superior se ha convertido en un montón, y toda la estructura también se ha convertido en un montón.
  • O ha caído hasta el final, en este momento él mismo es un montón, y toda la estructura se convierte en un montón

para resumir:

  1. Pop la parte superior del montón O (1)
  2. Tome el último elemento del montón como la raíz del árbol binario completo O (1)
  3. Realice un filtro descendente O (logn), el número de operaciones no excede la longitud del camino en el árbol

A continuación, use Python para implementar una clase de cola de prioridad basada en el montón, use la lista para almacenar elementos y agregue elementos al final de la tabla, con la cabecera como la parte superior del montón.

class PrioQueue:
    """
    implementing priority queues using heaps
    """
    def __init__(self, elist=[]):
        self._elems = list(elist)
        if elist:
            self.buildheap()
            
    def is_empty(self):
        return not self._elems
    
    def peek(self):
        if self.is_empty():
            raise PrioQueueError("in peek")
        return self._elems[0]
    
    def enqueue(self, e):
        self._elems.append(None) # add a dummy element
        self.siftup(e,len(self._elems)-1)
    
    def shiftup(self, e, last):
        elems, i, j = self._elems, last, (last-1) // 2
        while i > 0 and e < elems[j]:
            elems[i] = elems[j]
            i, j = j, (j-1)//2
        elems[i] = e
        
   	def dequeue(self):
   		if self.is_empty():
            raise PrioQueueError("in dequeue")
         elems = self._elems
        e0 = elems[0]
        e = elems.pop()
        if len(elems) > 0:
            self.shiftdown(e, 0, len(elems))
        return e0
    
    def shiftdown(self, e, begin, end):
        elems, i, j = self._elems, begin, begin*2+1
        while j < end:
            if j+1 < end and elems[j+1] < elems[j]:
                j += 1
            if e < elems[j]:
                break
            elems[i] = elems[j]
            i, j = j, 2*j+1
        elems[i] = e
        
    def buildheap(self):
        end = len(self._elems)
        for i in range(end//2, -1, -1):
            self.shiftdowm(sele._elems[i], i, end)

list (elist) El significado de hacer una copia de la tabla comenzando por elist:

  • Haga una copia para separar la tabla interna de la tabla original y excluir compartir
  • También se crea una nueva tabla vacía para el caso predeterminado, evitando la trampa de programación de Python de usar objetos mutables como valores predeterminados

En la implementación de shiftup, el elemento no se almacena primero y luego se considera el intercambio, pero "manténgalo" para encontrar la posición de inserción correcta. La condición de bucle asegura que los elementos que saltan son todos elementos con menor prioridad. Durante el proceso de inspección Bajarlos uno por uno

para resumir:

  1. La cola de prioridad se implementa en base al concepto de montón, y la complejidad de tiempo de la operación de creación es O (n). Esto solo debe hacerse una vez.
  2. La complejidad de las operaciones de inserción y extracción es O (logn). El primer paso de la operación de inserción es agregar un elemento al final de la tabla, lo que puede hacer que el objeto de lista reemplace el área de almacenamiento del elemento, por lo que el peor caso de Puede ocurrir O (n).
  3. Solo se usa una variable simple en todas las operaciones, no se usan otras estructuras, por lo que la complejidad del espacio es O (1)

Área, por lo que puede ocurrir el peor caso de O (n)
3. Todas las operaciones solo usan una variable simple, no se usa ninguna otra estructura, por lo que la complejidad del espacio es O (1)

Supongo que te gusta

Origin blog.csdn.net/weixin_46129834/article/details/113567245
Recomendado
Clasificación