580 likes | 720 Views
09 计算机 于馨培. 数学基础和数据结构. 学习目标. 掌握素数表的构造 掌握 素因子分解的方法 掌握三角形有向面积的意义和计算方法 掌握 栈、队列、二叉树及其应用方法 了解 DFS 、 BFS 、拓扑排 序. 数学基础. Cantor 数表 输入 n ,输出第 n 项. 1/1 1/2 1/3 1/4 1/5 … 2/1 2/2 2/3 2/4 … 3/1 3/2 3/3 … 4/1 4/2 … 5/1 … …. 1/1 1/2 1/3 1/4 1/5 … 2/1 2/2 2/3 2/4 …
E N D
09计算机于馨培 数学基础和数据结构
学习目标 • 掌握素数表的构造 • 掌握素因子分解的方法 • 掌握三角形有向面积的意义和计算方法 • 掌握栈、队列、二叉树及其应用方法 • 了解DFS、BFS、拓扑排序
数学基础 • Cantor数表 • 输入n,输出第n项 1/1 1/2 1/3 1/4 1/5 … 2/1 2/2 2/3 2/4 … 3/1 3/2 3/3 … 4/1 4/2 … 5/1 … … 1/1 1/2 1/3 1/4 1/5 … 2/1 2/2 2/3 2/4 … 3/1 3/2 3/3 … 4/1 4/2 … 5/1 … …
奇数行从下到上、偶数行从上到下 • 由于对称,只需要在k%2==0时交换分子分母 • Floor函数返回浮点数的整数部分(p18) • 正确性验证可以枚举[a,a+1]三部分
因子和阶乘 • 输入n • 返回n!的素数分解
将某个数标准分解是ACM数论题中最常用的一类算法。将某个数标准分解是ACM数论题中最常用的一类算法。 • 本题中由于n<=100,因此素因子不会超过100,因此素数表小可以暴力,实战中需要筛法来生成素数表
筛法复杂度 • 算法步骤: • 初始时容器内为2到n的所有数 • 取出最小的数p,p一定是质数,删去p的所有倍数(注: 只需从p2开始删除即可) (?) • 重复上述步骤直到容器为空 • 用bool数组实现即可 • 小优化:初始时只加入奇数 • 小于n的质数大约有n/ln(n)个,以此确定筛法的数组大小
叉积 • 叉积的绝对值 可以表示以a、b 为边的平行四边 形的面积
矩阵形式 • i、j、k为单位向量,行列式计算时为1 • 判断点在三角形内: • |Sabc|=|Spab|+|Spbc|+|Spca|(书上小错误,应带绝对值)
pab为正,pbc顺时针所以为负,pca为正,所以应带绝对值pab为正,pbc顺时针所以为负,pca为正,所以应带绝对值
浮点数判相等fabs(a-b)<eps • 可以认为在[b-eps,b+eps]区间内都相等 • 浮点数大于等于 • a>b-eps • 浮点数小于等于 • a<b+eps • 原因:浮点数不能表示所有的数! • (float范围为10-38~1038,却与int一样是4字节)
数据结构 • 1、队列 • 桌上有一叠牌,从第一张牌开始从上往下依次编号1~n。当至少还剩两张牌时进行以下操作:把第一张牌扔掉,然后把新的一张放到整叠牌最后。输入n,输出每次扔掉的牌,以及最后剩下的牌 • 样例输入:7 • 样例输出:1 3 5 7 4 2 6
出队 a1 a2 a3…………………….an 入队 front rear • 队列是一种先进先出的线性表(FIFO),所有的插入操作都在队列尾进行,所有的删除操作都在队列头进行。 • 队头front • 队尾rear 队列Q=(a1,a2,……,an)
5 4 3 2 1 0 • 队列基本操作 在本题中: While(front<rear) { printf(“%d ”,queue[front++]); //输出并使删除队头 queue[rear++]=queue[front++]; //将队头元素放到队尾 } J3 J2 J1 J1,J1,J3入队 空队列条件:front==rear 入队列:queue[rear++]=x; 出队列:x=queue[front++];
存在问题 • 设数组大小为M,则: • 当front=0,rear=M时,再有元素入队发生溢出——真溢出 • 当front0,rear=M时,再有元素入队发生溢出——假溢出 • 解决方案 • 循环队列 • 基本思想:把队列设想成环形,让queue[0]接在queue[M-1]之后,若rear+1==M,则令rear=0;
5 front 4 rear 3 2 J6 1 J5 0 J4 J3 J8 J7 J3,J4,J5,J6,J7,J8出队 • 入队: sq[rear]=x; • rear=(rear+1)%M; • 出队: x=sq[front]; • front=(front+1)%M; • front==rear时是队空还是队满? rear M-1 …… 0 1 front …… ……
J1 J2 J3 front rear J7 J6 • 队列为空的标志:front= =rear • 队列为满的标志:(rear+1) % MAXSIZE= =front • C++ STL中的队列: • 需要include<queue> • queue<T> s; • 是循环队列且自动分配内存,不需要 • 事先指定队列大小 • s.pop(),s.push(),s.front(),s.empty
2、栈: • 有n节列车从右方驶入,编号为1~n,你的任务是让它们按照某种特定的顺序进入左方的铁轨。 • 可以利用下方的中转站。 • 驶入中转站的车需按照相反顺序 • 离开。 • 一旦从右方到中转站就不能回 • 一旦进入左方铁轨就不能回中转站。
5 4 3 2 1 top 0 • 栈是一种特殊的线性表,它只能在表的一端(即栈顶)进行插入和删除运算。top为栈顶指针。 压栈:stack[top++]=x; 出栈:x=stack[top--];
由于火车的调度过程符合“后进先出”的特点,所以本题的模型是一个栈.可以通过简单模拟来判断火车能否到达目标状态.由于火车的调度过程符合“后进先出”的特点,所以本题的模型是一个栈.可以通过简单模拟来判断火车能否到达目标状态. 目标序列 5 4 3 2 1 4 5 A站车厢 B = 1 A = 4 A B 321 Station
A表示A站最前方车厢的编号 target[B]表示依照出栈序列 下一个需要进入B站的车厢的序号 用栈stack记录当前车站Station中的车厢 初始时,A=1,B=1,stack为空栈 。
如果A与target[B]相同,则将车厢直接开到B铁轨。如果A与target[B]相同,则将车厢直接开到B铁轨。 • 否则查看在中转站顶的车厢是否与target[B]相同,如果相同就将中转站顶的元素出栈。 • 否则,如果栈没满,就让A的最外一个车厢入栈。 • 如果以上都不行,则说明不能形成目标。 • 如果最后B=n,则说明形成目标。
“对拍”,自己生成随机数据,然后对比自己程序与标程或者其他程序的结果是否相同。“对拍”,自己生成随机数据,然后对比自己程序与标程或者其他程序的结果是否相同。 • freopen(“in.txt”,”r”,stdin); • freopen(“out.txt”,”w”,stdout); • srand(time(null));每个程序调用一次 • rand()%M;
3、二叉树 • 递归定义:二叉树要么为空,要么由根节点、左子树和右子树组成,而左子树和右子树分别是一棵二叉树。 • 题目:小球往下落,每落到一个节点上就将节点开关状态改变一次。问最后一个小球落在何处。
A B C L K F M G D E H I J 若干术语 ——即根结点(没有前驱) ——即终端结点(没有后继) ——指m棵不相交的树的集合(例如删除A后的子树个数) 根 叶子 森林 有序树 无序树 ——结点各子树从左至右有序,不能互换(左为第一) ——结点各子树可互换位置。 双亲 孩子 兄弟 堂兄弟 祖先 子孙 ——即上层的那个结点(直接前驱) ——即下层结点的子树的根(直接后继) ——同一双亲下的同层结点(孩子之间互称兄弟) ——即双亲位于同一层的结点(但并非同一双亲) ——即从根到该结点所经分支的所有结点 ——即该结点下层子树中的任一结点
A B C L K M F G D E H J I 若干术语(续) 结点 结点的度 结点的层次 终端结点 分支结点 ——即树的数据元素 ——结点挂接的子树数(有几个直接后继就是几度,亦称“次数”) ——从根到该结点的层数(根结点算第一层) ——即度为0的结点,即叶子 ——即度不为0的结点(也称为内部结点) 树的度 树的深度 (或高度) ——所有结点度中的最大值(Max{各结点的度}) ——指所有结点中最大的层数(Max{各结点的层次}) 问:右上图中的结点数=;树的度=;树的深度= 13 3 4
模拟方法缺点:需要存储的节点太多,如果树有D层,则需要2D-1个节点(叶子层不用存)。模拟方法缺点:需要存储的节点太多,如果树有D层,则需要2D-1个节点(叶子层不用存)。 • 注意到,对某个开关i,第奇数次到达的小球必然向左走,偶数次到达的向右走。 • 因此,第I个到达root的小球,若I为奇数,则对于左子树是第(I+1)/2个;若I为偶数,则对于右子树是第I/2。
书上程序也可改写成: • For(inti=0;i<D-1;i++) { k=k*2+I%2; I=(I+I%2)/2; }
层次遍历: • 已知从根节点到每个节点的移动序列构造二叉树,然后按照从上到下,从左到右的顺序输出各个节点的值。 • 输入样例: • (11,LL) (13,RL) • 如何存储? • 数组?如果树退化成链表则有256层。
typedefstructTnode • { • inthave_value; • int v; • structTnode *left,*right; • }Node; • 也可以直接存两个下标来代替指针,从编译的角度来说,用指针略快。
前序、后序和中序 先序遍历的结果是: 中序遍历的结果是: 后序遍历的结果是: A A B D E C D B E A C D E B C A B C E D DLR—先序遍历,即先根再左再右 LDR—中序遍历,即先左再根再右 LRD—后序遍历,即先左再右再根
strchar(s,x)返回指向字符串s中第一个x字符的指针strchar(s,x)返回指向字符串s中第一个x字符的指针 • 其实第一个参数没什么必要 • p为左子树大小
4、图的定义和术语 无向图 G2 有向图 G1 A B A B E C D C D 结点(顶点) 结点(顶点) A B A B 有向边(弧)、弧尾(初始结点)、弧头(终止结点) 边(无向边) A B A B 有向图:G2=(V2,E2) V2 = {A,B,C,D,E} E2 = {(A,B), (A,C),(B,D), (B,E), (C,E),(D,E)} 有向图:G1=(V1,E1) V1 = {A,B,C,D} E1 = {<A,B>, <A,C>, <C,D>, <D,A>}
无向图的连通性 路径:在无向图G=(V,E)中由顶点v至v’的顶点序列。 回路或环:第一个顶点和最后一个顶点相同的路径。 简单回路或简单环:除第一个顶点和最后一个顶点之外,其余顶点不重复出现的回路。 连通:顶点v至v’之间有路径存在 连通图:无向图图 G 的任意两点之间都是连通的,则称 G 是连通图。 连通分量:极大连通子图 无向图G 无向图G的三个连通分量 A B A B F G E F G E H I J I J H K L K L M M C D C D
有向图的连通性 路径:在有向图G=(V,E)中由顶点v经有向边至v’的顶点序列。 回路或环:第一个顶点和最后一个顶点相同的路径。 简单回路或简单环:除第一个顶点和最后一个顶点之外,其余顶点不重复出现的回路。 连通:顶点v至v’之间有路径存在 强连通图:有向图G的任意两点之间都是连通的,则称G是强连通图。 强连通分量:极大连通子图 A B A B C D C D 有向图G的两个强连通分量 有向图G
6.4.1黑白图像一题其实就是求无向图的联通分量个数,这在图论中是最最基础的一类应用。6.4.1黑白图像一题其实就是求无向图的联通分量个数,这在图论中是最最基础的一类应用。 • 邻接矩阵和邻接表: • 邻接矩阵mat[i][j]==1表示i到j有一条边。 • 邻接表:链表数组 • Head[i]中存的是所有与i相邻 • 的节点编号
1、深度优先(DFS)搜索 • 从图中某顶点v出发: • 访问顶点v; • 从v的未被访问的邻接点出发,继续对图进行深度优先遍历,若从某点出发所有邻接点都已访问过,退回前一个点继续上述过程,若退回开始点,结束。 • 对本题来说,每次dfs可以遍历一个连通分量。
2、广度优先搜索: • 访问顶点v ; • 访问同v相邻的所有未被访问的邻接点w1,w2, …wk; • 依次从这些邻接点出发,访问它们的所有未被访问的邻接点; 依此类推,直到图中所有访问过的顶点的邻接点都被访问;
1 12 11 2 3 6 7 10 4 5 8 9 1 11 2 12 3 6 7 10 4 5 8 9 图的广度优先的访问次序: 1、2、11、12、3、6、7、10、4、5、8、9 适用的数据结构:队列
将起点标记为已走过并入队; • while (队列非空) { • 出队一个点p; • if (p这个点是终点) • break; • 否则沿右、下、左、上四个方向探索相邻的点 • if (和p相邻的点有路可走,并且还没走过) • 将相邻的点标记为已走过并入队,它的前趋就是刚出队的p点; • } • if (p点是终点) { • 打印p点的坐标; • while (p点有前趋) { • p点 = p点的前趋; • 打印p点的坐标; • } • } else • 没有路线可以到达终点;
拓扑排序: • 把图中各顶点按照它们相互之间的优先关系排列一个线性序列的过程。若vi是vj前驱,则vi一定在vj之前;对于没有优先关系的点,顺序任意。 • 拓扑排序要求图上没有回路
v1 v2 v4 v3 v5 v6 拓扑排序的方法 (1)在有向图中选一个没有前驱的顶点且输出之 (2)从图中删除该顶点和所有以它为尾的弧 重复上述两步,直至全部顶点均已输出;或者当图中不存在无前驱的顶点为止(此时说明图中有环) v1
v4 v3 v5 拓扑排序的方法 (1)在有向图中选一个没有前驱的顶点且输出之 (2)从图中删除该顶点和所有以它为尾的弧 重复上述两步,直至全部顶点均已输出;或者当图中不存在无前驱的顶点为止(此时说明图中有环) v2 v6 v1
v4 v3 v5 拓扑排序的方法 (1)在有向图中选一个没有前驱的顶点且输出之 (2)从图中删除该顶点和所有以它为尾的弧 重复上述两步,直至全部顶点均已输出;或者当图中不存在无前驱的顶点为止(此时说明图中有环) v2 v6 v1 v5
v4 v3 拓扑排序的方法 (1)在有向图中选一个没有前驱的顶点且输出之 (2)从图中删除该顶点和所有以它为尾的弧 重复上述两步,直至全部顶点均已输出;或者当图中不存在无前驱的顶点为止(此时说明图中有环) v2 v6 v1 v5
v4 v3 拓扑排序的方法 (1)在有向图中选一个没有前驱的顶点且输出之 (2)从图中删除该顶点和所有以它为尾的弧 重复上述两步,直至全部顶点均已输出;或者当图中不存在无前驱的顶点为止(此时说明图中有环) v2 v6 v1 v5 v4