二叉树链式描述和二叉排序树实现(C++类模板)

二叉树链式描述和二叉排序树实现

二叉树链式描述

二叉树链式描述可以根据定义指针域数量的不同分为二叉链表表示和三叉链表表示。
1.二叉链表表示
每个结点包括数据域和指针域,指针域分别为leftchild指向左孩子和rightchild指向右孩子,也就意味着双亲结点有指向孩子结点的指针,但是孩子结点不包含指向双亲结点的指针。数据域用以存放结点中元素值。
二叉链表表示在这里插入图片描述
2.三叉链表表示
每个结点的指针域分别为leftchild指向左孩子和rightchild指向右孩子和parent指向双亲结点,也就意味着双亲结点有指向孩子结点的指针,孩子结点也包含指向双亲结点的指针。根节点没有双亲结点。所以它的parent指针为空(NULL)。
在这里插入图片描述

二叉链表实现

方法主要包括
1.简单构造函数(有参、无参)

2.判断二叉树是否为空
思路:初始根结点如果为空,则二叉树为空。

3.按照指定元素创建根结点
思路:先判断根结点是否为空,为空则直接将指定元素值赋值给根结点的数据域,否则new一个新节结点,并以指定元素作为该结点的数据域。

4.获取根结点

5.将一个结点作为指定节点的左、右孩子插入二叉树
思路:首先定义局部指针变量,创建新结点,将将指定节点指向左孩子(右孩子)的指针指向新节点。

6.修改、获取指定结点的元素值

7.获取指定节点的左、右孩子

8.递归中序、先序、后序遍历二叉树
思路:先序:根左右;中序:左根右;后序:左右根。

9.逐层遍历
思路:先从根结点开始(从第一层开始遍历),同一层中,自左向右遍历。通常采用队列实现遍历算法。首先将根结点插入队列,接着循环遍历,当队列不为空时,先将队首元素出队,访问其元素数据,紧接着判断是否存在左孩子,若存在,将左孩子结点插入队列;然后判断是否存在右孩子,若存在,将右孩子结点插入队列。以此循环,直到队列为空停止遍历。

10.非递归遍历(待续)

11.按非递归方式获取指定结点的双亲结点
思路:首先将根结点插入队列,接着循环遍历,当队列不空时,将队首结点出队作为当前指定结点,如果当前结点的左孩子或右孩子等于指定结点,则返回该结点,即为该指定结点的双亲结点。否则继续向下层寻找当前节点的左孩子、右孩子,直至队列为空。

12.删除以指定结点为根的子树
思路:首先定义一个结点指针并置空(用来存储双亲结点),判断指定结点是否为根结点,若为根结点,直接置空(实现逻辑上删除子树),如果指定结点不为根结点,则需要寻找指定结点的双亲结点,接着删除其左子树或右子树。若要在物理上真正实现删除子树,还需将结点内存进行释放。

13.按关键字查找结点
思路:根据指定元素进行查找,将根结点插入队列,利用循环方式查找,将队首元素出队,判断该元素是否与指定关键字相等,若相等,返回该结点。如果该结点有左孩子或右孩子,将左孩子、右孩子插入队列继续循环,直到队列为空完成查找。

14.将元素插入二叉排序树

二叉排序树定义:

根节点的值大于其左子树中任意一个节点的值,小于其右节点中任意一节点的值,这一规则适用于二叉查找树中的每一个节点。在这里插入图片描述
思路:首先判断二叉排序树是否为空,为空则以指定元素创建根结点;若不为空,则先获取根结点及根结点元素,如果指定元素等于根结点元素,意味着该元素已经存在于树中(假定树中不能有重复元素),如果该元素值小于根结点元素值,(则需要将该元素插入进该根结点的左子树中),当然如果左子树存在,意味着没办法继续插入新元素,这时候需要继续寻找新的位置;若大于,插入进右子树中(同左子树情形)。

15.生成二叉排序树
思路:将数组中的元素依次插入到二叉排序树中,调用14方法。

16.递归方式实现查找二叉排序树
思路:先获取给定结点的元素值并赋值给X,将给定元素值K与X后进行比较,若K=X,则查找成功;若K<X,则在给定结点的左子树中继续寻找(利用递归调用进行),若K>X,则在给定结点的左子树中继续寻找,直到结束。

代码

bintree.h

#include<string>
#include"linkqueue.h"
using namespace std;

template < class T >
class linkednode
{
	template <class T>
	friend class linkedbintree;
public:
	//无参构造
	linkednode()
	{
		m_pleftchild = m_prightchild = NULL;
	}
	//有参   
	linkednode(const T&x)
	{
		m_pleftchild = m_prightchild = NULL;
		m_data = x;
	}
private:
	T m_data;
	linkednode<T>*m_pleftchild, *m_prightchild;

};
template<class T>
class linkedbintree
{
public:
	linkedbintree();
	~linkedbintree();
	bool isempty();
	linkednode<T>*creatroot(const T&x);
	void clear();
	linkednode<T>*getroot();
	//将一个节点作为指定节点的左孩子插入
	linkednode<T>*insertleftchild(linkednode<T>*pnode, const T&x);
	//将一个节点作为指定节点的右孩子插入
	linkednode<T>*insertrightchild(linkednode<T>*pnode, const T&x);
	//修改指定节点的元素值
	bool modifynodevalue(linkednode<T>*pnode, const T&x);
	//获取指定节点的元素值
	bool getnodevalue(linkednode<T>*pnode,  T&x);
	linkednode<T>*getrightchild(linkednode<T>*pnode);
	linkednode<T>*getleftchild(linkednode<T>*pnode);

	//递归先序遍历
	void preorder(linkednode<T>*pnode);
	//中序
	void inorder(linkednode<T>*pnode);
	//后序
	void postorder(linkednode<T>*pnode);

	//非递归先序
	void preorder();
	//中序
	void inorder();
	//后序
	void postorder();

	//逐层遍历
	void levelorder();

	//按非递归方式获取指定节点的双亲结点
	linkednode<T>*getparent(linkednode<T>*pnode);
	//删除以指定节点为根的子树
	void deletetree(linkednode<T>*pnode);
	//由deletetree函数调用删除以指定节点为根的子树
	void deletetreenode(linkednode<T>*pnode);
	//按关键字查找节点
	linkednode<T>*searchbykey(const T &x);

	//将元素插入二叉排序树
	void insertBST(linkedbintree<T>&btree, T K);
	//生成二叉排序树
	void creatBST(T R[], int size, linkedbintree<T>&btree);
	//递归方式实现查找二叉排序树
	linkednode<T>*searchBST(linkednode<T>*proot, T K);
private:
	linkednode<T>*m_proot;
};

顺便提供队列链表描述代码:
linkqueue.h

#include<string>
#include<iostream>
using namespace std;

template < class T >
class linknode
{
template<class T>
friend class linkqueue;
public:
	linknode()
	{
		next = NULL;
	}
private:
	T data;
	linknode<T>* next;
};
template < class T >
class linkqueue
{
public:
	linkqueue();
	~linkqueue();
	bool isempty();
	bool isfull();
	bool insert(const T & x);
	bool getelement(T & x);
	bool Delete(T &x);
	void output(ostream &out)const;
private:
	int  size;
	linknode<T>*front, *back;
};
//构造函数
template <class T>
linkqueue<T>::linkqueue()
{
	front = NULL;
	back = NULL;
	size = 0;
}
//析构函数
template <class T>
linkqueue<T>::~linkqueue()
{
	T x;
	while (front != NULL)//当队列不为空时 删除队首元素
		Delete(x);
}
//判断队列是否为空  为空则返回大小为0
template <class T>
bool linkqueue<T>::isempty()
{
	return size == 0;
}
//插入元素   队尾插入
template <class T>
bool linkqueue<T>::insert(const T&x)
{
	//new出新的节点 用P接收
	linknode<T>*p = new  linknode < T > ;
	//如果p为空,返回错误
	if (p == NULL)
	{
		return false;
	}
	//如果不为空 
	else
	{
		//向p中插入数据
		p->data = x;
		//判断当前队列是否为空,为空则插入元素既是队尾又是队首
		if (front == NULL)
		{
			back = p;
			front = p;
		}
		//当前不为空,  队尾更新为p
		else
		{
			back->next = p;
			back = p;
		}
		size++;
		return true;
	}
}
//获取元素
template <class T>
bool linkqueue<T>::getelement(T&x)
{
	if (isempty())
	{
		return false;
	}
	else
	{
		//首部的值赋给X
		x = front->data;
		return true;
	}
}
//删除元素
template<class  T>
bool linkqueue<T>::Delete(T &x)
{
	//创建节点p 
	linknode<T>*p;
	if (isempty())
	{
		return false;
	}
	else
	{   //p指向front  front值赋给x  front指向下一节点
		p = front;
		x = front->data;
		front = front->next;
		delete(p);
		size--;
		return true;
	}
}
//输出队列
template<class  T>
void linkqueue<T>::output(ostream &out)const
{
	linknode<T>*p;
	p = front;
	for (int i = 0; i < size; i++)
	{
		cout << p->data << endl;
		p=p->next;
	}
}
//重载运算符
template<class T>
ostream &operator<<(ostream& out, const linkqueue<T>&x)
{
	x.output(out);
	return out;
};

测试:
bintree.cpp

#include<iostream>
#include"bintree.h"
using namespace std;



template <class T>
linkedbintree<T>::linkedbintree()
{
	m_proot = NULL;
}

template <class T>
linkednode<T>*linkedbintree<T>::creatroot(const T&x)
{
	if (m_proot != NULL)
	{
		m_proot->m_data = x;
	}
	else
	{
		m_proot = new linkednode<T>(x);
	}
	return m_proot;
}
template <class T>
bool linkedbintree<T>::isempty()
{
	if (m_proot == NULL)
	{
		return true;
	}
	return false;
}
template <class T>
linkednode<T>*linkedbintree<T>::getroot()
{
	return m_proot;
}
//将一个节点作为指定节点的左孩子插入
template <class T>
linkednode<T>*linkedbintree<T>::insertleftchild(linkednode<T>*pnode, const T&x)
{
	//局部指针  
	linkednode<T> *pnewnode;
	//参数1为空 没有节点
	if (pnode == NULL)
	{
		return NULL;
	}
	// 创建新节点,参数x作为新节点的data域
	pnewnode = new linkednode<T>(x);
	// 节点为空。。。创建失败
	if (pnewnode == NULL)
	{
		return NULL;
	}
	//将指定节点指向左孩子的指针 指向新节点
	pnode->m_pleftchild = pnewnode;
	return pnewnode;
}
//将一个节点作为指定节点的右孩子插入
template <class T>
linkednode<T>*linkedbintree<T>::insertrightchild(linkednode<T>*pnode, const T&x)
{
	//局部指针  
	linkednode<T> *pnewnode;
	//参数1为空 没有节点
	if (pnode == NULL)
	{
		return NULL;
	}
	// 创建新节点,参数x作为新节点的data域
	pnewnode = new linkednode<T>(x);
	// 节点为空。。。创建失败
	if (pnewnode == NULL)
	{
		return NULL;
	}
	//新节点指向左孩子的指针 指向新节点
	pnode->m_prightchild = pnewnode;
	return pnewnode;
}
//修改指定节点的元素值
template <class T>
bool linkedbintree<T>::modifynodevalue(linkednode<T>*pnode, const T&x)
{
	if (pnode == NULL)
	{
		return false;
	}
	pnode->m_data = x;
	return true;
}
//获取指定节点的元素值
template <class T>
bool linkedbintree<T>::getnodevalue(linkednode<T>*pnode, T&x)
{
	if (pnode == NULL)
	{
		return false;
	}
	x = pnode->m_data;
	return true;
}
//获取指定节点的左孩子节点
template <class T>
linkednode<T>*linkedbintree<T>::getleftchild(linkednode<T>*pnode)
{
	if (pnode == NULL)
	{
		return NULL;
	}
	return pnode->m_pleftchild;
}
//获取指定节点的右孩子节点
template <class T>
linkednode<T>*linkedbintree<T>::getrightchild(linkednode<T>*pnode)
{
	if (pnode == NULL)
	{
		return NULL;
	}
	return pnode->m_prightchild;
}


