c++数据结构二叉树(二叉链表实现)基本操作实现

二叉树: 

        二叉树(Binary tree)是树形结构的一个重要类型。许多实际问题抽象出来的数据结构往往是二叉树形式,即使是一般的树也能简单地转换为二叉树,而且二叉树的存储结构及其算法都较为简单,因此二叉树显得特别重要。二叉树特点是每个结点最多只能有两棵子树,且有左右之分

性质:

二叉树性质
性质1:二叉树的第i层上至多有2i-1(i≥1)个节点。
性质2:深度为h的二叉树中至多含有2h-1个节点。
性质3:若在任意一棵二叉树中,有n0个叶子节点,有n2个度为2的节点,则必有n0=n2+1。
性质4:具有n个节点的完全二叉树深为log2x+1(其中x表示不大于n的最大整数)。
性质5:若对一棵有n个节点的完全二叉树进行顺序编号(1≤i≤n),那么,对于编号为i(i≥1)的节点:
当i=1时,该节点为根,它无双亲节点。
当i>1时,该节点的双亲节点的编号为i/2。
若2i≤n,则有编号为2i的左节点,否则没有左节点。
若2i+1≤n,则有编号为2i+1的右节点,否则没有右节点。

输入:

 

运行结果:

代码:

/*
	朱海垅2030090111
	2021年11月10日
	二叉链表实现二叉树
*/

#include<iostream>
using namespace std;
template <class T>
struct BinTreeNode {
	T data;												//数据域
	BinTreeNode<T>* leftChiild, * rightChild;			//左右子域
	BinTreeNode() :leftChiild(NULL), rightChild(NULL) {}
	BinTreeNode(T x, BinTreeNode<T>* l = NULL, BinTreeNode<T>* r = NULL) :data(x), leftChiild(l), rightChild(r) {}
};
template<class T>
class BinaryTree {
public:
	BinaryTree() : root(NULL) {}							//构造函数
	BinaryTree(T value) :RefValue(value), root(NULL) {}//构造函数
	BinaryTree(BinaryTree<T>& s) { root = Copy(s.root); }						//复制构造函数
	~BinaryTree() { destory(root); }								//析构函数
	bool IsEmpty() { return (root == NULL) ? true : false; }	//返回二叉树是否为空
	BinTreeNode<T>* Parent(BinaryTree<T>* current) { return (root == NULL || root = current) ? NULL : Parent(root, current); }	//返回父节点
	BinTreeNode<T>* LeftChild(BinTreeNode<T>* current) { return (current != NULL) ? current->leftChiild : NULL; }	//返回其节点的左子节点
	BinTreeNode<T>* RightChild(BinTreeNode<T>* current) { return (current != NULL) ? current->rightChild : NULL; }	//返回其节点的右子节点
	int Hight() { return Hight(root); }							//返回树的高度(对数据进行封装)
	int NodeCount() { return NodeCount(root); }					//返回树的节点数目(对数据进行封装)
	int LeafCount() { return LeafCount(root); }					//返回树的叶子节点数(对数据进行封装)
	BinTreeNode<T>* GetRoot() const { return root; }			//返回根节点指针
	void preOrder(void(*vist)(BinTreeNode<T>* p)) { preOrder(root, vist); }//前序遍历
	void inOrder(void (*vist)(BinTreeNode<T>* p)) { inOrder(root, vist); }//中序遍历
	void postOrder(void(*vist)(BinTreeNode<T>* p)) { postOrder(root, vist); }//后序遍历
	/*void levelOrder(void(*vist)(BinTreeNode<T>* p))
	{
		Queue<BinTreeNode<T>*>Q;
		BinTreeNode<T>* p = root;
		Q.EnQueue(p);
		while (!Q.IsEmpty())		//队列不为空时
		{
			Q.DeQueue(p); visit(p);
			if (p->leftChiild != NULL)Q.EnQueue(p->leftChiild);
			if (p->rightChild != NULL)Q.EnQueue(p->rightChild);
		}
	}//层次序遍历(使用队列类实现简单)这里不列出队列类的构造*/

protected:
	BinTreeNode<T>* root;								//二叉树根指针
	T RefValue;											//数据输入停止标志
	void destory(BinTreeNode<T>*& subTree);					//删除
	BinTreeNode<T>* Parent(BinTreeNode<T>* subTree, BinTreeNode<T>* current);//返回父节点
	int Hight(BinTreeNode<T>* subTree);						//返回数的高度
	int NodeCount(BinTreeNode<T>* subTree);					//返回树的节点数
	int LeafCount(BinTreeNode<T>* subtree);						//返回树的叶子节点数
	void CreateBinTree(istream& in, BinTreeNode<T>*& subTree);	//键盘输入建立树(用前序遍历输入)
	BinTreeNode<T>* Copy(BinTreeNode<T>* orignode);				//复制节点函数
	void Traverse(BinTreeNode<T>* subtree, ostream& out);			//前序遍历输出
	void Traverse1(BinTreeNode<T>* subtree, ostream& out);			//中序遍历输出
	void Traverse2(BinTreeNode<T>* subtree, ostream& out);			//后序遍历输出
	void preOrder(BinTreeNode<T>& subtree, void (*vist)(BinTreeNode<T>* p))
	{
		if (subtree != NULL)//递归结束条件为根空
		{
			vist(subtree);							//访问根
			preOrder(subtree->leftChiild, vist);	//访问左子树
			preOrder(subtree->rightChild, vist);	//访问右子树 
		}
	}//前序遍历
	void inOrder(BinTreeNode<T>& subtree, void (*vist)(BinTreeNode<T>* p))
	{
		if (subtree != NULL)
		{
			inOrder(subtree->leftChiild, vist);
			vist(subtree);
			inOrder(subtree->rightChild, vist);
		}
	}//中序遍历
	void postOrder(BinTreeNode<T>& subTree, void (*vist)(BinTreeNode<T>* p))
	{
		if (subTree != NULL)
		{
			postOrder(subTree->leftChiild, vist);
			postOrder(subTree->rightChild, vist);
			vist(subTree);
		}
	}//后序遍历
	template <class T> friend istream& operator>>(istream& in, BinaryTree<T>& Tree);
	template <class T> friend ostream& operator<<(ostream& out, BinaryTree<T>& Tree);
	
};
//删除
template<class T>
void BinaryTree<T>::destory(BinTreeNode<T>*& subTree)
{
	if (subTree != NULL)
	{
		destory(subTree->leftChiild);
		destory(subTree->rightChild);				//递归删除节点
		delete subTree;
	}
}

