您的位置:首页 > 编程语言 > C语言/C++

[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 */


问题分析

先来讨论相对简单的访问二叉树问题。

遍历问题

前(先)序遍历



中序遍历



后序遍历



代码实现:

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);
}


问题解决

#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(); }
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: