Você está na página 1de 19

INSTITUTO SUPERIOR POLÍTECNICO

GREGORIO SEMEDO
Departamento de Engenharia e Novas Tecnologias

Israel M.M. Casimiro 200208

Árvore binária de busca


Árvore binária de busca balanciada
Organização Hash
Grafos e sua utilização
Representação de listas em memória externa

Lubango
2022
INDICE DE ILUSTRAÇÕES

FIGURAS

Figura 1 ABB...............................................................................................................................5
Figura 2 AVL...............................................................................................................................7
Figura 3 Grafo com 3 vértices {0, 1, 2} e 3 arestas {a, b, c}......................................................13
Figura 4 Grafo com 6 vértices....................................................................................................13

TABELAS

Tabela 1 Complexidade das árvores balanceadas........................................................................8


Tabela 2 Matriz de adjacência....................................................................................................15
Tabela 3 Vértices adjacentes......................................................................................................16

2
Sumário
1. Apresentação.......................................................................................................................4
2. Árvore binária de busca............................................................................................................5
2.1. Definição...........................................................................................................................5
2.1.1. Elementos......................................................................................................................5
2.1.2. Complexidade.................................................................................................................6
2.1.3. Árvore binária de busca balanciada....................................................................................6
2.1.4. Definição........................................................................................................................7
2.2. Uma árvore AVL................................................................................................................7
2.2.1. Complexidade.....................................................................................................................8
2.2.2. Aplicações.......................................................................................................................8
2.2.3. Dicionários......................................................................................................................9
2.2.4 Geometria Computacional..............................................................................................9
2.2.5. Conjuntos.......................................................................................................................9
2.3. Organização Hash.............................................................................................................9
2.3.1. Tabela de Hashing........................................................................................................10
2.3.2. Função de Hashing:......................................................................................................10
2.3.3. Hash e Espalhamento...................................................................................................10
2.3.4. Vantagens.....................................................................................................................11
2.3.5. Desvantagens...............................................................................................................11
2.4. Grafos e sua utilização.........................................................................................................12
2.4.1. Representação.............................................................................................................12
2.4.2. Terminologia................................................................................................................13
2.4.3. Vértice isolado..............................................................................................................13
2.4.4 Grafo trivial (ou ponto).................................................................................................13
2.4.5. Laço (ou loop/self-loop)...............................................................................................13
2.4.6. Grafo simples................................................................................................................14
2.4.7. Vértices adjacentes......................................................................................................14
2.4.8. Grafo pesado (ou grafo de arcos pesados)...................................................................14
2.4.9. Grau de um vértice(ou valência)..................................................................................14
2.4.10. Grafo direccionado.....................................................................................................14
2.4.11. Matriz de adjacência..................................................................................................14
2.4.12. Listas de adjacência....................................................................................................15
2.4.13. Aplicações dos grafos.................................................................................................16
2.5. Representação de listas em memória externa....................................................................17

3
3. Referências.........................................................................................................................19

1. Apresentação
O presente trabalho tem como objectivo a elaboração de um trabalho de investigação
cientifica, este a ser apresentado na cadeira de Algoritmo e estrutura de dados no curso
de Engenharia Informática, sob orientação científica do Msc. Daniel Moises.

4
2. Árvore binária de busca
Em Ciência da computação, uma árvore binária de busca  (ou árvore binária de
pesquisa)  é uma estrutura de dados de árvore binária baseada em nós, onde todos os
nós da subárvore esquerda possuem um valor numérico inferior ao nó raiz e todos os
nós da subárvore direita possuem um valor superior ao nó raiz (esta é a forma padrão,
podendo as subárvores serem invertidas, dependendo da aplicação).

O objetivo desta árvore é estruturar os dados de forma a permitir busca binária

2.1. Definição
Seja S = {s1, s2, ..., sn} um conjunto de chaves tais que s1 < s2 ... sn. Seja k um valor
dados. Deseja-se verificar se k ϵ S e identificar o índice i tal que k = si.

A Árvore Binária de Busca (ABB) resolve os problemas propostos. A figura ilustra uma
ABB.

Figura 1 ABB

Uma ABB é uma árvore binária rotulada T com as seguintes propriedades:

