[C++]封装二叉树
题目要求
(简单的说,就是把二叉树的功能封装起来)
binary tree is a tree data structure in which each node has at most two children, which are referred to as the left child and the right child.
Three Constructor:
creat a tree by copy.
creat a tree by a array.(using BFS)
creat a tree by preorder and inorder.
Methods:
clear: clear the tree.
copyTree: input old tree root and new tree root, copy get a new tree.
Static Methods:
three way to search tree.
测试文件:
#include <iostream>
#include "BinaryTree.hpp"
using namespace std;
void print(BinaryTree::Node * temp) {
cout << temp->val << " ";
}
std::vector<char> pre;
std::vector<char> in;
void getPreOrder(BinaryTree::Node * temp) {
pre.push_back(temp->val);
}
void getInOrder(BinaryTree::Node * temp) {
in.push_back(temp->val);
}
void testTree() {
cout << "test Tree" << endl;
int n = 1;
std::vector<char> tree;
cin >> n;
while (n--) {
char temp = ‘\0‘;
cin >> temp;
tree.push_back(temp);
}
BinaryTree x = BinaryTree(tree);
BinaryTree::preOrder(print, x.getRoot());
cout << endl;
BinaryTree::inOrder(print, x.getRoot());
cout << endl;
BinaryTree::postOrder(print, x.getRoot());
cout << endl;
BinaryTree::preOrder(getPreOrder, x.getRoot());
BinaryTree::inOrder(getInOrder, x.getRoot());
BinaryTree t = BinaryTree(pre, in);
BinaryTree::postOrder(print, t.getRoot());
cout << endl;
BinaryTree y = BinaryTree(t);
BinaryTree::preOrder(print, y.getRoot());
cout << endl;
BinaryTree::inOrder(print, y.getRoot());
cout << endl;
BinaryTree::postOrder(print, y.getRoot());
BinaryTree::preOrder(getPreOrder, y.getRoot());
BinaryTree::inOrder(getInOrder, y.getRoot());
}
int main() {
testTree();
}
接口文件:
//
// BinaryTree.hpp
// C++
//
// Created by 李天培 on 16/5/4.
// Copyright ? 2016年 lee. All rights reserved.
//
#ifndef BinaryTree_hpp
#define BinaryTree_hpp
#include <iostream>
#include <vector>
#include <queue>
#include <stack>
#define EMPTY_ELE ‘#‘
class BinaryTree {
public:
struct Node {
char val;
Node* left;
Node* right;
Node(char v, Node* l = NULL, Node* r = NULL):
val(v), left(l), right(r) {
}
};
BinaryTree(const BinaryTree&);
BinaryTree(std::vector<char>&);
// created by preorder and inorder
BinaryTree(const std::vector<char>& preOrder,
const std::vector<char>& inOrder);
~BinaryTree();
Node* getRoot() const;
void clear();
static void preOrder(void (*visite)(BinaryTree::Node*), Node*);
static void inOrder(void (*visite)(BinaryTree::Node*), Node*);
static void postOrder(void (*visite)(BinaryTree::Node*), Node*);
private:
Node * copyNode(Node * oldNode, Node * newNode);
Node * root;
};
#endif /* BinaryTree_hpp */
问题分析
先来讨论相对简单的访问二叉树问题。
遍历问题
前(先)序遍历
中序遍历
后序遍历
代码实现:
void BinaryTree::preOrder(void (*visite)(BinaryTree::Node *),
BinaryTree::Node * treeNode) {
if (treeNode != NULL) {
visite(treeNode);
preOrder(visite, treeNode->left);
preOrder(visite, treeNode->right);
}
}
void BinaryTree::inOrder(void (*visite)(BinaryTree::Node *),
BinaryTree::Node * treeNode) {
if (treeNode != NULL) {
inOrder(visite, treeNode->left);
visite(treeNode);
inOrder(visite, treeNode->right);
}
}
void BinaryTree::postOrder(void (*visite)(BinaryTree::Node *),
BinaryTree::Node * treeNode) {
if (treeNode != NULL) {
postOrder(visite, treeNode->left);
postOrder(visite, treeNode->right);
visite(treeNode);
}
}
根据前序后序求中序
已知前序遍历为GDAFEMHZ,中序遍历为ADEFGHMZ,请画出这棵二叉树。
①根据前序遍历特征,我们知道根结点必在首位置,所以为G;
②根据中序遍历特征。其中根节点G左侧的ADEF必然是根节点的左子树,G右侧的HMZ必然是根节点的右子树;
③根据前序中序特征,重复以上步骤。递归找到子树根节点;
那么,我们可以画出这个二叉树:
由图可知,后序遍历顺序为:AEFDHZMG
代码实现
BinaryTree::Node* recursionBuild(const std::vector<char>& preorder,
unsigned long preLeft,
unsigned long preRight,
const std::vector<char>& inorder,
unsigned long inLeft,
unsigned long inRight) {
if (preLeft > preRight || preRight == preorder.size() ||
inLeft > inRight || inRight == inorder.size())
return NULL;
unsigned long i = 0;
BinaryTree::Node* node = new BinaryTree::Node(preorder[preLeft]);
for (i = inLeft; i <= inRight; i++) {
if (inorder[i] == node->val) {
break;
}
}
node->left = recursionBuild(preorder,
preLeft + 1, preLeft + i -inLeft,
inorder,
inLeft, i - 1);
node->right = recursionBuild(preorder,
preLeft + i - inLeft + 1, preRight,
inorder,
i + 1, inRight);
return node;
}
BinaryTree::BinaryTree(const std::vector<char> & preorder,
const std::vector<char> & inorder) {
root = NULL;
unsigned long preSize = preorder.size();
unsigned long inSize = inorder.size();
if (preSize == 0 || preSize != inSize) {
return;
}
root = recursionBuild(preorder, 0, preSize - 1,
inorder, 0, inSize - 1);
}
根据后序中序求前序
已知一棵二叉树的中序序列和后序序列分别是BDCEAFHG 和 DECBHGFA,请画出这棵二叉树。
分析:
- ①由后序遍历特征,根结点必在后序序列尾部(即A);
- ②由中序遍历特征,根结点必在其中间,而且其左部必全部是左子树的子孙(即BDCE),其右部必全部是右子树的子孙(即FHG);
- ③递归找出子树根节点。
那么,我们可以画出这个二叉树:
注意事项:
左子树中序为BDCE,后序为DECB,说明B为A的左子树根节点,C为B的右子树(从BDCE看出)根节点(从DCE及DEC看出);
右子树中序为FHG,后序为HGF,说明F为A的右子树的根节点,H为G的左子树根节点。
构造过程
接下来讨论在构造过程中出现的难点。
用队列让vector构造二叉树
用队列可以实现FIFO,从而让每一个节点都依次赋值。但必须注意在queue中要存储_Node**,就是存储一个指向指针的指针。(因为在其内部应该实现了深复制。所以如果只用_Node*会就会复制指针所指向的对象(都为NULL),这与我们的算法就想违背了。)
BinaryTree::BinaryTree(std::vector<char>& orig) {
std::queue<_Node**> queue_Node;
if (!orig.empty() && orig[0] != EMPTY_ELE) {
root = new _Node(orig[0]);
queue_Node.push(&root->left);
queue_Node.push(&root->right);
int i = 1;
while (!queue_Node.empty()) {
_Node** temp = queue_Node.front();
queue_Node.pop();
if (i >= orig.size()) {
temp = NULL;
i++;
} else if (orig[i] == EMPTY_ELE) {
temp = NULL;
i++;
} else {
*temp = new _Node(orig[i++]);
queue_Node.push(&((*temp)->left));
queue_Node.push(&((*temp)->right));
}
}
} else {
root = NULL;
}
}
第二种方法:(更细致的实现方法。)
BinaryTree::BinaryTree(std::vector<char> & elements) {
unsigned long size = elements.size();
int index = 0;
std::queue<Node*> queue;
if (elements.empty() || elements[index] == EMPTY_ELE) {
root = NULL;
} else {
root = new Node(elements[index]);
queue.push(root);
index += 1;
while (index < size) {
Node* temp = queue.front();
queue.pop();
if (elements[index] != EMPTY_ELE) {
temp->left = new Node(elements[index]);
queue.push(temp->left);
}
index += 1;
if (index >= size) {
break;
}
if (elements[index] != EMPTY_ELE) {
temp->right = new Node(elements[index]);
queue.push(temp->right);
}
index += 1;
}
}
}
copy构造函数(递归实现)
BinaryTree::Node* BinaryTree::copyNode(BinaryTree::Node *oldNode,
BinaryTree::Node *newNode) {
if (oldNode == NULL) {
newNode = NULL;
return newNode;
}
newNode = new Node(oldNode->val);
newNode->left = copyNode(oldNode->left, newNode->left);
newNode->right = copyNode(oldNode->right, oldNode->right);
return newNode;
}
BinaryTree::BinaryTree(const BinaryTree &old) {
root = NULL;
root = copyNode(old.getRoot(), root);
}
问题解决
//
// BinaryTree.cpp
// C++
//
// Created by 李天培 on 16/5/4.
// Copyright ? 2016年 lee. All rights reserved.
//
#include "BinaryTree.hpp"
BinaryTree::Node* recursionBuild(const std::vector<char>& preorder,
unsigned long preLeft,
unsigned long preRight,
const std::vector<char>& inorder,
unsigned long inLeft,
unsigned long inRight) {
if (preLeft > preRight || preRight == preorder.size() ||
inLeft > inRight || inRight == inorder.size())
return NULL;
unsigned long i = 0;
BinaryTree::Node* node = new BinaryTree::Node(preorder[preLeft]);
for (i = inLeft; i <= inRight; i++) {
if (inorder[i] == node->val) {
break;
}
}
node->left = recursionBuild(preorder,
preLeft + 1, preLeft + i -inLeft,
inorder,
inLeft, i - 1);
node->right = recursionBuild(preorder,
preLeft + i - inLeft + 1, preRight,
inorder,
i + 1, inRight);
return node;
}
BinaryTree::BinaryTree(const BinaryTree &old) {
root = NULL;
root = copyNode(old.getRoot(), root);
}
BinaryTree::BinaryTree(const std::vector<char> & preorder,
const std::vector<char> & inorder) {
root = NULL;
unsigned long preSize = preorder.size();
unsigned long inSize = inorder.size();
if (preSize == 0 || preSize != inSize) {
return;
}
root = recursionBuild(preorder, 0, preSize - 1,
inorder, 0, inSize - 1);
}
BinaryTree::BinaryTree(std::vector<char> & elements) {
unsigned long size = elements.size();
int index = 0;
std::queue<Node*> queue;
if (elements.empty() || elements[index] == EMPTY_ELE) {
root = NULL;
} else {
root = new Node(elements[index]);
queue.push(root);
index += 1;
while (index < size) {
Node* temp = queue.front();
queue.pop();
if (elements[index] != EMPTY_ELE) {
temp->left = new Node(elements[index]);
queue.push(temp->left);
}
index += 1;
if (index >= size) {
break;
}
if (elements[index] != EMPTY_ELE) {
temp->right = new Node(elements[index]);
queue.push(temp->right);
}
index += 1;
}
}
}
BinaryTree::Node* BinaryTree::copyNode(BinaryTree::Node *oldNode,
BinaryTree::Node *newNode) {
if (oldNode == NULL) {
newNode = NULL;
return newNode;
}
newNode = new Node(oldNode->val);
newNode->left = copyNode(oldNode->left, newNode->left);
newNode->right = copyNode(oldNode->right, oldNode->right);
return newNode;
}
BinaryTree::Node* BinaryTree::getRoot() const {
return root;
}
BinaryTree::~BinaryTree() {
clear();
}
void BinaryTree::clear() {
std::queue<Node*> queue;
if (root != NULL) {
queue.push(root);
}
while (!queue.empty()) {
Node * temp = queue.front();
queue.pop();
if (temp->left != NULL)
queue.push(temp->left);
if (temp->right != NULL)
queue.push(temp->right);
delete temp;
}
}
void BinaryTree::preOrder(void (*visite)(BinaryTree::Node*), Node* r = NULL) {
Node *temp = r;
if (temp == NULL) {
return;
} else {
visite(temp);
preOrder(visite, temp->left);
preOrder(visite, temp->right);
}
}
void BinaryTree::inOrder(void (*visite)(BinaryTree::Node*), Node* r = NULL) {
Node *temp = r;
if (temp == NULL) {
return;
} else {
inOrder(visite, temp->left);
visite(temp);
inOrder(visite, temp->right);
}
}
void BinaryTree::postOrder(void (*visite)(BinaryTree::Node*), Node* r = NULL) {
Node *temp = r;
if (temp == NULL) {
return;
} else {
postOrder(visite, temp->left);
postOrder(visite, temp->right);
visite(temp);
}
}