根据前序遍历和中序遍历的结果确定一颗二叉树并用树形格式打印输出
2013-10-21 01:12 Ross Wang 阅读(1071) 评论(0) 编辑 收藏 举报前提
根据一颗二叉树的前序遍历和中序遍历结果肯定可以唯一地确定一颗二叉树.
证明: http://wenku.baidu.com/view/bf365b3431126edb6f1a1041.html
本篇文章主要解决两个问题:
1. 根据所给的前序和中序遍历结果确定一颗二叉树
2. 用我们熟悉的树形格式打印输出二叉树
确定二叉树
主要思想网上有很多帖子都提到了, 基本思路:
1. 从前序遍历结果获取父节点。
2. 用这个父节点把中序遍历结果分为两部分,左边是左子树的结点(可能为空),,右边是右子树的结点(也可能为空)。
3. 如果左子树不为空,递归进行1,2步,右子树类似。
树形格式输出二叉树
一般情况下,无论是前序、中序还是后序,都无法直接输出树形格式的二叉树,因为输出的时候会用到递归,不符合按层输出的要求。
当然如果二叉树的实现方式不同,就有可能直接按层输出。请参考http://www.cnblogs.com/Lowp/p/3379222.html
本文还是按照传统方式实现二叉树,使用类似于数组转置的思路完成。
输出树形结构示意图:
完整代码
1 #include<iostream> 2 #include<string> 3 #include<vector> 4 5 using namespace std; 6 7 /****************************** 8 定义二叉树节点结构 9 bValue: 结点值 10 lNode: 左结点指针 11 rNode: 右结点指针 12 ******************************/ 13 struct BNode 14 { 15 char bValue; 16 BNode * lNode; 17 BNode * rNode; 18 BNode(); 19 }; 20 21 /****************************** 22 定义默认构造函数是为了避免一些编译器在初始化时, 23 初始值不确定的情况。 24 比如微软编译器在release编译模式下会对默认构造函数进行优化, 25 初始值不确定 26 明确定义默认构造函数可以让程序按照我们设想的方式运行。 27 ******************************/ 28 BNode::BNode():bValue(0),lNode(NULL),rNode(NULL) 29 { 30 } 31 32 /****************************** 33 声明函数DetermineBTree 34 用来执行具体的二叉树确定和输出 35 node: 父节点指针 36 preOrderStr: 前序遍历结果 37 midOrderStr: 中序遍历结果 38 ******************************/ 39 void DetermineBTree(BNode * node, const string &preOrderStr, const string &midOrderStr); 40 41 /****************************** 42 声明函数PrintBTree,打印二叉树。 43 node: 节点指针 44 ******************************/ 45 void PrintBTree(BNode * node); 46 47 /****************************** 48 声明函数DeleteBTree,释放二叉树所有节点的空间并销毁。 49 node: 节点指针 50 ******************************/ 51 void DeleteBTree(BNode * node); 52 53 /****************************** 54 声明函数DepthOfBTree,获取二叉树的深度。 55 node: 节点指针 56 ******************************/ 57 int DepthOfBTree(BNode * node); 58 59 int main() 60 { 61 //定义前序和中序遍历结果 62 string preOrderStr = "ABDECFG"; 63 string midOrderStr = "DBEACGF"; 64 65 //定义根节点指针 66 BNode * rootNode = new BNode(); 67 //确定二叉树 68 DetermineBTree(rootNode,preOrderStr,midOrderStr); 69 if(!rootNode) 70 { 71 cout<<"Cannot determine a BTree according to the given preOrderStr and midOrderStr!"<<endl; 72 } 73 else 74 { 75 //打印二叉树 76 PrintBTree(rootNode); 77 //释放二叉树存储空间 78 DeleteBTree(rootNode); 79 cout<<"BTree has been destroyed!"<<endl; 80 } 81 82 getchar(); 83 return 0; 84 } 85 86 //定义DetermineBTree的实现体 87 void DetermineBTree(BNode * node, const string &preOrderStr, const string &midOrderStr) 88 { 89 //对前序和中序遍历结果进行基本的合法性检查。 90 if(preOrderStr.empty() || midOrderStr.empty() || 91 preOrderStr.length() !=midOrderStr.length()) 92 { 93 cout<<"preOrderStr or midOrderStr is not valid!"<<endl; 94 node = NULL; 95 return; 96 } 97 //根结点不能为空 98 //递归的时候结点指针在作为实参传入的时候已经初始化了,肯定不会是NULL 99 if(!node) 100 { 101 cout<<"Error occured, node is NULL!"<<endl; 102 return; 103 } 104 105 //前序结果的第一个char元素应该就是node的value。 106 node->bValue = preOrderStr[0]; 107 //在中序遍历结果中查找根节点。 108 int rootNodeIndex = midOrderStr.find(preOrderStr[0]); 109 if(rootNodeIndex < 0) 110 { 111 cout<<"midOrderStr has a char not in preOrderStr!"<<endl; 112 node = NULL; 113 return; 114 } 115 else if(rootNodeIndex == 0) 116 { 117 //说明该节点没有左子树 118 node->lNode = NULL; 119 } 120 else 121 { 122 string leftMidOrderSubBTreeStr = midOrderStr.substr(0,rootNodeIndex); 123 string leftPreOrderSubBTreeStr = preOrderStr.substr(1,rootNodeIndex); 124 node->lNode = new BNode(); 125 DetermineBTree(node->lNode,leftPreOrderSubBTreeStr, leftMidOrderSubBTreeStr); 126 } 127 128 129 if(rootNodeIndex ==( preOrderStr.length() - 1)) 130 { 131 //说明该节点没有右子树 132 node->rNode = NULL; 133 } 134 else 135 { 136 string rightMidOrderSubBTreeStr = midOrderStr.substr(rootNodeIndex+1); 137 string rightPreOrderSubBTreeStr = preOrderStr.substr(1+rootNodeIndex); 138 node->rNode = new BNode(); 139 DetermineBTree(node->rNode,rightPreOrderSubBTreeStr, rightMidOrderSubBTreeStr); 140 } 141 142 143 } 144 145 void GetConvertedBTree(const BNode * node, const int &depth, 146 int layer,vector<string> &outputBTree) 147 { 148 int i; 149 if(node==NULL) return; 150 GetConvertedBTree(node->lNode,depth,layer+1,outputBTree); 151 string row = ""; 152 for(i=0;i<2*layer-1;i++) 153 { 154 row.append(" "); 155 } 156 if(layer>0) 157 { 158 row.append("-"); 159 } 160 row.append(1,node->bValue); 161 row.resize(2*depth+1, ' '); 162 outputBTree.push_back(row); 163 GetConvertedBTree(node->rNode,depth,layer+1,outputBTree); 164 } 165 166 //定义PrintBTree的实现体 167 void PrintBTree(BNode * node) 168 { 169 int depth = DepthOfBTree(node) -1; 170 if(depth == 0) 171 { 172 cout<<"This is an empty BTree!"<<endl; 173 } 174 else 175 { 176 vector<string> outputBTree; 177 GetConvertedBTree(node,depth,0,outputBTree); 178 179 //中序遍历方式输出的二叉树。 180 cout<<"middle ordered output:"<<endl; 181 for(vector<string>::const_iterator it = outputBTree.begin(); 182 it != outputBTree.end(); ++it) 183 { 184 cout<<*it<<endl; 185 } 186 187 //调整方向后树形格式的二叉树 188 cout<<"adjusted output:"<<endl; 189 for(int column = 0; column < depth*2+1; ++column) 190 { 191 for(vector<string>::const_iterator it = outputBTree.begin(); 192 it != outputBTree.end(); ++it) 193 { 194 if((*it)[column] == '-') 195 cout<<"|"; 196 else 197 cout<<(*it)[column]; 198 } 199 cout<<endl; 200 } 201 } 202 } 203 204 205 //定义DepthOfBTree的实现体 206 int DepthOfBTree(BNode * node) 207 { 208 int depthTotal(0),depthLeft(0),depthRight(0); 209 if (!node) 210 depthTotal = 0; 211 else 212 { 213 depthLeft = DepthOfBTree( node->lNode ); 214 depthRight= DepthOfBTree( node->rNode ); 215 depthTotal =1 + (depthLeft > depthRight ?depthLeft : depthRight); 216 } 217 return depthTotal; 218 } 219 220 //定义DeleteBTree的实现体 221 void DeleteBTree(BNode * node) 222 { 223 //判断输入的根节点是否为空,也就是是否是个空树。 224 if(node) 225 { 226 if(node->lNode)DeleteBTree(node->lNode); 227 if(node->rNode)DeleteBTree(node->rNode); 228 delete node; 229 } 230 else 231 cout<<"This is an empty BTree!"<<endl; 232 }