//递归先序遍历
template <class T>
void linkedbintree<T>::preorder(linkednode<T>*pnode)
{
	if (pnode == NULL)
	{
		return;
	}
	cout << pnode->m_data << " ";
	preorder(pnode->m_pleftchild);
	preorder(pnode->m_prightchild);

}
//递归中序遍历
template <class T>
void linkedbintree<T>::inorder(linkednode<T>*pnode)
{
	if (pnode == NULL)
	{
		return;
	}
	inorder(pnode->m_pleftchild);
	cout << pnode->m_data << " ";
	inorder(pnode->m_prightchild);
}
//递归后序遍历
template <class T>
void linkedbintree<T>::postorder(linkednode<T>*pnode)
{
	if (pnode == NULL)
	{
		return;
	}
	postorder(pnode->m_pleftchild);
	postorder(pnode->m_prightchild);
	cout << pnode->m_data << " ";
}
//逐层遍历
template <class T>
void linkedbintree<T>::levelorder()
{
	//q为linkqueue类型的队列   存放linkednode类型的指针
	linkqueue<linkednode <T>*>q;
	linkednode<T>*pnode = NULL;
	if (m_proot == NULL)
	{
		return;
	}
	//将根节点插入进队列
	q.insert(m_proot);
	//如果队列不为空
	while (!q.isempty())
	{
		//将元素从队首出队
		q.Delete(pnode);
		//访问元素数据
		cout << pnode->m_data << " ";
		//如果存在左孩子,则将左孩子节点插入队列
		if (pnode->m_pleftchild)
		{
			q.insert(pnode->m_pleftchild);
		}
		//如果存在右孩子,则将右孩子节点插入队列
		if (pnode->m_prightchild)
		{
			q.insert(pnode->m_prightchild);
		}
	}
}
//按非递归方式获取指定节点的双亲结点
template<class T>
linkednode<T>*linkedbintree<T>::getparent(linkednode<T>*pnode)
{
	linkqueue<linkednode <T>*>q;
	linkednode<T>*pcurnode = NULL;
	if (pnode == m_proot)
	{
		return NULL;
	}
	if (m_proot == NULL)
	{
		return NULL;
	}
	//将根节点放入队列中去
	q.insert(m_proot);
	//如果队列不为空
	while (!q.isempty())
	{
		//将队首节点取出来给pcurnode
		q.Delete(pcurnode);
		//如果当前节点的左孩子或者右孩子等于指定节点   则返回该节点  即为指定节点的双亲节点
		if (pcurnode->m_pleftchild == pnode || pcurnode->m_prightchild == pnode)
		{
			return pcurnode;
		}
		if (pcurnode->m_pleftchild)
		{
			q.insert(pcurnode->m_pleftchild);
		}
		if (pcurnode->m_prightchild)
		{
			q.insert(pcurnode->m_prightchild);
		}
	}
	return NULL;
}
//删除以指定节点为根的子树
template<class T>
void linkedbintree<T>::deletetree(linkednode<T>*pnode)
{
	//定义一个节点为双亲节点  置为空
	linkednode<T>*pparentnode = NULL;
	//如果指定节点为空节点  则不返回
	if (pnode == NULL)
	{
		return;
	}
	//如果根节点为指定节点  则将指定节点(根节点)置空
	if (m_proot == pnode)
	{
		m_proot == NULL;
	}
	//找到指定节点的双亲结点赋值给新节点   如果不为空 即找到了双亲结点  则删除其左孩子或者右孩子
	else if ((pparentnode = getparent(pnode)) != NULL)
	{
		if (pparentnode->m_pleftchild == pnode)
		{
			pparentnode->m_pleftchild == NULL;
		}
		if (pparentnode->m_prightchild == pnode)
		{
			pparentnode->m_prightchild == NULL;
		}
	}
	else
		return;
	deletetreenode(pnode);
}

//由deletetree函数调用删除以指定节点为根的子树
template<class T>
void linkedbintree<T>::deletetreenode(linkednode<T>*pnode)
{
	linkqueue<linkednode <T>*>q;
	linkednode<T>*pcurnode = NULL;
	if (pnode == NULL)
	{
		return;
	}
	q.insert(pnode);
	while (!q.isempty())
	{
		//将队首节点取出来给pcurnode
		q.Delete(pcurnode);
		if (pcurnode->m_pleftchild)
		{
			q.insert(pcurnode->m_pleftchild);
		}
		if (pcurnode->m_prightchild)
		{
			q.insert(pcurnode->m_prightchild);
		}
		delete pcurnode;
	}
}
//按关键字查找节点
template<class T>
linkednode<T>*linkedbintree<T>::searchbykey(const T &x)
{
	linkqueue<linkednode <T>*>q;
	linkednode<T>*pmatchnode = NULL;
	if (m_proot == NULL)
	{
		return NULL;
	}
	//将根节点插入队列
	q.insert(m_proot);
	while (!q.isempty())
	{
		//将队首节点取出来
		q.Delete(pmatchnode);
		if (pmatchnode->m_data == x)
		{
			return pmatchnode;
		}
		if (pmatchnode->m_pleftchild)
		{
			q.insert(pmatchnode->m_pleftchild);
		}
		if (pmatchnode->m_prightchild)
		{
			q.insert(pmatchnode->m_prightchild);
		}
	}
	return NULL;
}
//清除二叉树
template<class T>
void linkedbintree<T>::clear()
{
	deletetree(m_proot);
}
//析构函数
template<class T>
linkedbintree<T>::~linkedbintree()
{
	clear();
}
//插入二叉排序树
template<class T>
void insertBST(linkedbintree<T>&btree, T K)
{
	//创建新节点
	linkednode <T>*pnode = NULL, *pchild = NULL;
	T x;
	//如果树为空 则直接以节点元素K创建根节点
	if (btree.isempty())
	{
		btree.creatroot(K);
	}
	//如果树不为空,则先获取根节点
	pnode = btree.getroot();
	//当根节点不为空

	while (pnode)
	{
		//获取根节点的数值
		btree.getnodevalue(pnode, x);
		//如果K=根节点数值  则K已经是树中的节点
		if (K == x)
		   return;
		//如果K<x  则将K插入到该节点的左子树中
		if (K < x)
		{
			//如果左子树存在,则继续寻找新的位置
			if ((pchild = btree.getleftchild(pnode)) != NULL)
			{
				pnode = pchild;
			}
			else
				//如果左子树不存在,则将新元素K作为根节点的左孩子插入
			{
				btree.insertleftchild(pnode, K);
				return;
			}
		}
		//如果K>x  则将K插入到该节点的右子树中
		else
		{   //如果右子树存在,则继续寻找新的位置
			if ((pchild = btree.getrightchild(pnode)) != NULL)
			{
				pnode = pchild;
			}
			else
				//如果右子树不存在,则将新元素K作为根节点的右孩子插入
			{
				btree.insertrightchild(pnode, K);
				return;
			}
		}
	}
}

//生成二叉排序树
template<class T>
void creatBST(T R[], int size, linkedbintree<T>&btree)
{
	//将数组中的元素依次插入到二叉排序树中

	for (int i = 0; i <= size; i++)
	{
		insertBST(btree, R[i]);
	}
}
//递归方式实现查找二叉排序树
template<class T>
linkednode<T>*searchBST(linkednode<T>*proot, T K)
{
	//定义二叉树对象
	linkedbintree<T>btree;
	T x;
	//如果子树为空,则查找失败
	if (proot == NULL)
	{
		return NULL;
	}
	//获取给定节点的元素值
	btree.getnodevalue(proot, x);
	//如果K=x  查找成功
	if (K == x)
		return proot;
	//如果K<x  在左子树中进行查找(递归调用)
	else if (K < x)
		return searchBST(btree.getleftchild(proot), K);
	//如果K>x  在右子树中进行查找(递归调用)
	else
		return searchBST(btree.getrightchild(proot), K);
}
int main()
{
	int treedata[] = { 12, 23, 56, 24, 13, 85, 25, 16, 14 };
	int size = sizeof(treedata) / sizeof(treedata[0]);
	int K = 56, X = 25;
	linkedbintree<int> btree;
	creatBST(treedata, size, btree);
	linkednode<int>*node = btree.searchbykey(12);
	cout << "中序遍历:";
	btree.inorder(node);
	cout << endl;
	cout << "后序遍历:";
	btree.postorder(node);
	cout << endl;
	
	linkednode<int>*node1 = btree.searchbykey(K);
	btree.modifynodevalue(node1, 55);
	cout << "修改后中序遍历" << endl;
	btree.inorder(node);
	cout << endl;
	//根据给定元素K进行二叉排序树的查找,用pnode指向匹配元素所在节点
	linkednode<int>*pnode;
	pnode = searchBST(btree.getroot(), K);
	//如果pnode不为空  则查找成功
	if (pnode != NULL)
	{
		//获取匹配元素的值并输出
		btree.getnodevalue(pnode, X);
		cout << "已找到该元素:" << X << endl;
	}
	else
		cout << "没有找到该元素。" << endl;
	system("pause");
	return 0;
;

输出结果:
在这里插入图片描述
这里出现了一串未知数字,找了半天错误,没解决,应该是逻辑漏洞。。。。

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值