二叉树的类定义,以及相关操作实现

二叉树的类定义,以及相关操作实现

//程序5.3 利用二叉链表的二叉树类定义  
#include <iostream>
#include "Queue.h"
#include <stdlib.h>
#include "Stack.h"
template <class T>
struct BinTreeNode
{
	T data;
	BinTreeNode<T>* leftChild, * rightChild;
	BinTreeNode() : leftChild(NULL), rightChild(NULL) {}
	BinTreeNode(T x, BinTreeNode<T>* l = NULL, BinTreeNode<T>* r = NULL)
		: data(x), leftChild(l), rightChild(r) {}
};

template <class T>
class BinaryTree
{
public:
	BinaryTree() : root(NULL) {}
	BinaryTree(T value) : RefValue(value), root(null) {}
	BinaryTree(BinaryTree<T>& s);
	~BinaryTree() { destroy(root); }
	//判断是否为空
	bool IsEmpty()
	{
		return (root == NULL) ? true : false;
	}
	//返回父节点
	BinTreeNode<T>* Parent(BinTreeNode<T>* current)
	{
		return (root == NULL || root == current) ? NULL : Parent(root, current);
	}
	//返回左子女
	BinTreeNode<T>* LeftChild(BinTreeNode<T>* current)
	{
		return (current != NULL) ? current->leftChild : NULL;
	}
	//返回右子女
	BinTreeNode<T>* RightChild(BinTreeNode<T>* current)
	{
		return (current != NULL) ? current->rightChild : NULL;
	}

	//返回树高度
	int Height()
	{
		return Height(root);
	}
	//返回结点数
	int Size()
	{
		return Size(root);
	}
	//取根
	BinTreeNode<T>* getRoot() const
	{
		return root;
	}
	//前序遍历
	void preOrder(void (*visit)(BinTreeNode<T>* p))
	{
		preOrder(root, visit);
	}
	//中序遍历
	void inOrder(void (*visit)(BinTreeNode<T>* p))
	{
		inOrder(root, visit);
	}
	//后序遍历
	void postOrder(void (*visit)(BinTreeNode<T>* p))
	{
		postOrder(root, visit);
	}
	//层次遍历
	void levelOrder(void (*visit)(BinTreeNode<T>* p));

	int Insert(const T item);
	//搜索
	BinTreeNode<T>* Find(T item) const;

protected:
	BinTreeNode<T>* root;
	T RefValue;
	void CreateBinTree(istream& in, BinTreeNode<T>*& subTree);
	bool Insert(BinTreeNode<T>*& subTree, const T& x);
	void destroy(BinTreeNode<T>*& subTree);
	bool Find(BinTreeNode<T>* subTree, const T& x) const;
	//复制
	BinTreeNode<T>* Copy(BinTreeNode<T>* orignode);

	//返回树高度
	int Height(BinTreeNode<T>* subTree);
	//返回结点数
	int Size(BinTreeNode<T>* subTree);
	//返回父节点
	BinTreeNode<T>* Parent(BinTreeNode<T>* subTree, BinTreeNode<T>* current);
	//搜寻X
	BinTreeNode<T>* Find(BinTreeNode<T>* subTree, const T& x) const;
	//前序遍历输出
	void Traverse(BinTreeNode<T>* subTree, ostream& out);
	//前序遍历
	void preOrder(BinTreeNode<T>* subTree, void (*visit)(BinTreeNode<T>* p));
	//中序遍历
	void inOrder(BinTreeNode<T>* subTree, void (*visit)(BinTreeNode<T>* p));
	//后序遍历
	void postOrder(BinTreeNode<T>* subTree, void (*visit)(BinTreeNode<T>* p));
	//重载操作,输入
	friend istream& operator>>(istream& in, BinaryTree<T>& Tree);
	//重载操作,输出
	friend ostream& operator<<(ostream& out, BinTreeNode<T>& Tree);
};
//程序5.4 二叉树 部分成员函数的实现
template<class T>
void BinaryTree<T>::destroy(BinTreeNode<T>*& subTree) {
	//私有函数,若 subTree 不为空,删除 subtree 的子树
	if (subTree != NULL)
	{
		destroy(subTree->leftChild);
		destroy(subTree->rightChild);
		delete subTree;
	}
};
template<class T>
BinTreeNode<T>* BinaryTree<T>::Parent(BinTreeNode<T>* subTree, BinTreeNode<T>* current) {
	//私有函数,从subtree 开始,搜索结点current的父节点,找到返回地址,否则返回null
	if (subTree == NULL) {
		return NULL;
	}
	if (subTree->leftChild == current || subTree->rightChild == current) {
		return subTree;//找到 ,返回父节点的subtree
	}
	BinTreeNode<T>* p;
	//递归在左子树中搜索
	if ((p = Parent(subTree->leftChild, current)) != NULL) {
		return p;
	}
	else {
		//递归在右子树中搜索
		return Parent(subTree->rightChild, current);
	}
};

