Complexidade de tempo do heapsort

Complexidade De Tempo Do Heapsort



Heap Sort, escrito como Heapsort, é um tipo de algoritmo de ordenação. Ele pega uma lista parcialmente ordenada e produz uma lista ordenada a partir dela. A ordenação pode ser ascendente ou descendente. Neste artigo, a classificação é crescente. Observe que o heapsort não classifica uma lista incompletamente não classificada. Ele classifica uma lista parcialmente ordenada (classificada). Essa lista parcialmente ordenada é um heap. Neste artigo, o heap considerado é o heap mínimo (ascendente).

Um heap é referido como “parcialmente ordenado” e não “parcialmente ordenado”. A palavra “sort” significa ordenação completa (ordenação completa). Um heap não é parcialmente ordenado arbitrariamente. Um heap é parcialmente ordenado seguindo um critério (padrão), conforme mostrado abaixo.

Assim, o heapsort consiste em duas etapas: construir o heap e extrair o elemento ordenado do topo do heap. Na segunda etapa, após cada extração, o heap é reconstruído. Cada reconstrução é mais rápida do que o processo de construção original, pois a reconstrução é feita a partir de uma construção anterior, onde um elemento foi removido. E com isso, o heapsort classifica uma lista completamente não classificada.







O objetivo deste artigo é explicar brevemente o heapsort e então produzir sua complexidade de tempo (veja o significado de complexidade de tempo abaixo). No final, a codificação é feita em C++.



Pilha Mínima

Um heap pode ser um heap mínimo ou um heap máximo. Um heap máximo é aquele em que o primeiro elemento é o elemento mais alto e toda a árvore ou lista correspondente é parcialmente ordenada em ordem decrescente. Um heap mínimo é aquele em que o primeiro elemento é o menor elemento e toda a lista é parcialmente ordenada em ordem crescente. Neste artigo, apenas o heap mínimo é considerado. Nota: no tópico do heap, um elemento também é chamado de nó.



Um heap é uma árvore binária completa. A árvore binária pode ser expressa como um array (lista); leia de cima para baixo e da esquerda para a direita. A propriedade heap para um heap mínimo é que um nó pai é menor ou igual a cada um de seus dois filhos. Um exemplo de lista não ordenada é:





9 19 24 5 3 onze 14 22 7 6 17 quinze nulo nulo nulo
0 1 dois 3 4 5 6 7 8 9 10 onze 12 13 14

A primeira linha desta tabela são os elementos da matriz. Na segunda linha estão os índices baseados em zero. Esta lista de elementos pode ser expressa como uma árvore. Os elementos nulos foram adicionados para fazer uma árvore binária completa. A rigor, os elementos nulos não fazem parte da lista (árvore). Esta lista não tem ordem, então ainda não é um heap. Ele se tornará um heap quando tiver ordenação parcial, de acordo com a propriedade do heap.

Relação entre nós e índices

Lembre-se, um heap é uma árvore binária completa antes de ter a configuração do heap (propriedade do heap). A lista anterior ainda não é um heap, pois os elementos não obedecem à propriedade heap. Ele se torna um heap depois de reorganizar os elementos em ordem parcial de acordo com a propriedade min-heap. A ordem parcial pode ser vista como ordenação parcial (embora a palavra “ordenar” signifique ordenação completa).



Quer uma árvore binária seja um heap ou não, cada pai tem dois filhos, exceto os nós folha (últimos). Existe uma relação matemática entre os índices entre cada pai e seus filhos. É o seguinte: Se o pai estiver no índice i, o filho da esquerda estará no índice:

dois * eu + 1

e o filho certo está no índice:

dois * eu + dois

Isso é para indexação baseada em zero. E assim, um pai no índice 0 tem seu filho esquerdo no índice 2×0+1=1 e seu filho direito em 2×0+2=2. Um pai no índice 1 tem seu filho esquerdo no índice 2×1+1=3 e o filho direito no índice 2×1+2=4; e assim por diante.

Pela propriedade min-heap, um pai em i é menor ou igual ao filho da esquerda em 2i+1 e menor ou igual ao filho da direita em 2i+2.

Pilha

Amontoar significa construir uma pilha. Significa reorganizar os elementos de uma lista (ou árvore correspondente) para que eles satisfaçam a propriedade do heap. No final do processo de heap, a lista ou árvore é um heap.

Se a lista não classificada anterior for empilhada, ela se tornará:

3 5 onze 7 6 quinze 14 22 9 19 17 24 nulo nulo nulo
0 1 dois 3 4 5 6 7 8 9 10 onze 12 13 14

Nota: existem 12 elementos e não 15 na lista. Na segunda linha estão os índices. No processo de construção do heap, os elementos precisavam ser verificados e alguns trocados.

Observe que o menor e o primeiro elemento é 3. O restante dos elementos segue de maneira ascendente, mas ondulante. Se os filhos esquerdo e direito nas posições 2i+1 e 2i+2 forem maiores ou iguais ao pai em i, então este é um heap mínimo. Isso não é ordenação ou classificação completa. Esta é uma ordenação parcial, de acordo com a propriedade heap. É a partir daqui que começa a próxima etapa para a classificação de heap.

Complexidade de tempo de amontoar

A complexidade de tempo é o tempo de execução relativo de algum código. Pode ser visto como o número de operações principais para que esse código seja concluído. Existem diferentes algoritmos para construção de heap. Os mais eficientes e mais rápidos dividem continuamente a lista por dois, verificando os elementos de baixo para cima e depois fazendo algumas trocas de elementos. Seja N o número de elementos práticos na lista. Com este algoritmo, o número máximo de operações principais (swapping) é N. A complexidade de tempo para heapificação é dada anteriormente como:

    O ( n )

Onde n é N e é o número máximo possível de operações principais. Essa notação é chamada de notação Big-O. Começa com O em maiúsculo, seguido de parênteses. Dentro dos parênteses está a expressão para o maior número possível de operações.

Lembre-se: a adição pode se tornar multiplicação se a mesma coisa que está sendo adicionada continuar se repetindo.

Ilustração Heapsort

A lista não classificada anterior será usada para ilustrar o heapsort. A lista dada é:

9 19 24 5 3 onze 14 22 7 6 17 quinze

O min-heap produzido a partir da lista é:

3 5 onze 7 6 quinze 14 22 9 19 17 24

O primeiro estágio no heapsort é produzir o heap que foi produzido. Esta é uma lista parcialmente ordenada. Não é uma lista ordenada (completamente ordenada).

A segunda etapa consiste em remover o menor elemento, que é o primeiro elemento, do heap, reagrupar o heap restante e remover os menores elementos nos resultados. O menor elemento é sempre o primeiro elemento no heap reagrupado. Os elementos não são removidos e jogados fora. Eles podem ser enviados para uma matriz diferente na ordem em que são removidos.

Ao final, o novo array teria todos os elementos ordenados (completamente), em ordem crescente; e não mais apenas parcialmente ordenado.

Na segunda etapa, a primeira coisa a fazer é remover 3 e colocá-lo no novo array. Os resultados são:

3

e

5 onze 7 6 quinze 14 22 9 19 17 24

Os elementos restantes devem ser empilhados antes que o primeiro elemento seja extraído. A pilha dos elementos restantes pode se tornar:

5 6 7 9 quinze 14 22 onze 19 17 24

Extrair 5 e adicionar à nova lista (array) fornece os resultados:

3 5

e

6 7 9 quinze 14 22 onze 19 17 24

Acumular o conjunto restante daria:

6 7 9 quinze 14 22 onze 19 17 24

Extrair 6 e adicionar à nova lista (array) fornece os resultados:

3 5 6

e

7 9 quinze 14 22 onze 19 17 24

Acumular o conjunto restante daria:

7 9 onze 14 22 quinze 19 17 24

Extrair 7 e adicioná-lo à nova lista fornece os resultados:

3 5 6 7

e

9 onze 14 22 quinze 19 17 24

