数据结构学习笔记(五)二叉树及其C++实现

一、树的基本概念

          树是一种层次结构,表达一对多的关系

          树的节点:包含数据元素,还有指向其他节点的指针:孩纸指针,父节点指针

叶子节点,根节点,孩纸节点,双亲节点,兄弟节点,堂兄弟节点,祖先节点,子孙节点

          节点的度:节点分支的个数

          树的度:所有节点的度的最大值

          树的路径:根节点到该节点上的所有节点连接起来的

          层次:从根节点开始定义,根为第一层,根的孩纸为第二层,若节点中在第k层,其子树的根在第k+1层

          树的深度(高度):树种节点的最大层次

          有序树:树中节点的各个子树从左到右看做是有次序的

          森林:即m个互不相交的树的集合

          树的基本操作:求根节点,求双亲节点,求孩纸节点,建立一棵树,销毁一棵树等


二、二叉树

           二叉树是每一个节点最多有两个子树的特殊的树,即树的度为2。二叉树是有序树,有左右子树之分。二叉树比较特殊的有完全二叉树、满二叉树,二叉平衡树等等。如下图所示:


            二叉树的操作:新建树,销毁树,前序遍历,中序遍历,后续遍历,层次遍历,查找节点,树的高度,节点个数。。。。。。。。。

            二叉树的性质:


                   二叉树在实现过程中,使用链表结构比较方便,下面给出二叉树的C++实现:

三、二叉树的C++实现

#pragma once
//#include"arrayQueue.h"//使用标准库的队列
#include<deque>
#include<iostream>

using namespace std;


//节点结构
template<class T>
struct TreeNode
{
	T element;//元素
	TreeNode<T>* leftchild;//左孩子
	TreeNode<T>* rightchild;//右孩子

	TreeNode()
	{ 
		leftchild = rightchild = NULL;
	}
	TreeNode(const T& theElement)
	{ 
		element = theElement; leftchild = rightchild = NULL; 
	}
	TreeNode(const T& theElement, TreeNode<T>* left, TreeNode<T>* right)
	{ 
		element = theElement; leftchild = left; rightchild = right;
	}
};
//二叉树
template<class T>
class binaryTree
{
public:
	//构造函数,复制构造函数和析构函数
	binaryTree(){ root = NULL; theSize = 0; }//构造一个空树
	~binaryTree(){ erase(); }//析构,通过调用erase函数删除所有节点
	binaryTree(const binaryTree<T> &thebinaryTree)//复制构造函数
	{
		theSize = thebinaryTree.theSize;
		if (theSize==0)//如果树为空
		{
			root = NULL;
			return;
		}
		//树不为空,挨个节点复制
		deque<TreeNode<T>*> q, p;//队列q存放原来的树的节点,p存放新建的树的节点
		TreeNode<T>* sourceNode = thebinaryTree.root;
		root = new TreeNode<T>(sourceNode->element);
		TreeNode<T>* targetNode = root;
		q.push_back(sourceNode);
		p.push_back(targetNode);
		//将sourceNode复制到targetNode
		while (q.empty()==0)
		{
			sourceNode = q.front();
			targetNode = p.front();
			if (sourceNode->leftchild != NULL)
			{
				q.push_back(sourceNode->leftchild);
				targetNode->leftchild = new TreeNode<T>(sourceNode->leftchild->element);
				p.push_back(targetNode->leftchild);
			}
			if (sourceNode->rightchild != NULL)
			{
				q.push_back(sourceNode->rightchild);
				targetNode->rightchild = new TreeNode<T>(sourceNode->rightchild->element);
				p.push_back(targetNode->rightchild);
			}
			q.pop_front();
			p.pop_front();
		}
	}
	//各种成员函数
	int size() const{ return theSize; }//树的大小
	bool empty() const{ return theSize == 0; }//树是否为空
	T* rootelement() const//返回根节点的地址
	{
		if (theSize == 0){  return NULL; }
		else { return &root->element; }//注意优先级
	}
	int height() const { return height(root); }//通过调用height(root)来求整个树的高度

	void makeTree(const T& element, binaryTree<T>& left, binaryTree<T>& right);//建造一个树
	binaryTree<T> removeLeftSubtree();//移除左子树
	binaryTree<T> removeRightSubtree();//移除右子树

	//整个树的前序遍历,形参表示一个函数用来处理遍历的当前节点,theVist是函数地址,返回值是void,其参数是TreeNode<T>*
	void preOrder(void(*theVisit) (TreeNode<T>*))   { preOrder(theVisit, root); }
	//整个树的中序遍历,
	void inOrder(void (*theVisit) (TreeNode<T>*))	{ inOrder(theVisit,root);	}
	//整个树的后序遍历,
	void postOrder(void (*theVisit) (TreeNode<T>*))	{ postOrder(theVisit,root);	}
	//整个树的层次遍历
	void levelOrder(void(*theVisit) (TreeNode<T>*)) { levelOrder(theVisit, root); }
	
	//几种不同的输出
	void preOrderOutput() { preOrder(output,root); cout << endl; }
	void inOrderOutput() { inOrder(output,root); cout << endl; }
	void postOrderOutput() { postOrder(output,root); cout << endl; }
	void levelOrderOutput() { levelOrder(output,root); cout << endl; }

