《Algorithms in C++》学习之连通性问题

连通性问题是《Algorithms in C++》讲述的第一个问题,目的是为了通过这个问题,来说明学习、分析、设计算法的一般过程,而我写这篇文章主要是为了整理思路,留下资料,加深理解。

一、问题描述

概念:和图论中的连通性概念一样,两点直接相连则连通,连通具有传递性,a-b,b-c=>a-c。则两点间接相连也连通。

假设:图G有N个顶点,顶点编号从0到N-1。

输入:M组数据,每组数据由两个整数对组成,写为(p,q),1<=p,q<=N,表示顶点p和顶点q之间有一条边。

输出:如果(p,q)之前没有连通,则在图G中增加一条连接这两个点的边,然后输出。

            如果(p,q)之前就连通,则不做任何事。

如图所示:N为10,第一列为每次读入的整数对(p,q),如果p,q之前没有连通,则在第二列中打印出此整数对,并在图G中加入一条连通p,q的边。如果p,q之前已经连通,则第三列打印出从p到q的一条路。



二、基本算法之快速查找

{CSDN:CODE:65856}

2.1 处理思路

用到了图中连通分量的概念,如下图所示,N为10,定义一个数组cc[N]记录顶点属于哪个连通分量,连通分量用分量内部的一个顶点号来表示,初始化为cc[i]=i;0<=i<=9,也就是每个顶点都属于一个只包含自己的连通分量。

对每个整数对(p,q),分别查找p和q所属的连通分量。

如果两者属于同一个连通分量,则表示p,q之前就连通,不做任何事。 

如果两者属于不同的连通分量,则表示p,q之前不连通,所以在p,q中加入一条边,使得两个连通分量合并为一个。

2.2 保存的数据及说明

数据保存是说我们记录了图G的什么信息?显然我们并没有记录图G的完整信息,因为N个顶点的无向图,至少需要N(N-1)/2个存储单位来保存所有边的信息,而我们只用到了cc[N],只保存了每一个顶点所属的连通分量的信息,而且根据2.1中描述,很容易根据cc[N]的信息来解决连通性问题,如果采用的是传统的图的表示方式,记录边的信息,反而在解决连通性问题的时候,不是那么直接。

所以在为一个问题设计算法的时候,(先?)要考虑需要保存问题的什么信息,往往这些信息和问题的本质联系紧密,我们要保存下来,用于实现算法。虽然连通性这个问题是图论中的概念,采用图的传统的表示方式貌似合情合理。但是上面的分析告诉我们,只维护一个记录连通性的数组cc[N],使得算法在时间、空间上都有更好的表现,思路也更加的清晰。(也就是大的类别概念-图论中的连通性,可以帮助我们更深刻的理解问题,但是在理解了问题之后,不一定非得用图的数据结构来解决问题)

2.3 抽象操作

查找:数据结构用的是数组,所以查找十分简单,O(1)时间完成。

合并:顶点p,q分别属于连通分量m,n,合并操作要将连通分量m和n合并成一个连通分量m(或者n),所以要遍历所有顶点,O(N)时间完成。

2.4 效率分析

显然时间复杂度为O(MN)。

2.5 一个重要的问题

图论中有一个定理,每个连通图G都有:边数>=顶点数减一。

在上面的问题中,边数为M,顶点数为N。每次输出一个整数对(q,p)都表示在图G中加入一条‘新’的边,可以证明,当向图G中加入了N-1条边后,图G就成为连通图,所以之后的整数对都是连通的,不用再判断。

这就是一个典型的例子,如果待解决的问题涉及到某个领域,往往这个领域里面的一两个结论可以为算法的设计提供很大的方便。所以码农要学的实在不嫌多······


三、基本算法之快速合并

{CSDN:CODE:65854}

3.1 基本思路

一样的数据结构,不一样的‘解释’。保存的信息一样,但是保存信息的方式的不一样。处理思路不变,但是具体的处理过程不一样。

cc[N]现在的‘意思’改变了。在快速查找算法中,cc[N]从始至终都保存了顶点i所属的连通分量,所以使得查找操作变的很简单,但是合并两个连通分量的时候,要遍历所有的顶点,使得合并操作稍嫌复杂。

现在,给出cc[N]的另一种解释,cc[N]的值只有在和顶点的编号相等的时候cc[i]==i,才表示所属的连通分量。比如初始化的时候就设置所有的顶点为cc[i]=I,表示每个顶点都属于一个只包含自己的连通分量。当cc[i]的值为j(j!=i)的时候,j是一个顶点的编号,表示i所属的连通分量和j所属的连通分量相同,要继续查看cc[j]的值,直到顶点编号和cc[顶点编号]的值相等的时候,才能确定i所属的连通分量。


3.2  抽象操作

查找操作:对每一个整数对(p,q),分别查询cc[p],cc[q],直到顶点编号i满足cc[i]==i,每次查找迭代过程从1此到N-1次不等,具体的次数如何确定参看后文。

合并操作:十分简单,设cc[p]的查找的终点为顶点m,cc[q]查找的终点为n,cc[m]=m.cc[n]=n,且m!=n,合并只需要将cc[m]=n即可。(能不能是cc[n]=m?两者有什么区别?这会影响程序的时间复杂度,具体分析参看后文。)


3.3 保存的数据及解释

下图是对上文例子的操作,从图中可以很直接的看出,虽然我们采用的是数组这个数据结构,但是在逻辑层面,是由树构成的。