//私有函数,搜索并输出,根为subTree的二叉树
template<class T>
void BinaryTree<T>::Traverse(BinTreeNode<T>* subTree, ostream& out) {
	if (subTree != NULL) {
		//输出subtree的数据值
		out << subTree->data << " ";
		//递归搜索并输出 subtree 的左子树
		Traverse(subTree->leftChild, out);
		//递归搜索并输出 subtree 的右子树
		Traverse(subTree->rightChild, out);
	}
};

//重载操作,输入并建立一颗二叉树,in 是输入流对象
template<class T>
istream& operator>>(istream& in, BinaryTree<T>& Tree) {
	CreateBinTree(in, Tree.root);
	return in;
};

//重载 操作 ,输出一颗二叉树,OUT是输出流对象
template<class T>
ostream& operator<<(ostream& out, BinaryTree<T>& Tree) {
	out << "二叉树的前序遍历:\n";
	Tree.Traverse(Tree.root, out);
	out << endl;
	return out;
}

//程序5.6 7 8二叉树的三种遍历
//1.前序遍历
template<class T>
void BinaryTree<T>::preOrder(BinTreeNode<T>* subTree, void (*visit)(BinTreeNode<T>* p)) {
	if (subTree != NULL) {
		visit(subTree);
		preOrder(subTree->leftChild, visit);
		preOrder(subTree->rightChild, visit);
	}
}
//2,中序遍历
template<class T>
void BinaryTree<T>::inOrder(BinTreeNode<T>* subTree, void (*visit)(BinTreeNode<T>* p)) {
	if (subTree != NULL) {
		inOrder(subTree->leftChild, visit);
		visit(subTree);
		inOrder(subTree->rightChild, visit);
	}
}
//3.后序遍历
template<class T>
void BinaryTree<T>::postOrder(BinTreeNode<T>* subTree, void (*visit)(BinTreeNode<T>* p)) {
	if (subTree != NULL) {
		postOrder(subTree->leftChild, visit);
		postOrder(subTree->rightChild, visit);
		visit(subTree);
	}
}
//应用后序遍历 ,5.9 统计结点总数
template<class T>
int BinaryTree<T>::Size(BinTreeNode<T>* subTree)const {
	if (subTree == NULL) {
		return 0;
	}
	else {
		//左右子树+根结点
		return 1 + Size(subTree->leftChild) + Size(subTree->rightChild);
	}
};
template<class T>
int BinaryTree<T>::Height(BinTreeNode<T>* subTree) {
	if (subTree == NULL) {
		return 0;
	}
	else {
		int i = Height(subTree->leftChild);
		int j = Height(subTree->rightChild);
		//高度 是 子树+1 (根结点的高度)
		return (i < j) ? j + 1 : i + 1;

	}
};
//5.10前序遍历的应用:复制二叉树
template<class T>
BinaryTree<T>::BinaryTree(const BinaryTree<T>& s) {
	//公共函数, 复制构造函数
	Copy(s.root);
};
template<class T>
BinaryTree<T>* BinaryTree<T>::Copy(BinTreeNode<T>* orignode) {
	//私有函数,该函数返回一个 指针,它给出一个以orignode为根结点的二叉树的副本
	if (orignode == NULL) {
		//根结点为空,返回null
		return NULL;
	}
	//创建根结点
	BinTreeNode<T>* temp = new BinTreeNode<T>;
	//传送数据
	temp->data = orignode->data;
	//复制左右子树
	temp->leftChild = Copy(orignode->leftChild);
	temp->rightChild = Copy(orignode->rightChild);
	//返回根指针
	return temp;

};
//5.11 判断两个 二叉树是否相等【利用前序遍历 】
template<class T>
int operator==(const BinaryTree<T>& s, const BinaryTree<T>& t) {
	//判断两个二叉树的等价性,假定它是 binaryTree类的友元函数
	return (equal(s.root, t.root)) ? true : false;
};
template<class T>
bool equal(BinTreeNode<T>* a, BinTreeNode<T>* b) {
	//若a和b子树不等同,返回false,or true 。假定 它是 BinTreeNode的友元函数
	if (a == NULL && b == NULL) {
		//两个都是 null
		return true;
	}
	//两者都不为空,根结点都相同,左右子树都相同。
	if (a != NULL && b != NULL && a->data == b->data &&
		equal(a->leftChild, b->leftChild) &&
		equal(a->rightChild, b->rightChild)) {
		return true;
	}
	else
	{
		return false;
	}

};



