前言
第三周总结
一、树是什么?
树结构是一种重要的非线性数据结构,其中二叉树用的最为广泛。如操作系统中用树表示文件目录的组织结构,在编译系统中表示源程序的语法结构,在数据库中,树结构也是信息的重要组织形式之一。
树的定义
树是n(n>=0)个结点的有限集,它或为空树即n等于0,或非空树,对于树T它有如下性质:
有且仅有一个称之为根的结点;
除根结点之外的其余结点可分为m个互不相交的有限集T1,T2,T3…Tm其中每个集合又是一颗数,并且称之为树的子根。
可以看出树的定义是一个递归的定义,即在树的定义中又用到了树的定义
树的基本术语
结点:树中的一个独立单元 包含一个数据元素及若干指向其子树的分支
结点的度:节点拥有的子树数称为节点的度
树的度:树的度是树那个各结点度的最大值
叶子:度为零的节点称为叶子或终端节点
非终端的结点:度不为零的结点称为非终端结点或分支结点
双亲和孩子:节点的子树的根称为该节点的孩子相应的该节点成为孩子的双亲
兄弟:同一个双亲的孩子之间互称兄弟
祖先:从根到该节点所经分之支的所有节点
*子孙:以某结点为根的子树中的任意节点都称为该结点的子孙
层次:节点都层次从根开始定义 根为第一层根的孩子为第二层数中任意节点的层数等于失去双亲结点的层次加一
堂兄弟:双亲在同一层的节点互为堂兄弟
**树的深度:**树中结点的最大层次称为树的深度或高度
有徐树和无序树:如果将树中结点的个子数看成从左至右 是有次序的 该数为有序树 否则称为无序树 在有序树中最左边的子树的根称为第一个孩子最右边成为最后一个孩子
森林; 是多颗互不相交的树的集合 对于树中每个节点而言 其子树的集合即为森林 此也可以用森林和树户乡递归的定义来描述树
二、二叉树
概念一棵二叉树是结点的一个有限集合,该集合或者为空,或者是由一个根节点加上两棵别称为左子树和右子树的二叉
树组成。
特点
-
每个结点最多有两棵子树,即二叉树不存在度大于 2 的结点。
-
二叉树的子树有左右之分,其子树的次序不能颠倒,因此二叉树是有序树。
二叉树的遍历
前序遍历(前根遍历):根——>左——>右
中序遍历(中根遍历):左——>根——>右
后序遍历(后根遍历):左——>右——>根
类别
满二叉树
指深度为k且有2k-1个结点的二叉树,即所有分支结点都存在左子树和右子树,并且所有叶子都在同一层上。
下图中深度为4,24-1=15个结点,且所有叶子都在第四层上。
完全二叉树
一颗深度为k的二叉树,k层的结点都是连续靠左并不可隔开的,并且1~k-1层的结点也组成了一棵满二叉树,这样的二叉树,我们称为完全二叉树。
三、递归
定义: 在数学与计算机科学中,递归(Recursion)是指在函数的定义中使用函数自身的方法。
思想:递归的基本思想就是把规模大的问题转化为规模小的相似的子问题来解决,函数必须有明确的结束条件,否则就会导致无限递归的情况。
记住 递归 = 递推 + 回溯
在递归过程中要注意的事
1、明确递归终止条件;
2、给出递归终止时的处理办法;
3、提取重复的逻辑,缩小问题规模。
Q:一个楼梯共有n级台阶,每次可以走一级或者两级,问从第0级台阶走到第n级台阶一共有多少种方案。
W;
#include<iostream>
using namespace std;
int tj(int n)
{
int t;
if(n==1)//当阶梯数只有1的时候,只能走1阶
t=1;
else
if(n==2)//当阶梯数为2的时候,可以先走1阶再走1阶,也可以直接走2阶.所以2种
t=2;
else
t=tj(n-1)+tj(n-2);//递归处理
return t;
}
int main()
{
int x;
scanf("%d",&x);
cout<<tj(x);
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);
}
在写题过程中可以直接使用在头文件 <algorithm.>中的sort函数
#include<iostream>
#include<algorithm>
using namespace std;
const int N = 10010;
int a[N],n;
int main()
{
cin>>n;
for(int i=0;i<n;i++)
{
cin>>a[i];
}
sort(a+2,a+4);//sotr函数为sort(a+n,a+m,cmp) 意思为从第n个数开始到m-1个数结束进行升序排序,cmp为升序的意思,若想修改为降序可以写一个关于cmp的函数
for(int i=0;i<n;i++)
{
cout<<a[i]<<" ";
}
return 0;
}
输入 6
6 5 4 3 2 1
输出为
6 5 3 4 2 1 //即对第2个数4 和第4个数的前一个数3,进行了升序排序
int A[100];
bool cmp(int a,int b)//int为数组数据类型
{
return a>b;//降序排列
}
sort(A,A+100,cmp);
int A[100];
bool cmp(int a,int b)//int为数组数据类型
{
return a<b;//默认的升序排列
}
sort(A,A+100,cmp);
归并排序
基本概念:将已有序的子序列合并,得到完全有序的序列;即先使每个子序列有序,再使子序列段间有序。若将两个有序表合并成一个有序表,称为二路归并。归并排序是一种稳定的排序方法。
归并排序模板:
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
区别
DFS的实现方法为 栈/递归 BFS为 队列
DFS的基本思想为回溯法,一次访问一条路,到达终点返回BFS为 分治限界法,一次访问多条路,每一层存储大量信息
DFS解决的问题有所有解问题,连通性问题 BFS最优解问题(最短路)
DFS浪费时间节省空间
BFS浪费空间节省时间
DFS算法
BFS算法
总结:dfs()到达递归终止条件即返回,否则继续递归;bfs()首先创建一个队列,然后把队首元素压入队列,再把下一层逐个元素送入队列。
题目传送门 ;acw113红与黑
BFS
#include <iostream>
#include <queue>
#include <algorithm>
#define x first
#define y second
using namespace std;
typedef pair<int, int> PII;
const int N = 25;
int n, m;
char g[N][N];
int bfs(int sx, int sy)
{
queue<PII> q;
q.push({sx, sy});
g[sx][sy] = '#';
int res = 0;
int dx[] = {-1, 0, 1, 0}, dy[] = {0, 1, 0, -1};
while (q.size())
{
auto t = q.front();
q.pop();
res ++ ;
for (int i = 0; i < 4; i ++ )
{
int x = t.x + dx[i], y = t.y + dy[i];
if (x < 0 || x >= n || y < 0 || y >= m || g[x][y] != '.') continue;
g[x][y] = '#';
q.push({x, y});
}
}
return res;
}
int main()
{
while (cin >> m >> n, n || m)
{
for (int i = 0; i < n; i ++ ) cin >> g[i];
int x, y;
for (int i = 0; i < n; i ++ )
for (int j = 0; j < m; j ++ )
if (g[i][j] == '@')
{
x = i;
y = j;
}
cout << bfs(x, y) << endl;
}
return 0;
}
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;
}