2021-01-31

本文介绍了二叉树的基本概念、性质及三种遍历方式:先序、中序、后序遍历,并提供了递归实现。此外,详细讲解了C++中的sort()函数用于数组排序的方法,包括默认从小到大排序和自定义排序规则。同时,对比了深度优先搜索(DFS)和宽度优先搜索(BFS)的区别,并通过实例展示了它们在解决实际问题中的应用。
摘要由CSDN通过智能技术生成

第三周学习总结

二叉树

一、对二叉树的理解

  • 二叉树的概念:一棵二叉树是节点的一个有限集合,该集合或者为空,或者由一个根节点加上两棵左子树和右子树组成
  • 二叉树的特点:
    1、每个节点最多有两棵子树,即二叉树不存在度大于2的节点
    2、二叉树的子树有左右之分,其子树的次序不能颠倒
  • 二叉树的性质:
    1、若规定根节点的层数为1,则一棵非空二叉树的第i层上最多有2i-1个节点
    2、若规定只有根节点的二叉树的深度为1,则深度为k的二叉树的最大节点数是2k-1
    3、对任何一棵二叉树,如果其叶子节点个数为n0,度为2的非叶子节点个数为n2,则n0=n2+1
    4、具有n个节点的完全二叉树的深度k为log2(n+1)向上取整
    5、对于具有n个节点的完全二叉树,如果按照从上至下从左至右的顺序对所有结点从0开始编号,则对于序号为i的节点有:
    (1)如果i>=0,则序号为i节点的双亲结点的序号为(i-1)/2;如果i=0,则序号i节点无双亲结点
    (2)如果2i+1<n,则序号i结点的左孩子的序号为2i+1,右孩子的序号为2i+2;如果2i+1>=n,则序号i节点无孩子节点

二、二叉树的遍历
二叉树的遍历是一个很常见的问题。二叉树的遍历方式主要有:先序遍历、中序遍历、后序遍历、层次遍历。先序、中序、后序其实指的是访问父节点的次序。在遍历过程中,若访问顺序是父节点-左孩子节点-右孩子节点,就是先序遍历;若访问顺序是左孩子节点-父节点-右孩子节点,就是中序遍历;若访问顺序是左孩子节点-右孩子节点-父节点,就是后序遍历。不论是先序遍历、中序遍历还是后序遍历,访问左右孩子节点的相对次序是不变的,总是先访问左孩子节点,再访问右孩子节点。而层次遍历,就是按照从上到下、从左到右的顺序访问二叉树的每个节点。在这里插入图片描述在这里插入图片描述

  • 先序遍历递归算法
//filename: BinTreeNode.h
template <typename T>
void travPre_R(BinTreeNode<T> * root) {//二叉树先序遍历算法(递归版)
	if (!root) return;
	cout << root->data;
	travPre_R(root->LeftChild);
	travPre_R(root->RightChild);
}
  • 中序遍历递归算法
template <typename T>
void travIn_R(BinTreeNode<T> * root) {//二叉树先序遍历算法(递归版)
   if (!root)
       return;
   travPre_R(root->LeftChild);
   cout << root->data;
   travPre_R(root->RightChild);
}
  • 后序遍历递归算法
template <typename T>
void travPost_R(BinTreeNode<T> * root) {//二叉树先序遍历算法(递归版)
	if (!root)
		return;
	travPost_R(root->LeftChild);
	travPost_R(root->RightChild);
	cout << root->data;
}

sort

sort()函数:对数组进行排序
sort()函数在algorithm头文件中,存储在std命名空间中。
sort()函数有三个参数:第一个是数组的起始地址;第二个是数组的结束地址;第三个是如何排序(从大到小或从小到大)。

  • 没有第三个参数,默认从小到大排序
#include<iostream>
#include<algorithm>
int main()
{
   int arr[10]={4,6,23,324,7854,94,34,6,655,3456};
   int i;
   for(i=0;i<10;i++)
   {
   	std::cout<<arr[i]<<"\t";
   }
   std::sort(arr,arr+10);
   std::cout<<"\n"; 
   for(i=0;i<10;i++)
   {
   	std::cout<<arr[i]<<"\t";
   }
   return 0;
}
  • 通过第三个参数来设置排序的方式
#include<iostream>
#include<algorithm>
bool com(int a,int b)
{
	return a>b;
}
int main()
{
	int arr[10]={4,6,23,324,7854,94,34,6,655,3456};
	int i;
	for(i=0;i<10;i++)
	{
		std::cout<<arr[i]<<"\t";
	}
	std::sort(arr,arr+10,com);
	std::cout<<"\n"; 
	for(i=0;i<10;i++)
	{
		std::cout<<arr[i]<<"\t";
	}
	return 0;
 } 
  • less<数据类型>()//从小到大排序 ,greater<数据类型>()//从大到小排序
#include<iostream>
#include<algorithm>
int main()
{
	int arr[10]={4,6,23,324,7854,94,34,6,655,3456};
	int i;
	for(i=0;i<10;i++)
	{
		std::cout<<arr[i]<<"\t";
	}
	//std::sort(arr,arr+10,std::less<int>());
	std::sort(arr,arr+10,std::greater<int>());
	std::cout<<"\n"; 
	for(i=0;i<10;i++)
	{
		std::cout<<arr[i]<<"\t";
	}
	return 0;
 } 

DFS与BFS

一、对DFS的理解

  • 深度优先搜索(Depth-First-Search)是搜索算法的一种。是沿着树的深度遍历树的节点,尽可能深的搜索树的分支。当节 v的所有边都己被探寻过,搜索将回溯到发现节点v的那条边的起始节点。这一过程一直进行到已发现从源节点可达的所有节点为止。如果还存在未被发现的节点,则选择其中一个作为源节点并重复以上过程,整个进程反复进行直到所有节点都被访问为止。属于盲目搜索。
  • DFS是图论里面的一种搜索算法,他可以由一个根节点出发,遍历所有的子节点,进而把图中所有的可以构成树的集合都搜索一遍,达到全局搜索的目的。所以很多问题都可以用dfs来遍历每一种情况,从而得出最优解,但由于时间复杂度太高,我们也叫做暴力搜索。
  • DFS如同数据结构中的栈结构,是属于一种后进先出的结构,比如说一个羽毛球筒,把它装满之后,我们开始使用时,拿的总是最后放进去的那一个。所以这就导致了所有的点进入栈时有一个顺序,我们称之为 :DFS序。
  • 例题
    在一个给定形状的棋盘(形状可能是不规则的)上面摆放棋子,棋子没有区别。要求摆放时任意的两个棋子不能放在棋盘中的同一行或者同一列,请编程求解对于给定形状和大小的棋盘,摆放k个棋子的所有可行的摆放方案C。
    Sample Input
    4 4
    …#
    …#.
    .#…
    #…
    Sample Output
    1
    题目要求:棋子只能放在#上并且k个棋子必须在不同行不同列,所以说这里 进行了状态的限制,我们如果用BFS做肯定不太好做,但是我们刚好可以运用DFS的回溯特点做这个题目;
    因为这个题目是二维的题目我们无法判断 该行该列到底有没有放棋子,我们只可以判断我们当前到的这一行放棋子了没有,于是我们在外面加一个数组VIS,它标记着第i列有没有放棋子,如果第i列放了棋子,那么我们就令vis[i]==true。然后我们DFS他的每一行,在其间遍历他的每一列具体可能说不太清楚,我把代码和注释附上:
bool vis[50];
int n,k;
char mp[50][50];//标记每一列
ll cnt=0;
void dfs(int x,int way)//用way记录我们放了多少棋子
{
    if(way==k)
    {
        cnt++;//cnt记录方案数
        return;//一定记得要return
    }
    if(x>=n) return;//这是判界 因为我们按行遍历,一共有n行不能多出去
    for(int i=0;i<n;i++)//判断这一行的每一列
    {
        if(mp[x][i]=='#'&&!vis[i])//如果说这mp[x][i]刚好是#而且 第i列没有放棋子 
        {
            vis[i]=1;//我们就放上
            dfs(x+1,way+1);//在下一行放,这一行已经无法放了,不同行不同列
            vis[i]=0;//这个地方比较关键,回溯的重点
        }
    }
    dfs(x+1,way);//这一行找不到的话就直接进行下一行
}
int main()
{
    while(~scanf("%d%d",&n,&k))
    {
        if(n==-1&&k==-1) break;
        cnt=0;
        memset(mp,0,sizeof(mp));
        for(int i=0;i<n;i++)
            scanf("%s",mp[i]);
        dfs(0,0);
        printf("%d\n",cnt);
    }
    return 0;
}

二、BFS的理解

  • 与DFS相对的那就是BFS了,BFS称为宽度优先搜索也叫做广度优先搜索,他是按层遍历每一种状态的下一种状态。
  • 例题
    求迷宫最短路
    在这里插入图片描述
int bfs()
{
	queue<node>q;
	q.push({1,1});
	num[1][1]=0;
	while(!q.empty)
	{
		node u=q.front();q.pop();//扔掉首元素
		for(int i=0;i<4;i++)
		{
			int mx=u.x+dx[i],my=u.y+dy[i];
			if(u.x==ex&&u.y==ey) return num[u.x][u.y];//放队列之前我们已经把距离更新了,只要找到这个点绝对是最小距离了。
			if(num[mx][my]==-1&&str[mx][my]==0)
			{
				num[mx][my]=num[u.x][u.y]+1;
				q.push({mx,my});
			}
		}
	}
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值