接着上一篇文章,下面给出 g++ 4.6.3 调试通过的通用二叉树程序的C++-0x源代码。由于Visual Studio和g++对模板的写法要求不完全一致,如果使用Visual Studio编译运行,可能需要对代码做一些小改动。使用g++编译运行时,请把本文中两个源文件以及上一篇文章中的 data_def.h 源文件拷贝到同一个文件夹中,然后使用这个命令行:
g++ -std=c++0x -O2 -obinary_tree binary_tree.cpp
从最后的main()函数以及所附的截图中可以清楚地看出,这个二叉树算法完全无视数据差异,同样的语法可以作用在两个完全不同的数据类型上。
这个是头文件。
//
// FILE: binary_tree.h, this is the header file for binary tree structure and algorithms.
//
// Author: DGU, email: gdyxgzy@hotmail.com
// If you would like to use whole or part of this code, or forward it to some other post,
// please keep above header and send an email to my inbox.
//
// Note that I only implemented some methods, yet it should be easy to implement other methods(like finding the least-common-ancestor, etc.)
//
#ifndef ALGO_TREE_HEADER
#define ALGO_TREE_HEADER
#include <vector>
#include <string>
#include <exception>
#include <stdexcept>
#include "data_def.h"
template<class T> class BinaryTree
{
public:
typedef typename T::key_type key_type;
typedef typename T::data_type data_type;
struct Node
{
T data;
Node* left;
Node* right;
Node() : data(T()), left(nullptr), right(nullptr) {};
Node(const T& d) : data(d), left(nullptr), right(nullptr) {};
explicit Node(const key_type& k, const data_type& d) : data(k, d), left(nullptr), right(nullptr) {};
const key_type GetKey(void) const { return data.get_key(); };
const data_type GetData(void) const { return data.get_data(); };
void SetData(data_type d) { data.set_data(d); };
};
class BinaryTreeException : public std::runtime_error
{
public:
BinaryTreeException(const std::string& msg) : std::runtime_error(msg) {};
};
BinaryTree() { m_root = nullptr; };
BinaryTree(const std::vector<T>& pre_seq, const std::vector<T>& in_seq) { m_root = build_tree(pre_seq, in_seq); };
virtual ~BinaryTree() { kill_tree(m_root); m_root=NULL; };
virtual const Node* GetRoot(void) const { return m_root; };
void PreOrderRecursive(const Node* root) const;
void InOrderRecursive(const Node* root) const;
void PostOrderRecursive(const Node* root) const;
const std::vector<data_type> InOrderNoneRecursive(void) const;
const std::vector<data_type> BreadthTraversal(void) const;
protected:
Node* build_tree(const std::vector<T>& pre_seq, const std::vector<T>& in_seq);
void kill_tree(Node*& root);
private:
Node* m_root;
};
/*
// You could derive some sub-classes from this basic BinaryTree class
template<class T>
class BinarySearchTree : public BinaryTree<T>
{
};
template<class T>
class RedBlackTree : public BinaryTree<T>
{
};
*/
#endif
//------------------- END OF THIS FILE ----------------//
这个是类的实现以及主程序。
//
// FILE: binary_tree.cpp
//
// Author: DGU, email: gdyxgzy@hotmail.com
// If you would like to use whole or part of this code, or forward it to some other site,
// please keep this header, and send an email to my inbox.
//
#include <iostream>
#include <sstream>
#include <stack>
#include <queue>
#include <algorithm>
#include "binary_tree.h"
using namespace std;
// build a tree from input pre-order and in-order traversal sequences, assume that all node keys
// are Unique, otherwise we cannot locate the root node. And, of course, the 2 sequences's length must be equal
template <class T>
typename BinaryTree<T>::Node* BinaryTree<T>::build_tree(const vector<T>& pre_order_seq, const vector<T>& in_order_seq)
{
int N=pre_order_seq.size();
if(in_order_seq.size() != N)
throw BinaryTreeException(string("sequence's length not equal"));
if(N==0)
return nullptr;
T root_val = pre_order_seq[0];
if(N==1)
{
Node* root = new Node(root_val);
if(root==nullptr)
throw BinaryTreeException(string("bad memory allocation"));
return root;
}
// find the root in the in-order sequence, before it is the left child, after it is the right child
typename vector<T>::const_iterator root_pos = std::find(in_order_seq.begin(), in_order_seq.end(), root_val);
// get the in-order sequence of left and right child respectively.
vector<T> left_inorder, right_inorder;
std::copy(in_order_seq.begin(), root_pos, back_inserter(left_inorder));
std::copy(++root_pos, in_order_seq.end(), back_inserter(right_inorder));
// get the pre-order sequence of left and right child respectively
vector<T> left_preorder, right_preorder;
std::copy(pre_order_seq.begin()+1, pre_order_seq.begin()+1+left_inorder.size(), back_inserter(left_preorder));
std::copy(pre_order_seq.begin()+1+left_inorder.size(), pre_order_seq.end(), back_inserter(right_preorder));
if( left_inorder.size()!=left_preorder.size() || right_inorder.size()!=right_preorder.size() )
throw BinaryTreeException(string("sub-sequence's length does not match"));
Node* left_child = build_tree(left_preorder, left_inorder);
Node* right_child = build_tree(right_preorder, right_inorder);
Node* root = new Node(root_val);
if(root == nullptr)
throw BinaryTreeException(string("bad memory allocation"));
root->left = left_child;
root->right = right_child;
return root;
}
template<class T> void BinaryTree<T>::kill_tree(Node*& root)
{
if(root)
{
kill_tree(root->left);
kill_tree(root->right);
delete root;
root = NULL;
}
}
template<class T> void BinaryTree<T>::PreOrderRecursive(const typename BinaryTree<T>::Node* root) const
{
if(root)
{
cout<<'|'<<root->GetData()<<"| ";
PreOrderRecursive(root->left);
PreOrderRecursive(root->right);
}
}
template<class T> void BinaryTree<T>::InOrderRecursive(const typename BinaryTree<T>::Node* root) const
{
if(root)
{
InOrderRecursive(root->left);
cout<<'|'<<root->GetData()<<"| ";
InOrderRecursive(root->right);
}
}
template<class T> void BinaryTree<T>::PostOrderRecursive(const typename BinaryTree<T>::Node* root) const
{
if(root)
{
PostOrderRecursive(root->left);
PostOrderRecursive(root->right);
cout<<'|'<<root->GetData()<<"| ";
}
}
template<class T> const vector<typename BinaryTree<T>::data_type> BinaryTree<T>::InOrderNoneRecursive(void) const
{
vector<data_type> result;
Node* root = m_root;
if(root)
{
stack<Node*>stk;
while(root || !stk.empty())
{
if(root)
{
stk.push(root);
root = root->left;
}
else
{
root = stk.top();
stk.pop();
result.push_back(root->GetData());
root = root->right;
}
}
}
return result;
}
template<class T> const vector<typename BinaryTree<T>::data_type> BinaryTree<T>::BreadthTraversal(void) const
{
vector<data_type> result;
queue<Node*> q;
q.push(m_root);
while(!q.empty())
{
Node* root = q.front();
q.pop();
if(root)
{
result.push_back(root->GetData());
if(root->left != nullptr)
q.push(root->left);
if(root->right != nullptr)
q.push(root->right);
}
}
return result;
}
// This template function is used to extract data from string inputs
template<class T> vector<T> get_seq(const string& seq_str)
{
vector<T> seq;
if(seq_str.length() <= 0)
return seq;
istringstream isstr(seq_str);
T t;
while(isstr>>t)
seq.push_back(t);
return seq;
}
int main()
{
cout << "***---------------- binary tree operations for DataStruct1 ----------------***" << endl;
const char *pre_key_str = "1 2 4 5 7 10 3 6 8 9";
const char *in_key_str = "4 2 7 10 5 1 3 8 6 9";
const char *pre_data_str = "aaa bbb ddd eee ggg jjj ccc fff hhh iii";
const char *in_data_str = "ddd bbb ggg jjj eee aaa ccc hhh fff iii";
vector<typename BinaryTree<DataStruct1>::key_type> pre_key_seq = get_seq<typename BinaryTree<DataStruct1>::key_type>(string(pre_key_str));
vector<typename BinaryTree<DataStruct1>::key_type> in_key_seq = get_seq<typename BinaryTree<DataStruct1>::key_type>(string(in_key_str));
vector<typename BinaryTree<DataStruct1>::data_type> pre_data_seq = get_seq<typename BinaryTree<DataStruct1>::data_type>(string(pre_data_str));
vector<typename BinaryTree<DataStruct1>::data_type> in_data_seq = get_seq<typename BinaryTree<DataStruct1>::data_type>(string(in_data_str));
vector<DataStruct1> pre_seq;
for(unsigned int i=0; i<pre_key_seq.size(); ++i)
pre_seq.push_back(DataStruct1(pre_key_seq[i], pre_data_seq[i]));
vector<DataStruct1> in_seq;
for(unsigned int i=0; i<in_key_seq.size(); ++i)
in_seq.push_back(DataStruct1(in_key_seq[i], in_data_seq[i]));
BinaryTree<DataStruct1> bt1(pre_seq, in_seq);
cout << "The in-order sequence is: ";
bt1.InOrderRecursive(bt1.GetRoot());
cout << endl << endl;
cout << "The pre-order sequence is: ";
bt1.PreOrderRecursive(bt1.GetRoot());
cout << endl << endl;
cout << "The post-order sequence is: ";
bt1.PostOrderRecursive(bt1.GetRoot());
cout << endl << endl;
vector<typename BinaryTree<DataStruct1>::data_type> breadth_seq = bt1.BreadthTraversal();
cout << "The breadth traversal sequence is: ";
for(auto x:breadth_seq)
cout << "|" << x << "| ";
cout << endl;
cout << "***---------------- binary tree operations for DataStruct2 ----------------***" << endl;
const char *pre_str = "1.1 2.2 4.4 5.5 7.7 10.10 3.3 6.6 8.8 9.9";
const char *in_str = "4.4 2.2 7.7 10.10 5.5 1.1 3.3 8.8 6.6 9.9";
vector<double> pre_dbl_seq = get_seq<double>(string(pre_str));
vector<double> in_dbl_seq = get_seq<double>(string(in_str));
vector<DataStruct2> pre_seq2;
for(auto x:pre_dbl_seq)
pre_seq2.push_back(DataStruct2(x));
vector<DataStruct2> in_seq2;
for(auto x:in_dbl_seq)
in_seq2.push_back(DataStruct2(x));
BinaryTree<DataStruct2> bt2(pre_seq2, in_seq2);
vector<typename BinaryTree<DataStruct2>::data_type> none_recur_in_seq = bt2.InOrderNoneRecursive();
cout << "The in-order sequence is: ";
for(auto x:none_recur_in_seq)
cout << "|" << x << "| ";
cout << endl;
return 0;
}
下面是程序运行的截图: