先序线索化二叉树

  先序线索化在很多书上都有详细解读,这里只是写了一个较为完整的一个程序罢了

  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 }

 

posted @ 2016-11-19 22:27  enjoy_Lify  阅读(4318)  评论(0编辑  收藏  举报