1 #include <iostream>
2 using namespace std;
3
4 enum flag{ Child, nChild }; // Child 表示有孩子 nChild 即 not Child 没有孩子
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_postTree(Node *); // 后序遍历输出
19 private:
20 Node * root;
21 Node * Create(); // 供构造函数调用初始化二叉树
22 void _postTree(Node *, Node *&); // 后序 线索化
23 };
24
25 int main() {
26 cout << "以先序方式输入二叉树('#'代表NULL):";
27
28 Tree T;
29
30 T.Show_postTree(T.getRoot());
31
32 system("pause");
33 return 0;
34 }
35
36 Tree::Tree() {
37 root = Create(); // 先创建一个默认的二叉树
38 Node * pre = NULL;
39 _postTree(root, pre);
40 }
41
42 Tree::~Tree() {
43 Node * Queue[100];
44 int rear = -1, front = -1;
45 if(root != NULL) {
46 Queue[++rear] = root;
47 }
48 Node * p = NULL;
49 while (rear != front) {
50 p = Queue[front+1];
51 if(p->ltag == Child) { // 有左孩子就进队,没有就不管,判断有无孩子 是看它的标志
52 Queue[++rear] = p->lchild;
53 }
54 if(p->rtag == Child) { // 有右孩子入队
55 Queue[++rear] = p->rchild;
56 }
57 cout << "析构:" << p->data << endl;
58 delete p; // 删除队头所指向的那一块存储空间
59 front++; // 出队一个 front+1
60 }
61 system("pause");
62 }
63
64 Node * Tree::Create() {
65 Node * root;
66 char ch;
67 cin >> ch;
68 if (ch == '#') {
69 root = NULL;
70 }
71 else {
72 root = new Node();
73 root->data = ch;
74 root->ltag = root->rtag = Child; // 默认设置左右指针域 为孩子
75 root->lchild = Create();
76 root->rchild = Create();
77 }
78 return root;
79 }
80
81 Node * Tree::getRoot() {
82 return root;
83 }
84
85 void Tree::_postTree(Node * root, Node *&pre) {
86 if (root == NULL) { // 空值不操作
87 return;
88 }
89 else {
90 _postTree(root->lchild, pre); // 递归左树,首先是递归到左子树的最左下的结点
91 _postTree(root->rchild, pre); // 递归右树,首先是递归到左子树的最左下的第一个右结点
92 // 对当前结点进行操作,只对含有空指针的结点指针域操作
93 if (root->lchild == NULL) { // 左孩子为空,操作的是前驱,前驱是 pre
94 root->ltag = nChild;
95 root->lchild = pre;
96 }
97 // 首先要判断 pre 是否为空,后才能判断他的指针域,因为第一次的 pre在未执行下面语句 pre = root 时是NULL 值, 指针为 NULL值的没有访问其他内存空间的权限
98 if (pre != NULL && pre->rchild == NULL) { // 右孩子为空,操作的是后继, pre是前驱的话,那么root不就是后继吗?
99 pre->rtag = nChild;
100 pre->rchild = root;
101 }
102 pre = root;
103 }
104 }
105
106 void Tree::Show_postTree(Node * root) {
107 cout << "后序线索化遍历(最大使用栈暂存元素个数 100):";
108 Node * Stack[100];
109 int top = -1;
110 Node * p = root;
111 Node * pre = NULL; // 作为前驱,保留上一次访问过的指针域
112 do {
113 while (p != NULL) { // 将当前结点的左孩子全部入栈,一直走到最左边的左孩子
114 Stack[++top] = p;
115 p = p->lchild;
116 if (p == pre) { // 防止对叶子结点操作中, p = p->rchild 导致 p 不为 NULL, 在执行上面一条语句 p = p->lchild时再次访问了已访问过的结点
117 break;
118 }
119 }
120 p = Stack[top]; // 将 p 指向栈顶指针域,进行操作当前结点
121 if (p->rtag == nChild || p->rchild == pre) { // 当前结点没有右孩子 或者 它的右孩子已经被访问过
122 cout << p->data << " ";
123 top--; // 输出一个结点,就出栈一个指针域
124 pre = p;
125 p = NULL; // p 为 NULL,目的是为了使其不满足第一个while,防止再次访问已访问过的结点,转去操作下一个结点
126 }
127 else {
128 p = p->rchild;
129 }
130 } while (top != -1 && pre != NULL);
131 cout << endl;
132 }