普林斯顿大学公开课 算法1-10:并检查集合-高速整合方法优化

本节介绍了高速综合优化算法。

重量的概念,每次操作的时候将重量小的部件挂在重量大的部件之下。

这样就避免了树形结构太高的问题。

下图展示了优化前后的树形结构深度的对照。

watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvY2FpcGVpY2hhbzI=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center" >

证明

能够证明每一个节点的深度最大为lgN。

  1. 由于每次合并的时候较小的部件要放在较大的部件之下,所以假设要添加树的高度。每次合并之后,树的大小至少要翻一番。
  2. 而N个节点最多仅仅能翻lgN番。

复杂度

这样的算法中合并操作最坏的复杂度为lgN,查询操作最坏情况的复杂度为lgN。

路径压缩

尽管眼下的算法已经可以保证复杂度在lgN下面。可是还有更好的方法。

基本想法就是在查找根节点时,将路径上的全部节点进行路径压缩。仅仅须要一行额外的代码。

使用路径压缩之后查询操作的复杂度是lg*N。lg*是第二种函数,表示的是lgN几次才干达到1。比方lg*16,须要三次lg,lg16=4,lg4=2,lg2=1,所以lg*16=3。

理论上来说查询操作的复杂度不是1,可是实际应用中,这样的算法的复杂度就是1。

结论

尽管现代的超级计算机速度非常快,可是好的算法能节省很多其它的时间。第一种高速查找算法解决一个问题须要30年时间,而如今有了更好的算法。解决相同的问题仅仅须要6秒。

所以,不要期望以后计算机速度快了算法就不须要了。算法是计算机的基础。它永远不会过时。

代码

public class UnionFind
{

    private int[]
id;

    private int[]
size;

    public UnionFind(int n)
{

        id
new int[n];

        size
new int[n];

        for(int i
0;
i < n; i++) {

            id[i]
= i;

            size[i]
1;

        }

    }

