中序線索化二叉樹
1 void Tree::_inTree(Node * root, Node * &pre) { 2 if (root == NULL) { // 結點為空, 1:二叉樹為空 2:已到達右子樹的最后一個右結點的 rchild 3 return; 4 } 5 _inTree(root->lchild, pre); // 到達當前結點的左子樹的底部左結點 6 if (root->lchild == NULL) { 7 root->ltag = nChild; // 當前結點 無左孩子, 設置標記為 nChild 8 root->lchild = pre; // 設置 lchild 的指針域 為前驅 pre 9 } // 注意下列的條件判斷, 要先判斷pre是不是空,再是 pre的其他指針域! 10 if (pre != NULL && pre->rchild == NULL) { // pre 為上一次訪問過的結點, root為當前結點,通過對 pre的操作,達到線索化,pre位於左子樹是作為前驅,位於右子樹作為后繼 11 pre->rtag = nChild; 12 pre->rchild = root; 13 } 14 pre = root; // 把 pre 指向當前結點,保存上一次訪問的結點 15 _inTree(root->rchild, pre); 16 }
較為完整可運行程序
1 #include <iostream> 2 using namespace std; 3 4 enum flag{Child, nChild}; 5 6 struct Node { 7 char data; 8 Node * lchild; 9 Node * rchild; 10 flag ltag, rtag; // Child 表示是左或右孩子 nChild 表示前驅或后繼 11 }; 12 13 class Tree { 14 public: 15 Tree(); 16 ~Tree(); 17 Node * getRoot(); 18 Node * _next(Node *); // 返回待查找結點的后繼 19 void Show_inTree(Node *); // 中序遍歷輸出 20 private: 21 Node * root; 22 Node * Create(); // 供構造函數調用初始化二叉樹 23 void Delete(Node *); // 供析構函數析構二叉樹 24 void _inTree(Node *, Node *&); // 中序 線索化 25 }; 26 27 int main() { 28 cout << "以先序方式輸入二叉樹:"; 29 30 Tree T; 31 T.Show_inTree(T.getRoot()); 32 33 system("pause"); 34 return 0; 35 } 36 37 Tree::Tree() { 38 root = Create(); // 先創建一個默認的二叉樹 39 Node * pre = NULL; 40 _inTree(root, pre); // 再對二叉樹進行線索化 41 } 42 43 Tree::~Tree() { 44 while (root->lchild != NULL) { // 將root,設置為左子樹的最左下角的結點 45 root = root->lchild; 46 } 47 Delete(root); 48 } 49 50 void Tree::Delete(Node * root) { 51 if (root->rchild != NULL) { // 右指針域 是一直指向下一個結點,直到指向為右子樹最右下角的最后結點 52 Delete(root->rchild); 53 delete root; 54 } 55 } 56 57 Node * Tree::Create() { 58 Node * root; 59 char ch; 60 cin >> ch; 61 if (ch == '#') { 62 root = NULL; 63 } else { 64 root = new Node(); 65 root->data = ch; 66 root->ltag = root->rtag = Child; // 默認設置左右指針域 為孩子 67 root->lchild = Create(); 68 root->rchild = Create(); 69 } 70 return root; 71 } 72 73 void Tree::_inTree(Node * root, Node * &pre) { 74 if (root == NULL) { // 結點為空, 1:二叉樹為空 2:已到達右子樹的最后一個右結點的 rchild 75 return; 76 } 77 _inTree(root->lchild, pre); // 到達當前結點的左子樹的底部左結點 78 if (root->lchild == NULL) { 79 root->ltag = nChild; // 當前結點 無左孩子, 設置標記為 nChild 80 root->lchild = pre; // 設置 lchild 的指針域 為前驅 pre 81 } // 注意下列的條件判斷, 要先判斷pre是不是空,再是 pre的其他指針域! 82 if (pre != NULL && pre->rchild == NULL) { // pre 為上一次訪問過的結點, root為當前結點,通過對 pre的操作,達到線索化,pre位於左子樹是作為前驅,位於右子樹作為后繼 83 pre->rtag = nChild; 84 pre->rchild = root; 85 } 86 pre = root; // 把 pre 指向當前結點,保存上一次訪問的結點 87 _inTree(root->rchild, pre); 88 } 89 90 Node * Tree::getRoot() { 91 return root; 92 } 93 94 void Tree::Show_inTree(Node * root) { 95 if (root == NULL) { 96 return; 97 } 98 Node * p = root; 99 while (p->ltag == Child) { // 索引到左子樹沒有孩子,即中序遍歷中的第一個結點 100 p = p->lchild; 101 } 102 cout << p->data << " "; // 輸出第一個結點 103 while (p->rchild != NULL) { // 通過線索化,右孩子為空的時候表示 整個二叉樹訪問完畢 104 p = _next(p); // 獲取當前結點的后繼,即下一個元素, 注:_next 函數返回的是下一個結點的地址,故此不需要 p = p->rchild; 105 cout << p->data << " "; 106 } 107 cout << endl; 108 } 109 110 Node * Tree::_next(Node * root) { 111 Node * p = NULL; 112 if (root->rtag == nChild) { // 右標志為 nChild,無右孩子,直接線索化得到 113 p = root->rchild; 114 } else { // 否則是,右孩子的左子樹的最左下結點 115 p = root->rchild; 116 while (p->ltag == Child) { 117 p = p->lchild; 118 } 119 } 120 return p; 121 }
