j_0003.gif二叉数

    二叉树是一棵特殊的树,二叉树每个节点最多有两个孩子结点,分别称为左孩子和右孩子。

满二叉树:高度为N的满二叉树有2^N - 1个节点的二叉树。

完全二叉树: 若设二叉树的深度为h,除第 h 层外,其它各层 (1~h-1) 的结点数都达到最大个数,第 h 层所有的结点都连续集中在最左边,这就是完全二叉树

遍历方式:

前序遍历(先根遍历):(1):先访问根节点;  (2):前序访问左子树;(3):前序访问右子树; 

中序遍历:          (1):中序访问左子树;(2):访问根节点;    (3):中序访问右子树;  

后序遍历(后根遍历):(1):后序访问左子树;(2):后序访问右子树;(3):访问根节点;      

层序遍历:         (1):一层层节点依次遍历。   

程序实现

#include<iostream>
#include<queue>

using namespace std;

template<class T>
struct BinaryTreeNode//树节点的结构体
{
	BinaryTreeNode<T>* _left;
	BinaryTreeNode<T>* _right;
	T _data;

	BinaryTreeNode(const T&x)
		:_left(NULL)
		, _right(NULL)
		, _data(x)
	{}
};
/*
实现如下接口
1.前序输出:void PrevOrder();
2.中序输出:void InOrder();
3.后序输出:void PostOrder();
4.层序输出:void Levelorder();
5.求结点个数:size_t Size();
6.求叶子结点:size_t LeafSize();
7.求深度(距离根结点最远的路径):size_t Depth();
*/
template<class T>
class BinaryTree
{
public:
	BinaryTree()//无参的构造函数
		:_root(NULL)
	{}
	BinaryTree(const T*a, size_t size, const T&invalid)//有参的构造函数
	{
		size_t index = 0;
		_root=_creatTree(a, size, index,invalid);
	}
	BinaryTree(const BinaryTree<T>&b)//拷贝构造
	{
		_root = _copy(b._root);
	}
	BinaryTree<T>operator=(const BinaryTree<T>&b)//赋值函数
	{
		if (this != &b)//检测自赋值
		{
			BinaryTreeNode<T>*tmp = _copy(b._root);
			_Destroy(_root);
			_root = tmp;
		}
		return *this;
	}
	/*
	现代写法
	BinaryTree<T>operator=( BinaryTree<T>&b)
	{
	if (this != &b)
	{
	swap(_root,b._root);

	}
	return *this;
	}
	*/
	~BinaryTree()//析构
	{
		_Destroy(_root);
	}
public:
	void PrevOrder()//前序
	{
		_printPrevOrder(_root);
		cout << endl;
	}
	void InOrder()//中序
	{
		_printInOrder(_root);
		cout << endl;
	}
	void PostOrder()//后序
	{
		_printPostOrder(_root);
		cout << endl;
	}
	void Levelorder()//层序
	{
		_printLevelorder(_root);
		cout << endl;
	}
	size_t Size()//求结点个数
	{
		return _size(_root);
	}
	size_t LeafSize()//求叶结点个数
	{
		return _leafSize(_root);
	}
	size_t Depth()//求深度
	{
		return _depth(_root);
	}
protected:
	BinaryTreeNode<T>*_creatTree(const T*a, size_t size, size_t&index, const T&invalid)
	{
		BinaryTreeNode<T>*root = NULL;
		if ((a[index] != invalid)&&index<size)
		{
			root = new BinaryTreeNode<T>(a[index]);
			root->_left = _creatTree(a, size, ++index, invalid);
			root->_right = _creatTree(a, size, ++index, invalid);
		}
		return root;
	}
	
	BinaryTreeNode<T> *_copy(BinaryTreeNode<T>*root)//赋值函数调用
	{
		BinaryTreeNode<T>*newroot = NULL;
		if (root == NULL)
			return NULL;
		newroot= new BinaryTreeNode<T>(root->_data);
		newroot->_left = _copy(root->_left);
		newroot->_right = _copy(root->_right);
			
		return newroot;
	}
	
	void _printPrevOrder(BinaryTreeNode<T>*root)//前序
	{
		if (root == NULL)
		{
			return;
		}
		cout << root->_data<<' ';
		_printPrevOrder(root->_left);
		_printPrevOrder(root->_right);
	}
	
	void _printInOrder(BinaryTreeNode<T>*root)//中序
	{
		if (root == NULL)
		{
			return;
		}
		_printInOrder(root->_left);
		cout << root->_data<<' ';
		_printInOrder(root->_right);
	}
	
	void _printPostOrder(BinaryTreeNode<T>*root)//后序
	{
		if (root == NULL)
		{
			return;
		}
		_printPostOrder(root->_left);
		_printPostOrder(root->_right);
		cout << root->_data<<' ';
	}
	
	void _printLevelorder(BinaryTreeNode<T>* root)//层序
	{
		if (root == NULL)
			return;
		queue<BinaryTreeNode<T>*> q;//利用队来存放
		q.push(root);
		
		while (q.size())//while(!q.empty())
		{
			if (q.front()->_left)
			{
				q.push(q.front()->_left);
			}
			if (q.front()->_right)
			{
				q.push(q.front()->_right);
			}
			cout << q.front()->_data<<" ";
			q.pop();
		}
	}
	
	size_t _size(BinaryTreeNode<T>*root)//求结点个数
	{
		if (root == NULL)
			return 0;
		return _size(root->_left) + _size(root->_right) + 1;
	}
	