    public void union(int a, int b)
{

        int root_a
= root(a);

        int root_b
= root(b);

        if(root_a
== root_b) {

            return;

        }

        //
为了保持树的平衡

        if(size[root_a]
< size[root_b]) {

            id[root_a]
= id[root_b];

            size[root_b]
+= size[root_a];

        else {

            id[root_b]
= id[root_a];

            size[root_a]
+= size[root_b];

        }

    }

    public boolean connected(int a, int b)
{

        return root(a)
== root(b);

    }

    public int root(int x)
{

        while(x
!= id[x]) {

            id[x]
= id[id[x]]; 
//
路径压缩

            x
= id[x];

        }

        return x;

    }

}

版权声明:本文博主原创文章,博客,未经同意不得转载。

时间: 2024-10-17 19:49:17

普林斯顿大学公开课 算法1-10:并检查集合-高速整合方法优化的相关文章

普林斯顿公开课 算法1-9:并查集-高速合并

本节讲的是并查集的第二种实现方法.这样的方法的合并操作开销非常小,可是查找操作开销非常大. 数据结构 这样的算法的数据结构和高速查找方法的数据结构是一样的,也是N个整数组成的数组. 数组中每一个元素id[i]的含义是指i的上级是id[i]. 根节点 一个节点的根节点就是id[id[id[...id[i]....]]],一直循环直到数值不再变化为止.因为算法的特性,这样的循环永远不会造成死循环. 查找操作 查找操作就是推断两个节点的根节点是否同样. 合并操作 合并节点p和节点q就是将p节点的根节点

普林斯顿公开课 算法1-6:内存

讲完了算法的运行时间,现在讲一下关于算法的内存占用率. 内存单位 在计算机中,内存是通过字节来表示的,一个字节表示8个位.1KB是2^10字节. 数据类型占用的内存 在32位系统中,一个指针占用4个字节.在64位系统中一个指针占用8个字节.本课程中使用64位机器,一个指针占用8字节. 基本数据类型 以下是Java中基本数据类型占用的内存 boolean 1字节 byte 1字节 char 2字节 int 4字节 float 4字节 long 8字节 double 8字节 Java数组 Java中

普林斯顿公开课 算法1-10:并查集-优化的快速合并方法

应用 渗透问题 游戏中会用到. 动态连接 最近共同祖先 等价有限状态机 物理学Hoshen-Kopelman算法:就是对网格中的像素进行分块 Hinley-Milner多态类型推断 Kruskai最小生成树 Fortran等价语句编译 形态学开闭属性 Matlab中关于图像处理的bwlabel函数 渗透问题 一个N×N的矩阵,判断顶部和底部是否连通就是渗透问题. 下图中左侧的矩阵能渗透,右侧矩阵不能渗透. 渗透问题在电学.流体力学.社会交际中都有应用. 在游戏中可能需要生成一张地图,但是作为地图

普林斯顿公开课 算法1-11:并查集的应用

应用 渗透问题 游戏中会用到. 动态连接 最近共同祖先 等价有限状态机 物理学Hoshen-Kopelman算法:就是对网格中的像素进行分块 Hinley-Milner多态类型推断 Kruskai最小生成树 Fortran等价语句编译 形态学开闭属性 Matlab中关于图像处理的bwlabel函数 渗透问题 一个N×N的矩阵,判断顶部和底部是否连通就是渗透问题. 下图中左侧的矩阵能渗透,右侧矩阵不能渗透. 渗透问题在电学.流体力学.社会交际中都有应用. 在游戏中可能需要生成一张地图,但是作为地图

普林斯顿公开课 算法2-1:排序概述

目标 对所有类型的数据进行排序. 问题 排序函数如何知道比较的是哪种类型的数据呢? 回调函数 这时候就需要引入回调函数的概念了.回调函数就是将可执行的代码作为参数进行传递. 实现回调的方法 在Java中可以通过接口来实现,在C语言中可以通过函数指针来实现,C++中可以通过class-type functor,也就是重载操作符operator ()的类,在C#中可以使用Delegate委托,在Python/Perl/ML/javascript中可以直接传递函数. JDK中提供了Comparable

普林斯顿公开课 算法1-1:算法分析

为什么要分析算法 分析算法能够预測算法的性能,比較算法之间的优劣,保证算法的正确性,理解算法的理论基础. 成功算法的样例 离散傅立叶变换,假设使用暴力方法,那么算法的复杂度是是N^2,假设使用FFT高速傅立叶变换能够实现O(N logN)复杂度 N-body模拟:使用Barnes-hut算法能够将复杂度减少到N logN 顺便发一张N-body模拟的炫图 Barnes-Hut算法示意图 算法分析的步骤 观察问题的特征和想到得到的结果 依据观察结果提出如果 使用如果来预測可能发生的情况 检測预測结

普林斯顿公开课 算法1-2:观察

这章通过一个简单的例子,详细说明算法分析的步骤. 算法 问题 给定N个不同的整数,从中任意取出三个整数.请问有几种情况,使得取出的3个整数之和为0? 解法 可以使用暴力算法,代码如下: 1 2 3 4 5 6 7 8 9 for(int i=0;i<N;i++){     for(int j=0;j<N;j++){         for(int k=0;k<N;k++){             if(a[i]+b[i]+a[k]==0){                 count+

普林斯顿公开课 算法1-3:数学模型

本节主要通过建立数学模型,来计算算法的运行时间. 公式 算法的运行时间=所有操作的开销乘以操作的次数之和 开销 下表展示了各种操作所需要的时间(单位:纳秒) 整数加法 2.1 整数乘法 2.4 整数除法 5.4 浮点加法 4.6 浮点乘法 4.2 浮点除法 13.5 sin 91.3 arctan 129.0 举例 问题 计算数据中0的个数 代码 1 2 3 4 int count = 0; for (int i= 0; i < N; i++)     if (a[i] == 0)       

普林斯顿公开课 算法1-5:算法理论

本节主要讲解的是算法的复杂度. 算法性能 算法的性能分为三种: 最佳情况:计算时间最短的情况 最差情况:计算时间最长的情况 平均情况:随机输入的期望开销 以二分查找为例 最佳情况是1,因为第一次就有可能找到需要找的整数. 最差情况是logN 平均情况是logN 算法复杂度 算法复杂度用于定义问题的难度,另外也有助于开发最优化的算法,算法复杂度可以通过分析最坏情况来减少输入数据对算法性能的影响. 为了简化问题难度的表示方法,算法复杂度减少了算法分析的细节,忽略常数系数. 最优算法 所谓的最佳算法就