1 //线索二叉树结点类 2 template<typename T> 3 struct ThreadNode //结点类 4 { 5 int ltag, rtag; //左右子树标志位 6 ThreadNode<T> *leftChild, *rightChild; //左孩子和右孩子 7 T data; //结点存储的值 8 ThreadNode(const T item) :data(item), leftChild(NULL), rightChild(NULL), ltag(0), rtag(0) {} //结点类的构造函数 9 };
1 //使用前序遍历创建二叉树(未线索化) 2 void CreateTree(ThreadNode<T>* &subTree) 3 { 4 T item; 5 if (cin >> item) 6 { 7 if (item != RefValue) 8 { 9 subTree = new ThreadNode<T>(item); //构造结点 10 if (subTree == NULL) 11 { 12 cout << "空间分配错误!" << endl; 13 exit(1); 14 } 15 CreateTree(subTree->leftChild); //递归创建左子树 16 CreateTree(subTree->rightChild); //递归创建右子树 17 } 18 else 19 { 20 subTree == NULL; 21 } 22 } 23 } 24 25 //中序遍历对二叉树进行线索化 26 void createInThread(ThreadNode<T> *current, ThreadNode<T> * &pre) 27 { 28 if (current == NULL) 29 { 30 return; 31 } 32 createInThread(current->leftChild, pre); //递归左子树的线索化 33 if (current->leftChild == NULL) //建立当前结点的前驱结点 34 { 35 current->leftChild = pre; 36 current->ltag = 1; 37 } 38 if (pre != NULL&&pre->rightChild == NULL) //建立当前结点的后继结点 39 { 40 pre->rightChild = current; 41 pre->rtag = 1; 42 } 43 pre = current; //用前驱记住当前的结点 44 createInThread(current->rightChild, pre); //递归右子树的线索化 45 } 46 47 //中序遍历对创建好的普通二叉树进行中序线索化 48 void CreateInThread() 49 { 50 ThreadNode<T> *pre = NULL; //第一个结点的左子树置为NULL 51 if (root != NULL) { 52 createInThread(root, pre); 53 //处理中序遍历的最后一个结点,最后一个结点的右子树置为空 54 pre->rightChild = NULL; 55 pre->rtag = 1; 56 } 57 }
1 //寻找中序下第一个结点 2 ThreadNode<T> * First(ThreadNode<T> *current) 3 //返回以*current为根的中序线索二叉树中序遍历的第一个结点 4 { 5 ThreadNode<T> *p = current; 6 while (p->ltag == 0) 7 { 8 p = p->leftChild; //循环找到最左下角结点 9 } 10 return p; 11 } 12 13 //寻找中序下的后继结点 14 ThreadNode<T>* Next(ThreadNode<T>* current) 15 { 16 ThreadNode<T>* p = current->rightChild; 17 if(current->rtag==0) 18 { 19 return First(p); 20 } 21 else 22 { 23 return p; 24 } 25 } 26 27 //寻找中序下最后一个结点 28 ThreadNode<T> * Last(ThreadNode<T> *current) 29 //返回以*current为根的中序线索二叉树中序遍历的最后一个结点 30 { 31 ThreadNode<T> *p = current; 32 while (p->rtag==0) 33 { 34 p = p->rightChild; 35 } 36 return p; 37 } 38 39 //寻找结点在中序下的前驱结点 40 ThreadNode<T>* Prior(ThreadNode<T>* current) 41 { 42 ThreadNode<T>* p = current->leftChild; 43 if (current->ltag==0) 44 { 45 return Last(p); 46 } 47 else 48 { 49 return p; 50 } 51 }
1 //中序线索化二叉树上执行中序遍历的算法 2 void InOrder(ThreadNode<T>* p) 3 { 4 for (p=First(root);p!=NULL;p=Next(p)) 5 { 6 cout << p->data<<" "; 7 } 8 cout << endl; 9 }
1 void PreOrder(ThreadNode<T>* p) 2 { 3 while (p!=NULL) 4 { 5 cout << p->data<<" "; //先访问根节点 6 if (p->ltag==0) 7 { 8 p = p->leftChild; //有左子树,即为后继 9 } 10 else if(p->rtag==0) //否则,有右子树,即为后继 11 { 12 p = p->rightChild; 13 } 14 else //无左右子树 15 { 16 while (p!=NULL&&p->rtag==1) //检测后继线索 17 { 18 p = p->rightChild; //直到找到有右子树的结点 19 } 20 if (p!=NULL) 21 { 22 p = p->rightChild; //该结点的右子树为后继 23 } 24 } 25 } 26 cout << endl; 27 }
1 //中序线索二叉树的后序遍历算法 2 void PostOrder(ThreadNode<T>* p) 3 { 4 ThreadNode<T>* t = p; 5 while (t->ltag==0||t->rtag==0) //寻找后续第一个结点 6 { 7 if(t->ltag==0) 8 { 9 t = t->leftChild; 10 } 11 else if(t->rtag==0) 12 { 13 t = t->rightChild; 14 } 15 } 16 cout << t->data<<" "; //访问第一个结点 17 while ((p=Parent(t))!=NULL) //每次都先找到当前结点的父结点 18 { 19 //若当前结点是父节点的右子树或者当前结点是左子树,但是这个父节点没有右子树,则后续下的后继为改父节点 20 if (p->rightChild==t||p->rtag==1) 21 { 22 t = p; 23 } 24 //否则,在当前结点的右子树(如果存在)上重复执行上面的操作 25 else 26 { 27 t = p->rightChild; 28 while (t->ltag==0||t->rtag==0) 29 { 30 if (t->ltag==0) 31 { 32 t = t->leftChild; 33 } 34 else if (t->rtag==0) 35 { 36 t = t->rightChild; 37 } 38 } 39 } 40 cout << t->data << " "; 41 } 42 }
1 //在中序线索化二叉树中求父节点 2 ThreadNode<T>* Parent(ThreadNode<T>* t) 3 { 4 ThreadNode<T>* p; 5 if(t==root) //根节点无父节点 6 { 7 return NULL; 8 } 9 for (p = t; p->ltag == 0; p = p->leftChild); //求*t为根的中序下的第一个结点p 10 //情况1 11 if (p->leftChild!=NULL) //当p左子树指向不为空 12 { 13 //令p为p的左子树指向的结点,判断此结点是否并且此节点的左右子树结点的指向都不为t,再将p为p的右孩子结点 14 for (p = p->leftChild; p != NULL&&p->leftChild != t&&p->rightChild != t; p = p->rightChild); 15 } 16 //情况2 17 //如果上面的循环完了,由于是p==NULL结束的循环,没有找到与t相等的结点,就是一直找到了中序线索化的第一个结点了,这时候这种就要用到情况2的方法 18 if (p==NULL||p->leftChild==NULL) 19 { 20 //找到*t为根的中序下的最后一个结点 21 for (p = t; p->rtag == 0; p = p->rightChild); 22 //让后让他指向最后一个结点指向的结点,从这个结点开始,以此判断它的左孩子孩子和右孩子是否和t相等 23 for (p = p->rightChild; p != NULL&&p->leftChild != t&&p->rightChild != t; p = p->leftChild); 24 } 25 return p; 26 }
1 //线索二叉树 2 template<typename T> 3 struct ThreadNode //结点类 4 { 5 int ltag, rtag; //左右子树标志位 6 ThreadNode<T> *leftChild, *rightChild; //左孩子和右孩子 7 T data; //结点存储的值 8 ThreadNode(const T item) :data(item), leftChild(NULL), rightChild(NULL), ltag(0), rtag(0) {} //结点类的构造函数 9 }; 10 11 template<typename T> 12 class ThreadTree 13 { 14 15 public: 16 //构造函数(普通) 17 ThreadTree() :root(NULL) {} 18 19 //指定结束标志RefValue的构造函数 20 ThreadTree(T value) :RefValue(value), root(NULL) {} 21 22 //使用前序遍历创建二叉树(未线索化) 23 void CreateTree() { CreateTree(root); } 24 25 //中序遍历对创建好的普通二叉树进行中序线索化 26 void CreateInThread() 27 { 28 ThreadNode<T> *pre = NULL; //第一个结点的左子树置为NULL 29 if (root != NULL) { 30 createInThread(root, pre); 31 //处理中序遍历的最后一个结点,最后一个结点的右子树置为空 32 pre->rightChild = NULL; 33 pre->rtag = 1; 34 } 35 } 36 //线索化二叉树上执行中序遍历的算法 37 void InOrder() { InOrder(root); } 38 //中序线索化二叉树上实现前序遍历的算法 39 void PreOrder() { PreOrder(root); } 40 //中序线索二叉树的后序遍历算法 41 void PostOrder() { PostOrder(root); } 42 private: 43 //使用前序遍历创建二叉树(未线索化) 44 void CreateTree(ThreadNode<T>* &subTree) 45 { 46 T item; 47 if (cin >> item) 48 { 49 if (item != RefValue) 50 { 51 subTree = new ThreadNode<T>(item); //构造结点 52 if (subTree == NULL) 53 { 54 cout << "空间分配错误!" << endl; 55 exit(1); 56 } 57 CreateTree(subTree->leftChild); //递归创建左子树 58 CreateTree(subTree->rightChild); //递归创建右子树 59 } 60 else 61 { 62 subTree == NULL; 63 } 64 } 65 } 66 //中序遍历对二叉树进行线索化 67 void createInThread(ThreadNode<T> *current, ThreadNode<T> * &pre) 68 { 69 if (current == NULL) 70 { 71 return; 72 } 73 createInThread(current->leftChild, pre); //递归左子树的线索化 74 if (current->leftChild == NULL) //建立当前结点的前驱结点 75 { 76 current->leftChild = pre; 77 current->ltag = 1; 78 } 79 if (pre != NULL&&pre->rightChild == NULL) //建立当前结点的后继结点 80 { 81 pre->rightChild = current; 82 pre->rtag = 1; 83 } 84 pre = current; //用前驱记住当前的结点 85 createInThread(current->rightChild, pre); //递归右子树的线索化 86 } 87 88 89 //寻找中序下第一个结点 90 ThreadNode<T> * First(ThreadNode<T> *current) //返回以*current为根的中序线索二叉树中序遍历的第一个结点 91 { 92 ThreadNode<T> *p = current; 93 while (p->ltag == 0) 94 { 95 p = p->leftChild; //循环找到最左下角结点 96 } 97 return p; 98 } 99 100 //寻找中序下的后继结点 101 ThreadNode<T>* Next(ThreadNode<T>* current) 102 { 103 ThreadNode<T>* p = current->rightChild; 104 if(current->rtag==0) 105 { 106 return First(p); 107 } 108 else 109 { 110 return p; 111 } 112 } 113 114 //寻找中序下最后一个结点 115 ThreadNode<T> * Last(ThreadNode<T> *current) //返回以*current为根的中序线索二叉树中序遍历的最后一个结点 116 { 117 ThreadNode<T> *p = current; 118 while (p->rtag==0) 119 { 120 p = p->rightChild; 121 } 122 return p; 123 } 124 //寻找结点在中序下的前驱结点 125 ThreadNode<T>* Prior(ThreadNode<T>* current) 126 { 127 ThreadNode<T>* p = current->leftChild; 128 if (current->ltag==0) 129 { 130 return Last(p); 131 } 132 else 133 { 134 return p; 135 } 136 } 137 //在中序线索化二叉树中求父节点 138 ThreadNode<T>* Parent(ThreadNode<T>* t) 139 { 140 ThreadNode<T>* p; 141 if(t==root) //根节点无父节点 142 { 143 return NULL; 144 } 145 for (p = t; p->ltag == 0; p = p->leftChild); //求*t为根的中序下的第一个结点p 146 //情况1 147 if (p->leftChild!=NULL) //当p左子树指向不为空 148 { 149 //令p为p的左子树指向的结点,判断此结点是否并且此节点的左右子树结点的指向都不为t,再将p为p的右孩子结点 150 for (p = p->leftChild; p != NULL&&p->leftChild != t&&p->rightChild != t; p = p->rightChild); 151 } 152 //情况2 153 //如果上面的循环完了,由于是p==NULL结束的循环,没有找到与t相等的结点,就是一直找到了中序线索化的第一个结点了,这时候这种就要用到情况2的方法 154 if (p==NULL||p->leftChild==NULL) 155 { 156 //找到*t为根的中序下的最后一个结点 157 for (p = t; p->rtag == 0; p = p->rightChild); 158 //让后让他指向最后一个结点指向的结点,从这个结点开始,以此判断它的左孩子孩子和右孩子是否和t相等 159 for (p = p->rightChild; p != NULL&&p->leftChild != t&&p->rightChild != t; p = p->leftChild); 160 } 161 return p; 162 } 163 164 //中序线索化二叉树上执行中序遍历的算法 165 void InOrder(ThreadNode<T>* p) 166 { 167 for (p=First(root);p!=NULL;p=Next(p)) 168 { 169 cout << p->data<<" "; 170 } 171 cout << endl; 172 } 173 //中序线索化二叉树上实现前序遍历的算法 174 void PreOrder(ThreadNode<T>* p) 175 { 176 while (p!=NULL) 177 { 178 cout << p->data<<" "; //先访问根节点 179 if (p->ltag==0) 180 { 181 p = p->leftChild; //有左子树,即为后继 182 } 183 else if(p->rtag==0) //否则,有右子树,即为后继 184 { 185 p = p->rightChild; 186 } 187 else //无左右子树 188 { 189 while (p!=NULL&&p->rtag==1) //检测后继线索 190 { 191 p = p->rightChild; //直到找到有右子树的结点 192 } 193 if (p!=NULL) 194 { 195 p = p->rightChild; //该结点的右子树为后继 196 } 197 } 198 } 199 cout << endl; 200 } 201 //中序线索二叉树的后序遍历算法 202 void PostOrder(ThreadNode<T>* p) 203 { 204 ThreadNode<T>* t = p; 205 while (t->ltag==0||t->rtag==0) //寻找后续第一个结点 206 { 207 if(t->ltag==0) 208 { 209 t = t->leftChild; 210 } 211 else if(t->rtag==0) 212 { 213 t = t->rightChild; 214 } 215 } 216 cout << t->data<<" "; //访问第一个结点 217 while ((p=Parent(t))!=NULL) //每次都先找到当前结点的父结点 218 { 219 //若当前结点是父节点的右子树或者当前结点是左子树,但是这个父节点没有右子树,则后续下的后继为改父节点 220 if (p->rightChild==t||p->rtag==1) 221 { 222 t = p; 223 } 224 //否则,在当前结点的右子树(如果存在)上重复执行上面的操作 225 else 226 { 227 t = p->rightChild; 228 while (t->ltag==0||t->rtag==0) 229 { 230 if (t->ltag==0) 231 { 232 t = t->leftChild; 233 } 234 else if (t->rtag==0) 235 { 236 t = t->rightChild; 237 } 238 } 239 } 240 cout << t->data << " "; 241 } 242 } 243 244 private: 245 //树的根节点 246 ThreadNode<T> *root; 247 T RefValue; 248 };
1 int main(int argc, char* argv[]) 2 { 3 //abc##de#g##f### 4 ThreadTree<char> tree(‘#‘); 5 tree.CreateTree(); 6 tree.CreateInThread(); 7 tree.InOrder(); 8 tree.PreOrder(); 9 tree.PostOrder(); 10 }
原文:https://www.cnblogs.com/WindSun/p/10871398.html