Quase todo projeto que possui algum modelo ou documento editável terá uma estrutura hierárquica. Pode ser útil implementar o 'nó hierárquico' como uma classe base para diferentes entidades. Frequentemente, a lista vinculada (irmão filho, segundo modelo) é a maneira natural de muitas bibliotecas de classes crescerem, no entanto, os filhos podem ser de diversos tipos e, provavelmente, um " modelo de objeto " não é o que consideramos quando se fala em árvores em geral.
Minha implementação favorita de uma árvore (nó) do seu primeiro modelo é uma linha (em C #):
public class node : List<node> { /* props go here */ }
Herdar de uma lista genérica do seu próprio tipo (ou herdar de qualquer outra coleção genérica do seu próprio tipo). É possível caminhar em uma direção: formar a raiz para baixo (os itens não conhecem seus pais).
Árvore apenas dos pais
Outro modelo que você não mencionou é aquele em que toda criança faz referência ao pai:
null
|
+---------+---------------------------------+
| parent |
| root |
+-------------------------------------------+
| | |
+---------+------+ +-------+--------+ +--+-------------+
| parent | | parent | | parent |
| node 1 | | node 2 | | node 3 |
+----------------+ +----------------+ +----------------+
Andar nessa árvore só é possível ao contrário, normalmente todos esses nós serão armazenados em uma coleção (matriz, hashtable, dicionário etc.) e um nó será localizado pesquisando a coleção em critérios diferentes da posição hierárquica no árvore que normalmente não seria de importância primária.
Essas árvores somente para pais são geralmente vistas em aplicativos de banco de dados. É muito fácil encontrar os filhos de um nó com instruções "SELECT * WHERE ParentId = x". No entanto, raramente os encontramos transformados em objetos de classe de nó de árvore, como tal. Em aplicativos statefull (desktop), eles podem ser agrupados em controles de nó de árvore existentes. Em aplicativos sem estado (web), mesmo isso pode ser improvável. Vi ferramentas de gerador de classe de mapeamento ORM gerarem erros de estouro de pilha ao gerar classes para tabelas que têm uma relação consigo mesma (risos), então talvez essas árvores não sejam tão comuns assim.
árvores navegáveis bidirecionais
Na maioria dos casos práticos, no entanto, é conveniente ter o melhor dos dois mundos. Os nós que possuem uma lista de filhos e também conhecem seus pais: árvores navegáveis bidirecionais.
null
|
+--------------------+--------------------+
| parent |
| root |
| child1 child2 child3 |
+--+------------------+----------------+--+
| | |
+---------+-----+ +-------+-------+ +---+-----------+
| parent | | parent | | parent |
| node1 | | node2 | | node3 |
| child1 child2 | | child1 child2 | | child1 child2 |
+--+---------+--+ +--+---------+--+ +--+---------+--+
| | | | | |
Isso traz muitos outros aspectos a serem considerados:
- Onde implementar a vinculação e desvinculação dos pais?
- deixe a lógica do negócio tomar cuidado e deixe o aspecto fora do nó (eles esquecerão!)
- os nós têm métodos para criar filhos (não permitem reordenar) (escolha Microsofts na implementação do DOM System.Xml.XmlDocument, que quase me deixou maluco quando o encontrei pela primeira vez)
- Nós assumem um pai em seu construtor (não permite reordenar)
- em todos os métodos add (), insert () e remove () e suas sobrecargas nos nós (geralmente minha escolha)
- Persistência
- Como percorrer a árvore ao persistir (deixe de fora os links dos pais, por exemplo)
- Como reconstruir o vínculo bidirecional após a desserialização (configurando todos os pais novamente como uma ação pós-desserialização)
- Notificações
- Mecanismos estáticos (sinalizador IsDirty), manipulam recursivamente nas propriedades?
- Eventos, borbulham nos pais, nos filhos ou nos dois sentidos (considere a bomba de mensagens do Windows, por exemplo).
Agora, para responder à pergunta , as árvores navegáveis bidirecionais tendem a ser (na minha carreira e campo até agora) as mais utilizadas. Os exemplos são a implementação de System.Windows.Forms.Control ou System.Web.UI.Control na estrutura .Net da Microsoft, mas também toda implementação de DOM (Document Object Model) terá nós que conhecem seus pais e uma enumeração dos filhos deles. O motivo: facilidade de uso sobre facilidade de implementação. Além disso, essas geralmente são classes base para classes mais específicas (XmlNode pode ser a base das classes Tag, Attribute e Text) e essas classes base são locais naturais para colocar arquiteturas genéricas de serialização e manipulação de eventos.
O Tree está no centro de muitas arquiteturas, e poder navegar livremente significa poder implementar soluções mais rapidamente.