540 likes | 666 Views
Trees 3: Construction of Dynamic Binary Trees. Andy Wang Data Structures, Algorithms, and Generic Programming. Overview. Definition of class TBinaryTree Recursive methods Inserting elements Removing elements Binary tree construction from file. Defining Class TBinaryTree.
E N D
Trees 3: Construction of Dynamic Binary Trees Andy Wang Data Structures, Algorithms, and Generic Programming
Overview • Definition of class TBinaryTree • Recursive methods • Inserting elements • Removing elements • Binary tree construction from file
Defining Class TBinaryTree template <typename T> class TBinaryTree { friend class TBinaryTreeNavigator<T>; public: typedef T value_type; // constructors TBinaryTree(); virtual ~TBinaryTree(); TBinaryTree(const TBinaryTree<T>& B); TBinaryTree<T>& operator=(const TBinaryTree<T>& B); // read-only operations int Empty() const; size_t Size() const; int Height() const;
Defining Class TBinaryTree void Display(std::ostream os, char ofc = ‘\0’) const; void Dump(std::ostream os, chcar ofc) const; void Dump(std::ostream os, const T& fill, char ofc) const; // operations int InsertRoot(const T& t); int InsertLeft(Navigator& N, const T& t); int InsertRight(Navigator& N, const T& t); int Insert(Iterator& I, const T& t); int Remove(Iterator& I); size_t Remove(const T& t); void Clear(); void Clear(Navigator &N); // clear subtree with root N
Defining Class TBinaryTree // iterator operators typedef TBinaryTreeInorderIterator<T> Iterator; typedef TBinaryTreePreorderIterator<T> PreorderIterator; typedef TBinaryTreePostorderIterator<T> PostorderIterator; typedef TBinaryTreeLevelorderIterator<T> LevelorderIterator; typedef TBinaryTreeNavigator<T> Navigator; Navigator Root() const; Iterator Begin() const; Iterator End() const; Iterator rBegin() const; Iterator rBegin() const;
Defining Class TBinaryTree protected: class TNode { friend class TBinaryTree<T>; friend class TBinaryTreeNavigator<T>; TNode(const T&); TNode(const TNode&); T value; char color; TNode *parent, *lchild, *rchild; }; TNode *root; static void RRelease(TNode *N); // recursive deletion of N’s children static TNode* RClone(const TNode *N); // deep copy of N static size_t RSize(const TNode *N); // return number of nodes at N static int RHeight(const TNode *N); // return height of tree at N };
Recursive Protected Methods template <typename T> size_t TBinaryTree<T>::RSize(const TNode *N) { if (N == 0) return 0; return (1 + RSize(N->lchild) + RSize(N->rchild)); } template <typename T> int TBinaryTree<T>::RHeight(const TNode *N) { if (N == 0) return -1; return (1 + max(RHeight(N->lchild), RHeight(N->rchild))); }
Recursive Protected Methods template <typename T> void TBinaryTree<T>::RRelease(TBinaryTree<T>::TNode *N) { if (N != 0) { if (N->lchild != 0) { TBinaryTree<T>::RRelease(N->lchild); delete N->lchild: N->lchild = 0; } if (N->rchild != 0) { TBinaryTree<T>::RRelease(N->rchild); delete N->rchild; N->rchild = 0; } } }
Recursive Protected Methods template <typename T> TBinaryTree<T>::TNode* TBinaryTree<T>::RClone(const TBinaryTree<T>::TNode *N) { if (N == 0) return 0; TBinaryTree<T>::TNode *newN = new TBinaryTree<T>::TNode(N->value); newN->lchild = TBinaryTree<T>::RClone(N->lchild); newN->rchild = TBinaryTree<T>::RClone(N->rchild); if (newN->lchild) { newN->lchild->parent = newN; } if (newN->rchild) { newN->rchild->parent = newN; } return newN; }
1 root 2 3 4 5 Recursive Protected Calls template <typename T> void TBinaryTree<T>::Dump(ostream& os, const T& fill) const { // idea: BFS 1 root 2 3 4 5
1 root 2 3 4 5 6 7 Recursive Protected Calls template <typename T> void TBinaryTree<T>::Dump(ostream& os, const T& fill) const { if (root == 0) return; TBinaryTree<T>::TNode *fillNode = new TBinaryTree<T>::TNode(fill); CQueue<TList<TBinaryTree<T, P>::TNode *> > Que; TBinaryTree<T>::TNode *current; unsigned int currLayerSize, nextLayerSize, j, k; Que.Push(root); k = 1 // always 2^(layer number) for (curLayerSize = 1, nextLayerSize = 0; currLayerSize > 0; currLayerSize = nextLayerSize) {
Recursive Protected Calls for (j = 0; j < k; ++j) { current = Que.Front(); Que.Pop(); os << current->value; if (current->lchild != 0) { Que.Push(current->lchild); ++nextLayerSize; } else { Que.Push(fillNode); } if (current->rchild != 0) { Que.Push(current->rchild); ++nextLayerSize; } else { Que.Push(fillNode); } } os << endl; k *= 2; }
Recursive Protected Calls Que.Clear(); delete fillNode; }
Helper Functions template <typename T> int TBinaryTree<T>::Empty() const { return (root == 0); } template <typename T> int TBinaryTree<T>::Height() const { return RHeight(root); } template <typename T> size_t TBinaryTree::Size() const { return RSize(root); } template <typename T> void TBinaryTree<T>::Clear() { TBinaryTree<T>::RRelease(root); delete root; root = 0; }
Helper Functions template <typename T> void TBinaryTree<T>::Clear(TBinaryTreeNavigator<T>& N) { if (N.Valid()) { TNode *P = N.currentNode->parent; if (N.IsLeftChild()) { P->lchild = 0; } else if (N.IsRightChild()) { P->rchild = 0; } TBinaryTree<T>::RRelease(N.currNode); delete N.currNode; N.currNode = P; } }
Helper Functions template <typename T> TBinaryTree<T>& TBinaryTree<T>::operator=(const TBinaryTree<T>& b) { if (this != &b) { Clear(); root = TBinaryTree<T>::RClone(b.root); } return *this; }
Supports for Iterators and Navigators template <typename T> TBinaryTreeInorderIterator<T> TBinaryTree<T>::Begin() const { TBinaryTree<T>::Iterator I; I.Initialize(*this); return I; } template <typename T> TBinaryTreeInorderIterator<T> TBinaryTree<T>::End() const { TBinaryTree<T>::Iterator I; return I; }
Supports for Iterators and Navigators template <typename T> TBinaryTreeInorderIterator<T> TBinaryTree<T>::rBegin() const { TBinaryTree<T>::Iterator I; I.rInitialize(*this); return I; } template <typename T> TBinaryTreeInorderIterator<T> TBinaryTree<T>::rEnd() const { TBinaryTree<T>::Iterator I; return I; } template <typename T> TBinaryTreeNavigator<T> TBinaryTree<T>::Root() const { TBinaryTree<T>::Navigator N; N.currNode = root; return N; }
Constructors template <typename T> TBinaryTree<T>::TNode::TNode(const T& t) : value(t), color(‘b’), parent(0), lchild(0), rchild(0) { } template <typename T> TBinaryTree<T>::TNode::TNode(const TNode& N) { std::cerr << “TBinaryTree<T>::TNode::TNode(const TNode&) called\n” } template <typename T> TBinaryTree<T>::TBinaryTree() : root(0) { } template <typename T> TBinaryTree<T>::~TBinaryTree() { Clear(); } template <typename T> TBinaryTree<T>::TBinaryTree(const TBinaryTree<T>& b) { root = TBinaryTree<T>::RClone(b.root); }
Tree Operations template <typename T> int TBinaryTree<T>::InsertRoot(const T& t) { if (root != 0) { root->value = t; return 1; } root = new TBinaryTree<T>::TNode(t); if (root == 0) { return 0; } return 1; }
Tree Operations template <typename T> int TBinaryTree<T>::InsertLeft(Navigator& N, const T& t) { if (!N.Valid()) { return 0; } if (N.HasLeftChild()) { ++N; *N = t; return 1; } N.currNode->lchild = new TBinaryTree<T>::TNode(t); if (N.currNode->lchild == 0) { return 0; } N.currNode->lchild->parent = N.currNode; ++N; return 1; }
Tree Operations template <typename T> int TBinaryTree<T>::InsertRight(Navigator& N, const T& t) { if (!N.Valid()) { return 0; } if (N.HasRightChild()) { N++; *N = t; return 1; } N.currNode->rchild = new TBinaryTree<T>::TNode(t); if (N.currNode->rchild == 0) { return 0; } N.currNode->rchild->parent = N.currNode; N++; return 1; }
Tree Operations template <typename T> int TBinaryTree<T>::Insert(TBinaryTree<T>::Iterator& I, const T& Tval) { // empty case: insert at root if (Empty()) { if (InsertRoot(Tval) { I.N = Root(); return 1; } else { return 0; } }
Tree Operations // valid case, insert Tval at I, move Told to ++I if (I.Valid()) { T Told = *I; Navigator N = I.N; if (N.HasRightChild())) { N++; while (N.HasLeftChild()) { ++N; } if (!InsertLeft(N, Told)) { return 0; } } else { if (!InsertRight(N, Told)) { return 0; } } *I = Tval; return 1; } Told I ->
Tree Operations // valid case, insert Tval at I, move Told to ++I if (I.Valid()) { T Told = *I; Navigator N = I.N; if (N.HasRightChild())) { N++; while (N.HasLeftChild()) { ++N; } if (!InsertLeft(N, Told)) { return 0; } } else { if (!InsertRight(N, Told)) { return 0; } } *I = Tval; return 1; } Tval I -> Told
Tree Operations // valid case, insert Tval at I, move Told to ++I if (I.Valid()) { T Told = *I; Navigator N = I.N; if (N.HasRightChild())) { N++; while (N.HasLeftChild()) { ++N; } if (!InsertLeft(N, Told)) { return 0; } } else { if (!InsertRight(N, Told)) { return 0; } } *I = Tval; return 1; } Told I ->
Tree Operations // valid case, insert Tval at I, move Told to ++I if (I.Valid()) { T Told = *I; Navigator N = I.N; if (N.HasRightChild())) { N++; while (N.HasLeftChild()) { ++N; } if (!InsertLeft(N, Told)) { return 0; } } else { if (!InsertRight(N, Told)) { return 0; } } *I = Tval; return 1; } Tval I -> Told
Tree Operations // invalid iterator: insert at the end; for (I.N = Root(); I.N.HasRightChild(); (I.N)++) { } if (InsertRight(I.N, Tval) { return 1; } else { I = End(); return 0; } }
Tree Operations template <typename T> int TBinaryTree<T>::Remove(Iterator &I) { // remove element at I, leave I at ++(), and preserve inorder if (!I.Valid()) { return 0; } TBinaryTree<T>::Navigator N = I.N; ++I; // I is now at the next place in an inorder traversal TBinaryTree<T>::TNode *R = N.currNode->rchild; TBinaryTree<T>::TNode *L = N.currNode->lchild; TBinaryTree<T>::TNode *P = N.currNode->parent; N-> I->
Tree Operations template <typename T> int TBinaryTree<T>::Remove(Iterator &I) { // remove element at I, leave I at ++(), and preserve inorder if (!I.Valid()) { return 0; } TBinaryTree<T>::Navigator N = I.N; ++I; // I is now at the next place in an inorder traversal TBinaryTree<T>::TNode *R = N.currNode->rchild; TBinaryTree<T>::TNode *L = N.currNode->lchild; TBinaryTree<T>::TNode *P = N.currNode->parent; N-> I->
Tree Operations template <typename T> int TBinaryTree<T>::Remove(Iterator &I) { // remove element at I, leave I at ++(), and preserve inorder if (!I.Valid()) { return 0; } TBinaryTree<T>::Navigator N = I.N; ++I; // I is now at the next place in an inorder traversal TBinaryTree<T>::TNode *R = N.currNode->rchild; TBinaryTree<T>::TNode *L = N.currNode->lchild; TBinaryTree<T>::TNode *P = N.currNode->parent; P-> N-> L-> R-> I->
Tree Operations • Nodes listed in inorder traversal before removal: L, N, I, R, … P • Nodes listed after removing N: • L, I, R, …P P-> N-> L-> R-> I->
Tree Operations • Nodes listed in inorder traversal before removal: L, N, I, R, … P • Nodes listed after removing N: • L, I, R, …P • How do we reconnect L, P, and R? P-> L-> R-> I->
R-> I-> Tree Operations • Nodes listed in inorder traversal before removal: L, N, I, R, … P • Nodes listed after removing N: • L, I, R, …P • How do we reconnect L, P, and R? P-> L->
Tree Operations // case 1: N has right child if (N.HasRightChild()) { if (I.N.HasLeftChild()) { std::cerr << “Error: structural problem” << endl; return 0; } if (L) { I.N.currNode->lchild = L; L->parent = I.N.currNode; N.currNode->lchild = 0; } P-> N-> L-> R-> I->
Tree Operations // case 1: N has right child if (N.HasRightChild()) { if (I.N.HasLeftChild()) { std::cerr << “Error: structural problem” << endl; return 0; } if (L) { I.N.currNode->lchild = L; L->parent = I.N.currNode; N.currNode->lchild = 0; } P-> N-> L-> R-> I->
L-> Tree Operations // case 1: N has right child if (N.HasRightChild()) { if (I.N.HasLeftChild()) { std::cerr << “Error: structural problem” << endl; return 0; } if (L) { I.N.currNode->lchild = L; L->parent = I.N.currNode; N.currNode->lchild = 0; } P-> N-> R-> I->
L-> Tree Operations // case 1: N has right child if (N.HasRightChild()) { if (I.N.HasLeftChild()) { std::cerr << “Error: structural problem” << endl; return 0; } if (L) { I.N.currNode->lchild = L; L->parent = I.N.currNode; N.currNode->lchild = 0; } P-> N-> R-> I->
L-> Tree Operations if (N.IsLeftChild()) { P->lchild = R; R->parent = P; } else if (N.IsRightChild()) { P->rchild = R; R->parent = P; } else { root = R; R->parent = 0; } delete N.currNode; return 1; } P-> N-> R-> I->
L-> Tree Operations if (N.IsLeftChild()) { P->lchild = R; R->parent = P; } else if (N.IsRightChild()) { P->rchild = R; R->parent = P; } else { root = R; R->parent = 0; } delete N.currNode; return 1; } P-> N-> R-> I->
L-> Tree Operations if (N.IsLeftChild()) { P->lchild = R; R->parent = P; } else if (N.IsRightChild()) { P->rchild = R; R->parent = P; } else { root = R; R->parent = 0; } delete N.currNode; return 1; } P-> N-> R-> I->
L-> Tree Operations if (N.IsLeftChild()) { P->lchild = R; R->parent = P; } else if (N.IsRightChild()) { P->rchild = R; R->parent = P; } else { root = R; R->parent = 0; } delete N.currNode; return 1; } P-> N-> R-> I->
L-> Tree Operations if (N.IsLeftChild()) { P->lchild = R; R->parent = P; } else if (N.IsRightChild()) { P->rchild = R; R->parent = P; } else { root = R; R->parent = 0; } delete N.currNode; return 1; } P-> N-> R-> I->
L-> Tree Operations if (N.IsLeftChild()) { P->lchild = R; R->parent = P; } else if (N.IsRightChild()) { P->rchild = R; R->parent = P; } else { root = R; R->parent = 0; } delete N.currNode; return 1; } P-> N-> R-> I->
L-> Tree Operations if (N.IsLeftChild()) { P->lchild = R; R->parent = P; } else if (N.IsRightChild()) { P->rchild = R; R->parent = P; } else { root = R; R->parent = 0; } delete N.currNode; return 1; } N-> root-> R-> I->
L-> Tree Operations if (N.IsLeftChild()) { P->lchild = R; R->parent = P; } else if (N.IsRightChild()) { P->rchild = R; R->parent = P; } else { root = R; R->parent = 0; } delete N.currNode; return 1; } N-> root-> R-> I->
L-> Tree Operations if (N.IsLeftChild()) { P->lchild = R; R->parent = P; } else if (N.IsRightChild()) { P->rchild = R; R->parent = P; } else { root = R; R->parent = 0; } delete N.currNode; return 1; } N-> root-> R-> I->
Tree Operations I-> P-> // case 2: N has no right child and has parent if (N.IsLeftChild()) { P->lchild = L; if (L) { L->parent = P; } } else if (N.IsRightChild()) { P->rchild = L; if (L) { L->parent = P } } else { // case 3: N has no right child and has no parent root = L; if (L) { L->parent = 0; } } delete N.currNode; return 1; } N-> L->
L-> Tree Operations I-> P-> // case 2: N has no right child and has parent if (N.IsLeftChild()) { P->lchild = L; if (L) { L->parent = P; } } else if (N.IsRightChild()) { P->rchild = L; if (L) { L->parent = P } } else { // case 3: N has no right child and has no parent root = L; if (L) { L->parent = 0; } } delete N.currNode; return 1; }
Tree Operations P-> // case 2: N has no right child and has parent if (N.IsLeftChild()) { P->lchild = L; if (L) { L->parent = P; } } else if (N.IsRightChild()) { P->rchild = L; if (L) { L->parent = P } } else { // case 3: N has no right child and has no parent root = L; if (L) { L->parent = 0; } } delete N.currNode; return 1; } N-> L->