Object Oriented Design -- Data and Algorithm Separation (2)

接着上一篇文章,下面给出 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;
}


下面是程序运行的截图:


















评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值