先序线索化二叉树
先序线索化在很多书上都有详细解读,这里只是写了一个较为完整的一个程序罢了
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 }