c++二叉树构建及面试常见问题代码实现

来源:互联网 发布:汤臣一品 知乎 编辑:程序博客网 时间:2024/06/06 13:38
二叉树面试常见问题包括:
  • 二叉树中的节点个数
  • 二叉树的深度
  • 前序遍历,中序遍历,后序遍历,层序遍历
  • 将二叉查找树变为有序的双向链表
  • 二叉树第K层的节点个数
  • 二叉树中叶子节点的个数
  • 判断二叉树是不是平衡二叉树
  • 二叉树的镜像
  • 二叉树中两个节点的最低公共祖先节点
  • 二叉树中节点的最大距离
  • 判断二叉树是不是完全二叉树

下面是完整二叉树及这些常见问题的代码实现:

头文件BTree.h

#ifndef BTREE_H#define BTREE_Hstruct BTreeNode{int data;BTreeNode *lChild,*rChild;};class BTree{public:void setRoot(BTreeNode* r){ root=r;}BTreeNode* getRoot(){ return root;}BTreeNode* createBTree();BTree():root(createBTree()){}//中序遍历(递归)void inOrder();//中序遍历(非递归)void NotReInOrder();//前序遍历(递归)void preOrder();//前序遍历(非递归)void NotRePreOrder();//后序遍历(递归)void postOrder();//后序遍历(非递归)void NotRePostOrder();//层序遍历BFS void LevelOrder(BTreeNode*); //求结点个数int BTreeSize();//求叶子结点个数int BTreeLeaves();//求树高int BTreeHeight();//将二叉查找树变为有序的双向链表void convert_tree_list(BTreeNode * pRoot, BTreeNode * & pFirstNode, BTreeNode * & pLastNode); //二叉树第k层节点个数int GetNodeNumKthLevel(BTreeNode * pRoot, int k);//判断二叉树是否是平衡的bool IsAVL(BTreeNode * pRoot,int & height); //求二叉树的镜像BTreeNode * Mirror(BTreeNode * pRoot); //判断一个节点是否存在 bool FindNode(BTreeNode * pRoot, BTreeNode * pNode);// 求二叉树两个节点的公共祖先BTreeNode * GetLastCommonParent(BTreeNode * pRoot,                                       BTreeNode * pNode1,                                       BTreeNode * pNode2);         //求二叉树节点的最大距离     int GetMaxDistance(BTreeNode * pRoot, int & maxLeft, int & maxRight);         //判断一颗树是不是完全二叉树bool IsCompleteBinaryTree(BTreeNode * pRoot); protected://中序遍历void inOrder(BTreeNode*);//前序遍历void preOrder(BTreeNode*);//后序遍历void postOrder(BTreeNode*);//结点个数int BTreeSize(BTreeNode*);//叶子结点int BTreeLeaves(BTreeNode*);//树高int BTreeHeight(BTreeNode*);private:BTreeNode* root;};#endif
源文件BTree.cpp

