挑战30天C++基本入门(DAY7--树)[part 2](速通哦~)

#昨天我们把树的基础知识部分给讲完啦,那我们今天趁热打铁,直接我们来手搓树的代码部分,这里我会让每个人都懂得哟!!

这里我们紧接着昨天的二叉查找树来继续说明。

二叉查找树的创建

我们昨天学习可以知道,二叉查找树的定义是:左子树小于根节点小于右子树。也是有一定顺序的排列的二叉树。

结点的建立:

我们要知道,一个树的最小元素为结点:包括了左孩子,右孩子,根节点,那我们应该怎么表示他们呢?

用结构体,这样就可以实现三者的联动,代码部分如下:

struct treenode{
	int data;
	treenode* lchild;
	treenode* rchild;
	treenode(int v){
		data=v,lchild=NULL,rchild=NULL;
	}
};

PS:在这个结构体中,下面的treenode(int v)这一部分用于树的初始化,可以不在结构体中添加,在下面的循环中添加也是可以的。我就直接在这里添加了,方便说明,也便于记忆。

树的建立:

写完结点的结构之后,我们就要思考,每一个结点的开辟都要空间,所以我们应该每一次新建一个结点就要new开辟一个新的空间。

我们首先应该把这棵树的第一个元素当作根节点存储起来,同时开辟一个空间。如下:

void build(vector<int> a)
{
	treenode* root=new treenode(a[0]);

这样我们的第一个根节点就算是储存下去了,之后我们要做的就是构建二叉查找树。

我们再次回忆一下定义:左子树小于根节点,根节点小于右子树。

这样我们的逻辑不就出来了嘛?

我们在for循环中,逐个比较各个元素和根节点的大小,如果比根节点大,那我们就排在右边,同时,如果右边已经存在了右子树,我们应该继续和右子树比较,如果比他大,同时没有了子节点,我们就可以把这个元素存进去右子树的右孩子这个位置。左子树同理。

逻辑就是:1.先和根节点比较大小  2.判断左子树(右子树)是否为空  3.若为空就储存进去  4.若不为空则重复前三个步骤。

那我们的代码部分也就出来啦,代码如下:

for(int i=1;i<a.size();i++)
	{
		treenode* tmp=new treenode(a[i]);
		treenode* troot=root;
		while(troot){
			if(tmp->data<troot->data){
				if(troot->lchild==NULL)
				{
					troot->lchild=tmp;
					break;
				}
				else troot=troot->lchild;
			}
			else if(tmp->data>troot->data){
				if(troot->rchild==NULL)
				{
					troot->rchild=tmp;
					break;
				}
				else troot=troot->rchild;
			}
		}
	}

之后我们结合上面两个步骤,我们就可以得到了我们搜索二叉树的创立过程啦:

代码如下,要多思考,同时这个模板也要多打,多记:

#include<bits/stdc++.h>
#include<vector>
using namespace std;
struct treenode{
	int data;
	treenode* lchild;
	treenode* rchild;
	treenode(int v){
		data=v,lchild=NULL,rchild=NULL;
	}
};
void build(vector<int> a)
{
	treenode* root=new treenode(a[0]);
	for(int i=1;i<a.size();i++)
	{
		treenode* tmp=new treenode(a[i]);
		treenode* troot=root;
		while(troot){
			if(tmp->data<troot->data){
				if(troot->lchild==NULL)
				{
					troot->lchild=tmp;
					break;
				}
				else troot=troot->lchild;
			}
			else if(tmp->data>troot->data){
				if(troot->rchild==NULL)
				{
					troot->rchild=tmp;
					break;
				}
				else troot=troot->rchild;
			}
		}
	}
	return root; 
}

int main()
{
	vector<int> a{1,2,3,4,5,6,7,8,9};
	treenode* root=build(a);
	return 0;
}

前中后序遍历:

那我们现在已经得到了我们的搜索二叉树。那我们如何实现我们的前中后序遍历呢?不遍历的话我们就无法将这个树给表示出来,那我们应该怎么遍历呢???

其实很好想,我们大概猜一下也就知道,我们应该用递归的思想,是吧?这样的话我们的代码会比较简洁,同时也很高效,就是不是很好想0.0🤔,其实也还好。

我们首先要判断根节点是否为空?如果为空,那我们直接结束递归,根节点为空,说明树不存在,我们也没有讨论的必要了。之后如果是中序遍历,那我们就首先返回左子树,输出根节点,在递归右子树不就实现中序遍历了吗?

代码如下:

void zhong(treenode* root)
{
	if(root==NULL)return ;
	zhong(root->lchild);
	cout<<root->data;
	zhong(root->rchild);
	
}

层次遍历:

我们用前中后序遍历并不能很好地反映出我们树的结构,而我们如果可以一层一层的输出树的结构,这样不就很清晰明了了嘛?这就要请到我们的层次遍历大将军出场啦。

我们首先要想层次遍历的逻辑,怎么实现层次遍历?

层次遍历:一层一层的输出,像极了一个队列,我们首先进去第一层,然后第一层再出来,第二层再进去,第二层再出去。是不是先进先出??那我们就可以用队列来模拟这个过程。

1.队列应该先把根节点导入进去,我们判断队列结束的条件就是队列是否为空

2.创立临时变量等于队列的最前面的元素,之后弹出这个元素,输出这个元素所对应的数值

3.判断这个元素的左右子树是否为空,如果不为空我们就push进去,这样就相当于把下一层给导入了进去。

那我们的代码部分就出来啦:

void layersearch(treenode* root)
{
	queue<treenode*>q;
	q.push(root);
while(!q.empty())
	{
		treenode* tmp=q.front();
		cout<<tmp->data;
		q.pop();
		if(tmp->lchild!=NULL)
		{
			q.push(tmp->lchild);
			nlast=tmp->lchild;
		}
		if(tmp->rchild!=NULL)
		{
			q.push(tmp->rchild);
			nlast=tmp->rchild;
		}
	}
		
	}
}

这样输出的话是一列数字,如果我们想要实现换行操作呢???

我们应该在代码里面怎么判断换行操作呢??

我们因该判断当我们的临时变量等于了我们的根节点,我们就换行。

这样说的是不是很不好理解?我们拿我们最早的根节点来说明,第一行就一个元素,是不是要求我们的临时变量等于我们的根节点,我们就换行?

后面也好理解,因为我们的根节点一直在变化,不断的赋值给临时变量,这就很好理解啦,同时我们也可用这种办法求出我们的树高。

代码如下啦:

void layersearch(treenode* root)
{
	queue<treenode*>q;
	q.push(root);
	treenode* last=root;
	treenode* nlask=NULL;
	while(!q.empty())
	{
		treenode* tmp=q.front();
		cout<<tmp->data;
		q.pop();
		if(tmp->lchild!=NULL)
		{
			q.push(tmp->lchild);
			nlast=tmp->lchild;
		}
		if(tmp->rchild!=NULL)
		{
			q.push(tmp->rchild);
			nlast=tmp->rchild;
		}
		if(tmp==last){
			cout<<endl;
			h++;
			last=nlast;
			
		}
		
	}
}

//以上就是我们搜索二叉树的相关知识啦,当然如果我们求树高,并不用这种麻烦的方法,在最后一张的知识体系中,我会教大家用递归的办法来求树高,这样的话会十分节约我们的时间,不用打那么多的代码,同时也简洁美观。还有一些零碎的知识点,我都会在后面的章节里面给大家写到哦。
 

如果文章对大家有帮助,希望大家多给点关注啦,码字不易,求点赞关注啦~~~~~~

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值