Die meisten der Antworten hier sind falsch . Die richtige Antwort lautet es kommt darauf an . Hier sind zum Beispiel zwei C-Funktionen, die einen Baum durchlaufen. Zuerst die rekursive Funktion:
static
void mm_scan_black(mm_rc *m, ptr p) {
SET_COL(p, COL_BLACK);
P_FOR_EACH_CHILD(p, {
INC_RC(p_child);
if (GET_COL(p_child) != COL_BLACK) {
mm_scan_black(m, p_child);
}
});
}
Und hier ist die gleiche Funktion, die mit Iteration implementiert wurde:
static
void mm_scan_black(mm_rc *m, ptr p) {
stack *st = m->black_stack;
SET_COL(p, COL_BLACK);
st_push(st, p);
while (st->used != 0) {
p = st_pop(st);
P_FOR_EACH_CHILD(p, {
INC_RC(p_child);
if (GET_COL(p_child) != COL_BLACK) {
SET_COL(p_child, COL_BLACK);
st_push(st, p_child);
}
});
}
}
Es ist nicht wichtig, die Details des Codes zu verstehen. Nur das p
Knotenpunkte sind und dass P_FOR_EACH_CHILD
macht den Spaziergang. In der iterativen Version benötigen wir einen expliziten Stapel st
auf die die Knoten geschoben und dann gepoppt und manipuliert werden.
Die rekursive Funktion läuft viel schneller als die iterative. Der Grund dafür ist, dass bei letzterer für jedes Element eine CALL
auf die Funktion st_push
benötigt wird und dann eine weitere an st_pop
.
Im ersten Fall haben Sie nur die rekursive CALL
für jeden Knoten.
Außerdem ist der Zugriff auf Variablen auf dem Aufrufstapel unglaublich schnell. Es bedeutet, dass Sie aus dem Speicher lesen, der sich wahrscheinlich immer im innersten Cache befindet. Ein expliziter Stack hingegen muss durch malloc
:ed Speicher aus dem Heap, auf den viel langsamer zugegriffen werden kann.
Bei sorgfältiger Optimierung, wie z. B. dem Inlining st_push
y st_pop
kann ich mit dem rekursiven Ansatz annähernd Parität erreichen. Aber zumindest auf meinem Computer sind die Kosten für den Zugriff auf den Heap-Speicher höher als die Kosten für den rekursiven Aufruf.
Aber diese Diskussion ist größtenteils überflüssig, denn rekursives Baumlaufen ist falsch . Wenn der Baum groß genug ist, wird der Platz im Aufrufstapel knapp, weshalb ein iterativer Algorithmus verwendet werden muss.