1. T possui n nós. Cada nó u armazena uma chave distinta sj  S e tem como rótulo o
valor r(u) = sj.
2. Para cada nó v de T r(v1) < r(v) e r(v2) > r(v), onde v1 pertence à subárvore
esquerda de v e v2 pertence à subárvore direita de v.
2.1.1. Elementos

 Nós - são todos os itens guardados na árvore


 Raiz - é o nó do topo da árvore (no caso da figura acima, a raiz é o nó 8)

5
 Filhos - são os nós que vem depois dos outros nós (no caso da figura acima,
o nó 6 é filho do 3)
 Pais - são os nós que vem antes dos outros nós (no caso da figura acima, o
nó 10 é pai do 14)
 Folhas - são os nós que não têm filhos; são os últimos nós da árvore (no
caso da figura acima, as folhas são 2, 5, 11, 4).
2.1.2. Complexidade
A complexidade das operações sobre ABB depende diretamente da altura da árvore.

Uma árvore binária de busca com chaves aleatórias uniformemente distribuídas tem
altura O(log n).

No pior caso, uma ABB poderá ter altura O(n). Neste caso a árvore é chamada de árvore
zig-zag e corresponde a uma degeneração da árvore em lista encadeada.

Em função da observação anterior, a árvore binária de busca é de pouca utilidade para


ser aplicada em problemas de busca em geral. Daí o interesse em árvores balanceadas,
cuja altura seja O(log n) no pior caso.

A busca em uma árvore binária por um valor específico pode ser um


processo recursivo ou iterativo.

A busca começa examinando o nó raiz. Se a árvore está vazia, o valor procurado não
pode existir na árvore. Caso contrário, se o valor é igual a raiz, a busca foi bem
sucedida. Se o valor é menor do que a raiz, a busca segue pela subárvore esquerda.
Similarmente, se o valor é maior do que a raiz, a busca segue pela subárvore direita.
Esse processo é repetido até o valor ser encontrado ou a subárvore ser nula (vazia). Se o
valor não for encontrado até a busca chegar na subárvore nula, então o valor não deve
estar presente na árvore.

2.1.3. Árvore binária de busca balanciada


Árvore AVL é uma árvore binária de busca balanceada, ou seja, uma árvore balanceada
(árvore completa) são as árvores que minimizam o número de comparações efetuadas
no pior caso para uma busca com chaves de probabilidades de ocorrências idênticas.
Contudo, para garantir essa propriedade em aplicações dinâmicas, é preciso reconstruir
a árvore para seu estado ideal a cada operação sobre seus nós (inclusão ou exclusão),

6
para ser alcançado um custo de algoritmo com o tempo de pesquisa tendendo a  O(log
n).

As operações de busca, inserção e remoção de elementos possuem complexidade  (no


qual  é o número de elementos da árvore), que são aplicados a árvore de busca binária.

O nome AVL vem de seus criadores soviéticos Adelson Velsky e Landis, e sua primeira


referência encontra-se no documento "Algoritmos para organização da
informação" de 1962.

Nessa estrutura de dados cada elemento é chamado de nó. Cada nó armazena uma chave
e dois ponteiros, uma para a subárvore esquerda e outro para a subárvore direita.

No presente artigo serão apresentados: os conceitos básicos, incluindo uma proposta de


estrutura; apresentação das operações busca, inserção e remoção, todas com
complexidade.

2.1.4. Definição
Uma árvore binária T é denominada AVL quando, para qualquer nó de T, as alturas de
suas duas subárvores, esquerda e direita, diferem em módulo de até uma unidade.

2.2. Uma árvore AVL


Pela definição fica estabelecido que todos os nós de uma árvore AVL devem respeitar a
seguinte propriedade:

|hd(u) - he(u)| ≤ 1, onde hd(u) é a altura da subárvore direita do nó u e he(u) é a altura da


subárvore esquerda do nó u.O valor hd(u) - he(u) é denominado fator de balanço do nó.
Quando um nó possui fator de balanço com valor -1, 0 ou 1 então o mesmo é um nó
regulado. Todos os nós de uma árvore AVL são regulados, caso contrário a árvore não
é AVL.

7
Figura 2 AVL

2.2.1. Complexidade
A árvore AVL tem complexidade O(log n) para todas operações e ocupa espaço n,
onde n é o número de nós da árvore.

Complexidade da árvore AVL em notação O

Média Pior caso

Espaço O(n) O(n)

Busca O(log n) O(log n)

