As estruturas de dados trie e radix trie são a mesma coisa?
Se eles são iguais, então qual é o significado de trie radical (também conhecido como trie Patricia)?
algorithm
data-structures
tree
patricia-trie
radix-tree
Aryak Sengupta
fonte
fonte
radix-tree
vez deradix-trie
? Além disso, existem algumas questões marcadas com ele.radix trie
artigo comoRadix tree
. Além disso, o termo "árvore Radix" é amplamente utilizado na literatura. Se qualquer coisa, chamar uma tentativa de "árvores de prefixo" faria mais sentido para mim. Afinal, são todas estruturas de dados em árvore .radix = 2
, o que significa que você atravessa a árvore procurando porlog2(radix)=1
bits da string de entrada de cada vez.Respostas:
Uma árvore raiz é uma versão compactada de um trie. Em um trie, em cada borda você escreve uma única letra, enquanto em uma árvore PATRICIA (ou árvore raiz) você armazena palavras inteiras.
Agora, suponha que você tenha as palavras
hello
,hat
ehave
. Para armazená-los em um trie , seria semelhante a:E você precisa de nove nós. Coloquei as letras nos nós, mas na verdade elas identificam as bordas.
Em uma árvore raiz, você terá:
e você precisa de apenas cinco nós. Na imagem acima, os nós são os asteriscos.
Portanto, no geral, uma árvore raiz ocupa menos memória , mas é mais difícil de implementar. Caso contrário, o caso de uso de ambos é praticamente o mesmo.
fonte
Resumindo, não. A categoria Radix Trie descreve uma categoria particular de Trie , mas isso não significa que todas as tentativas são tentativas radix.
Suponho que você pretendia escrever não está em sua pergunta, daí minha correção.
Da mesma forma, PATRICIA denota um tipo específico de trie raiz, mas nem todas as tentativas raiz são tentativas PATRICIA.
O que é um trie?
"Trie" descreve uma estrutura de dados em árvore adequada para uso como um array associativo, onde ramos ou arestas correspondem a partes de uma chave. A definição de partes é um tanto vaga, aqui, porque diferentes implementações de tentativas usam diferentes comprimentos de bit para corresponder às arestas. Por exemplo, um trie binário tem duas arestas por nó que correspondem a 0 ou 1, enquanto um trie de 16 vias tem dezesseis arestas por nó que correspondem a quatro bits (ou um dígito hexadecimal: 0x0 a 0xf).
Este diagrama, recuperado da Wikipedia, parece representar um trie com (pelo menos) as chaves 'A', 'para', 'chá', 'ted', 'dez' e 'pousada' inseridas:
Se este teste fosse armazenar itens para as chaves 't', 'te', 'i' ou 'in', seria necessário haver informações extras presentes em cada nó para distinguir entre nós nulos e nós com valores reais.
O que é um radix trie?
"Radix trie" parece descrever uma forma de trie que condensa partes de prefixos comuns, como Ivaylo Strandjev descreveu em sua resposta. Considere que um trie de 256 vias que indexa as teclas "smile", "sorriu", "sorri" e "sorrindo" usando as seguintes atribuições estáticas:
Cada subscrito acessa um nó interno. Isso significa que para recuperar
smile_item
, você deve acessar sete nós. Oito acessos de nó correspondem asmiled_item
esmiles_item
, e nove asmiling_item
. Para esses quatro itens, há quatorze nós no total. Todos eles têm os primeiros quatro bytes (correspondentes aos primeiros quatro nós) em comum, no entanto. Ao condensar esses quatro bytes para criar umroot
que corresponde a['s']['m']['i']['l']
, quatro acessos de nó foram otimizados. Isso significa menos memória e menos acessos a nós, o que é uma indicação muito boa. A otimização pode ser aplicada recursivamente para reduzir a necessidade de acessar bytes de sufixo desnecessários. Eventualmente, você chega a um ponto em que está apenas comparando as diferenças entre a chave de pesquisa e as chaves indexadas em locais indexados pelo trie. Este é um trie radical.Para recuperar itens, cada nó precisa de uma posição. Com uma chave de busca de "sorrisos" e
root.position
4, acessamosroot["smiles"[4]]
, que por acaso éroot['e']
. Armazenamos isso em uma variável chamadacurrent
.current.position
é 5, que é o local da diferença entre"smiled"
e"smiles"
, portanto, o próximo acesso serároot["smiles"[5]]
. Isso nos leva aosmiles_item
fim de nossa string. Nossa pesquisa terminou e o item foi recuperado, com apenas três acessos de nó em vez de oito.O que é um trie PATRICIA?
Um trie PATRICIA é uma variante de tentativas radix para as quais deve haver apenas
n
nós usados para contern
itens. No nosso trie pseudocódigo radix grosseiramente demonstrado acima, há cinco nós no total:root
(que é um nó nullary, que não contém nenhum valor real),root['e']
,root['e']['d']
,root['e']['s']
eroot['i']
. Em um teste PATRICIA deve haver apenas quatro. Vamos dar uma olhada em como esses prefixos podem diferir olhando para eles em binário, já que PATRICIA é um algoritmo binário.Vamos considerar que os nós são adicionados na ordem em que são apresentados acima.
smile_item
é a raiz desta árvore. A diferença, em negrito para torná-lo um pouco mais fácil de localizar, está no último byte de"smile"
, no bit 36. Até este ponto, todos os nossos nós têm o mesmo prefixo.smiled_node
pertence asmile_node[0]
. A diferença entre"smiled"
e"smiles"
ocorre no bit 43, onde"smiles"
tem um bit '1', entãosmiled_node[1]
ésmiles_node
.Ao invés de usar
NULL
como sucursais e / ou informação interna adicional para indicar quando uma pesquisa termina, os ramos ligar de volta até o lugar da árvore, então uma busca termina quando o deslocamento para teste diminui em vez de aumentar. Aqui está um diagrama simples de tal árvore (embora PATRICIA realmente seja mais um gráfico cíclico do que uma árvore, como você verá), que foi incluído no livro de Sedgewick mencionado abaixo:Um algoritmo PATRICIA mais complexo envolvendo chaves de comprimento variante é possível, embora algumas das propriedades técnicas de PATRICIA sejam perdidas no processo (ou seja, que qualquer nó contém um prefixo comum com o nó anterior a ele):
Ramificando assim, há uma série de benefícios: Cada nó contém um valor. Isso inclui a raiz. Como resultado, o comprimento e a complexidade do código se tornam muito mais curtos e provavelmente um pouco mais rápidos na realidade. Pelo menos um ramo e no máximo
k
ramos (ondek
é o número de bits na chave de pesquisa) são seguidos para localizar um item. Os nós são minúsculos , pois armazenam apenas duas ramificações cada, o que os torna bastante adequados para otimização de localidade do cache. Essas propriedades fazem de PATRICIA meu algoritmo favorito até agora ...Vou encurtar essa descrição aqui, a fim de reduzir a gravidade da minha artrite iminente, mas se você quiser saber mais sobre PATRICIA, pode consultar livros como "The Art of Computer Programming, Volume 3" de Donald Knuth , ou qualquer um dos "Algoritmos em {seu-idioma-favorito}, partes 1-4" de Sedgewick.
fonte
TRIE:
Podemos ter um esquema de pesquisa em que, em vez de comparar uma chave de pesquisa inteira com todas as chaves existentes (como um esquema de hash), também podemos comparar cada caractere da chave de pesquisa. Seguindo essa ideia, podemos construir uma estrutura (conforme mostrado abaixo) que possui três chaves existentes - “ dad ”, “ dab ” e “ cab ”.
Esta é essencialmente uma árvore M-ária com nó interno, representado como [*] e nó folha, representado como []. Essa estrutura é chamada de trie . A decisão de ramificação em cada nó pode ser mantida igual ao número de símbolos únicos do alfabeto, digamos R. Para alfabetos ingleses minúsculos az, R = 26; para alfabetos ASCII estendidos, R = 256 e para dígitos binários / strings R = 2.
TRIE compacto:
Normalmente, um nó em um trie usa uma matriz com tamanho = R e, portanto, causa desperdício de memória quando cada nó tem menos arestas. Para contornar a preocupação com a memória, várias propostas foram feitas. Com base nessas variações, os trie também são chamados de " trie compacto " e " trie compactado ". Embora uma nomenclatura consistente seja rara, uma versão mais comum de um trie compacto é formada pelo agrupamento de todas as arestas quando os nós têm aresta única. Utilizando este conceito, o acima (Fig-I) trie com teclas de “pai”, “dab”, e “cab” pode tomar abaixo formulário.
Observe que cada um de 'c', 'a' e 'b' é a única aresta de seu nó pai correspondente e, portanto, eles são conglomerados em uma única aresta “cab”. Da mesma forma, 'd' e a 'são mesclados em uma única aresta rotulada como “da”.
Radix Trie:
O termo radix , em matemática, significa uma base de um sistema numérico e indica essencialmente o número de símbolos únicos necessários para representar qualquer número nesse sistema. Por exemplo, o sistema decimal é a raiz dez e o sistema binário é a raiz dois. Usando o conceito semelhante, quando estamos interessados em caracterizar uma estrutura de dados ou um algoritmo pelo número de símbolos únicos do sistema representacional subjacente, marcamos o conceito com o termo “raiz”. Por exemplo, “classificação básica” para determinado algoritmo de classificação. Na mesma linha de lógica, todas as variantes do triecujas características (como profundidade, necessidade de memória, tempo de execução de busca / acerto, etc.) dependem da raiz dos alfabetos subjacentes, podemos chamá-los de “trie” de raiz. Por exemplo, tanto um trie não compactado quanto um compactado quando usa alfabetos az, podemos chamá-lo de trie raiz 26 . Qualquer trie que usa apenas dois símbolos (tradicionalmente '0' e '1') pode ser chamado de trie raiz 2 . No entanto, de alguma forma, muitas literaturas restringiram o uso do termo “Radix Trie” apenas para o trie compactado .
Prelúdio à Árvore / Teste de PATRICIA:
Seria interessante notar que até mesmo strings como chaves podem ser representadas usando alfabetos binários. Se assumirmos a codificação ASCII, então uma chave “dad” pode ser escrita na forma binária, escrevendo a representação binária de cada caractere em sequência, digamos como “ 01100100 01100001 01100100 ” escrevendo as formas binárias de 'd', 'a' e 'd' sequencialmente. Usando este conceito, um trie (com Radix Two) pode ser formado. Abaixo, descrevemos esse conceito usando uma suposição simplificada de que as letras 'a', 'b', 'c' e 'd' são de um alfabeto menor em vez de ASCII.
Nota para a Fig-III: como mencionado, para facilitar a representação, vamos supor um alfabeto com apenas 4 letras {a, b, c, d} e suas representações binárias correspondentes são “00”, “01”, “10” e “11” respectivamente. Com isso, nossas teclas de string “dad”, “dab” e ”cab” tornam-se “110011”, “110001” e “100001” respectivamente. A tentativa para isso será mostrada abaixo na Fig-III (os bits são lidos da esquerda para a direita, assim como as strings são lidas da esquerda para a direita).
PATRICIA Trie / Tree:
Se compactarmos o trie binário acima (Fig-III) usando compactação de borda única, ele teria muito menos nós do que mostrado acima e, ainda assim, os nós ainda seriam mais do que 3, o número de chaves que contém . Donald R. Morrison descobriu (em 1968) uma maneira inovadora de usar o trie binário para representar N chaves usando apenas N nós e chamou essa estrutura de dados de PATRICIA. Sua estrutura trie essencialmente se livrou de arestas únicas (ramificação unilateral); e, ao fazer isso, ele também se livrou da noção de dois tipos de nós - nós internos (que não representam nenhuma chave) e nós folha (que representam chaves). Ao contrário da lógica de compactação explicada acima, seu teste usa um conceito diferente em que cada nó inclui uma indicação de quantos bits de uma chave devem ser ignorados para tomar uma decisão de ramificação. Ainda outra característica de seu teste PATRICIA é que ele não armazena as chaves - o que significa que tal estrutura de dados não será adequada para responder a perguntas como listar todas as chaves que correspondem a um determinado prefixo , mas é bom para descobrir se existe uma chave ou não está no teste. No entanto, o termo Patricia Tree ou Patricia Trie tem, desde então, sido usado em muitos sentidos diferentes, mas semelhantes, como, para indicar um trie compacto [NIST], ou para indicar um trie de raiz com raiz dois [conforme indicado em um sutil maneira em WIKI] e assim por diante.
Trie que pode não ser uma Trie Radix: Trie de
Busca Ternária (também conhecida como Árvore de Busca Ternária) freqüentemente abreviada como TST é uma estrutura de dados (proposta por J. Bentley e R. Sedgewick ) que se parece muito com um trie com ramificação de três vias. Para tal árvore, cada nó tem um alfabeto característico 'x', de modo que a decisão de ramificação é determinada pelo fato de um caractere de uma chave ser menor, igual ou maior que 'x'. Devido a esse recurso fixo de ramificação de 3 vias, ele fornece uma alternativa eficiente em termos de memória para o trie, especialmente quando R (raiz) é muito grande, como para alfabetos Unicode. Curiosamente, o TST, ao contrário do trie (R-way) , não tem suas características influenciadas por R. Por exemplo, a falha de pesquisa do TST é ln (N)em oposição ao log R (N) para R-way Trie. Os requisitos de memória do TST, ao contrário do R-way trie é não uma função de R também. Portanto, devemos ter o cuidado de chamar um TST de radix-trie. Eu, pessoalmente, não acho que devemos chamá-lo de raiz-trie, uma vez que nenhuma (até onde eu sei) de suas características é influenciada pela raiz, R, de seus alfabetos subjacentes.
fonte
uintptr_t
como seu inteiro , uma vez que esse tipo parece ser normalmente esperado (embora não obrigatório).