C++数据结构二叉树的相关操作,完整版本

Posted Roam-G

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了C++数据结构二叉树的相关操作,完整版本相关的知识,希望对你有一定的参考价值。

//程序5.3 --194-利用二叉链表的二叉树类定义  
#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 --196--二叉树 部分成员函数的实现
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.5--197-输入广义表 建立二叉树
void CreateBinTree(istream& in, BinTreeNode<char>*& BT) {
	//从输入流in输入二叉树的广义表表示建立对应 的二叉树
	Stack<BinTreeNode<char>* > stack;
	BT = NULL;
	BinTreeNode<char>* p, * t;
	int k;//k用作处理左右子树标记。
	char ch;
	in >> ch;
	while (ch != RefValue) {//逐个字符处理# = RefValue
		switch (ch) {
		case '(':
			stack.Push(p);
			k = 1;
			break;
		case ')':
			stack.Pop(t);
			break;
		case ',':
			k = 2;
			break;
		default:
			p = new BinTreeNode<ch>;
			if (BT == NULL) {
				BT = p;
			}
			else if (k == 1) {
				stack.getTop(t);
				t->LeftChild = p;
			}
			else {
				stack.getTop(t);
				t->RightChild = p;
			}
		}
		in >> ch;
	}
};

//程序5.6 7 8二叉树的三种遍历--199
//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) {
	//公共函数, 复制构造函数
	root = Copy(s.root);
};
template<class T>
BinTreeNode<T>* BinaryTree<T>::Copy(BinTreeNode<T>* orignode) {
	//私有函数,该函数返回一个 指针,它给出一个以orignode为根结点的二叉树的副本
	if (orignode == NULL) {
		//根结点为空,返回null
		return NULL;
	}
	BinTreeNode<T>* temp = new BinTreeNode<T>;//创建xin根结点
	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,否则 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(ifstream& 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.13 以为广义表的形式输出二叉树的算法
template<class T>
void PrintBTree(BinTreeNode<T>* BT) {
	if (BT != NULL) {
		cout << BT->data;//先输出根结点
		if (BT->leftChild != NULL || BT->rightChild != NULL) {
			cout << '(';
			PrintBTree(BT->leftChild);
			cout << ",";
			if (BT->rightChild != NULL) {
				PrintBTree(BT->rightChild);
			}
			cout << ')';
		}
	}
};

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

 

以上是关于C++数据结构二叉树的相关操作,完整版本的主要内容,如果未能解决你的问题,请参考以下文章

c++二叉树按层序遍历顺序输入(由上到下),先序遍历顺序输出,求完整代码

数据结构(C语言版)严蔚敏---二叉树遍历操作二叉树的相关代码

数据结构(C语言版)严蔚敏---二叉树遍历操作二叉树的相关代码

二叉树,堆详解

Java实现二叉树的创建和遍历操作(有更新)

Java实现二叉树的创建和遍历操作(有更新)