[C++]二叉树总结
2016-05-08 20:17
411 查看
[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 */
问题分析
先来讨论相对简单的访问二叉树问题。遍历问题
前(先)序遍历
![](http://www.2cto.com/uploadfile/Collfiles/20140909/20140909084212174.png)
中序遍历
![](http://www.2cto.com/uploadfile/Collfiles/20140909/20140909084212175.png)
后序遍历
![](http://www.2cto.com/uploadfile/Collfiles/20140909/20140909084212176.png)
代码实现:
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必然是根节点的右子树;
③根据前序中序特征,重复以上步骤。递归找到子树根节点;
那么,我们可以画出这个二叉树:
![](http://www.2cto.com/uploadfile/Collfiles/20140909/20140909084213180.png)
由图可知,后序遍历顺序为: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);
③递归找出子树根节点。
那么,我们可以画出这个二叉树:
![](http://www.2cto.com/uploadfile/Collfiles/20140909/20140909084213181.png)
注意事项:
左子树中序为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); }
问题解决
#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);
}
}
搜索二叉树
关于搜索二叉树的具体知识点分析见:搜索二叉树
#ifndef BinarySearchTree_hpp #define BinarySearchTree_hpp #include <queue> #include <vector> class BinarySearchTree { public: struct Node { int val; Node* left; Node* right; Node(int v, Node* l = NULL, Node* r = NULL) : val(v), left(l), right(r) {} }; BinarySearchTree(); BinarySearchTree(const std::vector<int>&); ~BinarySearchTree(); bool insertNode(int); bool searchNode(int); bool deleteNode(int); void clear(); Node* getRoot() const; private: Node* root; }; #endif /* BinarySearchTree_hpp */ #include "BinarySearchTree.hpp" BinarySearchTree::BinarySearchTree() { root = NULL; } void delete_node(BinarySearchTree::Node* root) { if (root != NULL) { delete_node(root->left); delete_node(root->right); delete root; } } BinarySearchTree::~BinarySearchTree() { clear(); } void BinarySearchTree::clear() { delete_node(root); } BinarySearchTree::BinarySearchTree(const std::vector<int>& orig) { root = new Node(orig[0]); for (int i = 1; i < orig.size(); i++) { insertNode(orig[i]); } } void insert(BinarySearchTree::Node** root, int value) { if (*root == NULL) { *root = new BinarySearchTree::Node(value); return; } if (value < (*root)->val) { insert(&(*root)->left, value); } if (value > (*root)->val) { insert(&(*root)->right, value); } } bool BinarySearchTree::insertNode(int value) { if (searchNode(value)) { return false; } insert(&root, value); return true; } bool BinarySearchTree::searchNode(int value) { Node* temp = root; while (temp != NULL) { if (temp->val == value) { return true; } else if (temp->val > value) { temp = temp->left; } else if (temp->val < value) { temp = temp->right; } } return false; } BinarySearchTree::Node* BinarySearchTree::getRoot() const { return root; } /** * find the max value in the left tree * * @param t Node (which will be deleted later) * * @return Max Node */ BinarySearchTree::Node* findMax(BinarySearchTree::Node* t) { if (t == NULL) { return NULL; } else { while (t->right != NULL) t = t->right; return t; } } BinarySearchTree::Node* findMin(BinarySearchTree::Node* t) { if (t == NULL) { return NULL; } else { while (t->left != NULL) { t = t->left; } return t; } } // there is two kinds of way to delete Node void remove_Left(const int& x, BinarySearchTree::Node*& t) { if (t == NULL) return; if (x < t->val) remove_Left(x, t->left); else if (x > t->val) remove_Left(x, t->right); else if (t->left != NULL && t->right != NULL) { t->val = findMax(t->left)->val; remove_Left(t->val, t->left); } else { BinarySearchTree::Node* oldNode = t; t = (t->right != NULL) ? t->right : t->left; delete oldNode; } } void remove_Right(const int& x, BinarySearchTree::Node*& t) { if (t == NULL) return; if (x < t->val) remove_Right(x, t->left); else if (x > t->val) remove_Right(x, t->right); else if (t->left != NULL && t->right != NULL) { t->val = findMin(t->right)->val; remove_Right(t->val, t->right); } else { BinarySearchTree::Node* oldNode = t; t = (t->left != NULL) ? t->left : t->right; delete oldNode; } } bool BinarySearchTree::deleteNode(int value) { if (searchNode(value)) { remove_Left(value, root); return true; } return false; }
测试文件
#include <iostream> #include <vector> #include "BinarySearchTree.hpp" using std::cout; using std::cin; using std::endl; void preorder(BinarySearchTree::Node* node) { if (node == NULL) { return; } else { cout << node->val << " "; preorder(node->left); preorder(node->right); } } void inorder(BinarySearchTree::Node* node) { if (node == NULL) { return; } else { inorder(node->left); cout << node->val << " "; inorder(node->right); } } void displayTree(const BinarySearchTree& tree) { cout << "pre: "; preorder(tree.getRoot()); cout << endl; cout << "in: "; inorder(tree.getRoot()); cout << endl; } void testMinimalSpanningTrees() { cout << "testMinimalSpanningTrees" << endl; std::vector<int> elements; int n = 0; cin >> n; while (n--) { int temp = 0; cin >> temp; elements.push_back(temp); } BinarySearchTree tree(elements); displayTree(tree); cin >> n; cout << "insert : " << n << " -> " << tree.insertNode(n) << endl; displayTree(tree); cout << "search : " << n << " -> " << tree.searchNode(n) << endl; cout << "delete : " << n << " -> " << tree.deleteNode(n) << endl; cin >> n; cout << "delete : " << n << " -> " << tree.deleteNode(n) << endl; displayTree(tree); cin >> n; cout << "search : " << n << " -> " << tree.searchNode(n) << endl; cout << "insert : " << elements[0] << " -> " << tree.insertNode(elements[0]) << endl; displayTree(tree); } int main() { testMinimalSpanningTrees(); }