//返回父节点
template<class T>
BinTreeNode<T>* BinaryTree<T>::Parent(BinTreeNode<T>* subTree, BinTreeNode<T>* current)
{
	if (subTree == NULL)return NULL;
	if (subTree->leftChiild == current || subTree->rightChild == current)return subTree;
	BinTreeNode<T>* p;
	if ((p = Parent(subTree->leftChiild, current)) != NULL)return p;
	else return Parent(subTree->rightChild, current);
}

//返回树高度
template <class T>
int BinaryTree<T>::Hight(BinTreeNode<T>* subtree)
{
	//递归求出树的高度
	if (subtree == NULL)return 0;
	else
	{
		int m = Hight(subtree->leftChiild);
		int n = Hight(subtree->rightChild);
		if (m > n)return (m + 1);
		else return (n + 1);
		//m,n,要么为1,要么为0.从树底往上叠加
	}
}

//返回树节点数
template<class T>
int BinaryTree<T>::NodeCount(BinTreeNode<T>* subtree)
{
	if (subtree == NULL)return 0;
	else return NodeCount(subtree->leftChiild) + NodeCount(subtree->rightChild) + 1;//递归求出节点个数加一(根节点)
}

//返回树叶子节点数目
template<class T>
int BinaryTree<T>::LeafCount(BinTreeNode<T>* subtree)
{
	if (!subtree)return 0;
	if (!subtree->leftChiild && !subtree->rightChild)return 1;//左右子树为空
	else return LeafCount(subtree->leftChiild) + LeafCount(subtree->rightChild);
}

