算法第四版的一些小问题

union-find算法用于检测动态连通性,例如计算机网络中的两个节点是否连通,在一个特定圈子里的两个人是否有间接的朋友关系,等等。

quick-find算法是union-find算法的众多实现中最简单也最没有效率的一种,它的主要实现如下:

public int find(int p) {
  return id[p];
}
 
public void union(int p, int q) {
  // 查找点 p 和点 q 在id数组中的值,从而可以接着判断它们是否在相同的连通分量中
  int pID = find(p);
  int qID = find(q);
 
  // p, q已经在相同的分量中,无需任何操作
  if (pID == qID) {
    return;
  }
 
  // 执行到这里,说明 p 和 q 不在相同的分量中,因此需要把它们进行归并,在这里,是把 p 所在的分量里的所有元素全部重命名为 q 所在的分量里的名称(唯一)
  for (int i = 0; i < id.length; i++) {
    if (id[i] == pID) {
      id[i] = qID;
    }
  }
  count--;
}

find() 函数用于查找一个点 p 的名称;union() 函数用于归并两个点 p 和 q,如果它们已经在同一个连通分量里,那么不会产生任何归并效果。

之所以把这种算法叫quick-find,是因为它的 find() 操作很快,只需要访问id数组一次;但是quick-find的 union() 操作却很慢,因为它需要访问整个id数组。

事实上,union() 访问数组的次数,至少是 N+3,至多是 2N+1,其中N是点的个数。

这是怎么算出来的呢?下面来看一下。

union() 函数一开始的两个 find() 操作无论如何是逃不掉的,所以这里至少就访问了 2 次id数组。

而 if (pID == qID) 这一句,没有对数组进行任何访问,因此,最后的for循环应该是至少访问了 N+1 次数组,但这又是怎么算出来的呢?

i 从 0 循环到 id.length(即N),共执行了N次,所以for循环里的if语句一定会执行N次,所以数组访问至少会有N次,那么还差1次,是怎么来的呢?

由于一定有一个 i 使得 id[i] == pID 成立(也就是p所在的那个分量),所以 id[i] == qID 至少会被执行一次,所以for循环访问数组的次数就至少是 N+1 次了。在这种情况下,所有id数组中,只有一个元素是与p处于同一连通分量的(其实也就是p这一个,或者说,p很“孤独”),它会被合并到q所在的连通分量中。

那么union() 访问数组的次数,最多是 2N+1,这又是怎么算出来的呢?

当id数组中,除了q之外,其他所有元素都与p处于同一连通分量中的话,那么,if (id[i] == pID) 这个条件就会成立 N-1 次,这意味着 id[i] = qID 会被执行 N-1 次,而N次 if 判断无论如何都是会被执行的,所以for循环里访问数组的次数是 N+N-1=2N-1 次,另外前面说了,union()函数中两个find()操作是免不了的,所以还要再加2次,总共是 2N-1+2=2N+1 次。

因此,union()访问数组的次数在 N+3 到 2N+1 之间。

如果所有的 N 个分量其实都在一个连通分量中,那么在解这个union-find问题的时候,就要调用 N-1 次union()函数,则需要访问数组的次数至少是 (N+3)(N-1) 次,即等价于 N^2 次的复杂度。

于是得证。

