二叉树的类定义,以及相关操作实现
Posted Roam-G
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了二叉树的类定义,以及相关操作实现相关的知识,希望对你有一定的参考价值。
二叉树的类定义,以及相关操作实现
//程序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;
};
以上是关于二叉树的类定义,以及相关操作实现的主要内容,如果未能解决你的问题,请参考以下文章
数据结构C语言 《四》二叉树,堆的基本概念以及堆的相关操作实现(上)