Inserção O(log n) O(log n)

Deleção O(log n) O(log n)

Tabela 1 Complexidade das árvores balanceadas

A busca é a mesma utilizada em árvore binária de busca.

A busca pela chave de valor K inicia sempre pelo nó raiz da árvore.

Seja pt_u um ponteiro para o nó u sendo verificado. Caso o pt_u seja nulo então a busca
não foi bem sucedida (K não está na árvore ou árvore vazia). Verificar se a chave K
igual pt_u->chave (valor chave armazenado no nó u), então a busca foi bem sucedida.

8
Caso contrário, se K < pt_u->chave então a busca segue pela subárvore esquerda; caso
contrário, a busca segue pela subárvore direita.

2.2.2. Aplicações
A árvore AVL é muito útil, pois executa as operações de inserção, busca e remoção em
tempo O(log n). Comparado-a com a árvore rubro-negra, a AVL é mais rápido nas
aplicações que fazem uma quantidade excessiva de buscas, porém esta estrutura é um
pouco mais lenta para inserção e remoção. Isso se deve ao fato de as árvores
AVL serem mais rigidamente balanceadas.

2.2.3. Dicionários
Árvore AVL pode ser usada para formar um dicionário de uma linguagem ou de
programas, como os opcodes de um assembler ou um interpretador.

2.2.4 Geometria Computacional


Árvore AVL pode ser usada também na geometria computacional por ser uma estrutura
muito rápida. Sem uma estrutura com complexidade O(log n) alguns algoritmos da
geometria computacional poderiam demorar dias para serem executados.

2.2.5. Conjuntos
Árvore AVL podem ser empregadas na implementação de conjuntos, principalmente
aqueles cujas chave não são números inteiros.

A complexidade das principais operações de conjuntos usando árvore AVL:

 Inserir - O(log n);


 Remover - O(log n);
 Pertence - O(log n);
 União - O(n.log n);
 Interseção - O(n.log n).

2.3. Organização Hash


É uma forma extremamente simples, fácil de se implementar e intuitiva de se organizar
grandes quantidades de dados, permite armazenar e encontrar rapidamente dados por

chave. Quando tratamos de estrutura de dados estamos sempre interessados na


eficiência de operações fundamentais de coleções, como busca, inserção e remoção.
Nesse sentido, o array, embora seja uma estrutura elementar, é um excelente escolha

9
para diversos cenários, pois nos fornece acesso, inserção e remoção em tempo O(1). Isto
é, se soubermos o índice em que um elemento está, o tempo de acesso a esse elemento é
extremamente eficiente.

Possui como idéia central a divisão de um universo de dados a ser organizado em


subconjuntos mais gerenciáveis

Possui dois conceitos centrais:

2.3.1. Tabela de Hashing: Estrutura que permite o acesso aos subconjuntos.

2.3.2. Função de Hashing: Função que realiza um mapeamento entre valores de chaves


e entradas na tabela, isto é chamado de função hashing:

 Possuir um índice que me permita encontrar o início do subconjunto certo,


depois de calcular o hashing. Isto é a tabela de hashing.
 Possuir uma ou um conjunto de estruturas de dados para os subconjuntos.
Existem duas filosofias: hashing fechado ou deendereçamento aberto ou
o hashing aberto ouencadeado.

.Possui uma série de limitações em relação às árvores:

 Não permite recuperar/imprimir todos os elementos em ordem de chave nem


tampouco outras operações que exijam seqüência dos dados.
 Não permite operações do tipo recuperar o elemento com a maior ou a menor
chave.

Constroi-se a tabela de forma a facilitar a busca, colocando-se cada elemento numa


posição pré-determinada. Tal posição é obtida aplicando-se ao elemento uma função
(função de hash) que devolve a sua posição na tabela. Daí basta verificar se o elemento
realmente está nesta posição. O objetivo então é transformar a chave de busca em um
índice na tabela

Exemplo: Construir uma tabela com os elementos 34, 45, 67, 78, 89. Vamos usar uma
tabela com 10 elementos e a função de hash x%10 (resto da divisão por 10). A tabela
ficaria.

10
i 0 1 2 3 4 5 6 7 8 9
a[i] -1 -1 -1 -1 34 45 -1 67 78 89

Tabela 2 Tabela dos elementos no ex

