二叉树遍历
二叉树的操作有前序递归遍历,前序非递归遍历,中序递归遍历,中序非递归遍历,后序递归遍历,后序非递归遍历,层序遍历,
递归打印叶子结点,非递归打印叶子结点。
若一棵树的结构如下,它的前序遍历是ABD##E#F##CG###
则对树的操作代码如下:
类BiTree, 则bitree.h的代码如下:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #ifndef BITREE_H 2 #define BITREE_H 3 4 const int MaxSize = 100; 5 6 template <class T> 7 struct BiNode //二叉树的结点结构 8 { 9 T data; 10 BiNode<T> *lchild, *rchild; 11 }; 12 13 template<class T> 14 struct element //二叉树的结点结构,用于后序非递归遍历时 15 { 16 BiNode<T>* ptr; 17 int flag; 18 }; 19 20 template <class T> 21 class BiTree 22 { 23 public: 24 BiTree( ); //构造函数,初始化一棵二叉树,其前序序列由键盘输入 25 ~BiTree(void); //析构函数,释放二叉链表中各结点的存储空间 26 BiNode<T>* Getroot(); //获得指向根结点的指针 27 void PreOrder(BiNode<T> *root); //递归前序遍历二叉树 28 void NoPreOrder(BiNode<T>* root); //非递归前序遍历二叉树 29 void InOrder(BiNode<T> *root); //中序遍历二叉树 30 void NoInOrder(BiNode<T>* root); //非递归中序遍历二叉树 31 void PostOrder(BiNode<T> *root); //后序遍历二叉树 32 void NoPostOrder(BiNode<T>* root); //非递归后序遍历二叉树 33 void LeverOrder(BiNode<T> *root); //层序遍历二叉树 34 void CountLeaf(BiNode<T> *root); //递归求二叉树的叶子结点个数 35 void NoCountLeaf(BiNode<T> *root); //非递归求二叉树的叶子结点个数 36 int getCount(); 37 private: 38 BiNode<T> *root; //指向根结点的头指针 39 BiNode<T> *Creat( ); //有参构造函数调用 40 void Release(BiNode<T> *root); //析构函数调用 41 int count; 42 }; 43 44 #endif // BITREE_H
对二叉树的操作,bitree.cpp
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include<iostream> 2 #include<string> 3 #include"bitree.h" 4 using namespace std; 5 6 template<class T> 7 BiTree<T>::BiTree( ) 8 { 9 this->root = Creat( ); 10 count=0; 11 } 12 13 template<class T> 14 BiTree<T>::~BiTree(void) 15 { 16 Release(root); 17 } 18 19 template<class T> 20 BiNode<T>* BiTree<T>::Getroot( ) 21 { 22 return root; 23 } 24 25 26 template<class T> 27 void BiTree<T>::PreOrder(BiNode<T> *root) 28 { 29 if(root==NULL) return; 30 else{ 31 cout<<root->data<<" "; 32 PreOrder(root->lchild); 33 PreOrder(root->rchild); 34 } 35 } 36 37 template<class T> 38 void BiTree<T>::NoPreOrder(BiNode<T>*root) 39 { 40 BiNode<T> *s[MaxSize]; 41 int top=-1; 42 while(root!=NULL||top!=-1) 43 { 44 while(root!=NULL) 45 { 46 cout<<root->data<<" "; 47 s[++top]=root; 48 root=root->lchild; 49 } 50 if(top!=-1) 51 { 52 root=s[top--]; //此处为s[top--],意思是当栈顶结点没有左子树时,返回得到栈顶结点 53 root=root->rchild; //判断此栈顶结点有没有右子树 54 } 55 } 56 57 } 58 59 template<class T> 60 void BiTree<T>::NoInOrder(BiNode<T> *root) 61 { 62 int top=-1; 63 BiNode<T> *s[MaxSize]; 64 65 while(root!=NULL||top!=-1) 66 { 67 while(root!=NULL) 68 { 69 s[++top]=root; 70 root=root->lchild; 71 } 72 73 if(top!=-1) 74 { 75 root=s[top--]; 76 cout<<root->data<<" "; 77 root=root->rchild; 78 } 79 } 80 81 } 82 83 template <class T> 84 void BiTree<T>::InOrder (BiNode<T> *root) 85 { 86 if (root==NULL) return; //递归调用的结束条件 87 else{ 88 InOrder(root->lchild); //中序递归遍历root的左子树 89 cout<<root->data<<" "; //访问根结点的数据域 90 InOrder(root->rchild); //中序递归遍历root的右子树 91 } 92 } 93 94 95 template <class T> 96 void BiTree<T>::PostOrder(BiNode<T> *root) 97 { 98 if (root==NULL) return; //递归调用的结束条件 99 else{ 100 PostOrder(root->lchild); //后序递归遍历root的左子树 101 PostOrder(root->rchild); //后序递归遍历root的右子树 102 cout<<root->data<<" "; //访问根结点的数据域 103 } 104 } 105 106 107 108 //后序非递归遍历与前序和中序不同,在后序 109 //遍历中结点要两次入栈, 两次出栈, 110 111 //第一次出栈:只遍历完左子树,尚未遍历右子 112 //树,则该结点不出栈,利用栈顶找到右子树 113 114 //第二次出栈,遍历完右子树,将该结点出栈 115 //该结点可以访问 116 // 117 118 template<class T> 119 void BiTree<T>::NoPostOrder(BiNode<T> *root) 120 { 121 int top=-1; 122 element<T> s[MaxSize]; 123 while(root!=NULL||top!=-1) 124 { 125 while(root!=NULL) 126 { 127 top++; 128 s[top].ptr=root; 129 s[top].flag=1; 130 root=root->lchild; 131 } 132 while(top!=-1 &&s[top].flag==2) 133 { 134 root=s[top--].ptr; 135 cout<<root->data<<" "; 136 root=NULL; /*若缺少这一句,导致死循环,即在top=-1时,此时的root却并不为空而是整棵树的根结点*/ 137 } 138 if(top!=-1) 139 { 140 s[top].flag=2; 141 root=s[top].ptr->rchild; 142 } 143 } 144 } 145 146 147 template <class T> 148 void BiTree<T>::LeverOrder(BiNode<T> *root) 149 { 150 int front = 0; 151 int rear = 0; //采用顺序队列,并假定不会发生上溢 152 153 BiNode<T>* Q[MaxSize]; 154 BiNode<T>* q; 155 156 if (root==NULL) return; 157 else{ 158 Q[rear++] = root; 159 while (front != rear) 160 { 161 q = Q[front++]; 162 cout<<q->data<<" "; 163 if (q->lchild != NULL) Q[rear++] = q->lchild; 164 if (q->rchild != NULL) Q[rear++] = q->rchild; 165 } 166 } 167 } 168 169 template<class T> 170 void BiTree<T>::NoCountLeaf(BiNode<T> *root) 171 { 172 int front, rear; 173 front = rear = 0; 174 BiNode<T> *Q[MaxSize]; 175 BiNode<T> *q; 176 if(root == NULL) return; 177 else 178 { 179 Q[rear++] = root; 180 while(rear != front) 181 { 182 q = Q[front++]; 183 if(q->lchild != NULL) Q[rear++] = q->lchild; 184 if(q->rchild != NULL) Q[rear++] = q->rchild; 185 if(!q->lchild && !q->rchild) 186 { 187 cout << q->data << " "; 188 } 189 } 190 } 191 } 192 193 template <class T> 194 BiNode<T>* BiTree<T>::Creat( ) 195 { 196 BiNode<T>* root; 197 T ch; 198 cout<<"请输入创建一棵二叉树的结点数据"<<endl; 199 cin>>ch; 200 if (ch=="#") root = NULL; 201 else{ 202 root = new BiNode<T>; //生成一个结点 203 root->data=ch; 204 root->lchild = Creat( ); //递归建立左子树 205 root->rchild = Creat( ); //递归建立右子树 206 } 207 return root; 208 } 209 210 211 template<class T> 212 void BiTree<T>::Release(BiNode<T>* root) 213 { 214 if (root != NULL){ 215 Release(root->lchild); //释放左子树 216 Release(root->rchild); //释放右子树 217 delete root; 218 } 219 } 220 221 222 /*递归求二叉树的叶子结点的个数,如果要非递归求二叉树的叶子结点, 223 //只需在前序、中序、后序的遍历中,加上一个判断语句,判断该结点的左右子树是否为空,若是则count++*/ 224 template<class T> 225 void BiTree<T>::CountLeaf(BiNode<T> *root) 226 { 227 if(root!=NULL) 228 { 229 if(root->lchild==NULL&& root->rchild==NULL) 230 { 231 count++; 232 cout<<root->data<<" "; 233 } 234 CountLeaf(root->lchild); 235 CountLeaf(root->rchild); 236 } 237 } 238 239 240 //返回叶子结点的个数 241 template<class T> 242 int BiTree<T>::getCount() 243 { 244 return count; 245 }
对二叉树操作的测试,main.cpp
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 //#include<iostream> 2 //#include<string> 3 #include"bitree.cpp" 4 5 //using namespace std; 6 7 int main() 8 { 9 BiTree<string> bt; //创建一棵树 10 BiNode<string>* root = bt.Getroot( ); //获取指向根结点的指针 11 12 cout<<"------递归前序遍历------ "<<endl; 13 bt.PreOrder(root); 14 cout<<endl; 15 16 cout<<"------非递归前序遍历------"<<endl; 17 bt.NoPreOrder(root); 18 cout<<endl; 19 20 cout<<"------递归中序遍历------ "<<endl; 21 bt.InOrder(root); 22 cout<<endl; 23 24 cout<<"------非递归中序遍历------ "<<endl; 25 bt.NoInOrder(root); 26 cout<<endl; 27 28 cout<<"------递归后序遍历------ "<<endl; 29 bt.PostOrder(root); 30 cout<<endl; 31 32 cout<<"------非递归后序遍历------ "<<endl; 33 bt.NoPostOrder(root); 34 cout<<endl; 35 36 cout<<"------层序遍历------ "<<endl; 37 bt.LeverOrder(root); 38 cout<<endl; 39 40 cout<<"----递归求二叉树的叶子结点----"<<endl; 41 bt.CountLeaf(root); 42 cout<<endl; 43 44 cout<<"----非递归求二叉要的叶子结点--"<<endl; 45 bt.NoCountLeaf(root); 46 cout << endl; 47 48 cout<<"-----叶子结点的个数是-------"<<endl; 49 cout<<bt.getCount(); 50 cout<<endl; 51 52 return 0; 53 } 54 55 /* 56 * main.cpp中文件头所需要的头文件,如果是下面这样: 57 * #include<iostream> 58 * #include<string> 59 * #include<bitree.h> 60 * using namespace std; 61 * 这样会出错。因为BiTree<T>是一个模板,BiTree<string>是一个实例,从BiTree到BiTree<string>的过程是实例化的过程 62 * 按照传统编译方式时,编译器在bitree.h中看到了模板的声明,但没有看到模板的定义,故而会错。 63 * 64 *更改方式: 65 *1. 直接在main.cpp的文件头中包含 #include "bitree.cpp"即可 66 * 67 *2. 将bitree.h和bitree.cpp合并,将函数的实现写在bitree.h 68 * 69 * 70 * 71 * 72 */