(1小时数据结构)数据结构c++描述(十七) --- 树与二叉树

树(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();

 }

输出结果:

 

这就是输出的树了,喜欢的话就关注我的博客。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值