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

二叉树面试常见问题包括:
  • 二叉树中的节点个数
  • 二叉树的深度
  • 前序遍历,中序遍历,后序遍历,层序遍历
  • 将二叉查找树变为有序的双向链表
  • 二叉树第K层的节点个数
  • 二叉树中叶子节点的个数
  • 判断二叉树是不是平衡二叉树
  • 二叉树的镜像
  • 二叉树中两个节点的最低公共祖先节点
  • 二叉树中节点的最大距离
  • 判断二叉树是不是完全二叉树

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

头文件BTree.h

#ifndef BTREE_H
#define BTREE_H

struct 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的个数比数值的个数多1
	if(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*部分赋给r
			if(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)
{
	//二叉树的结点个数为左右子树的高度之和再+1
	if(r==0) return 0; 
	else	return 1+BTreeSize(r->lChild)+BTreeSize(r->rChild);
}

//重载形式
int BTree::BTreeLeaves()
{
	return BTreeLeaves(root);
}

//求二叉树叶子结点个数的函数
int BTree::BTreeLeaves(BTreeNode* r)
{
	//当为空时,返回0;当找到叶子时返回1
	if(r==0) return 0; 
	else if(r->lChild==0&&r->rChild==0)	return 1;
	else	return BTreeLeaves(r->lChild)+BTreeLeaves(r->rChild);
}

//重载形式
int BTree::BTreeHeight()
{
	return BTreeHeight(root);
}

//求二叉树高度的函数
int BTree::BTreeHeight(BTreeNode* r)
{
	if(r==0) return 0;
	//二叉树的高度为左右子树的最大者+1
	else	return 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
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值