您的位置:首页 > 其它

二叉树各种操作

2016-04-05 19:21 369 查看
#include<iostream>
#include <deque>
#include <stack>
using namespace std;
//二叉树的节点类
class BinTreeNode
{
private:
int data;
BinTreeNode *left, *right;
public:
//利用初始化列表完成data,left,rightn的初始化
BinTreeNode(const int &item, BinTreeNode *lPtr = NULL, BinTreeNode *rPtr = NULL) :data(item), left(lPtr), right(rPtr){};
void set_data(int item)
{
data = item;
}
int get_data()const
{
return data;
}
void set_left(BinTreeNode *l)
{
left = l;
}
BinTreeNode* get_left()const
{
return left;
}
void set_right(BinTreeNode *r)
{
right = r;
}
BinTreeNode* get_right()const
{
return right;
}
};

//二叉树
class BinTree
{
private:
BinTreeNode *root;
public:
BinTree(BinTreeNode *t = NULL) :root(t){};
~BinTree(){ delete root; };
void set_root(BinTreeNode *t)
{
root = t;
}
BinTreeNode* get_root()const
{
return root;
}
//1.创建二叉树
BinTreeNode* create_tree();
//2.前序遍历
void pre_order(BinTreeNode *r)const;
//3.中序遍历
void in_order(BinTreeNode *r)const;
//4.后序遍历
void post_order(BinTreeNode *r)const;
//5.层次遍历
void level_order(BinTreeNode *r)const;
//6.获得叶子节点的个数
int get_leaf_num(BinTreeNode *r)const;
//7.获得二叉树的高度
int get_tree_height(BinTreeNode *r)const;
//8.交换二叉树的左右儿子
void swap_left_right(BinTreeNode *r);
//9.求两个节点pNode1和pNode2在以r为树根的树中的最近公共祖先
BinTreeNode* get_nearest_common_father(BinTreeNode *r, BinTreeNode *pNode1, BinTreeNode *pNode2)const;
//10.打印和为某一值的所有路径
void print_rout(BinTreeNode *r, int sum)const;
//11.判断一个节点t是否在以r为根的子树中
bool is_in_tree(BinTreeNode *r, BinTreeNode *t)const;
};

//创建二叉树,这里不妨使用前序创建二叉树,遇到‘#’表示节点为空
BinTreeNode* BinTree::create_tree()
{
char item;
BinTreeNode *t, *t_l, *t_r;
cin >> item;
if (item != '#')
{
BinTreeNode *pTmpNode = new BinTreeNode(item - 48);
t = pTmpNode;
t_l = create_tree();
t->set_left(t_l);
t_r = create_tree();
t->set_right(t_r);
return t;
}
else
{
t = NULL;
return t;
}
}

//前序遍历
void BinTree::pre_order(BinTreeNode *r)const
{
BinTreeNode *pTmpNode = r;
if (pTmpNode != NULL)
{
cout << pTmpNode->get_data() << " ";
pre_order(pTmpNode->get_left());
pre_order(pTmpNode->get_right());
}
}
//中序遍历
void BinTree::in_order(BinTreeNode *r)const
{
BinTreeNode *pTmpNode = r;
if (pTmpNode != NULL)
{
in_order(pTmpNode->get_left());
cout << pTmpNode->get_data() << " ";
in_order(pTmpNode->get_right());
}
}
//后序遍历
void BinTree::post_order(BinTreeNode *r)const
{
BinTreeNode *pTmpNode = r;
if (pTmpNode != NULL)
{
post_order(pTmpNode->get_left());
post_order(pTmpNode->get_right());
cout << pTmpNode->get_data() << " ";
}
}

//层次遍历,用队列很方便
void BinTree::level_order(BinTreeNode *r)const
{
if (r == NULL)
return;
deque<BinTreeNode*> q;
q.push_back(r);
while (!q.empty())
{
BinTreeNode *pTmpNode = q.front();
cout << pTmpNode->get_data() << " ";
q.pop_front();
if (pTmpNode->get_left() != NULL)
{
q.push_back(pTmpNode->get_left());
}
if (pTmpNode->get_right() != NULL)
{
q.push_back(pTmpNode->get_right());
}
}
}

//树中的叶子节点的个数 = 左子树中叶子节点的个数 + 右子树中叶子节点的个数。利用递归代码也是相当的简单,易懂。
//获取叶子节点的个数
int BinTree::get_leaf_num(BinTreeNode *r)const
{
if (r == NULL)//该节点是空节点,比如建树时候用'#'表示
{
return 0;
}
if (r->get_left() == NULL && r->get_right() == NULL)//该节点并不是空的,但是没有孩子节点
{
return 1;
}
//递归整个树的叶子节点个数 = 左子树叶子节点的个数 + 右子树叶子节点的个数
return get_leaf_num(r->get_left()) + get_leaf_num(r->get_right());
}