2.3.3. Hash e Espalhamento, a idéia central das técnicas de hash é sempre espalhar os
elementos de forma que os mesmos sejam rapidamente encontrados. Haverão elementos
vazios na tabela, mas isso não é um problema. Estamos gastando mais memória, mas
aumentando a eficiência dos algoritmos de busca.

Colisões, No caso geral, não temos informações sobre os elementos e seus valores. É
comum sabermos somente a quantidade máxima de elementos que a tabela conterá.
Assim, ainda existe um problema a ser resolvido. Como tratar os elementos cujo valor
da função de hash é o mesmo? Chamamos tal situação de colisões. Existe uma forma
simples de tratar o problema das colisões. Basta colocar o elemento na primeira posição
livre seguinte e considerar a tabela circular (o elemento seguinte ao último a[n-1] é o
primeiro a[0]). Isso se aplica tanto na inserção de novos elementos quanto na busca.
Considere os elementos acima e a função x%10. A tabela ficaria:

i 0 1 2 3 4 5 6 7 8 9
a[i] -1 -1 42 23 33 52 12 -1 58 -1

Tabela 3 segundo exemplo, colisão

2.3.4. Vantagens

 Simplicidade
o É muito fácil de imaginar um algoritmo para implementar hashing.
 Escalabilidade
o Podemos adequar o tamanho da tabela de hashing ao n esperado em
nossa aplicação.
 Eficiência para n grandes
o Para trabalharmos com problemas envolvendo n = 1.000.000 de dados,
podemos imaginar uma tabela de hashing com 2.000 entradas, onde
temos uma divisão do espaço de busca da ordem de n/2.000 de imediato.
 Aplicação imediata a arquivos

11
o Os métodos de hashing, tanto de endereçamento aberto como fechado,
podem ser utilizados praticamente sem nenhuma alteração em um
ambiente de dados persistentes utilizando arquivos em disco.

2.3.5. Desvantagens

 Dependência da escolha de função de hashing


o Para que o tempo de acesso médio ideal T(n) = c1 . (1/b).n + c2 seja
mantido, é necessário que a função de hashing divida o universo dos
dados de entrada em b conjuntos de tamanho aproximadamente igual.
 Tempo médio de acesso é ótimo somente em uma faixa
o A complexidade linear implica em um crescimento mais rápido em
relação a n do que as árvores, p.ex.
 Existe uma faixa de valores de n, determinada por b, onde o hashing será muito
melhor do que uma árvore.
o Fora dessa faixa é pior.

2.4. Grafos e sua utilização


É uma estrutura composta por um conjunto (não vazio) de pontos (vértices) e um
conjunto de linhas que ligam esses pontos (arestas).

Formalmente, um grafo é uma colecção de vértices (V) e uma colecção de arcos (E)


constituídos por pares de vértices. É uma estrutura usada para representar um modelo
em que existem relações entre os objectos de uma certa colecção.
Pense nos vértices como “locais“. O conjunto dos vértices é o conjunto de todos os
locais possíveis. Nesta analogia, os arcos (ou arestas) representam caminhos entre estes
locais. O conjunto E (vou usar o termo mais comum – “E” do inglês “edges“) contém
todas as ligações entre os locais.
 Utilizar grafos é de grande utilidade na representação de problemas da vida real.
 Podem ser cidades, e uma rede de estradas. Redes de computadores. Até mesmo
os movimentos de um cavalo num tabuleiro de xadrez podem ser representados
através de um grafo. Na prática:
 As linhas de metro das grandes cidades utilizam grafos de modo a minimizarem
o tempo das ligações;
 A distribuição de correio, minimizando percursos de forma a optimizar as
deslocações, tanto para um único carteiro como para uma equipa (o mesmo se
aplica a empresas de distribuição);
 Os sistemas de patrulha da PSP permitem estudos de optimização recorrendo a
grafos.

12
2.4.1. Representação
Graficamente, um grafo é normalmente representado da seguinte forma:
Figura 3 Grafo com 3 vértices {0, 1, 2} e 3 arestas {a, b, c}

Figura 4 Grafo com 6 vértices

Vértices são pontos ou círculos; arcos são linhas entre eles.