//5.12 以前序遍历 建立二叉树
template<class T>
void BinaryTree<T>::CreateBinTree(istream& in, BinTreeNode<T>*& subTree) {
	T item;
	//未读完,读入并建立 树
	if (!in.eof()) {
		//读入根结点的值
		in >> item;
		if (item != RefValue) {
			//建立根结点
			subTree = new BinTreeNode<T>(item);
			if (subTree == NULL) {
				cerr << "存储分配错误!" << endl;
				exit(1);
			}
			//递归建立左右子树
			CreateBinTree(in, subTree->leftChild);
			CreateBinTree(in, subTree->rightChild);
		}
		else {
			//封闭指向空子树
			subTree = NULL;
		}
	}
};

//5.14二叉树 前序遍历的 非递归 算法       该方法 只有 右子女进栈!
template<class T>
void BinaryTree<T>::preOrder(void (*visit)(BinTreeNode<T>* p)) {
	Stack<BinTreeNode<T>*> S;
	BinTreeNode<T>* p = root;
	//先在栈中存入一个 null ,然后遇到 根结点 就访问,如果有 右子女 就压入栈。
	//返回就 前进到 左子女 并访问了,如果 左子女为null,就弹出 栈顶元素 并访问了。
	S.Push(NULL);
	while (p != NULL) {
		//首先访问根结点
		visit(p);
		//若 有右子女 就压入栈
		if (p->rightChild != NULL) {
			S.Push(p->rightChild);
		}
		//若 有左子女 就前进到左子女
		if (p->leftChild != NULL) {
			p->leftChild;
		}
		//否则,弹出栈顶元素
		else
		{
			S.Pop(p);
		}
	}
};
//5.15 修改 5.14 ,使得 左右子女都进展。先进 右子女,后进左子女。
template<class T>
void BinaryTree<T>::preOrder(void (*visit)(BinTreeNode<T>* p)) {
	Stack<BinTreeNode<T>*> S;
	BinTreeNode<T>* p;
	//先把根结点压入栈
	S.Push(root);


	while (!S.IsEmpty()) {
		//只要栈 不为空,就弹出 栈顶元素,并访问
		S.Pop(p);
		visit(p);
		//先压入右子女
		if (p->rightChild != NULL) {
			S.Push(p->rightChild);
		}
		//后 压入 做左子女  因为 栈是FILO
		if (p->leftChild != NULL) {
			S.Push(p->leftChild);
		}
	}
};
//5.16 层次遍历  需要用到 队列
template<class T>
void BinaryTree<T>::levelOrder(void (*visit)(BinTreeNode<T>* p)) {
	Queue<BinTreeNode<T>* > Q;
	BinTreeNode<T>* p = root;
	//先 把根结点 入队
	Q.EnQueue(p);
	while (!Q.IsEmpty()) {
		// 队首元素出队,并访问
		Q.DeQueue(p);
		visit(p);
		//把它的左子女入队
		if (p->leftChild != NULL) {
			Q.EnQueue(p->leftChild);
		}
		//把它的右子女 入队     层次遍历,先左后右
		if (p->rightChild != NULL) {
			Q.EnQueue(p->rightChild);
		}
	}
};
//5.17 利用栈的 中序遍历 非递归算法
template<class T>
void BinaryTree<T>::inOrder(void (*visit)(BinTreeNode* p)) {
	Stack<BinTreeNode<T>*> S;
	//p是遍历指针,从根结点 开始
	BinTreeNode<T>* p = root;
	do {
		//遍历指针未到 最左下 的结点,不空
		while (p != NULL) {
			//该子树 沿途结点 进栈
			S.Push(p);
			//遍历指针进入到左子女结点
			p = p->leftChild;
		}
		if (!S.IsEmpty()) {
			//栈 不空时,退出 并 访问
			S.Pop(p);
			visit(p);
			//遍历指针进入到 右子女结点
			p = p->rightChild;
		}
	} while (p != NULL || !S.IsEmpty());
};

