/* VerifyThis 2016 - Challenge 2: Binary Tree Traversal * https://docs.google.com/document/d/1TvvoRovDQtmuXth6vcWtUNCQCNmzZO9X_DdcxM9aXbQ/edit * * We are given a binary tree with the following properties: * - It is well formed, in the sense that following a child pointer (left or * right) and then following a parent pointer brings us to the original * node. Moreover, the parent pointer of the root is null. * - It has at least one node, and each node has 0 or 2 children. * We do not know the initial value of the mark fields. * Our goal is to set all mark fields to true. The algorithm below (Morris * 1979) works in time linear in the number of nodes, as usual, but uses * only a constant amount of extra space. * * Tasks. Prove that: * (1) upon termination of the algorithm, all mark fields are set * (2) the tree shape does not change * (3) the code does not crash, and * (4) the code terminates. * (bonus) the nodes are visited in depth-first order * * This solution verifies tasks (1) to (4). * * Author: Stephen Siegel */ #include #include #include #include $input int DB = 5; // depth bound typedef struct _tree { struct _tree *left; struct _tree *right; struct _tree *parent; _Bool mark; } *Tree; // algorithm to mark every node in tree... void markTree(Tree root) { Tree x, y; x = root; while (true) { x->mark = $true; if (x->left == NULL && x->right == NULL) { y = x->parent; } else { y = x->left; x->left = x->right; x->right = x->parent; x->parent = y; } x = y; if (x==NULL) break; } } // make a new Tree from given children, allocating on heap Tree makeTree(Tree left, Tree right, _Bool mark) { Tree result = (Tree)malloc(sizeof(struct _tree)); result->left = left; result->right = right; result->mark = mark; result->parent = NULL; if (left != NULL) left->parent = result; if (right != NULL) right->parent = result; return result; } // construct an arbitrary tree of depth at most "depth" Tree makeArbitrary(int depth) { if (depth == 0) return NULL; // nondeterministic choice between two things: // 0: return tree with 0 nodes // 1: return tree with 2 nodes if ($choose_int(2) == 0) return makeTree(NULL, NULL, false); Tree t1 = makeArbitrary(depth - 1); Tree t2 = makeArbitrary(depth - 1); Tree result = makeTree(t1, t2, false); return result; } // print tree, for debugging only... void printTree(Tree tree) { if (tree == NULL) printf("NULL\n"); else { printf("Begin Tree: %p\n", tree); printf("Mark: "); if (tree->mark) printf("true\n"); else printf("false\n"); printf("Parent: %p\n", tree->parent); printf("Left:\n"); printTree(tree->left); printf("Right:\n"); printTree(tree->right); printf("End Tree\n"); } } // deep copy a tree, ignoring marks... Tree copyTree(Tree root) { if (root == NULL) return NULL; Tree t1 = copyTree(root->left); Tree t2 = copyTree(root->right); return makeTree(t1, t2, false); } // free all nodes in the tree rooted at root... void freeTree(Tree root) { if (root != NULL) { freeTree(root->left); freeTree(root->right); free(root); } } // example for debuggin only... Tree makeExample1() { Tree n1 = makeTree(NULL, NULL, false); Tree n2 = makeTree(NULL, NULL, true); Tree n3 = makeTree(n1, n2, false); return n3; } // example for debuggin only... Tree makeExample2() { Tree n1 = makeTree(NULL, NULL, false); Tree n2 = makeTree(NULL, n1, false); Tree n3 = makeTree(NULL, n2, false); return n3; } // checks every node in Tree t is marked... _Bool checkAllMarked(Tree t) { if (t != NULL) { if (!(t->mark)) return false; if (!checkAllMarked(t->left)) return false; if (!checkAllMarked(t->right)) return false; } return true; } // checks two trees have same "shape" void checkIso(Tree t1, Tree t2) { if (t1 == NULL) $assert(t2 == NULL); if (t2 == NULL) $assert(t1 == NULL); if (t1 != NULL) { checkIso(t1->left, t2->left); checkIso(t1->right, t2->right); } } // generate arbitrary tree up to depth bound // and check all marked, termination, no invalid // pointer operations, and resulting tree has unchanged // shape... int main() { Tree t1 = makeArbitrary(DB); Tree t2 = copyTree(t1); $assume(t1 != NULL); markTree(t1); $assert(checkAllMarked(t1)); checkIso(t1, t2); freeTree(t1); freeTree(t2); }