Usando o primeiro exemplo, V = {1, 2, 3, 4, 5, 6} e E = {(1,3), (1,6), (2,5), (3,4), (3,6)}.
Cada vértice (também chamado “nó“) é um membro do conjunto V. Cada arco é um
membro do conjunto E.
2.4.2. Terminologia
Como é de esperar, tendo aplicações tão variadas, o grafo adapta-se às nossas
necessidades. Assim, existem vários tipos de grafos. Aliados a isso, existem termos
comummente usados para descrever um grafo, ou parte dele. Vou listar alguns (entre
eles os mais comuns):

2.4.3. Vértice isolado


Um vértice é considerado isolado se não possuir nenhuma ligação a outro vértice (bastante
óbvio).

13
2.4.4 Grafo trivial (ou ponto)
Grafo sem arestas e um único nó.

2.4.5. Laço (ou loop/self-loop)


Um arco é um laço se em ambas as extremidades estiver o mesmo vértice (nenhum dos grafos
apresentados possui laços).

2.4.6. Grafo simples


Um grafo é simples se não contiver laços nem arcos repetidos em E.

2.4.7. Vértices adjacentes


Dois vértices (u e v) são adjacentes se existir um arco que possui uma extremidade em u e outra
em v. Os vizinhos de um vértice são todos os vértices adjacentes a ele.

2.4.8. Grafo pesado (ou grafo de arcos pesados)


A cada aresta está associado um valor. Pode ser uma distância, um custo, seja o que for.

Uma definição similar existe para grafo de nós pesados.


2.4.9. Grau de um vértice(ou valência)
O grau de um vértice é o número de arcos que lhe são incidentes. Um arco  (u,v) é incidente
tanto no vértice u como no vértice v.

Pode-se distinguir grau de entrada e grau de saída em grafos direccionados (ver à


frente).

2.4.10. Grafo direccionado


Cada arco tem um nó de origem e um nó de chegada. O exemplo típico é o das redes de
estradas, uma vez que existem estradas só com um sentido seria o caos se um GPS não soubesse
distingui-las.

2.4.11. Matriz de adjacência


Esta é uma representação bastante fácil de programar, mas bastante pouco eficiente em
termos de memória.

Consiste uma matriz N x N (onde N é um número de vértices) onde (i,j) indica se existe


uma ligação do vértice i para o vértice j. Alternativamente, pode representar o tamanho
dessa ligação.
 Vantagens:

Fácil de programar.
Pode representar um grafo pesado sem comprometer a complexidade.
Caso o grafo não seja pesado e seja possível existir mais do que uma ligação entre
dois vértices, (i,j) pode representar o número de ligações entre eles.

14
Verificar se dois vértices são adjacentes é muito rápido, tal como adicionar ou
remover ligações.
 Desvantagens:

Elevado desperdício de memória (especialmente se o grafo for disperso).


Debugging é difícil, uma vez que a matriz tende a ser grande.
Listar todas as arestas incidentes num dado vértice é demorado (força-nos a percorrer
todos os vértices).

V1 V1 V2 V3 V4 V5 V6

V1 0 0 1 0 0 1

V2 0 0 0 0 1 0

V3 1 0 0 1 0 1

V4 0 0 1 0 0 0

V5 0 1 0 0 0 0

V6 1 0 1 0 0 0

Tabela 2 Matriz de adjacência

2.4.12. Listas de adjacência

Nesta representação limitamos-nos a guardar a informação de todas as arestas


incidentes num dado vértice.

Isto pode ser feito usando um vector de tamanho V (número de vértices),


onde v[ i ] guardará a lista dos arcos ou vértices conectados ao vértice i.
A maneira de guardar estes vértices/arcos varia, dependendo da linguagem, podendo-
se usar listas encadeadas ou mesmo transformar o vector numa matriz.

Vantagens:

 Listar todas as arestas incidentes num dado vértice é fácil (a operação mais frequente na
maioria dos algoritmos).

15
 Baixo desperdício de memória.
Desvantagens:

 Dependendo da implementação, difícil de programar.


 Representar um grafo pesado implica uma matriz de estruturas ou mais um campo na
lista encadeada.
 Para verificar se dois vértices são adjacentes necessitamos de percorrer todos os vértices
adjacentes a um deles.

Mais uma vez, o primeiro grafo fornecido poderia ser representado desta forma:

Vértice Vértices Adjacentes

1 3, 6

2 5

3 1, 4, 6

4 3

5 2

6 1, 3

Tabela 3 Vértices adjacentes