输入第一个整数对(3,4),cc[3]=3,cc[4]=4,顶点3、4不属于同一个连通分量,则执行cc[3]=4.则第3号顶点,就成了叶子结点,以后对3号顶点的查找操作都要一层一层向上,直到跟结点。

3.4 效率分析

显然这个快速合并算法的时间复杂度要比快速查找算法快,因为每次查找的时候并不需要遍历所有的cc[N],但是快多少呢?等学到后面再来解答。


四、快速合并算法的改进版本-带权重的快速合并

{CSDN:CODE:65860}

4.1 基本思想

如果你对树这个数据结构有一定的了解,你肯定会知道这个数据结构很犀利,比如红黑树,可以在ln(n)的时间存取数据,为什么?因为平衡的力量,这也就是树->二叉树->平衡二叉树出现的原因。快速合并算法合并操作非常快,但是查找操作偏慢,原因就是在查找一个顶点的连通分量时,要从树的叶子结点一级一级的向上找,直到找到根结点(cc[i]==i),所以,如果我们可以在合并的时候,把树的高度考虑进去,尽量的降低树的高度,那么自然就使得查找的步数减少,效率提高。如果看到这里还不明白,那么就去草稿纸上去手动跟踪快速合并算法以及快速合并算法的改进版本,用这样的输入做测试:N=6,整数对分别为(1,2)(2,3)(3,4)(4,5)(1,5)(1,5).....画出两者形成的连通分量数组的逻辑结构‘树’,观察树的高度,一定会恍然大悟。

4.2 效率分析

改进版本的快速合并算法,在进行合并操作的时候,都是将一颗短树,合并成为长树的子树,所以如果每次合并的时候,两颗树的长度相等,则算法的效率最差,设图有2的N次方个结点,则每个cc[i]的深度为N=ln(2的N次方),则显然这个算法的时间复杂度为M*ln(N),已经是一个相当好的算法了。

4.3 路径压缩
带权重的快速合并算法已经很好的缩短了树的深度,但是仔细考虑之后,仍然是可以继续的缩短树的深度。
在进行查证操作的时候,我们可以一边找,一边把当前的树结点上升一层,即把代码改为:
for(i=p;i!=cc[i];i=cc[i])
cc[i]=cc[cc[i]];
但是一定记住,这样的优化并没有改变算法的时间复杂度的数量级,到底优化了多少,在理论在是比较难计算的,实际中可能影响也不多,所以对于这种优化,了解思想很重要,但是不一定说每次实际应用的时候就要使用。




Robert Sedgewick has thoroughly rewritten and substantially expanded and updated his popular work to provide current and comprehensive coverage of important algorithms and data structures. Christopher Van Wyk and Sedgewick have developed new C++ implementations that both express the methods in a concise and direct manner, and also provide programmers with the practical means to test them on real applications. Many new algorithms are presented, and the explanations of each algorithm are much more detailed than in previous editions. A new text design and detailed, innovative figures, with accompanying commentary, greatly enhance the presentation. The third edition retains the successful blend of theory and practice that has made Sedgewick's work an invaluable resource for more than 250,000 programmers! This particular book, Parts 1n4, represents the essential first half of Sedgewick's complete work. It provides extensive coverage of fundamental data structures and algorithms for sorting, searching, and related applications. Although the substance of the book applies to programming in any language, the implementations by Van Wyk and Sedgewick also exploit the natural match between C++ classes and ADT implementations. Highlights * Expanded coverage of arrays, linked lists, strings, trees, and other basic data structures * Greater emphasis on abstract data types (ADTs), modular programming, object-oriented programming, and C++ classes than in previous editions * Over 100 algorithms for sorting, selection, priority queue ADT implementations, and symbol table ADT (searching) implementations * New implementations of binomial queues, multiway radix sorting, randomized BSTs, splay trees, skip lists, multiway tries, B trees, extendible hashing, and much more * Increased quantitative information about the algorithms, giving you a basis for comparing them * Over 1000 new exercises to help you learn the properties of algorithms Whether you are learning the algorithms for the first time or wish to have up-to-date reference material that incorporates new programming styles with classic and new algorithms, you will find a wealth of useful information in this book.
《算法:C语言实现(第1-4部分)基础知识、数据结构、排序及搜索(原书第3版)》细腻讲解计算机算法的C语言实现。全书分为四部分,共16章。包括基本算法分析原理,基本数据结构、抽象数据结构、递归和树等数据结构知识,选择排序、插入排序、冒泡排序、希尔排序、快速排序方法、归并和归并排序方法、优先队列与堆排序方法、基数排序方法以及特殊用途的排序方法,并比较了各种排序方法的性能特征,在进一步讲解符号表、树等抽象数据类型的基础上,重点讨论散列方法、基数搜索以及外部搜索方法。书中提供了用C语言描述的完整算法源程序,并且配有丰富的插图和练习,还包含大量简洁的实现将理论和实践成功地相结合,这些实现均可用在真实应用上。 《算法:C语言实现(第5部分)图算法(原书第3版)》是深入论述算法的三卷本教程《算法:C语言实现》(第3版)中的第二卷——图算法。作者在这次修订中重写了许多内容,增加了数千个新练习、数百个新图表、数十个新程序,并对图表和程序做了详尽的注释说明。新版中不仅涵盖了新的主题,而且还提供了对许多经典算法的更充分的解释,包括图的性质、图搜索、有向图、最小生成树、最短路径和网。《算法:C语言实现(第5部分)图算法(原书第3版)》涵盖了足够的基本内容及较详细的图算法高级主题,既可单独用作数据结构与算法课程的教材,也可与第一卷(第1~4部分)结合使用。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值