先序線索化在很多書上都有詳細解讀,這里只是寫了一個較為完整的一個程序罷了
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 void Show_preTree(Node *); // 先序遍歷輸出 19 private: 20 Node * root; 21 Node * Create(); // 供構造函數調用初始化二叉樹 22 void Delete(Node *); // 供析構函數析構二叉樹 23 void _preTree(Node *, Node *&); // 先序 線索化 24 }; 25 26 int main() { 27 cout << "以先序方式輸入二叉樹:"; 28 29 Tree T; 30 T.Show_preTree(T.getRoot()); 31 32 system("pause"); 33 return 0; 34 } 35 36 Tree::Tree() { 37 root = Create(); // 先創建一個默認的二叉樹 38 Node * pre = NULL; 39 _preTree(root, pre); 40 } 41 42 Tree::~Tree() { 43 Node * p = NULL; 44 while (root != NULL) { 45 p = root; // 待刪除結點 46 if (root->ltag == Child) { 47 root = root->lchild; // 有左孩子,則指向左孩子 48 } else { 49 root = root->rchild; // 沒有左孩子,指向右孩子或者 后繼 50 } 51 delete p; 52 } 53 } 54 55 Node * Tree::Create() { 56 Node * root; 57 char ch; 58 cin >> ch; 59 if (ch == '#') { 60 root = NULL; 61 } else { 62 root = new Node(); 63 root->data = ch; 64 root->ltag = root->rtag = Child; // 默認設置左右指針域 為孩子 65 root->lchild = Create(); 66 root->rchild = Create(); 67 } 68 return root; 69 } 70 71 Node * Tree::getRoot() { 72 return root; 73 } 74 75 void Tree::_preTree(Node * root, Node * &pre) { 76 if (root == NULL) { // 空結點,不操作,返回 77 return; 78 } 79 80 if (root->lchild == NULL) { // 左孩子為空,設置前驅,前驅為pre, pre表示上一次訪問過的結點 81 root->lchild = pre; 82 root->ltag = nChild; // 左標志置為 nChild 表示是前驅 83 } 84 if (pre != NULL && pre->rchild == NULL) { // 上一個結點的,即上一次訪問過的結點右孩子為空,則在此時設置后繼 85 pre->rchild = root; 86 pre->rtag = nChild; // 右標志置為 nChild 表示是后繼 87 } 88 89 pre = root; // pre 指向當前結點,下面開始遞歸一次,遞歸時,pre作為上一次訪問過的結點,即當前指向的結點 90 91 if (root->ltag == Child) { // 當前結點還有左孩子,遞歸一次 92 _preTree(root->lchild, pre); 93 } 94 if (root->rtag == Child) { // 當前結點還有右孩子,遞歸一次 95 _preTree(root->rchild, pre); 96 } 97 } 98 99 void Tree::Show_preTree(Node * root) { 100 Node * p = root; 101 if (p == NULL) { 102 return; 103 } else if (p->ltag == Child) { 104 cout << p->data << " "; 105 Show_preTree(p->lchild); 106 } else { 107 cout << p->data << " "; 108 Show_preTree(p->rchild); 109 } 110 /* 111 由於先序線索化(遍歷根、左、右),可以看出(畫圖看最清晰): 112 當 this(當前結點)的 ltag為Child的時候表示它是有孩子的應該先遍歷左子樹,直接可以 p = p->lchild然后輸出當前結點 113 當 this 的 ltag為 nChild的時候,表示沒有了左孩子,這個時候就應該遍歷它的右孩子 或者 是它的后繼 ( p = p->rchild) 114 由於 當某個結點沒有右孩子的時候,它會存在后繼,所以可以當做是“右孩子”一樣,當結點不存在右孩子或后繼時,表明已經到了右子樹的尾端 115 */ 116 }