Ao empilhar o conjunto restante, obtém-se:

9 onze 14 22 quinze 19 17 24

Extraindo 9 e adicionando à nova lista, dá os resultados:

3 5 6 7 9

e

onze 14 22 quinze 19 17 24

Ao empilhar o conjunto restante, obtém-se:

onze 14 17 quinze 19 22 24

Extrair 11 e adicioná-lo à nova lista fornece os resultados:

3 5 6 7 9 onze

e

14 17 quinze 19 22 24

Acumular o conjunto restante daria:

14 17 quinze 19 22 24

Extrair 14 e adicioná-lo à nova lista fornece os resultados:

3 5 6 7 9 onze 14

e

17 quinze 19 22 24

Acumular o conjunto restante daria:

quinze 17 19 22 24

Extrair 15 e adicioná-lo à nova lista fornece os resultados:

3 5 6 7 9 onze 14 quinze

e

17 19 22 24

Acumular o conjunto restante daria:

17 19 22 24

Extrair 17 e adicioná-lo à nova lista fornece os resultados:

3 5 6 7 9 onze 14 quinze 17

e

19 22 24

Acumular o conjunto restante daria:

19 22 24

Extrair 19 e adicioná-lo à nova lista fornece os resultados:

3 5 6 7 9 onze 14 quinze 17 19

e

22 24

Ao empilhar o conjunto restante, obtém-se:

22 24

Extrair 22 e adicioná-lo à nova lista fornece os resultados:

3 5 6 7 9 onze 14 quinze 17 19 22

e

24

Ao empilhar o conjunto restante, obtém-se:

24

Extrair 24 e adicioná-lo à nova lista fornece os resultados:

3 5 6 7 9 onze 14 quinze 17 19 22 24

e

- - -

A matriz de heap agora está vazia. Todos os elementos que tinha no início estão agora no novo array (lista) e ordenados.

Algoritmo de Heapsort

Embora o leitor possa ter lido em livros didáticos que o heapsort consiste em dois estágios, o heapsort ainda pode ser visto como consistindo em um estágio, que reduz iterativamente o array fornecido. Com isso, o algoritmo para ordenar com heapsort é o seguinte:

  • Empilhe a lista não classificada.
  • Extraia o primeiro elemento do heap e coloque-o como o primeiro elemento da nova lista.
  • Empilhe a lista restante.
  • Extraia o primeiro elemento do novo heap e coloque como próximo elemento da nova lista.
  • Repita as etapas anteriores em ordem até que a lista de heap esteja vazia. No final, a nova lista é ordenada.

Complexidade de tempo de heapsort adequada

A abordagem de um estágio é usada para determinar a complexidade de tempo para heapsort. Suponha que existam 8 elementos não ordenados a serem ordenados.

O número máximo possível de operações para empilhar o 8 elementos é 8 .
o número máximo possível de operações para empilhar o restante 7 elementos é 7 .
o número máximo possível de operações para empilhar o restante 6 elementos é 6 .
o número máximo possível de operações para empilhar o restante 5 elementos é 5 .
o número máximo possível de operações para empilhar o restante 4 elementos é 4 .
o número máximo possível de operações para empilhar o restante 3 elementos é 3 .
o número máximo possível de operações para empilhar o restante dois elementos é dois .
o número máximo possível de operações para empilhar o restante 1 elemento é 1 .

O número máximo possível de operações é:

8 + 7 + 6 + 5 + 4 + 3 + dois + 1 = 36

A média desses números de operações é:

36 / 8 = 4,5

Observe que os últimos quatro heaps na ilustração anterior não foram alterados quando o primeiro elemento foi removido. Alguns dos heaps anteriores também não foram alterados quando o primeiro elemento foi removido. Com isso, um melhor número médio de operações principais (swappings) é 3 e não 4,5. Assim, um melhor número médio total de operações principais é:

24 = 8 x 3
=> 24 = 8 x registro < sub > dois < / sub > 8

desde log dois 8 = 3.