2.4.13. Aplicações dos grafos

Modelagem de Circuitos Eletrônicos:

 Placas de circuito impresso.


 Circuitos integrados.

Redes de Transporte:

 Representação de Rodovias.
 Representação de Rodovias.
 Mapa de Vôos

Redes de Computadores:

16
 Redes Locais.
 Internet.

Bancos de Dados:

 Diagrama Entidade-Relacionamento.

2.5. Representação de listas em memória externa


O armazenamento secundário (também conhecido como memória
externa ou armazenamento auxiliar) difere do armazenamento primário por não ser
diretamente acessível pela unidade de processamento central (CPU) . O computador
geralmente usa seus canais de entrada/saída para acessar o armazenamento secundário e
transferir os dados desejados para o armazenamento primário. O armazenamento
secundário não é volátil (retém os dados quando a alimentação é desligada). Os sistemas
de computador modernos normalmente têm duas ordens de magnitude a mais de
armazenamento secundário do que o armazenamento primário porque o armazenamento
secundário é mais barato.

Lista linear é uma estrutura de dados na qual elementos de um mesmo tipo de dado
estão organizados de maneira sequencial. Não necessariamente, estes elementos estão
fisicamente em sequência, mas a idéia é que exista uma ordem lógica entre eles. Um
exemplo disto seria um consultório médico: as pessoas na sala de espera estão sentadas
em qualquer lugar, porém sabe-se quem é o próximo a ser atendido, e o seguinte, e
assim por diante. Assim, é importante ressaltar que uma lista linear permite representar
um conjunto de dados afins (de um mesmo tipo) de forma a preservar a relação de
ordem entre seus elementos. Cada elemento da lista é chamado de nó, ou nodo

Quanto a forma de alocar memória para armazenamento de seu elementos, uma lista
pode ser:

 Sequencial ou Contígua

Numa lista linear contígua, os nós além de estarem em uma sequência lógica, estão
também fisicamente em sequência. A maneira mais simples de acomodar uma lista
linear em um computador é através da utilização de um vetor.

17
Figura 5 Ilustração da lista na memória

A representação por vetor explora a sequencialidade da memória de tal forma que os


nós de uma lista sejam armazenados em endereços contíguos.

 Encadeada

Os elementos não estão necessariamente armazenados sequencialmente na memória,


porém a ordem lógica entre os elementos que compõem a lista deve ser mantida.

Figura 6 Ilustração do vetor

Repare que temos um vetor de inteiros, certo? E esse vetor possui 10 posições.

Cada uma das posições é ocupada por um int, e sabemos que o tipo primitivo int tem
um tamanho que equivale a 4 bytes, conforme vemos na tabela abaixo:

Figura 7 Tipos de variáveis

Tamanho do tipo int = 32bits

1 byte = 8 bits

18
32/8 = 4 bytes

Os elementos do vetor são armazenados sequencialmente na memória do


computador.

Assim, na figura, se cada valor de tipo int ocupar 4 bytes de memória, teremos 40 bytes
consecutivos reservados na memória do computador para armazenar todos os valores do
vetor.

3. Referências
Árvore binária de busca. (11 de Março de de 2021). Obtido de Árvore binária de busca:
https://pt.wikipedia.org/wiki/%C3%81rvore_bin%C3%A1ria_de_busca
Baranauskas, J. A. (2007). Árvores Binárias de Busca. Obtido de Árvores Binárias de
Busca: extension://bfdogplmndidlpjfhoijckpakkdjkkil/pdf/viewer.html?
file=https%3A%2F%2Fdcm.ffclrp.usp.br%2F~augusto%2Fteaching%2Faedi
%2FAED-I-Arvores-Binarias-Busca.pdf
Ribeiro, P. (06 de Maio de 2012). CASA DAS CIÊNCIAS. Obtido de CASA DAS
CIÊNCIAS: https://wikiciencias.casadasciencias.org/wiki/index.php/Grafo
Rodrigues, G. C. (18 de Junho de 2021). alura. Obtido de Referência do vetor na
memória: https://cursos.alura.com.br/forum/topico-referencia-do-vetor-na-
memoria-157028
Vale, S. (27 de Junho de 2020). Voitto. Obtido de Artigos salvos:
https://www.voitto.com.br/blog/artigo/o-que-e-hash-e-como-funciona

19

Você também pode gostar