对于二叉树,其常见操作方法的逻辑 + 实现,这些都是面试高频:
求节点个数
求树的高度
求根节点
求当前节点的左孩子
求当前节点的右孩子
查找当前节点
查找当前节点的父节点
将二叉树置空
两个二叉树是否相同的比较
复制一个二叉树
。。。。。。
1、二叉树上的操作
均是C++实现先根序创建二叉树及其其它方法。
我认为在二叉树的创建方法和遍历以外,以下方法值得我们关注:
1public:
2 int size()const; //求结点个数
3 int height()const; //求树的高度
4 BinTreeNode* root_1()const; //求根节点 5 BinTreeNode* leftChild(BinTreeNode* cur)const; //求当前结点的左孩子 6 BinTreeNode* rightChild(BinTreeNode* cur)const; //求当前结点的右孩子 7 BinTreeNode* find(const Type &key)const; //查找当前结点 8 BinTreeNode* parent(BinTreeNode* cur)const; //查找当前结点的父结点 9 void makeEmpty(); //将二叉树置空10 bool equal(const BinTree &t)const; //两个二叉树是否相同的比较11 BinTreeNode* copy(BinTreeNode *t)const; //拷贝构造函数的方法,复制一个二叉树
2、方法一一实现
(1)、求结点个数
1template<typename Type>
2int BinTree::size(BinTreeNode *t)const{3 if(t == NULL){4 return 0;5 }67 return size(t->leftChild) + size(t->rightChild) + 1;8}
(2)、求树的高度
1template<typename Type>
2int BinTree::height(BinTreeNode *t)const{ 3 if(t == NULL){ 4 return 0; 5 } 6 int leftHeight = height(t->leftChild); 7 int rightHeight = height(t->rightChild); 8 9 return (leftHeight > rightHeight ? leftHeight : rightHeight) + 1;10}
(3)、查找当前结点
1template<typename Type>
2BinTreeNode* BinTree::find(const Type &key, BinTreeNode *t)const{ 3 if(t == NULL){ 4 return NULL; 5 } 6 if(t->data == key){ 7 return t; 8 } 910 BinTreeNode *p = find(key, t->leftChild);11 if(p != NULL){12 return p;13 }1415 return find(key, t->rightChild);16}
(4)、查找当前结点的父结点
1template<typename Type>
2BinTreeNode* BinTree::parent(BinTreeNode* cur, BinTreeNode *t)const{ 3 if(t == NULL || cur == NULL || cur == t){ 4 return NULL; 5 } 6 if(t->leftChild == cur || t->rightChild == cur){ 7 return t; 8 } //思路:利用父的孩子节点和当前节点比较 9 BinTreeNode *p = parent(cur, t->leftChild);10 if(p != NULL){11 return p;12 }1314 return parent(cur, t->rightChild);15}
(5)、将二叉树置空
1template<typename Type>
2void BinTree::makeEmpty(BinTreeNode *t){3 if(t != NULL){4 makeEmpty(t->leftChild);5 makeEmpty(t->rightChild);6 delete t;7 }8}
(6)、两个二叉树是否相同的比较
1template<typename Type>
2bool BinTree::equal(BinTreeNode *t, BinTreeNode *t1)const{ 3 if(t == NULL && t1 == NULL){ //取反判断与这个是一个道理 4 return true; 5 } 6 if(t != NULL && t1!= NULL && t->data == t1->data && equal(t->leftChild, t1->leftChild) 7 && equal(t->rightChild, t1->rightChild)){ 8 return true; 9 }else{1011 return false;12 }13}
(7)、拷贝一个二叉树
1template<typename Type>
2BinTreeNode* BinTree::copy(BinTreeNode *t)const{ 3 BinTreeNode* tmp; 4 5 if(t == NULL){ 6 return NULL; 7 }else{ 8 tmp = new BinTreeNode(t->data); 9 tmp->leftChild = copy(t->leftChild);10 tmp->rightChild = copy(t->rightChild);11 }1213 return tmp;14}
以上的这些方法都是利用二叉树的性质递归实现,比较好想清楚,就不做解释了,实在有问题,画画图就会好很多。
3、二叉树的所有方法,测试,及测试结果如下
(1)、所有关于二叉树的代码:
1#ifndef _BIN_TREE_H_
2#define _BIN_TREE_H_
3
4#include
5#include //非递归遍历引入栈
6#include //层次遍历引入队列
7using namespace std;
8
9template<typename Type> //为的是声明友元类,调用BinTreeNode的私有数据
10class BinTree;
11
12template<typename Type> //BinTreeNode类
13class BinTreeNode{
14 friend class BinTree;
15public:
16 BinTreeNode() : data(Type()), leftChild(NULL), rightChild(NULL){}
17 BinTreeNode(Type value, BinTreeNode *left = NULL, BinTreeNode *right = NULL) : 18 data(value), leftChild(left), rightChild(right){} 19 ~BinTreeNode(){} 20private: 21 Type data; 22 BinTreeNode *leftChild; 23 BinTreeNode *rightChild; 24}; 25/// 26template<typename Type> //BinTree类 27class BinTree{ 28public: 29 BinTree() : root(NULL){} 30 BinTree(Type ref) : root(NULL), refval(ref){} 31 BinTree(const BinTree &t){ 32 root = copy(t.root); //调用拷贝方法 33 } 34 ~BinTree(){ 35 makeEmpty(); //析构函数这里将二叉树置空 36 root = NULL; 37 } 38public: //创建二叉树 39 void createBinTree(); 40 void createBinTree(const char *str); 41 void createBinTree(const char *VLR, const char *LVR, int n); 42 void createBinTree_1(const char *LVR, const char *LRV, int n); 43public: //递归遍历 44 void prevOrder()const; 45 void inOrder()const; 46 void endOrder()const; 47public: //各种方法的声明 48 int size()const; 49 int height()const; 50 BinTreeNode* root_1()const; //以下的三个方法比较简单,就不在进行调用保护方法了; 51 BinTreeNode* leftChild(BinTreeNode* cur)const; 52 BinTreeNode* rightChild(BinTreeNode* cur)const; 53 BinTreeNode* find(const Type &key)const; 54 BinTreeNode* parent(BinTreeNode* cur)const; 55 void makeEmpty(); 56 bool equal(const BinTree &t)const; 57 BinTreeNode* copy(BinTreeNode *t)const; 58public: //非递归遍历 59 void prevOrder_1()const; 60 void inOrder_1()const; 61 void endOrder_1()const; 62 void levelOrder()const; //puublic:供外界提供的接口, 63 64protected: //protected:供自己函数内部调用,写保护方法 65 void prevOrder_1(BinTreeNode* t)const; 66 void inOrder_1(BinTreeNode* t)const; 67 void endOrder_1(BinTreeNode* t)const; 68 void levelOrder(BinTreeNode* t)const; 69protected: 70 int size(BinTreeNode *t)const; 71 int height(BinTreeNode *t)const; 72 BinTreeNode* find(const Type &key, BinTreeNode *t)const; 73 BinTreeNode* parent(BinTreeNode* cur, BinTreeNode *t)const; 74 void makeEmpty(BinTreeNode* t); 75 bool equal(BinTreeNode *t, BinTreeNode *t1)const; 76protected: 77 void prevOrder(BinTreeNode *t)const; 78 void inOrder(BinTreeNode *t)const; 79 void endOrder(BinTreeNode *t)const; 80protected : 81 void createBinTree(BinTreeNode *&t); 82 BinTreeNode* createBinTree_1(); 83 void createBinTree(const char *&str, BinTreeNode *&t); 84 BinTreeNode* createBinTree_1(const char *&str); 85 void createBinTree(BinTreeNode *&t, const char *VLR, const char *LVR, int n); 86 void createBinTree_1(BinTreeNode *&t, const char *LVR, const char *LRV, int n); 87 //以上都只是在类内声明; 88private: 89 BinTreeNode *root; 90 Type refval; //'#' 91}; 92/// 93template<typename Type> //类外实现公有方法的调用 94void BinTree::createBinTree(){ //创建二叉树 95 //createBinTree(root); 96 root = createBinTree_1(); 97} 98template<typename Type> 99void BinTree::prevOrder()const{ //先序递归遍历100 cout<<"先根序如下: "<<endl;101 prevOrder(root);102}103template<typename Type>104void BinTree::inOrder()const{ //中序递归遍历105 cout<<"中根序如下: "<<endl;106 inOrder(root);107}108template<typename Type>109void BinTree::endOrder()const{ //后序递归遍历110 cout<<"后根序如下: "<<endl;111 endOrder(root);112}113114template<typename Type>115void BinTree::createBinTree(const char *str){ //创建二叉树116// createBinTree(str, root);117 root = createBinTree_1(str);118}119template<typename Type>120int BinTree::size()const{ //求结点个数121 return size(root);122}123template<typename Type>124int BinTree::height()const{ //求树的高度125 return height(root);126}127template<typename Type>128BinTreeNode* BinTree::root_1()const{ //求根节点129 return root;130}131template<typename Type>132BinTreeNode* BinTree::leftChild(BinTreeNode* cur)const{ //求当前结点的左孩子133 return cur->leftChild;134}135template<typename Type>136BinTreeNode* BinTree::rightChild(BinTreeNode* cur)const{ //求当前结点的右孩子137 return cur->rightChild;138}139template<typename Type>140BinTreeNode* BinTree::find(const Type &key)const{ //查找当前结点141 return find(key, root);142}143template<typename Type>144BinTreeNode* BinTree::parent(BinTreeNode* cur)const{ //查找当前结点的父结点145 return parent(cur, root);146}147template<typename Type>148void BinTree::makeEmpty(){ //将二叉树置空149 makeEmpty(root);150}151template<typename Type>152bool BinTree::equal(const BinTree &t)const{ //两个二叉树是否相同的比较153 return equal(t.root, root);154}155template<typename Type>156void BinTree::prevOrder_1()const{ //非递归先序157 prevOrder_1(root);158}159template<typename Type>160void BinTree::inOrder_1()const{ //非递归中序161 inOrder_1(root);162}163template<typename Type>164void BinTree::endOrder_1()const{ //非递归后序165 endOrder(root);166}167template<typename Type>168void BinTree::levelOrder()const{ //层次遍历169 levelOrder(root);170}171template<typename Type>172void BinTree::createBinTree(const char *VLR, const char *LVR, int n){ //创建二叉树173 createBinTree(root, VLR, LVR, n);174}175template<typename Type> 176void BinTree::createBinTree_1(const char *LVR, const char *LRV, int n){ //创建二叉树177 createBinTree_1(root, LVR, LRV, n);178}179//180template<typename Type> //以下的都是写保护的方法,供自己使用181void BinTree::createBinTree_1(BinTreeNode *&t, const char *LVR, const char *LRV, int n){ //中序和后序创建二叉树182 if(n == 0){183 t = NULL;184 return;185 }186 int k = 0;187 while(LVR[k] != LRV[n-1]){188 k++;189 }190 t = new BinTreeNode(LVR[k]);191192 createBinTree_1(t->rightChild, LVR+k+1, LRV+k, n-k-1);193 createBinTree_1(t->leftChild, LVR, LRV, k);194}195template<typename Type>196void BinTree::createBinTree(BinTreeNode *&t, const char *VLR, const char *LVR, int n){ //先序和中序创建二叉树197 if(n == 0){198 t = NULL;199 return;200 }201 int k = 0;202 while(LVR[k] != VLR[0]){203 k++;204 }205 t = new BinTreeNode(LVR[k]);206 createBinTree(t->leftChild, VLR+1, LVR, k);207 createBinTree(t->rightChild, VLR+k+1, LVR+k+1, n-k-1);208}209template<typename Type>210void BinTree::levelOrder(BinTreeNode* t)const{ //层次遍历211 queue *> qu;212 BinTreeNode *p;213214 if(t != NULL){215 qu.push(t);216 while(!qu.empty()){217 p = qu.front();218 qu.pop();219 cout<data<<" ";220 if(p->leftChild){221 qu.push(p->leftChild);222 }223 if(p->rightChild){224 qu.push(p->rightChild);225 }226 }227 }228}229typedef enum{L, R}Tag;230template<typename Type>231class stkNode{232public:233 stkNode(BinTreeNode *p = NULL) : ptr(p), tag(L){}234public:235 BinTreeNode *ptr;236 Tag tag; //L R237};238template<typename Type>239void BinTree::endOrder_1(BinTreeNode* t)const{ //非递归后序240 stkNode n;241 stack> st;242 BinTreeNode *p = t;243244 do{245 while(p != NULL){246 n.ptr = p;247 n.tar = L;248 st.push(n);249 p = p->leftChild;250 }251 bool isRun = true;252 while(isRun && !st.empty()){253 n = st.top();254 st.pop();255256 switch(n.tag){257 case L:258 p = n.ptr;259 n.tag = R;260 st.push(n);261 p = p->rightChild;262 isRun = false;263 break;264 case R:265 cout<data<<" ";266 break;267 }268 }269 }while(!st.empty());//不用p1=NULL,因为当栈空时,最后一个节点刚好被访问完成。270}271template<typename Type>272void BinTree::inOrder_1(BinTreeNode* t)const{ //非递归中序273 stack *> st;274 BinTreeNode *p = t;275276 do{277 while(p != NULL){278 st.push(p);279 p = p->leftChild;280 }281 if(!st.empty()){282 p = st.top();283 st.pop();284 cout<data<<" ";285 p = p->rightChild;286 }//中序遍历时,当root出栈时,此时占空,287 }while(p != NULL || !st.empty()); //为根的时候右边还要入栈。288}289290template<typename Type>291void BinTree::prevOrder_1(BinTreeNode* t)const{ //非递归先序292 stack *> st;293 BinTreeNode *tmp;294295 if(t != NULL){296 st.push(t);297 while(!st.empty()){298 tmp = st.top();299 st.pop();300 cout<data<<" ";301 if(tmp->rightChild){302 st.push(tmp->rightChild);303 }304 if(tmp->leftChild){305 st.push(tmp->leftChild);306 }307 }308 }309}310template<typename Type>311BinTreeNode* BinTree::copy(BinTreeNode *t)const{ //拷贝函数312 BinTreeNode* tmp;313314 if(t == NULL){315 return NULL;316 }else{317 tmp = new BinTreeNode(t->data);318 tmp->leftChild = copy(t->leftChild);319 tmp->rightChild = copy(t->rightChild);320 }321322 return tmp;323}324template<typename Type>325bool BinTree::equal(BinTreeNode *t, BinTreeNode *t1)const{ //两个二叉树是否相同的比较326 if(t == NULL && t1 == NULL){ //取反判断与这个是一个道理327 return true;328 }329 if(t != NULL && t1!= NULL && t->data == t1->data && equal(t->leftChild, t1->leftChild)330 && equal(t->rightChild, t1->rightChild)){331 return true;332 }else{333334 return false;335 }336}337template<typename Type>338void BinTree::makeEmpty(BinTreeNode *t){ //将二叉树置空339 if(t != NULL){340 makeEmpty(t->leftChild);341 makeEmpty(t->rightChild);342 delete t;343 }344}345template<typename Type>346BinTreeNode* BinTree::parent(BinTreeNode* cur, BinTreeNode *t)const{ //查找当前结点的父结点347 if(t == NULL || cur == NULL || cur == t){348 return NULL;349 }350 if(t->leftChild == cur || t->rightChild == cur){351 return t;352 } //思路:利用父的孩子节点和当前节点比较353 BinTreeNode *p = parent(cur, t->leftChild);354 if(p != NULL){355 return p;356 }357358 return parent(cur, t->rightChild);359}360template<typename Type>361BinTreeNode* BinTree::find(const Type &key, BinTreeNode *t)const{ //查找当前结点362 if(t == NULL){363 return NULL;364 }365 if(t->data == key){366 return t;367 }368369 BinTreeNode *p = find(key, t->leftChild);370 if(p != NULL){371 return p;372 }373374 return find(key, t->rightChild);375}376template<typename Type>377int BinTree::height(BinTreeNode *t)const{ //求树的高度378 if(t == NULL){379 return 0;380 }381 int leftHeight = height(t->leftChild);382 int rightHeight = height(t->rightChild);383384 return (leftHeight > rightHeight ? leftHeight : rightHeight) + 1;385}386template<typename Type>387int BinTree::size(BinTreeNode *t)const{ //求结点个数388 if(t == NULL){389 return 0;390 }391392 return size(t->leftChild) + size(t->rightChild) + 1;393}394template<typename Type>395BinTreeNode* BinTree::createBinTree_1(const char *&str){ //创建二叉树396 BinTreeNode *t;397398 if(refval == *str){399 t = NULL;400 }else{401 t = new BinTreeNode(*str);402 t->leftChild = createBinTree_1(++str);403 t->rightChild = createBinTree_1(++str);404 }405 return t;406}407408template<typename Type>409void BinTree::createBinTree(const char *&str, BinTreeNode *&t){ //创建二叉树410 if(*str == refval){411 t = NULL;412 }else{413 t = new BinTreeNode(*str);414 createBinTree(++str, t->leftChild); //前加,后加不一样!!!在这里,就是传引用,保证每次字符串都是往后走的415 createBinTree(++str, t->rightChild);416 }417}418template<typename Type>419BinTreeNode* BinTree::createBinTree_1(){ //创建二叉树420 Type createData;421 cin>>createData;422 BinTreeNode *t;423424 if(refval == createData){425 t = NULL;426 }else{427 t = new BinTreeNode(createData);428 t->leftChild = createBinTree_1();429 t->rightChild = createBinTree_1();430 }431432 return t;433}434template<typename Type>435void BinTree::endOrder(BinTreeNode *t)const{ //后序递归遍历436 if(t == NULL){437 return;438 }else{439 endOrder(t->leftChild);440 endOrder(t->rightChild);441 cout<data<<" ";442 }443}444445template<typename Type> 446void BinTree::inOrder(BinTreeNode *t)const{ //中序递归遍历447 if(t == NULL){448 return;449 }else{450 inOrder(t->leftChild);451 cout<data<<" ";452 inOrder(t->rightChild);453 }454}455456template<typename Type>457void BinTree::prevOrder(BinTreeNode *t)const{ //先序递归遍历458 if(t == NULL){459 return;460 }else{461 cout<data<<" ";462 prevOrder(t->leftChild);463 prevOrder(t->rightChild);464 }465}466//根据先根序创建二叉树467template<typename Type>468void BinTree::createBinTree(BinTreeNode *&t){ //创建二叉树469 Type createData;470 cin>>createData;471472 if(refval == createData){473 t = NULL;474 }else{475 t = new BinTreeNode(createData);476 createBinTree(t->leftChild);477 createBinTree(t->rightChild);478 }479}480481#endif
以上代码我采用折叠的方式进行写的;类外公有调用下面紧跟保护方法的实现。
(2)、测试代码
1#include"BinTree.h"
2//ABC##DE##F##G#H##
3/* 4先根序如下: 5A B C D E F G H 6中根序如下: 7C B E D F A G H 8后根序如下: 9C E F D B H G A10*/
11int main(void){
12// char *VLR = "ABCDEFGH";
13// char *LVR = "CBEDFAGH";
14// char *LRV = "CEFDBHGA";
15
16// BinTree bt; //对象初始化不写'#';
17// int n = strlen(VLR);
18// bt.createBinTree(VLR, LVR, n); //在这里创建二叉树不用'#'结束,因为是由先序和中序创建,不看结束标志'#';
19// bt.createBinTree_1(LVR, LRV, n);
20// bt.prevOrder();
21// cout<2223 //bt.createBinTree(VLR, LRV, n); 不能创建2425/*26 BinTree bt('#');27 char *str = "ABC##DE##F##G#H##";28// char *str = "ABC##DE###G#H##";29 bt.createBinTree(str);30 BinTree bt1(bt);31 bt1.levelOrder();32 cout<3334*/3536/* 3738// st.createBinTree();39 BinTree bt('#');40 BinTree bt1('#');41 char *str = "ABC##DE##F##G#H##";42 bt.createBinTree(str);43 bt1.createBinTree(str); //构建的是一颗空树,引用传递构建,原先字符串已经为空!4445 if(bt.equal(bt1)){46 cout<47 }else{48 cout<49 }50*/ 51 BinTree<char> bt('#');52 char *str = "ABC##DE##F##G#H##";53 bt.createBinTree(str);54 cout<endl;
55 cout<endl;56 BinTreeNode<char> *p = bt.find('H');57 BinTreeNode<char> *t = bt.find('G');58 printf("%p\n", t);59 BinTreeNode<char> *q = bt.parent(p);60 printf("%p\n", q);6162 bt.prevOrder();63 cout<<endl;64 bt.inOrder();65 cout<<endl;66 bt.endOrder();67 cout<<endl;6869 return 0;70}
这是所有测试要用的代码,在编写时,写一个方法测试一个,将测试过的就注释起来了。
(3)、部分测试结果
至于其它的测试结果就不在给出了,有兴趣可以在测测其它的方法。
推荐阅读:
从零开始学习数据结构-->入门篇
从零开始学习数据结构-->链表
从零开始学习数据结构-->线性表
从零开始学习数据结构-->栈
从零开始学习数据结构-->队列
从零开始学习数据结构-->矩阵+串
从零开始学习数据结构-->哈希表
从零开始学习数据结构-->散列桶
从零开始学习数据结构-->二叉树
认真的人 自带光芒