热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

数据结构(第六章)

图上图(上)第一讲一.什么是图图其实是一种很抽象的东西,它可以表示很多东西,举个例子,就你的朋友圈而言

图上
图(上)
第一讲
一.什么是图
图其实是一种很抽象的东西,它可以表示很多东西,举个例子,就你的朋友圈而言,你所交的朋友就可以构成一个图,生活中有很多很多的例子,因此图是比较复杂的,它表示的是“多对多"的关系。
回到数据结构,图一般包含两个要素:
一组顶点:通常用V表示顶点集合;
一组边:通常用E表示边的集合;
边是顶点对:(v,w)属于E,其中圆括号表示无向边,类似于一个这样的东西,——,双行线。
有向边表示v——>w,它是单行线。
我们不考虑重边和自回路,重边容易理解,自回路是什么呢?自回路其实就是一个由自己指出的边然后又指回自己,这就是自回路。
二.图的表示方法
作为程序员的我们,怎么用程序来表示一个图呢?
这里我们要引出一个新的概念叫邻接矩阵。
邻接矩阵其实就是存放关系的矩阵,有关系则为1,没有关系则为0;当然数值不一定用01表示,你可以用任何数。这里来放一个图就一目了然了
在这里插入图片描述
在图中,我们很清楚的看到,如果v1与v2有关系,则为1,没有关系就为0,然后图中的一条红线,红线经过的数字全为0,这是为什么呢,因为我们没有自回路,也就是没有自己指向自己的。而且以红线为轴,两边是对称的,因为我们是无向边,很好理解。
同时我们会发现既然是对称的,那么我们就没必要存放两个一样的东西,这样会浪费了一半的空间呀,与此同时,完善的方法就诞生了。
我们可以用一个长度为N(N+1)/2的一维数组存储,存储的顺序是按照从上至下,从左至右的,
那么i与j的关系如何呢,通过计算也就是规律,可得 数组的下标为(i*(i+1)/2+j),然后我们看它对应的数组元素的值,就可以判断有无关系了。
邻接矩阵的缺点:很明显,浪费空间,但是也是相对而言的,对于稀疏图,也就是顶点很多,边很少,显然很浪费空间也浪费时间,但是对于稠密图,特别是对于完全图(一个点和所有点都有关系),还是很合算的。
看完了邻接矩阵,看看邻接表吧
邻接表:G[N]为指针数组,对应矩阵每行一个链表,只存非0元素,也就是说只存有关系的。
在这里插入图片描述
大概就长这个样子吧!让我们想一想,它真的比邻接矩阵要好吗?
我们仔细分析,一个结点既要存指针,还要存有关系的下标,就占了两个域了,然后每一个结点都有,所以也无法避免重复的情况,因此它也是浪费空间的。但是,它很方便找出所有的相邻的点,比邻接矩阵还是要节约一些空间的,但也存在浪费。
第二讲
一.图的遍历
从图中某这一点出发访遍图中其余顶点,且每一个顶点仅被访问一次,这一过程叫做图的遍历。
对于图的遍历来说,为了避免陷入死循环,设计出两种遍历方案:DFS(深度优先搜索),BFS(广度优先搜索)。
二.深度优先搜索
具体思想:打个比方,比如我们需要在100间房子里找一把钥匙,深度优先搜索就是,从任意的一间房子开始,把该房间里的所有地方都搜遍了,才肯离开,然后在另一间房间继续按照此方法找,知道找到为止。
深度优先搜索其实就像似一棵树的先序遍历,它是从图上的某个顶点v出发,访问此顶点,然后从v的未被访问的邻接点出发深度优先遍历图,直到所有顶点都被访问到。如果有些顶点没有访问到,则另选图中的一个未被访问的顶点作为起始点,重复上述过程直到所有顶点被访问到。
邻接矩阵