#include <iostream>#include <stack>#include <queue>#include <algorithm>#include "BTree.h"using namespace std;//建立二叉树的算法BTreeNode* BTree::createBTree(){BTreeNode* current=0;int val=0;cin>>val;//-1的个数比数值的个数多1if(val==-1)return NULL;else{current=new BTreeNode;current->data=val;current->lChild=createBTree();current->rChild=createBTree();return current;}}//利用重载的方法void BTree::inOrder(){inOrder(root);cout<<endl;}//中序访问二叉树(递归)void BTree::inOrder(BTreeNode* r){if(r!=0) //是if,而不是while{inOrder(r->lChild); //递归访问cout<<r->data<<" ";inOrder(r->rChild); //递归访问}}//中序遍历(非递归)//往左放,放完访问,回溯到右 void BTree::NotReInOrder(){stack<BTreeNode*> s;BTreeNode* r=getRoot();while(!s.empty()||r!=0){while(r!=0){s.push(r);r=r->lChild;}if(!s.empty()){r=s.top();s.pop();cout<<r->data<<" ";r=r->rChild;}}}//重载形式void BTree::preOrder(){preOrder(root);cout<<endl;}//前序递归访问二叉树(递归)void BTree::preOrder(BTreeNode* r){if(r!=0) //是if,而不是while{cout<<r->data<<" ";preOrder(r->lChild); //递归访问preOrder(r->rChild); //递归访问}}//前序遍历(非递归)//过程可以理解为:放入一个元素,访问它,弹出,//放入她的右孩子以便返回,放入左孩子用于下次访问 void BTree::NotRePreOrder(){stack<BTreeNode*> s;BTreeNode* r=getRoot();s.push(r);while(!s.empty()){r=s.top();s.pop();cout<<r->data<<" ";if(r->rChild!=0)s.push(r->rChild);if(r->lChild!=0)s.push(r->lChild);}}//重载形式void BTree::postOrder(){postOrder(root);cout<<endl;}//后序遍历(递归)void BTree::postOrder(BTreeNode* r){if(r!=0) //是if,而不是while{postOrder(r->lChild); //递归访问postOrder(r->rChild); //递归访问cout<<r->data<<" ";}}//后序非递归访问要定义新的结构体类型struct Node{BTreeNode* tp;bool flag;};//后序遍历(非递归)void BTree::NotRePostOrder(){Node node; //定义Node结构体的一个结点stack<Node> s;BTreeNode* r=getRoot();while(!s.empty()||r!=0){while(r!=0){node.tp=r;node.flag=0;s.push(node);r=r->lChild;}if(!s.empty()){node=s.top();s.pop();r=node.tp; //将栈顶的BTreeNode*部分赋给rif(node.flag==1){cout<<r->data<<" ";r=0; //表示已经访问了该结点}else{node.flag=1;s.push(node);r=r->rChild;}}}}//层序遍历,即广度优先搜索,用到queue void BTree::LevelOrder(BTreeNode* pRoot)  {      if(pRoot == NULL)          return;      queue<BTreeNode *> q;      q.push(pRoot);      while(!q.empty())      {          BTreeNode * pNode = q.front();          q.pop();          cout<<pNode->data; // 访问节点          if(pNode->lChild != NULL)              q.push(pNode->lChild);          if(pNode->rChild != NULL)              q.push(pNode->rChild);      }}//重载形式int BTree::BTreeSize(){return BTreeSize(root);}//求二叉树结点个数的函数int BTree::BTreeSize(BTreeNode* r){//二叉树的结点个数为左右子树的高度之和再+1if(r==0) return 0; elsereturn 1+BTreeSize(r->lChild)+BTreeSize(r->rChild);}//重载形式int BTree::BTreeLeaves(){return BTreeLeaves(root);}//求二叉树叶子结点个数的函数int BTree::BTreeLeaves(BTreeNode* r){//当为空时,返回0;当找到叶子时返回1if(r==0) return 0; else if(r->lChild==0&&r->rChild==0)return 1;elsereturn BTreeLeaves(r->lChild)+BTreeLeaves(r->rChild);}//重载形式int BTree::BTreeHeight(){return BTreeHeight(root);}//求二叉树高度的函数int BTree::BTreeHeight(BTreeNode* r){if(r==0) return 0;//二叉树的高度为左右子树的最大者+1elsereturn max(BTreeHeight(r->lChild),BTreeHeight(r->rChild))+1;}void BTree::convert_tree_list(BTreeNode * pRoot, BTreeNode * & pFirstNode, BTreeNode * & pLastNode){      BTreeNode *pLastLeft, * pFirstRight;      if(pRoot == NULL)       {          pFirstNode = NULL;          pLastNode = NULL;          return;      }        if(pRoot->lChild == NULL)      {          // 如果左子树为空,对应双向有序链表的第一个节点是根节点          pFirstNode = pRoot;      }      else      {          convert_tree_list(pRoot->lChild, pFirstNode, pLastLeft);            // 将根节点和左子树转换后的双向有序链表的最后一个节点连接          pRoot->lChild = pLastLeft;          pLastLeft->rChild = pRoot;      }        if(pRoot->rChild == NULL)      {          // 对应双向有序链表的最后一个节点是根节点          pLastNode = pRoot;      }      else      {          convert_tree_list(pRoot->rChild, pFirstRight, pLastNode);          // 将根节点和右子树转换后的双向有序链表的第一个节点连接          pRoot->rChild = pFirstRight;          pFirstRight->lChild = pRoot;      }  } //二叉树第k层节点个数int BTree::GetNodeNumKthLevel(BTreeNode * pRoot, int k)  {      if(pRoot == NULL || k < 1)  return 0;      else if(k == 1)  return 1;      else return (GetNodeNumKthLevel(pRoot->lChild, k-1) + GetNodeNumKthLevel(pRoot->rChild, k-1));  }  //判断二叉树是否是平衡的bool BTree::IsAVL(BTreeNode * pRoot,int & height){if(pRoot == NULL) // 空树,返回真      {          height = 0;          return true;      }      int heightLeft;      bool resultLeft = IsAVL(pRoot->lChild, heightLeft);      int heightRight;      bool resultRight = IsAVL(pRoot->rChild, heightRight);      if(resultLeft && resultRight && abs(heightLeft - heightRight) <= 1) // 左子树和右子树都是AVL,并且高度相差不大于1,返回真      {          height = max(heightLeft, heightRight) + 1;          return true;      }      else      {          height = max(heightLeft, heightRight) + 1;          return false;      }  }//求二叉树的镜像BTreeNode * BTree::Mirror(BTreeNode * pRoot){if(pRoot == NULL)  return NULL;  // 交换左子树和右子树      pRoot->lChild = Mirror(pRoot->rChild);    pRoot->rChild = Mirror(pRoot->lChild);       return pRoot;  } //判断一个节点是否存在 bool BTree::FindNode(BTreeNode * pRoot, BTreeNode * pNode){if(pRoot == NULL || pNode == NULL)  return false;      else if(pRoot == pNode)  return true;    else return FindNode(pRoot->lChild, pNode)||FindNode(pRoot->rChild, pNode);  }// 求二叉树两个节点的公共祖先BTreeNode * BTree::GetLastCommonParent(BTreeNode * pRoot,                                   BTreeNode * pNode1,                                   BTreeNode * pNode2){bool lf1=FindNode(pRoot->lChild,pNode1);bool lf2=FindNode(pRoot->lChild,pNode2);bool rf1=FindNode(pRoot->rChild,pNode1);bool rf2=FindNode(pRoot->rChild,pNode2);if(lf1&&lf2) return GetLastCommonParent(pRoot->lChild,pNode1,pNode2);else if(rf1&&rf2) return GetLastCommonParent(pRoot->rChild,pNode1,pNode2);else return pRoot;}//求二叉树节点的最大距离 //用到分治策略 int BTree::GetMaxDistance(BTreeNode * pRoot, int & maxLeft, int & maxRight){// maxLeft, 左子树中的节点距离根节点的最远距离      // maxRight, 右子树中的节点距离根节点的最远距离      if(pRoot == NULL)      {          maxLeft = 0;          maxRight = 0;          return 0;      }      int maxLL, maxLR, maxRL, maxRR;      int maxDistLeft, maxDistRight;      if(pRoot->lChild != NULL)      {          maxDistLeft = GetMaxDistance(pRoot->lChild, maxLL, maxLR);          maxLeft = max(maxLL, maxLR) + 1;      }      else      {          maxDistLeft = 0;          maxLeft = 0;      }      if(pRoot->rChild != NULL)      {          maxDistRight = GetMaxDistance(pRoot->rChild, maxRL, maxRR);          maxRight = max(maxRL, maxRR) + 1;      }      else      {          maxDistRight = 0;          maxRight = 0;      }      return max(max(maxDistLeft, maxDistRight), maxLeft+maxRight); } //判断一颗树是不是完全二叉树// 按层序遍历,当遇到一个节点的左子树为空时,则该节点右子树必须为空且后面节点的左右子树都为空// 当遇到右子树为空,则后面节点左右子树都为空 bool BTree::IsCompleteBinaryTree(BTreeNode * pRoot)  {      if(pRoot == NULL)          return false;      queue<BTreeNode *> q;      q.push(pRoot);      bool mustHaveNoChild = false;      bool result = true;      while(!q.empty())      {          BTreeNode * pNode = q.front();          q.pop();          if(mustHaveNoChild) // 已经出现了有空子树的节点了,后面出现的必须为叶节点(左右子树都为空)          {              if(pNode->lChild != NULL || pNode->rChild != NULL)              {                  result = false;                  break;              }          }          else          {              if(pNode->lChild != NULL && pNode->rChild != NULL)              {                  q.push(pNode->lChild);                  q.push(pNode->rChild);              }              else if(pNode->lChild != NULL && pNode->rChild == NULL)              {                  mustHaveNoChild = true;                  q.push(pNode->rChild);              }              else if(pNode->lChild == NULL && pNode->rChild != NULL)              {                  result = false;                  break;              }              else              {                  mustHaveNoChild = true;              }          }      }      return result;  } 

参考文章:

http://blog.csdn.net/luckyxiaoqiang/article/details/7518888/

http://blog.csdn.net/iqrocket/article/details/8266365#cpp

1 0