//利用栈的后序遍历 非递归算法
//5.18    后序遍历 中 所用栈的结点定义
template<T>
struct stkNode
{
	//指向树结点的指针
	BinTreeNode<T>* ptr;
	//结点  退栈标记
	enum tag{L,R};
	//构造函数
	stkNode(BinTreeNode<T> *N=NULL):ptr(N),tag(L){}
};
//后序遍历的非递归算法
template<T>
void BinaryTree<T>::postOrder(void (*visit)(BinTreeNode<T>* p)) {
	Stack<stkNode<T>> S;
	stkNode<T> w;
	//p是 遍历指针
	BinTreeNode<T>* p = root;
	do
	{
		//左子树 经过结点加L进栈
		while (p != NULL) {
			w.ptr = p;
			w.tag = L;
			S.Push(w);
			//向 最左结点 走下去
			p = p->leftChild;
		}
		//继续循环标记,用于R
		int continuel = 1;
		while (continuel && !S.IsEmpty()) {
			//栈不空 退栈
			S.Pop(w);
			p = w.ptr;
			//判断 栈顶的tag标记
			switch (w.tag) {
			case L:
				//从 左子树 退回,修改栈顶tag
				w.tag = R;
				S.Push(w);
				continuel = 0;
				//向右子树 遍历下去
				p = p->rightChild;
				break;

			case R:
				//从右子树结点退回,访问根结点
				visit(p);
				break;
			}

		}
		//还有未遍历结点,继续循环
	} while (!S.IsEmpty());
	cout << endl;
};


//5.20 利用 前序遍历和中序遍历 构造二叉树
template<T>
BinTreeNode<T>* createBinaryTree(T* VLR, T* LVR, int n) {
	
	if (n == 0) {
		return NULL;
	}
	int k = 0;
	//在中序遍历 序列中 寻找根结点
	while (VLR[0] != LVR[k])
		k++;
	//创建 根结点
	BinTreeNode<T>* t = new BinTreeNode<T>(VLR[0]);
	
	//从前序遍历 VLR+1开始对中序遍历的0~k-1左子序列的k个元素  递归建立 左子树
	t->leftChild = createBinaryTree(VLR + 1, LVR, k);

	//从前序遍历 VLR+K+1开始对中序遍历的K+1~N-1右子序列的n-k-1个元素  递归建立 右子树
	t->rightChild = createBinaryTree(VLR + k + 1, LVR + k + 1, n - k - 1);
	
	//构造出的 二叉树根指针 由函数返回。
	return t;
};

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Roam-G

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值