Binary Search Tree, Speicher wieder freiegeben
-
Habs lokaler gekriegt (normalerweise).
~bstree() { if(!root) return;//einfach gut, weil doch viele //Destruktor-Aufrufe auf einem leeren bstree geschehen. Node* r=root; while(r){ if(!r.left){//weg Node* toDie=r; r=r->right; delete toDie; } else if(!r.right){//weg Node* toDie=r; r=r->left; delete toDie; } else{//rotieren an der root! Die wird nämlich als nächstes bearbeitet. //Ist jetzt ein Stack statt einer Queue für die vertagten Jobs. //Gute Vermutung, daß Löschungen relativ nah nach Rotierungen kommen, //also der Mist noch im Cache ist. Perfekt für Bäume, die "quasi" ballanciert //sind, in normalen Anwendungsfällen "quasi" immer, aber man kann's //nicht garantieren. Node* e=r->left->right; Node* newR=r->left; newR->right=r; r->left=e; r=newR; } } } //ungetestet
-
if(!root) return;//einfach gut, weil doch viele //Destruktor-Aufrufe auf einem leeren bstree geschehen.Aber dir ist doch sicher klar dass die logisch komplett äquivalente Abfrage 2 Zeilen darunter sowieso durchgeführt wird und das Ganze keinen Takt langsamer ist?

-
Ethon schrieb:
if(!root) return;//einfach gut, weil doch viele //Destruktor-Aufrufe auf einem leeren bstree geschehen.Aber dir ist doch sicher klar dass die logisch komplett äquivalente Abfrage 2 Zeilen darunter sowieso durchgeführt wird und das Ganze keinen Takt langsamer ist?

Uups!!!

Wie offensichtlich!!!
*lach*Habe mich ums Rotieren gequält. Bäume sind nicht mein Ding eigentlich. Fast immer gibt es bessere Alternativen. War heldenfroh, es gepackt zu haben. Habe zwar sofort gesehen, daß es so möglich ist, Algos mögen mich irgendwie, aber die Reihenfolge der elemetaren Zuweisungen, nööö, da habe ich keine Intuition. Eher eine Drecksintuition. Hätte an der Hochschule bleiben müssen, damit Doktoranden für mich den lästigen Quark ausarbeiten. *hihi*
Produktivcode wäre das nicht bei mir geworden. Ich schaue mir immer was funktionierendes nochmal später an. Wobei ich dem gcc sogar zutraue, daß er das auch packt, der ist ein Monster.
-
volkard schrieb:
Wobei ich dem gcc sogar zutraue, daß er das auch packt, der ist ein Monster.
Für den rb-tree jedenfalls nicht, da arbeitet der Algorithmus rekursiv (in-oder mit ausgeschriebener Tail-Rekursion). Da der Baum immer ausbalanciert ist, kann man hier Stacküberläufe ausschliessen. Wie es mit internen Datenstrukturen des Compilers aussieht, weiss ich nicht.
aus /usr/lib/gcc/x86_64-pc-linux-gnu/4.8.1/include/g++-v4/bits/stl_tree.h
template<typename _Key, typename _Val, typename _KeyOfValue, typename _Compare, typename _Alloc> void _Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>:: _M_erase(_Link_type __x) { // Erase without rebalancing. while (__x != 0) { _M_erase(_S_right(__x)); _Link_type __y = _S_left(__x); _M_destroy_node(__x); __x = __y; } }
-
camper schrieb:
volkard schrieb:
Wobei ich dem gcc sogar zutraue, daß er das auch packt, der ist ein Monster.
Für den rb-tree jedenfalls nicht, da arbeitet der Algorithmus rekursiv. Da der Baum immer ausbalanciert ist, kann man hier Stacküberläufe ausschliessen. Wie es mit internen Datenstrukturen des Compilers aussieht, weiss ich nicht.
Ich meinte, das dumme if wegzuoptimieren. Aus dem rekursiven Löschen soll er gar keine andere Version bauen.
-
Man kann das if auch funktional machen.Wobei ich bezweifle, dass diese Optimierung irgendeinen messbaren Einfluss hat. wie üblich ungetestet.~bstree() { auto die = [](Node* p, Node* next) { delete p; return next; }; Node* r=root; while(r){ if(!r->left) { _: die( r, r->right ); continue; } if(!r->right) { die( r, r->left ); continue; } do { Node* e=r->left->right; Node* newR=r->left; newR->right=r; r->left=e; r=newR; } while ( r->left ); goto _; } }Edit: nochmal überarbeitet. Jetzt ist der Anfangstest doch nicht nötig.
-
Laesst sich das nicht vereinfachen zu
Node* r=root; while(r){ if( !r->left || !r->right ) { _: delete r; continue; } \\ ...Oder uebersehe ich etwas?
-
camper schrieb:
Man kann das if auch funktional machen.Wobei ich bezweifle, dass diese Optimierung irgendeinen messbaren Einfluss hat. wie üblich ungetestet.~bstree() { auto die = [](Node* p, Node* next) { delete p; return next; }; Node* r=root; while(r){ if(!r->left) { _: die( r, r->right ); continue; } if(!r->right) { die( r, r->left ); continue; } do { Node* e=r->left->right; Node* newR=r->left; newR->right=r; r->left=e; r=newR; } while ( r->left ); goto _; } }Edit: nochmal überarbeitet. Jetzt ist der Anfangstest doch nicht nötig.
Hab zweimal r= zugefügt.
~bstree() { auto die = [](Node* p, Node* next) { delete p; return next; }; Node* r=root; while(r){ if(!r->left) { _: r=die( r, r->right ); continue; } if(!r->right) { r=die( r, r->left ); continue; } do { Node* e=r->left->right; Node* newR=r->left; newR->right=r; r->left=e; r=newR; } while ( r->left ); goto _; } }
-
Arcoth schrieb:
Laesst sich das nicht vereinfachen zu
...Je nachdem, welcher Kindknoten nicht existiert, ändert sich, in welche Richtung weiterzulaufen ist.
volkard schrieb:
Hab zweimal r= zugefügt.
danke, so war es gemeint. und das goto ist auch unnötig.
~bstree() { auto die = [](Node* p, Node* next) { delete p; return next; }; Node* r = root; while ( r ) { if ( !r->right ) { r = die( r, r->left ); } else { while ( r->left ) { Node* e = r->left->right; Node* newR = r->left; newR->right = r; r->left = e; r = newR; } r = die( r, r->right ); } } }