Em geral, a complexidade média de tempo de caso para heapsort é:

    O ( n. log2n )

Onde o ponto significa multiplicação e n é N, o número total de elementos na lista (qualquer lista).

Observe que a operação de extração do primeiro elemento foi ignorada. No tópico de Complexidade de Tempo, as operações que levam tempos relativamente curtos são ignoradas.

Codificando em C++

Na biblioteca de algoritmos de C++, existe uma função make_heap(). A sintaxe é:

modelo < classe RandomAccessIterator, classe Comparar >
constexpr vazio make_heap ( RandomAccessIterator primeiro, RandomAccessIterator por último, Compare comp ) ;

Ele usa o iterador apontando para o primeiro elemento de um vetor como seu primeiro argumento e, em seguida, o iterador apontando logo além do final do vetor como seu último argumento. Para a lista não classificada anterior, a sintaxe seria usada da seguinte maneira para obter um heap mínimo:

vetor < int > vtr = { 9 , 19 , 24 , 5 , 3 , onze , 14 , 22 , 7 , 6 , 17 , quinze } ;
vetor < int > :: iterador iterB = vtr. começar ( ) ;
vetor < int > :: iterador iterE = vtr. fim ( ) ;
make_heap ( iterB, iterE, maior < int > ( ) ) ;

Este código altera um conteúdo vetorial para uma configuração mínima de heap. Nos seguintes vetores C++, dois vetores serão usados ​​em vez de dois arrays.

Para copiar e retornar o primeiro elemento de um vetor, use a sintaxe de vetor:

constexpr frente de referência ( ) ;

Para remover o primeiro elemento de um vetor e jogá-lo fora, use a sintaxe de vetor:

constexpr apagar iterador ( posição const_iterator )

Para adicionar um elemento na parte de trás de um vetor (próximo elemento), use a sintaxe de vetor:

constexpr vazio retrocesso ( const T & x ) ;

O início do programa é:

#include
#include
#include
usando namespace padrão ;

O algoritmo e as bibliotecas de vetores estão incluídos. A seguir no programa está a função heapsort(), que é:

vazio heapsort ( vetor < int > & velhoV, vetor < int > & novoV ) {
E se ( velhoV. Tamanho ( ) > 0 ) {
vetor < int > :: iterador iterB = velhoV. começar ( ) ;
vetor < int > :: iterador iterE = velhoV. fim ( ) ;
make_heap ( iterB, iterE, maior < int > ( ) ) ;

int próximo = velhoV. frente ( ) ;
velhoV. apagar ( iterB ) ;
novoV. retrocesso ( próximo ) ;
heapsort ( velhoV, novoV ) ;
}
}

É uma função recursiva. Ele usa a função make_heap() da biblioteca de algoritmos C++. O segundo segmento de código na definição da função extrai o primeiro elemento do vetor antigo após a construção do heap e adiciona como o próximo elemento para o novo vetor. Observe que na definição da função, os parâmetros vetoriais são referências, enquanto a função é chamada com os identificadores (nomes).

Uma função principal C++ adequada para isso é:

int a Principal ( int argc, Caracteres ** argv )
{
vetor < int > velhoV = { 9 , 19 , 24 , 5 , 3 , onze , 14 , 22 , 7 , 6 , 17 , quinze } ;
vetor < int > novoV ;
heapsort ( velhoV, novoV ) ;

por ( int eu = 0 ; eu < novoV. Tamanho ( ) ; eu ++ ) {
cout << novoV [ eu ] << ' ' ;
}
cout << fim ;

Retorna 0 ;
}

A saída é:

3 5 6 7 9 onze 14 quinze 17 19 22 24

ordenado (completamente).

Conclusão

O artigo discutiu em detalhes a natureza e a função do Heap Sort comumente conhecido como Heapsort, como um algoritmo de ordenação. Heapify Time Complexity, Heapsort ilustração e Heapsort como algoritmo foram cobertos e apoiados por exemplos. A complexidade de tempo média para um programa heapsort bem escrito é O(nlog(n))