	//删除树,清空整个树
	void erase()
	{
		postOrder(dispose,root);
		root = NULL;
		theSize = 0;
	}
	//查找树的某一个节点
	bool find(const T& theElement)
	{
		deque<TreeNode<T>*> q;//队列
		TreeNode<T> *t = root;
		while (t != NULL)
		{
			if (t->element==theElement)
			{
				return true;
			}

			// 将t的孩纸加入队列
			if (t->leftchild != NULL)
				q.push_back(t->leftchild);
			if (t->rightchild != NULL)
				q.push_back(t->rightchild);

			// 获得下一个节点
			if (q.empty() == 0)
				t = q.front();
			else
				break;
			q.pop_front();
		}
		return false;
	}
	
	
protected:
	TreeNode<T>* root;//指向根节点的指针
	int theSize;//树的元素个数

	//前序遍历以t为根节点的树,参数visit是对节点的处理函数,
	static void preOrder(void(*visit) (TreeNode<T>*), TreeNode<T> *t)
	{
		if (t != NULL)
		{
			visit(t);
			preOrder(visit,t->leftchild);
			preOrder(visit,t->rightchild);
		}
	}
	//中序遍历以t为根节点的树,参数visit是对节点的处理函数,
	static void inOrder(void(*visit) (TreeNode<T>*), TreeNode<T> *t)
	{
		if (t != NULL)
		{
			inOrder(visit,t->leftchild);
			visit(t);
			inOrder(visit,t->rightchild);
		}
	}
	//后序遍历以t为根节点的树,参数visit是对节点的处理函数,
	static void postOrder(void(*visit) (TreeNode<T>*), TreeNode<T> *t)
	{
		if (t != NULL)
		{
			postOrder(visit,t->leftchild);
			postOrder(visit,t->rightchild);
			visit(t);
		}
	}
	//层次遍历以t为根节点的树
	void levelOrder(void(*theVisit) (TreeNode<T>*),TreeNode<T>* t)
	{
		deque<TreeNode<T>*> q;//队列
		//TreeNode<T> *t = root;
		while (t != NULL)
		{
			theVisit(t);  // 处理节点t

			// 将t的孩纸加入队列
			if (t->leftchild != NULL)
				q.push_back(t->leftchild);
			if (t->rightchild != NULL)
				q.push_back(t->rightchild);

			// 获得下一个节点
			if (q.empty() == 0)
				t = q.front();
			else
				return;
			q.pop_front();
		}
	}
	//返回节点t为根节点的树的节点个数,使用层次遍历好写,其他遍历方法也可以实现。。
	static int countNodes(TreeNode<T> *t)
	{
		int count = 0;
		deque<TreeNode<T>*> q;//队列
		while (t != NULL)
		{
			count++;  // 处理节点t

			// 将t的孩纸加入队列
			if (t->leftchild != NULL)
				q.push_back(t->leftchild);
			if (t->rightchild != NULL)
				q.push_back(t->rightchild);
			 
			// 获得下一个节点
			if (q.empty() == 0)
				t = q.front();
			else
				break;
			q.pop_front();

		}
		return count;
	}
	static void dispose(TreeNode<T> *t) { delete t; }//删除节点t
	static void output(TreeNode<T> *t)	{ cout << t->element << ' ';	}//输出节点t
	static int height(TreeNode<T> *t)//返回节点t为根节点的树的高度
	{
		if (t == NULL)
			return 0;                    // 空树
		int hl = height(t->leftchild);  // 左树高度
		int hr = height(t->rightchild); // 右树高度
		if (hl > hr)
			return ++hl;
		else
			return ++hr;
	}
};
//创建一棵树
template<class T>
void binaryTree<T>::makeTree(const T& element, binaryTree<T>& left, binaryTree<T>& right)
{
	root = new TreeNode<T>(element, left.root, right.root);
	theSize = left.theSize + right.theSize + 1;
	left.root = right.root = NULL;
	left.theSize = right.theSize = 0;

}


template<class T>
binaryTree<T> binaryTree<T>::removeLeftSubtree()
{// 删除左子树
	if (theSize == 0)
	{
		cerr << "The tree is empty"; exit(0);
	}
	binaryTree<T> leftSubtree;
	leftSubtree.root = root->leftchild;
	leftSubtree.theSize = countNodes(leftSubtree.root);
	//原来的树的左子树为空,theSize改变
	root->leftchild = NULL;
	theSize -= leftSubtree.theSize;

	return leftSubtree;//需要定义复制构造函数
}

template<class T>
binaryTree<T> binaryTree<T>::removeRightSubtree()
{// 删除右子树

	if (theSize == 0)
	{
		cerr << "The tree is empty"; exit(0);
	}

	binaryTree<T> rightSubtree;
	rightSubtree.root = root->rightchild;	
	rightSubtree.theSize = countNodes(rightSubtree.root);

	root->rightchild = NULL;
	theSize -= rightSubtree.theSize;

	return rightSubtree;
}

测试代码:

#include "binaryTree.h"
#include<iostream>
using namespace std;
void main()
{
	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 << "Number of nodes = ";
	cout << y.size() << endl;
	cout << "height = ";
	cout << y.height() << endl;
	cout << "Rootment of The tree is ";
	cout << *(y.rootelement()) << endl;
	cout << "Preorder sequence is ";
	y.preOrderOutput();
	cout << "Inorder sequence is ";
	y.inOrderOutput();
	cout << "Postorder sequence is ";
	y.postOrderOutput();
	cout << "Level order sequence is ";
	y.levelOrderOutput();
	(y.find(4) == 1) ? cout << "The tree have 4" : cout << "The tree have not 4";
	cout << endl;
	cout << "The leftSubtree:";
	y.removeLeftSubtree().postOrderOutput();
	cout << "The copy of the Tree is ";
	binaryTree<int> s = y;
	s.levelOrderOutput();
}


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值