第14次课 认识图 A
课堂回顾
树的概念
概念A
树是一种非线性的数据结构,能很好地描述有分支和层次特性的数据集合。
一棵树是由n(n≥0)个元素组成的有限集合。
1)每个元素都可以称为结点(node):
2)任意一棵非空树中(>0),有一个特定的结点,称为根结点或树根(root);
3)在一棵非空树中,结点a是树的一个结点,由a以及的所有后代组成的结构,称为树的子树。
4)在一棵非空树中,从某个结点向下,分出若干结点a1,
a2,...分出的结点α以及它的所有后代,称为结点的子树。
5)没有子树的结点,称为叶结点。
一个结点的子树个数,称为这个结点的度。
树中各结点度的最大值,称为这棵树的度。
棵树中所有的结点层次的最大值称为树的深度。
概念B
二叉树是一种特殊的树型结构,树中结点的度都不大于2,它是一种最简单且最重要的树。
在二叉树的第层上最多有2的i-1次方个结点(i≥1)。
深度为k的二叉树最多有2的k次方-1个结点(k≥1)。
满二叉树:
一棵深度为k且有2的k次方-1个结点的二叉树称为满二叉树。
完全二叉树:
二叉树中除去最后一层结点为满二叉树,且最后一层的结点依次从左到右分布。
需要注意的是,满二叉树也是完全二叉树。
二叉树的遍历
二叉树是由三个基本单元组成:根结点、左子树和右子树。
二叉树的三种遍历:
先序:访问根结点一>遍历左子树一>遍历右子树(简称:根左右)
中序:遍历左子树一>访问根结点一>遍历右子树(简称:左根右)
后序:遍历左子树一>遍历右子树一>访问根结点(简称:左右根)
先序遍历
访问根结点一>遍历左子树一>遍历右子树(简称:根左右)
先序序列的第一个点是根结点。
在子树的先序序列中,第一个点是该子树的根。
中序遍历
遍历左子树一>访问根结点一>遍历右子树(简称:左根右)
第1步:有左子树一直找左子树。
第2步:当没有左子树或左子树已经遍历完,访问根结点。
第3步:找右子树,重复上述步骤。
中序序列可以通过根结点划分左右子树。
后序遍历
遍历左子树一>遍历右子树一>访问根结点(简称:左右根)
第1步:有左子树一直找左子树。
第2步:没有左子树,找右子树,重复上述步骤。
第3步:当没有右子树或左右子树已经遍历完,访问根结点。
后序序列的最后一个点是根结点。
在子树的后序序列中,最后一个点是该子树的根。
序列构造二叉树
中序遍历序列和先序遍历序列可以构造一棵二叉树。
1.根据先序遍历序列确定根结点
2.根据中序遍历序列确定左右子树结点
3.循环上述步骤,直到确定所有结点
中序遍历序列和后序遍历序列可以构造一棵二叉树。
1.根据后序遍历序列确定根结点
2.根据中序遍历序列确定左右子树结点
3.循环上述步骤,直到确定所有结点
中序遍历序列和层序遍历序列可以构造一棵二叉树。
1.根据层序遍历序列确定根结点
2.根据中序遍历序列确定左右子树结点
3.循环上述步骤,直到确定所有结点
课堂学习
图的概念
六位朋友用圈和数字的图案表示。
圈1的好友:圈2;圈4;圈5。
圈2的好友:圈3;圈5;圈6。
圈6的好友:圈3;圈4。
两人之间建立好友,用线段连接。
上述所列举的好友关系组成一张关系网。这种网状结构,就是数据结构的图。
数据结构中图的概念:
图是由有限个结点,和结点之间的边组成。
结点数目为有限非0,也就是不能没有结点;边数目为有限。
图的分类
图按照边分为无向图和有向图。(离散数学)
1.无向图讲解:
无向图:图中任意一条边都没有方向。
无向图表示为:G=(V,E)
结点集合V={1,2,3,4}
边集合E={(1,2),(2,3),(1,3),(1,4),(3,4)}
无向边用小括号把两端结点括起来。
说明:由于边没有方向,因此(3,4)和(4,3)是同一条边,意味着两个结点相互可达。
2.有向图讲解:
有向图:图中任意一条边都有方向。
有向图表示为:G=(V,E)
结点集合V={1,2,3,4}
边集合E={<1,2>,<2,3>,<1,3>,<4,1>,<3,4>}
有向图的边叫做弧。起始端叫弧尾,终端叫弧头。
有向边用尖括号把两端结点括起来:<弧尾,弧头>。
说明:由于有方向,因此<3,4>和<4,3>是两条边。
简单图
图结构中,同一条边不重复出现,且不存在结点到自身的边,则称图为简单图。
观察下面两个图结构:
平时接触的更多是简单图;没有特殊说明,默认图是简单图。
练一练
下列4个图结构中,属于简单图的是(AD)
已知图的表示方式为:G=(V,E),V表示结点集合,E表示边的集合,对下面的有向图G,表示正确的一项是()。
A.G=(V,E);V={1,2,3,4,5};E={<1,4>,<4,5>,<5,1>,<5,2>,<2,3>,<3,5>}
B.G=(V,E);V={1,2,3,4,5};E={<4,1>,<5,4>,<1,5>,<2,5>,<3,2>,<5,3>}
C. G=(V,E); V={1,2,3,4,5); E={(1,4),(4,5),(5,1),(5,2),(2,3),(3,5)}
D. G=(V,E); V={1,2,3,4,5); E={(4,1),(5,4),(1,5),(2,5),(3,2),(5,3)}
完全图
思考题:
简单图前提下,图中有n个结点,什么样的图拥有最多的边呢?
图有3个结点:
图有4个结点:
结论:
完全图:图中任意两个结点间都存在边相连。
完全图分为:
1.有向完全图
有向图中任意两个结点都存在方向互为相反的两条边。
4个结点,有12条边。
每个结点都有指向其他3个结点的边。
图有4个结点,共有4*3=12条边。
思考一下:
假设n个结点,有多少条边?
每个结点都有指向其他n-1个结点的边。
3n个结点,共有n*(n-1)条边。
2.无向完全图
无向图中任意两个结点都存在边。
4个结点,有6条边。
假设n个结点,有多少条边?
有向完全图任意两个结点存在2条边:n个结点,共有n*(n-1)条边。
无向完全图任意两个结点比有向都少1条。n个结点,共有n*(n-1)/2条边。
练一练
无向完全图是图中每对结点之间都恰好有一条边的简单图。已知无向完全图G有
7个结点,则它共有(B)条边。
A.7
B.21
C.42
D.49
【解析】n个结点的无向完全图,边数=n*(n-1)/2。n=7,边数=7*(7-1)/2=21。
1个简单无向图有10个结点,图中当前存在40条边,请问增加( )条边可以成为完全图。
A. 2
B.3
C.4
D.5
【解析】n个结点的无向完全图,边数=n*(n-1)/2。n=10,边数=10*(10-1)/2=45,当前存在40条边,需增加5条边。
结点的度
结点v的度:结点v相连边的数目
以微信为例:6
用户2相连的好友有4位,有4条边。
结点2的度为4。
以抖音为例:
用户2存在关系的有5位,有5条边。
结点2的度为5。
入度与出度
有向图中,结点的边有进有出,度可以分为:入度,出度。
以抖音为例:
用户2粉丝有3个,结点2入度等于3。
用户2关注用户1,3,结点2出度等于2。
结点v入度:有向图中以结点v作为终点边的数目。
结点v出度:有向图中以结点v作为起点边的数目。
有向图中,结点的度=入度+出度。
练一练
设简单无向图G有16条边且每个结点的度数都是2,则图G有(D)个结点。
A.10
B.12
C.8
D.16
【解析】图中每增加1条边,度数之和增加2,因此m条边的图,度数之和=2*m。16条边的图,度数之和是32;每个结点的度数都是2,结点数=32/2=16
有向图中每个结点的度等于该结点的(c)。
A.入度
B.出度
C.入度和出度之和
D.入度和出度之差
【解析】有向图中,结点的度等于该结点入度和出度之和。
图的概念总结
图是一种数据结构。
1.概念:
图是由有限个结点和结点之间的边组成。通常表示为G=(V,E)。
2.两种图:
(1) 无向图:图中任意一条边都没有方向。
(2)有向图:图中任意一条边都有方向。
3.简单图:若同一条边不重复出现,且不存在结点到自身的边,则称图为简单图。
4.完全图:
(1)有向完全图:有向图任意两个结点都存在方向互为相反的两条边。
(2)无向完全图:无向图任意两个结点都存在边。
n个结点:有向图边数=n*(n-1)
无向图边数=n*(n-1)/2
5.结点v的度:结点v相连边的数目。
(1) 结点v入度:有向图中以结点v作为终点边的数目。
(2) 结点v出度:有向图中以结点v作为起点边的数目。
有向图中,结点的度=入度+出度。
权和网
在一些实际场景中,图中的每条边(或弧)会赋予一个数字来表示一定的含义。
以城市的分布图为例:
北京~上海:1073km
上海~深圳:1212km
深圳~拉萨:2429km
拉萨~北京:2555km
图中边上的数字叫做“权值”
带权的图通常称为“网”
说明:有向图或无向图都可以。
生活中有带权图的案例
1.快递员在不同地点间送快递。权值:距离,时间
2.货车在地点之间的道路上行驶。权值:距离,时间,汽油消耗
注意:权值可以表示从一个结点到另一个结点的距离,时间或其他一些代价。
路径和回路
如果能从一个结点到另一个结点,途中经过的所有结点称为一条路径。
结点2~结点3的路径:2,4,5,3
如果一条路径的起点与终点相同,则称此路径为"回路"
结点2的回路:2,4,1,2
说明:有向图或无向图都可以。
练一练
在下面的有向图中,从结点3到结点4,共有(D)条路径。
注意:一条路径中,一个结点只能经过一次。
A. 1 B.2 C.3 D. 4
【解析】从结点3到结点4共存在4条路径。分别为:
3->7->4
3->7->1->4
3->6->7->4
3->6->7->1->4
子图
初步理解图的一部分就是子图。
以无向图G1和G2为例:
图G1属于图G2的一部分,图G1是G2的子图。
图G1所有的结点和边都属于图G2,则称图G1为图G2的子图。
G1=(V1,E1))G2=(V2,E2)如果V1是V2子集,且E1是E2子集。则G1是G2的子图。
子图按照是否有边分为两种:
第一种无边,子图是独立结点:
第二种有边,2边将结点连G2接起来:
给定的有向图中,子图的个数有(B)个。
说明:如果子图中结点的数量超过1,所有结点需要通过边串联在一起,不可以独立。
【解析】以子图的结点数划分情况:分为1个结点,2个结点,3个结点三种。
1个结点时,子图有3个;
2个结点时,子图有3个;
3个结点时,结合2条边,子图有3个;结合3条边,子图有1个(原图)。
合计10个子图。
连通和强连通
在无向图中,如果两个结点间存在路径,则称两个结点连通。
答案:存在路径。(1,2) (2,5)
结点1与结点5是连通的。
在无向图中,任意两个结点都连通,则称该图为连通图。
练一练
在一个无向图中,如果任意两点之间都存在路径相连,则称其为连通图。下图是一个有4个结点、6条边的连通图。若要使它不再是连通图,至少要删去其中的(C)条边。
【解析】在无向的情况下,只要所有结点属于一个图,该图就是连通图,因此,需
选择一个结点,删除它的所有边即可。
给定图中每个结点都有3条边,所以至少删除3个边。
有10个结点的无向图至少应该有(A)条边才能确保是一个连通图。
A. 9
B.10
C. 11
D.12
【解析】在无向图中,只要所有结点连在一起,该图即为连通图。假设:
图中有2个结点,至少需要1条边;图中有3个结点,至少需要2条边;以此类推...
图中有n个结点,至少需要n-1条边。因此,对于10个结点的无向图,至少需要9条边。
强连通与强连通图
强连通图
强连通,强连通图可以与连通概念对比理解。
连通描述的对象是无向图。
强连通,强连通图描述的对象是有向图。
右侧的有向图中:
结点1至结点4存在路径吗?<1,3><3,4>
结点4至结点1存在路径吗?<4,2><2,1>
结点1与结点4是强连通的。
有向图中的两个结点相互可以到达,则称两个结点强连通。
有向图中任意两个结点间 都强连通,则称有向图是强连通图。
练一练
在下列四个图结构中,属于强连通图的是(C)。
【解析】强连通图概念:在有向图中,任意两点都可以相互到达。
要求1:有向图;要求2:任意两点相互到达。
只有选项C符合要求。
对一个有向图而言,如果每个结点都存在到达其他任何结点的路径,那么就称它是强连通的。例如,下图就是一个强连通图。事实上,在删掉边(A)后,它依然是强连通的。
【解析】逐项验证:删除选项中的边,检查删除后的有向图是否还是强连通图。A选项正确。
强连通分量
强连通分量:有向图中,最大的强连通子图。
强连通子图:子图的任意两点相互可以到达。
以下图为例,介绍“最大”的含义:
同理,结点3不可以扩展更大的强连通子图,结点3也是强连通分量。
练一练
图的概念总结
1.权和网:
(1)图中边上的数字叫做“权值”
(2)带权的图通常称为“网”。
注意:权值可以表示从一个结点到另一个结点的距离,时间或其他一些代价。
2.路径和回路:
(1) 从一个结点到另一个结点,途中经过的所有结点称为一条路径。
(2)一条路径的起点与终点相同,则称此路径为“回路”。
3.子图:图G1所有的结点和边都属于图G2,则称图G1为图G2的子图。
G1=(V1,E1)G2=(V2,E2)如果V1是V2子集,且E1是E2子集。则G1是G2的子图。
4.连通与连通图:
(1) 无向图中,两个结点间存在路径,则称两个结点连通。
(2)无向图中,任意两个结点都连通,则称该图为连通图。
5.强连通与强连通图:
(1)有向图中,两个结点相互可以到达,则称两个结点强连通。
(2)有向图中,任意两个结点间都强连通,则称有向图是强连通图。
6.强连通分量:有向图中,最大的强连通子图。
图的存储
1.邻接矩阵:存储图的二维数组。矩阵行列规模要大于最大结点编号
(1)图:用1表示两个结点有边;用0表示两个结点没边。
(2)网:用权值表示两个结点有边;用极大值表示两个结点没边。极大值要大于最大的权值
相同点:有向边赋1次;无向边赋2次。
2.代码实现步骤:
存储图:
(1)输入结点数n,边数m。
(2)创建邻接矩阵同时初始化为0。
(3)循环m次:先输入边;再赋值1。
存储网:
(1)输入结点数n,边数m。
(2)先创建邻接矩阵;再全部赋极大值。
(3)循环m次:先输入边;再赋权值。
相同点:有向边赋1次;无向边赋2次。
课堂训练
4469 图的邻接矩阵
描述
输入一个无向图,存进邻接矩阵并输出。
输入描述
第一行两个整数 n 和 m,表示图有 n 个结点,m 条边。(结点编号 1∼n)
接下来有 m 行,每行有两个整数 x 和 y,表示一条边的两端结点。
输出描述
输出邻接矩阵。
样例输入 1
4 5
1 2
1 3
2 4
1 4
4 3
样例输出 1
0 1 1 1
1 0 0 1
1 0 0 1
1 1 1 0
提示
数据范围与提示
n≤20
#include<bits/stdc++.h>
using namespace std;
int main(){int n,m;cin>>n>>m;//创建邻接矩阵int g[21][21]={};int x,y;//循环m次:先输入边的两端结点x和y,再赋值2次1for(int i=1;i<=m;i++){cin>>x>>y;g[x][y]=1;g[y][x]=1;}//输出邻接矩阵for(int i=1;i<=n;i++){for(int j=1;j<=n;j++)cout<<g[i][j]<<" ";cout<<endl;}return 0;
}
4470 网的邻接矩阵1
描述
输入一个有向的网,存进邻接矩阵并输出。
输入描述
第一行两个整数 n 和 m,表示有 n 个结点,m 条边。(结点编号 1∼n)
接下来有 m 行,每行有三个整数 x,y 和 w。表示一条结点 x 到 y 的边,权值为 w。
输出描述
输出邻接矩阵。
样例输入 1
4 5
2 1 2
3 1 3
3 2 10
1 4 8
4 3 5
样例输出 1
999 999 999 8
2 999 999 999
3 10 999 999
999 999 5 999
提示
数据范围与提示
n≤20,0≤w≤10
提示:如果两个结点间没边,极大值取 999。
#include<bits/stdc++.h>
using namespace std;
int main(){int n,m;cin>>n>>m;//创建邻接矩阵int g[21][21]={};//矩阵全部赋极大值999for(int i=0;i<=20;i++)for(int j=0;j<=20;j++)g[i][j]=999;int x,y,w;//循环m次:先输入一条边,再赋权值for(int i=1;i<=m;i++){cin>>x>>y>>w;g[x][y]=w;}//输出矩阵for(int i=1;i<=n;i++){for(int j=1;j<=n;j++)cout<<g[i][j]<<" ";cout<<endl;}return 0;
}
4471 网的邻接矩阵2
描述
输入一个无向的网,存进邻接矩阵并输出。
输入描述
第一行两个整数 n 和 m,表示有 n 个结点,m 条边。(结点编号 1∼n)
接下来有 m 行,每行有三个整数 x,y 和 w。表示一条结点 x 到 y 的边,权值为 w。
输出描述
输出邻接矩阵。
样例输入 1
4 5
2 1 2
3 1 3
3 2 10
1 4 8
4 3 5
样例输出 1
999 2 3 8
2 999 10 999
3 10 999 5
8 999 5 999
提示
数据范围与提示
n≤20,0≤w≤10
如果两个结点间没边,极大值取 999。
#include<bits/stdc++.h>
using namespace std;
int main(){int n,m;cin>>n>>m;//创建邻接矩阵int g[21][21]={};//矩阵全部赋极大值999for(int i=0;i<=20;i++)for(int j=0;j<=20;j++)g[i][j]=999;int x,y,w;//循环m次:先输入一条边,再赋权值for(int i=1;i<=m;i++){cin>>x>>y>>w;g[x][y]=w;g[y][x]=w;}//输出矩阵for(int i=1;i<=n;i++){for(int j=1;j<=n;j++)cout<<g[i][j]<<" ";cout<<endl;}return 0;
}
课后作业
3158 无向图结点m的度
描述
给定无向图n*n的邻接矩阵,编程计算指定结点的度。
输入描述
第一行两个整数n和m,分别表示结点总数n,指定结点m。(4<=n<=10,1<=m<=n)
下面n行,每行n个整数,表示邻接矩阵。
输出描述
一个整数,表示结点m的度。
样例输入 1
5 3
0 1 1 0 0
1 0 1 1 0
1 1 0 1 1
0 1 1 0 1
0 0 1 1 0
样例输出 1
4
#include<bits/stdc++.h>
using namespace std;
int main(){int n,m;cin>>n>>m;int g[11][11]={};for(int i=1;i<=n;i++)for(int j=1;j<=n;j++)cin>>g[i][j];//无向图结点m的度,就是下标m这行,非0元素个数int d=0;for(int i=1;i<=n;i++){if(g[m][i]!=0)d++;}cout<<d;return 0;
}
3154 有向图结点m的度
描述
给定有向图n*n的邻接矩阵,编程计算指定结点的出度,入度和度。
输入描述
第一行两个整数n和m,分别表示结点总数n,指定结点m。(4<=n<=10,1<=m<=n)
下面n行,每行n个整数,表示有向图的邻接矩阵。
输出描述
一行输出空格分隔的三个整数,分别表示结点m出度,入度和度。
样例输入 1
6 4
0 1 0 1 0 0
0 0 1 0 0 0
1 0 0 0 0 1
0 0 1 0 0 1
0 0 0 1 0 0
1 0 0 0 1 0
样例输出 1
2 2 4
#include<bits/stdc++.h>
using namespace std;
int main(){int n,m; //图有n个结点;计算结点m的度cin>>n>>m;//创建并输入邻接矩阵int g[11][11]={};for(int i=1;i<=n;i++)for(int j=1;j<=n;j++)cin>>g[i][j];//第m行非0元素个数就是m的出度int c=0;for(int i=1;i<=n;i++){if(g[m][i]!=0)c++;}//第m列非0元素个数就是m的入度int r=0;for(int i=1;i<=n;i++){if(g[i][m]!=0)r++;}//度=出度+入度int d=c+r;cout<<c<<" "<<r<<" "<<d;return 0;
}