The problem that we consider is not a toy problem; it is a fundamental computational task, and the solution that we develop is of use in a variety of applications, from percolation in physical chemistry to connectivity in communications networks. We start with a simple solution, then seek to understand that solution’s performance characteristics, which help us to see how to improve the algorithm.
Dynamic connectivity We start with the following problem specification: The input is a sequence of pairs of integers, where each integer represents an object of some type and we are to interpret the pair p q as meaning "p is connected to q." We assume that "is connected to" is an equivalence relation, which means that it is:
■ Reflexive : p is connected to p.
■ Symmetric : If p is connected to q, then q is connected to p.
■ Transitive : If p is connected to q and q is connected to r, then p is connected to r.
An equivalence relation partitions the objects into equivalence classes. In this case, two objects are in the same equivalence class if and only if they are connected. Our goal is to write a program to filter out extraneous pairs (pairs where both objects are in the same equivalence class) from the sequence. In other words, when the program reads a pair p q from the input, it should write the pair to the output only if the pairs it has seen to that point do not imply that p is connected to q. If the previous pairs do imply that p is connected to q, then the program should ignore the pair p q and proceed to read in the next pair. The figure on the facing page gives an example of this process. To achieve the desired goal, we need to devise a data structure that can remember sufficient information about the pairs it has seen to be able to decide whether or not a new pair of objects is connected. Informally, we refer to the task of designing such a method as the dynamic connectivity problem. This problem arises applications such as the following:
Networks. The integers might represent computers in a large network, and the pairs might represent connections in the network. Then, our program determines whether we need to establish a new direct connection for p and q to be able to communicate or whether we can use existing connections to set up a communications path. Or, the integers might represent contact sites in an electrical circuit, and the pairs might represent wires connecting the sites. Or, the integers might represent people in a social network, and the pairs might represent friendships. In such applications, we might need to process millions of objects and billions of connections.
Variable-name equivalence. In certain programming environ- ments, it is possible to declare two variable names as being equivalent (references to the same object). After a sequence of such declarations, the system needs to be able to determine whether two given names are equivalent. This application is an early one (for the FORTRAN programming language) that motivated the development of the algorithms that we are about to consider.
Mathematical sets. On a more abstract level, you can think of the integers as belonging to mathematical sets. When we process a pair p q, we are asking whether they belong to the same set.If not, we unite p’s set and q’s set, putting them in the same set.
To specify the problem, we develop an API that encapsulates the basic operations that we need: initialize, add a connection between two sites, identify the component containing a site, determine whether two sites are in the same component, and count the number of components. Thus, we articulate the following API:
public class UF { public UF(int N) {} // initialize N sites with integer names (0 to N-1) void union(int p, int q) {} // add connection between p and q int find(int p) {} // component identifier for p (0 to N-1) // return true if p and q are in the same component boolean connected(int p, int q) {} int count() {} // number of components }
The union() operation merges two components if the two sites are in different com- ponents, the find() operation returns an integer component identifier for a given site, the connected() operation determines whether two sites are in the same component, and the count() method returns the number of components. We start with N components, and each union() that merges two different components decrements the number of components by 1.
public class UF { private int[] id; // id[i] = parent of i private int[] sz; // sz[i] = number of objects in subtree rooted at i private int count; // number of components /** * Create an empty union find data structure with N isolated sets. * * @throws java.lang.IllegalArgumentException * if N < 0 */ public UF(int N) { if (N < 0) throw new IllegalArgumentException(); count = N; id = new int[N]; sz = new int[N]; for (int i = 0; i < N; i++) { id[i] = i; sz[i] = 1; } } /** * Return the id of component corresponding to object p. * * @throws java.lang.IndexOutOfBoundsException * unless 0 <= p < N */ public int find(int p) { if (p < 0 || p >= id.length) throw new IndexOutOfBoundsException(); while (p != id[p]) { p = id[p]; } return p; } /** * Return the number of disjoint sets. */ public int count() { return count; } /** * Are objects p and q in the same set? * * @throws java.lang.IndexOutOfBoundsException * unless both 0 <= p < N and 0 <= q < N */ public boolean connected(int p, int q) { return find(p) == find(q); } /** * Replace sets containing p and q with their union. * * @throws java.lang.IndexOutOfBoundsException * unless both 0 <= p < N and 0 <= q < N */ public void union(int p, int q) { int i = find(p); int j = find(q); if (i == j) return; // make smaller root point to larger one if (sz[i] < sz[j]) { id[i] = j; sz[j] += sz[i]; } else { id[j] = i; sz[i] += sz[j]; } count--; } }
Analysis of complexity:
相关推荐
数据结构、算法相关的资源 数据结构、算法相关的资源 数据结构、算法相关的资源 数据结构、算法相关的资源 数据结构、算法相关的资源 数据结构、算法相关的资源 数据结构、算法相关的资源 数据结构、算法相关的资源 ...
总之,《数据结构基本算法大全》Word版是一本难得的算法学习资料,它系统地介绍了数据结构和算法的核心知识,使得读者能够通过这些具体算法的学习,深化对计算机科学基础的理解,提升解决实际问题的能力。...
**UnionFind算法**,也称为并查集算法,是一种用于解决动态连通性问题的数据结构。该算法主要用于判断图中的两个节点是否属于同一个连通分量,并且可以高效地合并不同的连通分量。UnionFind算法在多种场景下都有广泛...
并查集是一种用于处理不相交集合操作的数据结构,它主要包含两个基本操作:查找(Find)和合并(Union)。在并查集中,通常用森林的结构来表示各个集合,每棵树代表一个集合,树的根节点代表集合的标识。 **查找...
在“西安电子科技大学网络与继续教育学院数据结构与算法全真试题”中,我们可以期待涵盖一系列关键概念和技能的测试题目,这些题目可能涉及到以下几个方面: 1. **基本数据结构**:包括数组、链表、栈、队列、哈希...
数据结构与算法是计算机科学的基础,对于理解和设计高效的软件至关重要。在这个标题为“数据结构及其算法详细”的资源中,我们可预见到它将全面深入地探讨这个领域,如同一本字典,提供了丰富的知识和信息。 首先,...
Union-Find数据结构是一种特殊的数据结构,用于管理一组不相交的集合(Disjoint-sets),支持三个基本操作:MAKE-SET、FIND和UNION。这种数据结构广泛应用于解决动态连通性问题,例如图形算法、编译器设计等领域。 ...
数据结构和算法是计算机科学的基础,对于理解和解决复杂问题至关重要。这个标程库提供了C/C++语言实现的主要数据结构和算法,涵盖了多个重要的计算概念。下面将详细解释这些知识点: 1. 高精度计算:在C和C++中实现...
本资源总共涵盖了12个知识点,涵盖了数据结构和算法的基础知识,涵盖了栈、二维矩阵、直方图、链表、LRU Cache、并查集、岛屿个数、树、二叉树前序、中序、后序遍历、二分查找树、AVL树和红黑树等知识点。
- `class UnionFind`:自定义的并查集类,包括 `find()`(查找顶点所属集合的根节点)和 `unionSet()`(合并两个集合)等方法。 - `void kruskalMST()`:Kruskal算法的主要函数,进行上述步骤。 在代码设计和变量...
根据给定文件的信息,我们可以提炼出以下IT领域的关键知识点,主要围绕...这些算法不仅展示了数据结构和算法设计的基本原理,也是解决实际问题的有效工具。理解并掌握它们,对于提升编程能力和解决复杂问题至关重要。
算法与数据结构是计算机科学的基础,它们是解决问题的核心工具。本课程为初学者提供了全面的入门知识,涵盖了从基础...通过这个课程,初学者将掌握一系列基础和进阶的算法与数据结构,为解决实际编程问题打下坚实基础。
数据结构算法实现(严蔚敏版配套实现程序) 1.1 数组和字符串 2 1.1.1 一维数组的倒置 2 范例1-1 一维数组的倒置 2 ∷相关函数:fun函数 1.1.2 一维数组应用 3 范例1-2 一维数组应用 3 1.1.3 一维数组的高级应用 5 ...
### ACM程序设计常用算法与数据结构知识点概览 #### 排序算法 在计算机科学领域,排序算法是解决数据组织的...以上列举的算法和数据结构是ACM程序设计竞赛中常用的工具和技术,掌握它们能够帮助参赛者更好地解决问题。
数据结构课程设计中的Kruskal算法是图论领域的一个重要概念,主要应用于寻找图的最小生成树。在本课程设计中,我们利用...通过这样的课程设计,学生可以提高对数据结构和算法的理解,为未来的学习和工作奠定坚实基础。
在这个实验中,我们探讨了“渗透问题(Percolation)”,这是一个使用数据结构和算法解决的问题。实验主要涉及了以下知识点: 1. **合并-查找(Union-Find)数据结构**:这是解决渗透问题的关键。在这个问题中,...