Artigo Diretório
Um e dois garfos
O heap binário é essencialmente uma árvore binária completa, que é dividida em dois tipos:
- Heap máximo: o valor de qualquer nó pai do heap máximo é maior ou igual ao valor de seus nós filho esquerdo e direito.
- Pilha mínima: O valor de qualquer nó pai da pilha menor é menor ou igual ao valor de seus nós filho esquerdo e direito.
O nó raiz de um heap binário é chamado de topo do heap. As características do maior heap e do menor heap determinam que o topo do maior heap é o maior elemento de todo o heap; o topo do menor heap é o menor elemento de todo o heap.
Em segundo lugar, o autoajuste da pilha
1. Insira o nó
Vamos pegar o menor heap como exemplo para ver como o heap binário é ajustado.
Conforme mostrado na figura, ao inserir o nó 0 no heap binário, o nó 0 e o nó 5 não atendem à estrutura do heap binário, então o nó 0 e o nó 5 são trocados; o nó 0 e o nó 3 não atendem à estrutura do heap binário, então o nó 0 e o nó 3 são trocados, e ao mesmo tempo, após a troca, ver se o nó 3 e o nó 5 atendem a estrutura da árvore binária, sim! O nó 0 e o nó 1 não atendem a estrutura da árvore binária, eles são trocados e, ao mesmo tempo, veja se o nó 1 e o nó 3 atendem a estrutura da árvore binária da mesma forma.
Princípios principais:
Se o nó inserido e o nó pai atendem à estrutura do heap binário, se não, o nó inserido é ajustado para cima e o nó pai é ajustado para baixo.
2. Exclua o nó
Excluir um nó significa retirar um nó do heap, geralmente removendo o topo do heap. Vamos pegar o menor heap como exemplo para mostrar como o heap binário exclui nós.
Quando excluímos o topo do menor heap (não excluímos completamente, mas substituímos até o fim)
Conforme mostrado na figura, primeiro troque o nó superior 1 pelo último nó folha 10. Então veja se o nó 10 atende a estrutura do heap binário, se não, ajuste para baixo, e o nó 10 troca com o nó folha pequeno 2 (se ele troca com o nó folha 3, a estrutura do heap binário ainda não está satisfeita) , O nó 10 ainda não atende à definição de heap mínimo e troca com o nó folha 7.
3. Construir um heap binário
Construa um heap binário. É para ajustar uma árvore binária completa desordenada a um heap binário, que é essencialmente para fazer todos os nós não-folha afundarem de uma vez.
- debaixo para cima
- Careca
O seguinte descreve a abordagem ascendente para ajustar a árvore binária não ordenada acima para o menor heap:
Primeiro, o nó 6 troca com o nó 10, o nó 2 troca com o nó 3. Como o nó 5 e o nó 2 são nós folha na árvore binária original, não há necessidade de ajustar para baixo. O nó 1 é trocado pelo nó 7, o nó 7 é ajustado para baixo, o nó 7 é trocado pelo nó 5 e o heap binário mínimo é estabelecido!
Três, a realização da pilha
Embora o heap binário seja uma árvore binária completa, seu método de armazenamento não é armazenamento em cadeia, mas armazenamento sequencial . Em outras palavras, todos os nós do heap binário são armazenados na matriz .
Então, como localizar o nó pai do nó filho ou o nó filho do nó pai?
O heap binário pode ser convertido em uma matriz. Os arrays também podem ser convertidos em heaps binários. A relação de índice entre o nó filho e o nó pai na matriz é a seguinte:
Se o índice do nó pai for n, os índices dos dois nós filhos serão 2n + 1, 2n + 2, respectivamente.
Conforme mostrado na figura acima, os índices dos nós 6, 9 e 10 são 3,
7 e
8. 7 = 2 × 3 + 1 8 = 2 × 3 + 2
Se o índice do nó filho for conhecido, ( nó filho index-1) / 2 e, em seguida, arredondar para baixo.
Quatro, LeetCode
215. Encontre o maior k-ésimo elemento na matriz não classificada (você precisa encontrar o k-ésimo maior elemento após a matriz ser classificada)
Entrada: [3,2,1,5,6,4] e
saída k : 5
class Solution():
def findKthLarget(self, nums, k):
self._k = k
return self.heap_sort(nums)
def heap_sort(self, nums):
"""
堆排序
将根节点取出与最后一位做对调,对前面len-1个节点继续进行堆调整过程
:param nums: 数组
:return:
"""
self.build_max_heap(nums)
print(nums)
cnt = 0
# 调整后列表的第一个元素就是这个列表中最大的元素,
# 将其与最后一个元素交换,然后将剩余的列表再递归的调整为最大堆
for i in range(len(nums) - 1, -1, -1):
nums[0], nums[i] = nums[i], nums[0]
cnt += 1
if cnt == self._k:
return nums[i]
self.max_heapify(nums, i, 0)
def build_max_heap(self, nums):
"""
构建最大堆
:param nums: 数组
:return: 最大堆
"""
length = len(nums)
for i in range((length - 2) // 2, -1, -1): # 自底向上建堆
self.max_heapify(nums, length, i)
def max_heapify(self, nums, length, root):
'''
调整列表中的元素并保证以root为根的堆是一个大根堆
给定某个节点的下标root,这个节点的父节点、左子节点、右子节点的下标都可以被计算出来。
索引从0开始时
父节点:(root-1)//2
左子节点:2*root + 1
右子节点:2*root + 2 即:左子节点 + 1
'''
left = 2 * root + 1
right = left + 1
larger = root
if left < length and nums[larger] < nums[left]:
larger = left
if right < length and nums[larger] < nums[right]:
larger = right
# larger的值等于左节点或者右节点的值时,需要做堆调整
if larger != root:
nums[larger], nums[root] = nums[root], nums[larger]
# 递归的对子树做调整
self.max_heapify(nums, length, larger)
def main():
nums = [3,2,1,5,6,4]
k = 2
s = Solution()
kth_element = s.findKthLarget(nums, k)
print('数组中第%d个最大元素为%d' % (k, kth_element))
if __name__ == '__main__':
main()
[6, 5, 4, 3, 2, 1]
数组中第2个最大元素为5