ref: 6669ea8ed594d206d16171b7034125deeca6b806
dir: /treewalk.c/
/* * Demonstrates how simple recursive traversing a non-balanced tree can * eat your stack (fast). Demonstrates an iterative O(N) complexity + * O(1) space traversal to be used instead if your tree may look like a * very long stick. * * Read the code. * * 7c -FTVw treewalk.c && 7l treewalk.7 && ./7.out [options] */ #include <u.h> #include <libc.h> #include <thread.h> #include <bio.h> typedef struct Tree Tree; struct Tree { int v; Tree *left; Tree *right; }; enum { PreOrder, InOrder, PostOrder, }; static Biobuf *b; static int simple; static int mode = PreOrder; /* * A tree that is on https://en.wikipedia.org/wiki/Tree_traversal#Depth-first_search * (as of 2024/10/24). It's to verify the correctness with. */ static Tree stC = {'C'}, stE = {'E'}, stH = {'H'}; static Tree stA = {'A'}, stD = {'D', &stC, &stE}, stI = {'I', &stH}; static Tree stB = {'B', &stA, &stD}, stG = {'G', nil, &stI}; static Tree st = {'F', &stB, &stG}; static void visit(Tree *t) { Bprint(b, simple ? "%c " : "%d\n", t->v); } /* nothing special here */ static void walkrecursive(Tree *t) { if(mode == PreOrder) visit(t); if(t->left) walkrecursive(t->left); if(mode == InOrder) visit(t); if(t->right) walkrecursive(t->right); if(mode == PostOrder) visit(t); } /* * To morris-traverse in post-order we have to visit nodes in reverse * upon discovering an earlier created thread. This function flips the * subtree in-place, then visits each node while flipping the subtree * back to what it was. It still does not allocate any extra space. */ static void postwalk(Tree *a, Tree *b) { Tree *v, *vr, *vr2; if(a != b){ for(v = a, vr = v->right; vr != b; v = vr, vr = vr2){ vr2 = vr->right; vr->right = v; } vr->right = v; for(v = b, vr = v->right; vr != a; v = vr, vr = vr2){ visit(v); vr2 = vr->right; vr->right = v; } visit(v); vr->right = v; } visit(a); } /* this one is more interesting */ static void walkmorris(Tree *t) { Tree *p, t0; if(mode == PostOrder){ /* in post-order we need to have a fake root to return to */ t0.v = 'X'; t0.left = t; t0.right = nil; t = &t0; } for(; t ;){ if(t->left){ for(p = t->left; p->right && p->right != t; p = p->right); if(p->right){ if(mode == InOrder) visit(t); else if(mode == PostOrder) postwalk(t->left, p); p->right = nil; t = t->right; }else{ if(mode == PreOrder) visit(t); p->right = t; t = t->left; } }else{ if(mode != PostOrder) visit(t); t = t->right; } } } void threadmain(int argc, char **argv) { Tree *t; int n, i, num = 1<<16; int nol, nor, morris; nol = nor = simple = morris = 0; ARGBEGIN{ case 'l': /* no left nodes will be set */ nol++; break; case 'r': /* no right nodes will be set */ nor++; break; case 'm': /* use iterative traversal */ morris++; break; case 'i': mode = InOrder; break; case 'p': mode = PostOrder; break; case 's': /* use a small and simple tree */ simple++; break; default: fprint(2, "usage: %s [-i | -p] [-l | -r] [-m] [-s]\n", argv0); threadexitsall("usage"); }ARGEND if(nol && nor) sysfatal("it wouldn't even be a list, dumbass"); b = Bfdopen(1, OWRITE); if(simple){ t = &st; }else{ t = calloc(num, sizeof(*t)); for(i = 0, n = 1; i < num; i++){ if(!nol && n < num) t[i].left = &t[n++]; if(!nor && n < num) t[i].right = &t[n++]; t[i].v = i; } } if(morris) walkmorris(t); else walkrecursive(t); if(simple) Bprint(b, "\n"); Bterm(b); threadexitsall(nil); }