文章来源:http://www.codelast.com/

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
本书带完整书签 第1章 基础 1 1.1 基础编程模型 4 1.1.1 Java程序的基本结构 4 1.1.2 原始数据类塑与表达式 6 1.1.3 语句 8 1.1.4 简便记法 9 1.1.5 数组 10 1.1.6 静态方法 12 1.1.7 API 16 1.1.8 字符串 20 1.1.9 输入输出 21 1.1.10 二分査找 28 1.1.11 展望 30 1.2 数据抽象 38 1.2.1 使用抽象数据类型 38 1.2.2 抽象数据类型举例 45 1.2.3 抽象教据类型的实现 52 1.2.4 更多抽象数据类型的实现 55 1.2.5 数据类型的设计 60 1.3 背包、队列和栈 74 1.3.1 API 74 1.3.2 集合类數据类型的实现 81 1.3.3 链表 89 1.3.4 综述 98 1.4 算法分析 108 1.4.1 科学方法 108 1.4.2 观察 108 1.4.3 数学模型 112 1.4.4 增长数量级的分类 117 1.4.5 设计更快的算法 118 1.4.6 倍率实验 121 1.4.7 注意事项 123 1.4.8 处理对于输入的依赖 124 1.4.9 内存 126 1.4.10 展望 129 1.5 案例研究:union-find算法 136 1.5.1 动态连通性 136 1.5.2 实现 140 1.5.3 展望 148 第2章 排序 152 2.1 初级排序算法 153 2.1.1 游戏规则 153 2.1.2 选择排序 155 2.1.3 插入排序 157 2.1.4 排序算法的可视化 159 2.1.5 比较两种排序算法 159 2.1.6 希尔排序 162 2.2 归并排序 170 2.2.1 原地归并的抽象方法 170 2.2.2 自顶向下的归并排序 171 2.2.3 自底向上的归并排序 175 2.2.4 排序算法的复杂度 177 2.3 快速排序 182 2.3.1 基本算法 182 2.3.2 性能特点 185 2.3.3 算法改进 187 2.4 优先队列 195 2.4.1 API 195 2.4.2 初级实现 197 2.4.3 堆的定义 198 2.4.4 堆的算法 199 2.4.5 堆排序 205 2.5 应用 214 2.5.1 将各种數据排序 214 2.5.2 我应该使用啷种排序算法 218 2.5.3 问题的归约 219 2.5.4 排序应用一览 221 第3章查找 227 3.1 符号表 228 3.1.1 API 228 3.1.2 有序符号表 230 3.1.3 用例举例 233 3.1.4 无序链表中的顺序查找 235 3.1.5 有序數组中的二分查找 238 3.1.6 对二分査找的分析 242 3.1.7 预览 244 3.2 二叉查找树 250 3.2.1 基本实现 250 3.2.2 分析 255 3.2.3 有序性相关的方法与删除操作 257 3.3 平衡査找树 269 3.3.1 2-3査找树 269 3.3.2 红黑二叉查找树 275 3.3.3 实现 280 3.3.4 删除操作 282 3.3.5 红黑树的性质 284 3.4 散列表 293 3.4.1 散列函数 293 3.4.2 基于拉链法的散列表 297 3.4.3 基于线性探测法的散列表 300 3.4.4 调整教组大小 304 3.4.5 内存使用 306 3.5 应用 312 3.5.1 我应该使用符号表的哪种实现 312 3.5.2 集合的API 313 3.5.3 字典类用例 315 3.5.4 索引类用例 318 3.5.5 稀疏向量 322 第4章 图 329 4.1 无向图 331 4.1.1 术语表 331 4.1.2 表示无向图的数据类型 333 4.1.3 深度优先搜索 338 4.1.4 寻找路径 342 4.1.5 广度优先搜索 344 4.1.6 连通分量 349 4.1.7 符号图 352 4.1.8 总结 358 4.2 有向图 364 4.2.1 术语 364 4.2.2 有向图的数据类型 365 4.2.3 有向图中的可达性 367 4.2.4 环和有向无环图 369 4.2.5 有向图中的强连通性 378 4.2.6 总结 385 4.3 最小生成树 390 4.3.1 原理- 391 4.3.2 加权无向图的数据类型 393 4.3.3 最小生成树的API和测试用例 396 4.3.4 Prim算法 398 4.3.5 Prim算法的即时实现 401 4.3.6 Kruskal算法 404 4.3.7 展望 407 4.4 最短路径 412 4.4.1 最短路径的性质 413 4.4.2 加权有向图的数据结构 414 4.4.3 最短路径算法的理论基础 420 4.4.4 Dijkstra算法 421 4.4.5 无环加权有向图中的最短路径算法 425 4.4.6 一般加权有向图中的最短路径问题 433 4.4.7 展望 445 第5章 字符串 451 5.1 字符串排序 455 5.1.1 键索引计数法 455 5.1.2 低位优先的字符串排序 458 5.1.3 高位优先的字符串排序 461 5.1.4 三向字符串快速排序 467 5.1.5 字符串排序算法的选择 470 5.2 单词查找树 474 5.2.1 单词查找树 475 5.2.2 单词查找树的性质 483 5.2.3 三向单词查找树 485 5.2.4 三向单词查找树的性质 487 5.2.5 应该使用字符串符号表的哪种实现 489 5.3 子字符串查找 493 5.3.1 历史简介 493 5.3.2 暴力子字符串査找算法 494 5.3.3 Knuth-Morris-Pratt子字符串查找算法 496 5.3.4 Boyer-Moore字符串查找算法 502 5.3.5 Rabin-Karp指纹字符串查找算法 505 5.3.6 总结 509 5.4 正则表达式 514 5.4.1 使用正则表达式描述模式 514 5.4.2 缩略写法 516 5.4.3 正则表达式的实际应用 517 5.4.4 非确定有限状态自动机 518 5.4.5 模拟NFA的运行 520 5.4.6 构造与正则表达式对应的NFA 522 5.5 数据压缩 529 5.5.1 游戏规则 529 5.5.2 读写二进制数据 530 5.5.3 局限 533 5.5.4 热身运动:基因组 534 5.5.5 游程编码 537 5.5.6 霍夫曼压缩 540 第6章背景 558 索引 611

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值