	size_t _leafSize(BinaryTreeNode<T>*root)//求叶子个数
	{
		if (root == NULL)
			return 0;
		
		if ((root->_left == NULL) && (root->_right == NULL))
		{
			return 1;
		}
		return _leafSize(root->_left) + _leafSize(root->_right);
	}
	
	size_t _depth(BinaryTreeNode<T>*root)//深度
	{
		int leftdepth = 0;
		int rightdepth = 0;
		if (root == NULL)
			return 0;
		else
		{
			leftdepth = _depth(root->_left);
			rightdepth = _depth(root->_right);
			/*if (leftdepth > rightdepth)
			{
				return leftdepth + 1;
			}
			else
				return rightdepth + 1;*/
			return leftdepth > rightdepth ? leftdepth + 1 : rightdepth + 1;
		}
	}
	
	void _Destroy(BinaryTreeNode<T>*root)
	{
		if (root == NULL)//空树直接返回
			return;
		if ((root->_left == NULL) && (root->_right == NULL))//无左右孩子
			delete root;
		else
		{
			_Destroy(root->_left);
			_Destroy(root->_right);
		}
	}
private:
	BinaryTreeNode<T>* _root;
};

测试

void test()
{
	int a[10] = { 1, 2, 3, '#', '#', 4, '#', '#', 5, 6 };
	BinaryTree<int>t1(a, 10, '#');
	cout << "中序:";
	t1.InOrder();
	cout << "后序:";
	t1.PostOrder();
	cout << "前序:";
	t1.PrevOrder();
	cout << "层序:";
	t1.Levelorder();
	cout<<"结点数"<<t1.Size()<<endl;
	cout << "深度" << t1.Depth()<<endl;
	cout << "叶子数" << t1.LeafSize() << endl;
	
}
void test2()
{
	int a[10] = { 1, 2, 3, '#', '#', 4, '#', '#', 5, 6 };
	BinaryTree<int>t1(a, 10, '#');
	BinaryTree<int>t2(t1);
	t2.PrevOrder();
	t2.InOrder();
	t2.PostOrder();

	BinaryTree<int>t3;
	t3 = t2;
	t3.PrevOrder();
	t3.InOrder();
	t3.PostOrder();
}
int main()
{
        test();
	test2();
}

思考函数    

1.求树节点个数上面的程序中是用递归的方式实现,若以遍历树的方式一个一个计算结点个数程序如下。

//size()实现方式2
size_t BinaryTree<T>::Size()//求结点个数
	{
		static size_t sSize = 0;
		_size(_root, sSize);
			return sSize;
	}
void BinaryTree<T>::_size(BinaryTreeNode<T>*root,size_t &sSize)
{
	if (root == NULL)
		return ;
	sSize++;
	_size(root->_left, sSize);
	_size(root->_right, sSize);

}

    static修饰的变量有了静态的属性,在数据段,它的作用域与自动变量相同,但生存期延长,故可以以静态变量引用的方式来传参(全局变量也类似于静态变量的情况)


ps: 栈用于存储局部变量,堆用于存储动态开辟,数据段存储全局和静态变量,代码段存放常量和指令(只读)。


    然而这两种实现方式(使用全局变量和静态变量)在测试时却出现了很大的问题,如果测试函数中同时调用size函数,则在调用第二次的时候结点个数发生了错误,此时,涉及到了“线程安全”的问题。

    原因是数据段是线程公共的,而他们都调用了size函数size函数又引用了共有的数据段变量,故发生了错误。而局部变量不会发生这个问题,因为局部变量存在栈中,是每个线程独有的,故不会有线程安全的问题。

//size实现方式3
size_t BinaryTree<T>::Size()//求结点个数
	{
		size_t size = 0;
		_size(_root,size);
			return size;
	}
void BinaryTree<T>::_size(BinaryTreeNode<T>*root,size_t &size)
	{
		if (root == NULL)
			return ;
		size++;
		_size(root->_left,size);
		_size(root->_right,size);

	}

2.遍历

    上面层序遍历是用队列实现的,同样,前、中、后序遍历可以用栈来实现。

前序:

void _printPrevOrder(BinaryTreeNode<T>*root)//用栈来存放结点
	{
		if (root == NULL)
			return;
		stack<BinaryTreeNode<T>*> s;
		s.push(root);
		
		while (!s.empty())
		{
			BinaryTreeNode<T>*cur = s.top();
			s.pop();
			
			cout << cur->_data << " ";
			if (cur->_right != NULL)
				s.push(cur->_right);
			if (cur->_left != NULL)
				s.push(cur->_left);
		}
	}

中序:

void _printInOrder(BinaryTreeNode<T>*root)
	{
		BinaryTreeNode<T>*cur = root;
		stack<BinaryTreeNode<T>*>s;
		
		while (cur || !s.empty())
		{
			while (cur)
			{
				s.push(cur);
				cur = cur->_left;
			}
		
			BinaryTreeNode<T>*top = s.top();
			cout << top->_data << " ";
			cur = top->_right;
			s.pop();
		}
	}

后序

void _printPostOrder(BinaryTreeNode<T>* root)
	{
		stack<BinaryTreeNode<T>*>s;
		BinaryTreeNode<T>*cur = root;
		BinaryTreeNode<T>*prev = NULL;
		while (cur!=NULL || !s.empty())
		{
			while (cur!=NULL)
			{
				s.push(cur);
				cur = cur->_left;
			}
			cur = s.top();
			if (cur->_right == NULL || cur->_right == prev)
			{
				cout << cur->_data << " ";
				prev = cur;
				s.pop();
				cur = NULL;
			}
			else
			{
				cur = cur->_right;
			}
		}