树(tree)
t 是一个非空的有限元素的集合,其中一个元素为根(root),余下的元素(如果有的话)组成t 的子树(subtree)。
如下图:
二叉树(binary tree)
t 是有限个元素的集合(可以为空)。当二叉树非空时,其中有一个称为根的元素,余下的元素(如果有的话)被组成 2个二叉树,分别称为t的左子树和右子树。
二叉树图:
树与二叉树的区别:
- 二叉树可以为空,但树不能为空。
- 二叉树中每个元素都恰好有两棵子树(其中一个或两个可能为空)。而树中每个元素可有若干子树。
- 在二叉树中每个元素的子树都是有序的,也就是说,可以用左、右子树来区别。而树的子树间是无序的。
二叉树的特性:
- 包含n (n> 0 )个元素的二叉树边数为n-1。
- 若二叉树的高度为h, h≥0,则该二叉树最少有h个元素,最多有2^h - 1个元素。
- 包含n 个元素的二叉树的高度最大为n,最小为log2 (n+1) 向上取整数
- 设完全二叉树中一元素的序号为i, 1≤i≤n。则有以下关系成立:
1) 当i = 1时,该元素为二叉树的根。若i > 1,则该元素父节点的编号为 i / 2 。
2) 当2i >n时,该元素无左孩子。否则,其左孩子的编号为 2i。
3) 若2i + 1 >n,该元素无右孩子。否则,其右孩子编号为 2i + 1
代码表示:
二叉树节点定义:
/*
数组结构中 二叉树
对应书中代码:数据结构算法与应用c++描述
程序编写:比卡丘不皮
编写时间:2020年7月20日 11:17:13
*/
#pragma once
#include <iostream>
#include "LinkedQueue.h"
using namespace std;
template <class T>
class BinaryTree;
template<class T>
class BinaryTreeNode
{
friend BinaryTree<T>;
public:
//建立二叉树节点方式1:默认构造方式
BinaryTreeNode() { LeftChild = RightChild = 0; }
//建立二叉树节点方式2
BinaryTreeNode(const T &e)
{
data = e;
LeftChild = RightChild = 0;
}
//建立二叉树节点方式3
BinaryTreeNode(const T& e, BinaryTreeNode<T> *left, BinaryTreeNode<T> *right)
{
data = e;
LeftChild = left;
RightChild = right;
}
private:
T data; //节点数据
BinaryTreeNode<T> * LeftChild, //左子树
*RightChild; //右子树
};
这是二叉树的节点,包含的头文件在我写的博客中,队列链表描述,这个用在遍历数据使用,若不想自己定义的话可以使用stl中的queue来代替。
二叉树定义:
//二叉树类
int _count = 0; //记录节点个数变量
template <class T>
class BinaryTree
{
public:
BinaryTree() { root = 0; }
~BinaryTree() {};
bool IsEmpty()const; //判断二叉树是否为空
bool Root(T &x) const //取根节点的data域,放入x中,若不存在,返回false
{
if (root)
{
x = root->data;
return true;
}
else
return false;
}
//将树left和树right以及element合并成一棵新树
void MakeTree(const T& element, BinaryTree<T> &left, BinaryTree<T> &right);
//分解一个树
void BreakTree(T& element, BinaryTree<T> &left, BinaryTree<T> &right);
//前序遍历函数
void PreOrder(void(* Visit)(BinaryTreeNode<T> * u))
{
PreOrder(Visit, root);
}
//中序遍历函数
void InOrder(void(*Visit)(BinaryTreeNode<T>* u))
{
InOrder(Visit, root);
}
//后序遍历函数
void PostOrder(void(*Visit)(BinaryTreeNode<T> *u))
{
PostOrder(Visit, root);
}
//逐层遍历函数
void LevelOrder(void(*Visit)(BinaryTreeNode<T> *u));
//前序遍历输出函数---公有的,便于外部访问
void PreOutput()
{
PreOrder(Output, root); cout << endl;
}
//中序遍历输出函数
void InOutput()
{
InOrder(Output, root); cout << endl;
}
//后序遍历输出函数
void PostOutput()
{
PostOrder(Output, root); cout << endl;
}
//逐层遍历输出函数
void LevelOutput()
{
LevelOrder(Output); cout << endl;
}
//删除一棵二叉树.采用后序遍历的方式删除一棵二叉树
void Delete()
{
PostOrder(Free, root); root = 0;
}
//计算树的高度
int Height()const { return Height(root); }
//获取树的节点个数
int Size()
{
_count = 0;
PreOrder(Add1, root);
return _count;
}
private:
BinaryTreeNode<T> *root; //根节点指针
//前序遍历---私有的,有利于封装,并且可实现多次操作
void PreOrder(void(*Visit)(BinaryTreeNode<T> *u), BinaryTreeNode<T> *t);
//中序遍历
void InOrder(void(*Visit)(BinaryTreeNode<T> *u), BinaryTreeNode<T> *t);
//后序遍历
void PostOrder(void(*Visit)(BinaryTreeNode<T> *u), BinaryTreeNode<T> *t);
//输出节点函数
static void Output(BinaryTreeNode<T> *t)
{
cout << t->data << " ";
}
//删除节点函数
static void Free(BinaryTreeNode<T> *t)
{
delete t;
}
//计算子树的最大高度
int Height(BinaryTreeNode<T> *t) const;
//记录节点个数
static void Add1(BinaryTreeNode<T> *t) { _count++; }
};
IsEmpty函数:
template<class T>
bool BinaryTree<T>::IsEmpty() const
{
return ((root)? false: true);
}
MakeTree组合树:
template<class T>
void BinaryTree<T>::MakeTree(const T & element, BinaryTree<T>& left, BinaryTree<T>& right)
{
// 将left, right和element 合并成一棵新树
// left, right和this必须是不同的树
//创建新树
root = new BinaryTreeNode<T>(element, left.root, right.root);
// 阻止访问left和right
left.root = right.root = 0;
}
BreakTree拆分树
template<class T>
void BinaryTree<T>::BreakTree(T & element, BinaryTree<T>& left, BinaryTree<T>& right)
{
// left, right和this必须是不同的树
// 检查树是否为空
if (!root)
{
throw OutOfBounds();
}
//分解树
element = root->data;
left.root = root->LeftChild;
right.root = root->RightChild;
delete root;
root = 0;
}
逐层遍历:
template<class T>
void BinaryTree<T>::LevelOrder(void(*Visit)(BinaryTreeNode<T>*u))
{
LinkedQueue<BinaryTreeNode<T> *> Q;//声明节点为二叉树节点类型的链表队列Q
BinaryTreeNode<T>* t; //声明二叉树节点t
t = root; //t赋为根节点
while (t)
{
Visit(t);
if (t->LeftChild)
{
Q.Add(t->LeftChild); //左节点
}
if (t->RightChild)
{
Q.Add(t->RightChild); //右节点
}
if (!Q.IsEmpty())
{
Q.Delete(t); //依次出队列
}
else
{
break; //跳出while循环。
}
}
}
前序遍历:
template<class T>
void BinaryTree<T>::PreOrder(void(*Visit)(BinaryTreeNode<T>*u), BinaryTreeNode<T>* t)
{
if (t)
{
Visit(t); //访问根节点
PreOrder(Visit, t->LeftChild); //递归前序遍历左子树
PreOrder(Visit, t->RightChild); //递归前序遍历右子树
}
}
中序遍历:
template<class T>
void BinaryTree<T>::InOrder(void(*Visit)(BinaryTreeNode<T>*u), BinaryTreeNode<T>* t)
{
if (t)
{
InOrder(Visit, t->LeftChild);
Visit(t);
InOrder(Visit, t->RightChild);
}
}
后序遍历:
template<class T>
void BinaryTree<T>::PostOrder(void(*Visit)(BinaryTreeNode<T>*u), BinaryTreeNode<T>* t)
{
if (t)
{
PostOrder(Visit,t->LeftChild);
PostOrder(Visit, t->RightChild);
Visit(t);
}
}
树的高度:
template<class T>
int BinaryTree<T>::Height(BinaryTreeNode<T>* t) const
{
if (!t) //树为空
{
return 0;
}
int height_left = Height(t->LeftChild); //左子树高度
int height_right = Height(t->RightChild); //右子树高度
if (height_left > height_right) //若左子树高度大于右子树
{
return ++height_left; //左子树返回值加1
}
else
{
return ++height_right; //否则,右子树高度加1
}
}
测试函数:
void testBinaryTree()
{
BinaryTree<int> a, x, y, z;
y.MakeTree(1, a, a);
z.MakeTree(2, a, a);
x.MakeTree(3, y, z);
y.MakeTree(4, x, a);
cout << "数中的节点数" << y.Size() << endl;
cout << "前序遍历树: ";
y.PreOutput();
cout << "中序遍历树: ";
y.InOutput();
cout << "后序遍历树: ";
y.PostOutput();
cout << "逐层遍历树: ";
y.LevelOutput();
cout << "树中高度: "<< y.Height();
}
输出结果:
这就是输出的树了,喜欢的话就关注我的博客。