二叉树各种操作
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(); }
相关文章推荐
- 时间类1
- ReactNative学习八-搜索栏的基本布局
- 算法训练 字符串编辑
- 算法训练 最大值与最小值的计算
- 第五周上机实践项目 项目3--时间类(1)
- Java编程手册—异常处理与断言
- 2016-04-05
- 指定数据库ASMIFS使用的存储类型[]:
- awk解密
- C#委托和事件
- 优秀程序设计的18大原则
- Codeforces Round #251(Div. 2) 439C. Devu and Partitioning of the Array 构造
- JAVA连接MYSQL数据库以及操作
- 算法训练 判定数字
- int *a[10],int (*a)[10],int *a[10],int (*a)(int),int (*a[10])(int)
- adb连接时出现如下错误CreateProcess failure, error 2 * could not start server *
- Eclipse常用快捷键
- Leetcode 99. Recover Binary Search Tree
- C语言编程——有趣的数(使用动态规划实现)
- 使用windows上 mxnet 预编译版本