void DFS(MGraph G,int i)//递归算法
{int j;visit[i]&#61;1;//标记为已访问printf("%c",G.data[i]);for(j&#61;0;j<G.num;j&#43;&#43;){if(G.map[i][j]&&!visit[j])//相邻的点&#xff0c;未被访问&#xff0c;直接DFSDFS(G,j);}
}
void DFSL(MGraph G)//遍历操作
{int i;for(i&#61;0;i<G.num;i&#43;&#43;){visit[i]&#61;0;}for(i&#61;0;i<G.num;i&#43;&#43;){if(!visit[i])DFS(G,i);}
}

邻接表

void DFS(MGraph G,int i)//递归算法
{MGraph *p;visit[i]&#61;1;printf("%c",G->List[i].data);p&#61;G->List[i].first;while(p){if(!visit[p->ad]){DFS(G,p->ad);//访问邻接点}p&#61;p->next}
}
void DFSL(MFGraph G)//遍历操作
{int i;for(i&#61;0;i<G.num;i&#43;&#43;){visit[i]&#61;0;}for(i&#61;0;i<G.num;i&#43;&#43;){if(!visit[i])DFS(G,i);}
}

三.广度优先搜索
具体思想&#xff1a;还是以房间为例&#xff0c;广度优先搜索是先把家里钥匙可能掉的地方找一遍&#xff0c;一步一步扩大面积去找&#xff0c;扩大查找范围&#xff0c;知道找到为止。广度优先搜索就类似与树的层序遍历。
邻接矩阵

void BFS&#xff08;MGraph G)
{int i,j;Queue Q;for(i&#61;0;i<G.num;i&#43;&#43;)//初始化全部没有访问visit[i]&#61;0;InitQueue(&Q);for(i&#61;0;i<G.num;i&#43;&#43;){if(!visit[i])//未访问进入{visit[i]&#61;1;printf("%c",g->data[i]);EnQueue(&Q,i);while(!QueueEmpty(Q)){DeQueue(&Q,&i);for(j&#61;0;j<G.num;j&#43;&#43;){if(G.map[i][j]&&!visit[j]){visit[j]&#61;1;printf("%c",G->data[j]);EmqQueue(%&Q,j);}}}}}
}

邻接表

void BFS&#xff08;MGraph G)
{int i;MGraph *p;Queue Q;for(i&#61;0;i<G.num;i&#43;&#43;){visit[i]&#61;0;}InitQueue(&Q);for(i&#61;0;i<G.num;i&#43;&#43;){if(!visit[i]){visit[i]&#61;1;printf("%c",G->ad[i].data);EnQueue(&Q,i);while(!QueueEmpty(Q)){DeQueue(&Q,&i);p&#61;G->ad[i].first;while(p){if(!visit[p->da]){visit[p->da]&#61;1;printf("%c",G->ad[p->da].data);EnQueue(&Q,p->da);}p&#61;p->next;}}}}
}


推荐阅读
  • 深入解析Linux下的I/O多路转接epoll技术
    本文深入解析了Linux下的I/O多路转接epoll技术,介绍了select和poll函数的问题,以及epoll函数的设计和优点。同时讲解了epoll函数的使用方法,包括epoll_create和epoll_ctl两个系统调用。 ... [详细]
  • 提升Python编程效率的十点建议
    本文介绍了提升Python编程效率的十点建议,包括不使用分号、选择合适的代码编辑器、遵循Python代码规范等。这些建议可以帮助开发者节省时间,提高编程效率。同时,还提供了相关参考链接供读者深入学习。 ... [详细]
  • JVM 学习总结(三)——对象存活判定算法的两种实现
    本文介绍了垃圾收集器在回收堆内存前确定对象存活的两种算法:引用计数算法和可达性分析算法。引用计数算法通过计数器判定对象是否存活,虽然简单高效,但无法解决循环引用的问题;可达性分析算法通过判断对象是否可达来确定存活对象,是主流的Java虚拟机内存管理算法。 ... [详细]
  • Go语言实现堆排序的详细教程
    本文主要介绍了Go语言实现堆排序的详细教程,包括大根堆的定义和完全二叉树的概念。通过图解和算法描述,详细介绍了堆排序的实现过程。堆排序是一种效率很高的排序算法,时间复杂度为O(nlgn)。阅读本文大约需要15分钟。 ... [详细]
  • Learning to Paint with Model-based Deep Reinforcement Learning
    本文介绍了一种基于模型的深度强化学习方法,通过结合神经渲染器,教机器像人类画家一样进行绘画。该方法能够生成笔画的坐标点、半径、透明度、颜色值等,以生成类似于给定目标图像的绘画。文章还讨论了该方法面临的挑战,包括绘制纹理丰富的图像等。通过对比实验的结果,作者证明了基于模型的深度强化学习方法相对于基于模型的DDPG和模型无关的DDPG方法的优势。该研究对于深度强化学习在绘画领域的应用具有重要意义。 ... [详细]
  • STL迭代器的种类及其功能介绍
    本文介绍了标准模板库(STL)定义的五种迭代器的种类和功能。通过图表展示了这几种迭代器之间的关系,并详细描述了各个迭代器的功能和使用方法。其中,输入迭代器用于从容器中读取元素,输出迭代器用于向容器中写入元素,正向迭代器是输入迭代器和输出迭代器的组合。本文的目的是帮助读者更好地理解STL迭代器的使用方法和特点。 ... [详细]
  • 生成式对抗网络模型综述摘要生成式对抗网络模型(GAN)是基于深度学习的一种强大的生成模型,可以应用于计算机视觉、自然语言处理、半监督学习等重要领域。生成式对抗网络 ... [详细]
  • 本文分享了一个关于在C#中使用异步代码的问题,作者在控制台中运行时代码正常工作,但在Windows窗体中却无法正常工作。作者尝试搜索局域网上的主机,但在窗体中计数器没有减少。文章提供了相关的代码和解决思路。 ... [详细]
  • LeetCode笔记:剑指Offer 41. 数据流中的中位数(Java、堆、优先队列、知识点)
    本文介绍了LeetCode剑指Offer 41题的解题思路和代码实现,主要涉及了Java中的优先队列和堆排序的知识点。优先队列是Queue接口的实现,可以对其中的元素进行排序,采用小顶堆的方式进行排序。本文还介绍了Java中queue的offer、poll、add、remove、element、peek等方法的区别和用法。 ... [详细]
  • 动态规划算法的基本步骤及最长递增子序列问题详解
    本文详细介绍了动态规划算法的基本步骤,包括划分阶段、选择状态、决策和状态转移方程,并以最长递增子序列问题为例进行了详细解析。动态规划算法的有效性依赖于问题本身所具有的最优子结构性质和子问题重叠性质。通过将子问题的解保存在一个表中,在以后尽可能多地利用这些子问题的解,从而提高算法的效率。 ... [详细]
  • 本文详细介绍了Java中vector的使用方法和相关知识,包括vector类的功能、构造方法和使用注意事项。通过使用vector类,可以方便地实现动态数组的功能,并且可以随意插入不同类型的对象,进行查找、插入和删除操作。这篇文章对于需要频繁进行查找、插入和删除操作的情况下,使用vector类是一个很好的选择。 ... [详细]
  • [大整数乘法] java代码实现
    本文介绍了使用java代码实现大整数乘法的过程,同时也涉及到大整数加法和大整数减法的计算方法。通过分治算法来提高计算效率,并对算法的时间复杂度进行了研究。详细代码实现请参考文章链接。 ... [详细]
  • 浏览器中的异常检测算法及其在深度学习中的应用
    本文介绍了在浏览器中进行异常检测的算法,包括统计学方法和机器学习方法,并探讨了异常检测在深度学习中的应用。异常检测在金融领域的信用卡欺诈、企业安全领域的非法入侵、IT运维中的设备维护时间点预测等方面具有广泛的应用。通过使用TensorFlow.js进行异常检测,可以实现对单变量和多变量异常的检测。统计学方法通过估计数据的分布概率来计算数据点的异常概率,而机器学习方法则通过训练数据来建立异常检测模型。 ... [详细]
  • 本文介绍了一道经典的状态压缩题目——关灯问题2,并提供了解决该问题的算法思路。通过使用二进制表示灯的状态,并枚举所有可能的状态,可以求解出最少按按钮的次数,从而将所有灯关掉。本文还对状压和位运算进行了解释,并指出了该方法的适用性和局限性。 ... [详细]
  • 面试经验分享:华为面试四轮电话面试、一轮笔试、一轮主管视频面试、一轮hr视频面试
    最近有朋友去华为面试,面试经历包括四轮电话面试、一轮笔试、一轮主管视频面试、一轮hr视频面试。80%的人都在第一轮电话面试中失败,因为缺乏基础知识。面试问题涉及 ... [详细]
author-avatar
呜呀002_107_284
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有