第三周


一、树和二叉树。

树的基本概念

树(Tree)是由一个或多个结点组成的有限集合T,其中有一个特定的称为根的结点;其余结点可分为m(m≥0)个互不相交的有限集T1,T2,T3 ,…,Tm,每一个集合本身又是一棵树,且称为根的子树。
结点(Node):树中的元素,包含数据项及若干指向其子树的分支。
结点的度(Degree):所有结点当中,子树分支最最多的就是树的度
结点的层次:从根结点开始算起,根为第一层,
叶子(Leaf):度为零的结点,也称端结点。
孩子(Child):结点子树的根称为该结点的孩子结点。
双亲(Parent):孩子结点的上层结点,称为这些结点的双亲。
兄弟(Sibling):同一双亲的孩子。
深度(Depth): 树中结点的最大层次数
森林(Forest):互不相交的树的集合

一般树与二叉树的区别

1.树的结点个数至少为1,而二叉树的结点个数可以为0;
2.树的结点最大度数没有限制,而二叉树结点的最大度数为2;
3.树的结点无左、右之分,而二叉树的结点有左、右之分。

二叉树的遍历

在这里插入图片描述

先序遍历

访问根结点
访问左子树的左子树,再访问左子树中的右子树
访问右子树的左子树,再访问右子树中的右子树
任意子树输出顺序为:父结点——左子结点——右子结点
如上图先序遍历顺序为:A-B-D-H-I-E-J-C-F-K-G

中序遍历

先访问左子树中的左子树,再访问左子树中的右子树
访问根结点。
后访问右子树中的左子树,再访问右子树中的右子树
任意子树输出顺序为:左子结点——父结点——右子结点
如上图中序遍历顺序为:H-D-I-B-E-J-A-F-K-C-G

后序遍历

先访问左子树中的左子树,再访问左子树中的右子树
再访问右子树中的左子树,再访问右子树中的右子树
访问根结点
任意子树输出顺序为:左子结点——右子结点——父结点
如上图后序遍历顺序为:H-I-D-J-E-B-K-F-G-C-A

二、递归

含义:函数调用本身( 自己调用自己)
1.构成递归的条件:①能将一个问题转换成一个更小的问题,且新问题与原问题解法相同②必须有递归出口( 否则会造成死循环)
2.递归函数的底层是由栈实现的,是系统帮我们写好的,可以直接使用
3.递归 = 递推 + 回溯

斐波那契数列

斐波那契数列的是这样一个数列:1、1、2、3、5、8、13、21、34…,即第一项 f(1) = 1,第二项 f(2) = 1…,第 n 项目为 f(n) = f(n-1) + f(n-2)。求第 n 项的值是多少。

#include<iostream>
#include<cstdio>

using namespace std;
int f(int n){
    // 1.先写递归结束条件
    if(n <= 2){
        return 1;
    }
    // 2.接着写等价关系式
    return f(n-1) + f(n - 2);
}
int main()
{
	int n;
	cin>>n;
	cout<<f(n);
	return 0; 
}


三,快速排序,归并排序

快速排序

快速排序基本思想:

1、先从数列中取出一个数作为基准数。

2、分区过程,将比这个数大的数全放到它的右边,小于或等于它的数全放到它的左边。

3、再对左右区间(重新选择中心元素)重复第二步,直到各区间只有一个数。
模板

void quick_sort(int q[], int l, int r)
{
    if (l >= r) return;

    int i = l - 1, j = r + 1, x = q[l + r >> 1];
    while (i < j)
    {
        do i ++ ; while (q[i] < x);
        do j -- ; while (q[j] > x);
        if (i < j) swap(q[i], q[j]);
    }
    quick_sort(q, l, j), quick_sort(q, j + 1, r);
}

使用sort,首先头文件:
#include< algorithm>
形式:sort(first_pointer,first_pointer+n,cmp)
有三个参数,第一个参数是写数组的首地址【一般写数组名即可】;第二个参数写首地址+数组长度n;第三个参数写比较函数的名称【自定义函数cmp】。
如果第三个参数不写,则sort默认按数组升序排序。【eg:将数组a的0~n-1个元素按升序排序——sort(a,a+n);】
如果要写降序排列要写一个比较函数:
模板:

#include<iostream>
#include<algorithm>
using namespace std;
const int N = 10010;
int a[N],n;
bool cmp(int a,int b)//int为数组数据类型
{
return a>b;//降序排列
}
int main()
{
	cin>>n;
	for(int i=0;i<n;i++)
	{
		cin>>a[i];
	}
	sort(a,a+n,cmp);
	for(int i=0;i<n;i++)
	{
		cout<<a[i]<<" ";
	}
	return 0;
}

归并排序

基本概念:将已有序的子序列合并,得到完全有序的序列;即先使每个子序列有序,再使子序列段间有序。若将两个有序表合并成一个有序表,称为二路归并。归并排序是一种稳定的排序方法。
模板**

void merge_sort(int q[], int l, int r)
{
    if (l >= r) return;

    int mid = l + r >> 1;
    merge_sort(q, l, mid);
    merge_sort(q, mid + 1, r);

    int k = 0, i = l, j = mid + 1;
    while (i <= mid && j <= r)
        if (q[i] <= q[j]) tmp[k ++ ] = q[i ++ ];
        else tmp[k ++ ] = q[j ++ ];

    while (i <= mid) tmp[k ++ ] = q[i ++ ];
    while (j <= r) tmp[k ++ ] = q[j ++ ];

    for (i = l, j = 0; i <= r; i ++, j ++ ) q[i] = tmp[j];
}

二、bfs和dfs

1,DFS(深度优先搜素算法)

1、基本概念
深度优先搜索算法(depth first search, 简称dfs) 是一种用于遍历或搜索树或图的算法。沿着数的深度遍历树的节点,尽可能深的搜索树的分支。当节点v所在边都已被探寻或者在搜索时节点不满足条件, 搜索将回溯到发现节点v的那条边的起始节点。整个进程反复进行直到所有满足条件的所有节点被访问为止。

2、算法思路
深度优先遍历图的方法是,从图中某顶点v出发:
(1)访问顶点v;

(2)依次从v的未被访问的邻接节点出发,对图进行深度优先遍历,直至途中和v有路径相通的顶点都被访问;

(3)若此图中尚有顶点未被访问,则从一个未被访问的顶点出发,重新进行深度优先遍历,直至图中所有顶点均被访问为止。
思想:一直往深处走,直到找到解或者走不下去为止
在这里插入图片描述

2、BFS(广/宽度优先遍历)

1、基本概念
已知图G=(V, E)和一个源顶点s,宽度优先搜索以一种系统的方式探寻G的边,从而“发现”s所能到达的所有顶点,并计算s到所有这些顶点的距离(最少边数),该算法同时能生成一棵根为s且包括所有可达顶点的宽度优先树。对从s可达的任意顶点v,宽度优先树中从s到v的路径对应于图G中从s到v的最短路径,即包含最小边数的路径。

2、算法思路
之所以称之为宽度优先算法,是因为算法自始至终一直通过已找到和未找到顶点之间的边界向外扩展,就是说,算法首先搜索和s距离为k的所有顶点,然后再去搜索和S距离为k+l的其他顶点。
在这里插入图片描述
列题
在这里插入图片描述
BFS

#include<iostream>
#include<queue>
#include<cstring> //string.h
using namespace std;

typedef pair<int,int> PII;

int dx[4] = {-1,0,1,0},dy[4] = {0,1,0,-1};

const int N = 25;
char g[N][N]; //存图的
int st[N][N]; //标记这个点有没有被搜过
int n,m; //n行m列
int res;

void bfs(int x,int y)
{
    queue<PII> q; 
    q.push({x,y});
    
    while(q.size() > 0) //队列不空 
    {
        PII t = q.front(); //取出队头
        q.pop();//出队
        
        for(int i=0; i<4; i++) //遍历四个方向
        {
            int a = t.first + dx[i], b = t.second + dy[i]; //队头邻接点的坐标
            if(a<0 || a>=n || b<0 || b>=m) continue; //出界
            if(st[a][b] == 1) continue; //已经被访问过
            if(g[a][b] != '.') continue; //不能走
            
            res++;
            q.push({a,b});
            st[a][b] = 1; //标记(a,b)已经被访问过
        }
    }
}


int main()
{
    while(cin >> m >> n)
    {
        if(m==0 && n==0) break;
        res = 1;
        memset(st,0,sizeof st); //memset(数组名,值,sizeof 数组名); 0/-1/0x3f
        
        for(int i=0; i<n; i++) cin >> g[i];
    
        for(int i=0; i<n; i++)
            for(int j=0; j<m; j++)
                if(g[i][j] == '@')
                {
                    bfs(i,j);
                    break;
                }
        cout << res << endl;        
    }
   

DFS

#include<iostream>
#define N 30

using namespace std;
int  m,n;
char g[N][N];
int dx[]={-1,0,1,0},dy[]={0,1,0,-1};
int dfs(int x,int y)
{
    int res=1;
    g[x][y]='#';//**之前的g[x][y]是为#的 之前已经令res=1了**
    int a,b;
    for(int i=0;i<4;i++)
    {
        a=x+dx[i],b=y+dy[i];
        if(a>=0&&a<n&&b>=0&&b<=m&&g[a][b]=='.')
            res+=dfs(a,b);//递归
    }
    return res;
}
int main()
{
    int i,j,a,b;

    while(cin>>m>>n,m!=0&&n!=0)//等价于while(cin>>m>>n,m||n)
    {
        for(i=0;i<n;i++)cin>>g[i];
        for(i=0;i<n;i++)
            for(j=0;j<m;j++)
                if(g[i][j]=='@')
                {
                    a=i,b=j;
                }
            cout<<dfs(a,b)<<endl;
    }
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值