//求二叉树的高度也是非常简单,不用多说:树的高度 = max(左子树的高度,右子树的高度) + 1 。
//获得二叉树的高度
int BinTree::get_tree_height(BinTreeNode *r)const
{
if (r == NULL)//节点本身为空
{
return 0;
}
if (r->get_left() == NULL && r->get_right() == NULL)//叶子节点
{
return 1;
}
int l_height = get_tree_height(r->get_left());
int r_height = get_tree_height(r->get_right());
return l_height >= r_height ? l_height + 1 : r_height + 1;
}

//交换二叉树的左右儿子,可以先交换根节点的左右儿子节点,然后递归以左右儿子节点为根节点继续进行交换。树中的操作有先天的递归性。。
//交换二叉树的左右儿子
void BinTree::swap_left_right(BinTreeNode *r)
{
if (r == NULL)
{
return;
}
BinTreeNode *pTmpNode = r->get_left();
r->set_left(r->get_right());
r->set_right(pTmpNode);
swap_left_right(r->get_left());
swap_left_right(r->get_right());
}

//判断一个节点t是否在以r为根的子树中
bool BinTree::is_in_tree(BinTreeNode *r, BinTreeNode *t)const
{
if (r == NULL)
{
return false;
}
else if (r == t)
{
return true;
}
else
{
bool has = false;
if (r->get_left() != NULL)
{
has = is_in_tree(r->get_left(), t);
}
if (!has && r->get_right() != NULL)
{
has = is_in_tree(r->get_right(), t);
}
return has;
}
}

// 求两个节点的公共祖先可以用到上面的:判断一个节点是否在一颗子树中。
//(1)如果两个节点同时在根节点的右子树中,则最近公共祖先一定在根节点的右子树中。
//(2)如果两个节点同时在根节点的左子树中,则最近公共祖先一定在根节点的左子树中。
//(3)如果两个节点一个在根节点的右子树中,一个在根节点的左子树中,则最近公共祖先一定是根节点。当然,要注意的是:可能一个节点pNode1在以另一个节点pNode2为根的子树中,
//	   这时pNode2就是这两个节点的最近公共祖先了。显然这也是一个递归的过程啦:
//求两个节点的最近公共祖先
BinTreeNode* BinTree::get_nearest_common_father(BinTreeNode *r, BinTreeNode *pNode1, BinTreeNode *pNode2)const
{
//pNode2在以pNode1为根的子树中(每次递归都要判断,放在这里不是很好。)
if (is_in_tree(pNode1, pNode2))
{
return pNode1;
}
//pNode1在以pNode2为根的子树中
if (is_in_tree(pNode2, pNode1))
{
return pNode2;
}
bool one_in_left, one_in_right, another_in_left, another_in_right;
one_in_left = is_in_tree(r->get_left(), pNode1);
another_in_right = is_in_tree(r->get_right(), pNode2);
another_in_left = is_in_tree(r->get_left(), pNode2);
one_in_right = is_in_tree(r->get_right(), pNode1);
if ((one_in_left && another_in_right) || (one_in_right && another_in_left))
{
return r;
}
else if (one_in_left && another_in_left)
{
return get_nearest_common_father(r->get_left(), pNode1, pNode2);
}
else if (one_in_right && another_in_right)
{
return get_nearest_common_father(r->get_right(), pNode1, pNode2);
}
else
{
return NULL;
}
}

//2.9 从根节点开始找到所有路径,使得路径上的节点值和为某一数值(路径不一定以叶子节点结束)
//注意这两个栈的使用
stack<BinTreeNode *>dfs_s;
stack<BinTreeNode *>print_s;
//打印出从r开始的和为sum的所有路径
void BinTree::print_rout(BinTreeNode *r, int sum)const
{
if (r == NULL)
{
return;
}
//入栈
sum -= r->get_data();
dfs_s.push(r);
if (sum <= 0)
{
if (sum == 0)
{
while (!dfs_s.empty())
{
print_s.push(dfs_s.top());
dfs_s.pop();
}
while (!print_s.empty())
{
cout << print_s.top()->get_data() << " ";
dfs_s.push(print_s.top());
print_s.pop();
}
cout << endl;
}
sum += r->get_data();
dfs_s.pop();
return;
}
//递归进入左子树
print_rout(r->get_left(), sum);
//递归进入右子树
print_rout(r->get_right(), sum);
//出栈
sum += r->get_data();
dfs_s.pop();
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: