Ce n'est pas un devoir, c'est une question d'entrevue.
Le problème ici est que l'algorithme doit être un espace constant ... Je ne sais pas trop comment le faire sans pile, je posterais ce que j'ai écrit avec une pile, mais ce n'est pas pertinent de toute façon.
Voici ce que j'ai essayé: j'ai essayé de faire une traversée de pré-commande et je suis arrivé au nœud le plus à gauche, mais je suis coincé là. Je ne sais pas comment "recurse" sauvegarder sans un pointeur pile/parent.
Toute aide serait appréciée.
(Je le nomme comme Java car c'est ce que je suis à l'aise d'utiliser, mais c'est assez agnostique comme on peut le voir.)
Je n'y ai pas bien réfléchi, mais je pense que c'est possible tant que vous êtes prêt à tout gâcher.
Chaque nœud a 2 pointeurs, il peut donc être utilisé pour représenter une liste doublement chaînée. Supposons que vous passiez de Root à Root.Left = Current. Le pointeur Root.Left étant désormais inutile, affectez-le à Current.Right et passez à Current.Left. Au moment où vous atteignez l'enfant le plus à gauche, vous aurez une liste chaînée avec des arbres suspendus à certains nœuds. Maintenant, parcourez cela en répétant le processus pour chaque arbre que vous rencontrez au fur et à mesure
EDIT: réfléchi. Voici l'algorithme qui imprime dans l'ordre:
void traverse (Node root) {
traverse (root.left, root);
}
void traverse (Node current, Node parent) {
while (current != null) {
if (parent != null) {
parent.left = current.right;
current.right = parent;
}
if (current.left != null) {
parent = current;
current = current.left;
} else {
print(current);
current = current.right;
parent = null;
}
}
}
Qu'en est-il de la traversée d'arbres Morris Inorder? Il est basé sur la notion d’arbres threadés et modifie l’arbre, mais le rétablit quand il est terminé.
Linkie: http://geeksforgeeks.org/?p=6358
N'utilise pas d'espace supplémentaire.
Si vous utilisez une arborescence basée sur un pointeur descendant et que vous n'avez pas de pointeur parent ou une autre mémoire, il est impossible de le parcourir dans un espace constant.
Cela est possible si votre arbre binaire est dans un tableau au lieu d'une structure d'objet basée sur un pointeur. Mais alors vous pouvez accéder directement à n’importe quel nœud. Ce qui est une sorte de tricherie ;-)
Voici une version abrégée de réponse originale ..__ de iluxa. Il exécute exactement les mêmes étapes de manipulation et d'impression des nœuds, dans le même ordre, mais de manière simplifiée [1]:
void traverse (Node n) {
while (n) {
Node next = n.left;
if (next) {
n.left = next.right;
next.right = n;
n = next;
} else {
print(n);
n = n.right;
}
}
}
[1] De plus, cela fonctionne même lorsque le nœud racine de l’arbre n’a pas d’enfant de gauche.
Le titre de la question ne mentionne pas l'absence de pointeur "parent" dans le nœud. Bien que cela ne soit pas nécessairement requis pour BST, de nombreuses implémentations d'arborescence binaire ont un pointeur parent . Classe Node { Nœud * à gauche; Node * right; Nœud * parent; DONNÉES données; };
Si tel est le cas, créez un diagramme de l’arbre sur du papier et dessinez avec un crayon autour de l’arbre, en montant et en descendant des deux côtés des bords (en descendant, vous resterez à gauche du bord, et en montant, vous serez du côté droit). Fondamentalement, il y a 4 états:
Traverse( Node* node )
{
enum DIRECTION {SW, NE, SE, NW};
DIRECTION direction=SW;
while( node )
{
// first, output the node data, if I'm on my way down:
if( direction==SE or direction==SW ) {
out_stream << node->data;
}
switch( direction ) {
case SW:
if( node->left ) {
// if we have a left child, keep going down left
node = node->left;
}
else if( node->right ) {
// we don't have a left child, go right
node = node->right;
DIRECTION = SE;
}
else {
// no children, go up.
DIRECTION = NE;
}
break;
case SE:
if( node->left ) {
DIRECTION = SW;
node = node->left;
}
else if( node->right ) {
node = node->right;
}
else {
DIRECTION = NW;
}
break;
case NE:
if( node->right ) {
// take a u-turn back to the right node
node = node->right;
DIRECTION = SE;
}
else {
node = node->parent;
}
break;
case NW:
node = node->parent;
break;
}
}
}
C'est un arbre de recherche, vous pouvez donc toujours obtenir la prochaine clé/entrée
Vous avez besoin de quelque chose comme (je n'ai pas testé le code, mais c'est aussi simple que cela)
Java.util.NavigableMap<K, V> map=...
for (Entry<K, V> e = map.firstEntry(); e!=null; e = map.higherEntry(e.getKey())) {
process(e)
}
pour plus de clarté, c'est higherEntry
, donc ce n'est pas récursif. Voilà :)
final Entry<K,V> getHigherEntry(K key) {
Entry<K,V> p = root;
while (p != null) {
int cmp = compare(key, p.key);
if (cmp < 0) {
if (p.left != null)
p = p.left;
else
return p;
} else {
if (p.right != null) {
p = p.right;
} else {
Entry<K,V> parent = p.parent;
Entry<K,V> ch = p;
while (parent != null && ch == parent.right) {
ch = parent;
parent = parent.parent;
}
return parent;
}
}
}
return null;
}
La réponse acceptée nécessite la modification suivante, sinon elle n'imprimera pas l'arborescence dans laquelle le fichier BST ne comporte qu'un seul nœud.
if (current == NULL && root != NULL)
print(root);
cas spécial mineur pour la réponse iluxa ci-dessus
if(current== null)
{
current = root;
parent = current.Right;
if(parent != null)
{
current.Right = parent.Left;
parent.Left = current;
}
}