//前序遍历方法输入建立树,以此类推也可以用中序和和后序算法建立
template<class T>
void BinaryTree<T>::CreateBinTree(istream& in, BinTreeNode<T>*& subTree)
{
	T item;
	if (!in.eof())           //表示未读完,继续读取
	{
		cout << "请输入数据:" << endl;
		in >> item;
		if (item != RefValue)
		{
			subTree = new BinTreeNode<T>(item);			//建立根节点
			if (subTree == NULL) { cout << "存储分配错误" << endl; exit(1); }
			cout << "请输入左树:" << endl;
			CreateBinTree(in, subTree->leftChiild);		//建立左子树
			cout << "请输入右树: " << endl;
			CreateBinTree(in, subTree->rightChild);		//建立右子树
		}
		else subTree = NULL;
	}
}

//返回一个以orignode为根的二叉树副本
template<class T>
BinTreeNode<T>* BinaryTree<T>::Copy(BinTreeNode<T>* orignode)
{
	if (orignode == NULL)return NULL;
	BinTreeNode<T>* temp = new BinTreeNode<T>;
	temp->data = orignode->data;
	temp->leftChiild = Copy(orignode->leftChiild);
	temp->rightChild = Copy(orignode->rightChild);
	return temp;
}

//搜索并输出根为subTree的二叉树(前序遍历输出)
template<class T>
void BinaryTree<T>::Traverse(BinTreeNode<T>* subTree, ostream& out)
{
	if (subTree != NULL)//是空则返回,否则一直输出到空
	{
		out << subTree->data << ' ';			//根
		Traverse(subTree->leftChiild, out);		//左
		Traverse(subTree->rightChild, out);		//右
	}
}

//搜索并输出根为subTree的二叉树(中序遍历输出)
template<class T>
void BinaryTree<T>::Traverse1(BinTreeNode<T>* subTree, ostream& out)
{
	if (subTree != NULL)//是空则返回,否则一直输出到空
	{
		Traverse(subTree->leftChiild, out);		//左
		out << subTree->data << ' ';			//根
		Traverse(subTree->rightChild, out);		//右
	}
}

//搜索并输出根为subTree的二叉树(后序遍历输出)
template<class T>
void BinaryTree<T>::Traverse2(BinTreeNode<T>* subTree, ostream& out)
{
	if (subTree != NULL)//是空则返回,否则一直输出到空
	{
		Traverse(subTree->leftChiild, out);		//左
		Traverse(subTree->rightChild, out);		//右
		out << subTree->data << ' ';			//根
	}
}


//重载输入流操作,输入并建立一颗二叉树Tree
template<class T>
istream& operator>>(istream& in, BinaryTree<T>& Tree)
{
	Tree.CreateBinTree(in, Tree.root);
	return in;
}

//重载输出操作,输出二叉树Tree
template<class T>
ostream& operator<<(ostream& out, BinaryTree<T>& Tree)
{
	out << "二叉树的前序遍历:" << endl;
	Tree.Traverse(Tree.root, out);//从根开始输出
	out << endl;
	out << "二叉树的中序遍历:" << endl;
	Tree.Traverse1(Tree.root, out);
	out << endl;
	out << "二叉树的后序遍历:" << endl;
	Tree.Traverse2(Tree.root, out);
	out << endl;
	return out;
}

int main()
{
	char a='#';
	BinaryTree<char> A(a);		//默认构造函数以输入#为结束构造树
	cout << "输入”#“为构造函数结束" << endl;
	cout << "输入二叉树A:" << endl;
	cin >> A;
	char g = A.GetRoot()->data;
	cout << "根节点数据:     " << g << endl;
	int h = A.Hight();
	cout << "树高:     " << h << endl;
	int l = A.LeafCount();
	cout << "叶子节点数:       " << l << endl;
	cout << A;
	return 0;
}

 ps:

部分知识点来自百度百科。

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值