来自普林斯顿大学 的 Coursera 课程《算法,第一部分》 ,课程地址:https://www.coursera.org/course/algs4partI

第一周的内容是 Union-Find算法和算法分析两个部分,这一篇只总结Union-Find。

问题描述:

有N个元素,从 0 ~ N-1 编号,假设用通路表示元素之间的连接,当执行多次任意两个元素的连接之后,如何判断某两个元素是否能够通过已有路径相连通。连接的动作我们称之为 union,判断两元素是否相连的操作称之为 find,类比下图:

从图上可以看出,0, 1, 2, 5, 6, 7 中任意两个元素都是相连的,同样 3, 4, 8, 9 中任意两个元素也是互连的,但是第一个集合和第二个集合的元素却是无法连通的。

实际操作中可用于在一个庞大的网路环境下,如何迅速判断某两个点是否相连,如下图:

开发有效算法的步骤:

1) 构建模型
2) 寻找算法
3) 方法的效率和内存使用
4) 效率差,内存使用率高,找出问题的原因所在
5) 寻找解决方法重复3

首先确认 union 和 find 操作应该满足什么样的条件:

find操作:确认两个对象是否连接:
a. p连接到q
b. p连接到q,则q也连接到p
c. p连接到q,q连接到r,则p也连接到r
union操作:连接在一起的对象,我们统称为一个连接集合,执行一次union操作就相当于将两个对象所在的集合连接到一起,组成一个新的集合。新集合中的任意两个成员也应该都处于连接状态。

然后寻找合适的算法:

演示三种算法,循序渐进,展示算法的优化过程

原课程是采用 Java,在这里我将 Java 的实现修改为 C 实现。

(1)Quick-find

数据结构:采用简单的一维数组。

struct qf {int*    qf_array;int     count;
};

算法描述:当且仅当p和q具有相同的ID,则p和q处于连接状态
find:     查看两个数组成员是否具有相同ID
union: 将所有和 id[p] 相同 ID 值的数组成员的值,全部转换为 id[q] 的ID值。

图示算法的效果:

算法实现:

int qf_union(QuickFind qf, int p, int q)
{int i, pid, qid;pid = qf->qf_array[p];qid = qf->qf_array[q];for (i = 0; i < qf->count; i++)if (qf->qf_array[i] == pid)qf->qf_array[i] = qid;return 0;
}int qf_connected(QuickFind qf, int p, int q)
{return qf->qf_array[p] == qf->qf_array[q];
}

算法效率:
        a. 初始化:N
        b.  union:N
        c.  find:1

算法总结:
Quick-find 有一个很严重的问题,对 N 个元素执行 N 次 union 操作,数组访问次数就是 N^2 次,当N变得很大的时候,效率会很差。

(2)Quick-Union

数据结构:采用和 Quick-find 一样简单的一维数组

struct qu {int*    qu_array;int     count;
};

算法描述:若p和q具有相同的根元素,则p和q 处于连接状态。根元素的标识为 id[p] = p
find:     查看p和q是否具有相同的根元素
union: 将p的根元素修改为q的根元素

算法实现图示:

算法实现:

static int root(QuickUnion qu, int i)
{while (qu->qu_array[i] != i)i = qu->qu_array[i];return i;
}int qu_union(QuickUnion qu, int p, int q)
{int proot, qroot;proot = root(qu, p);qroot = root(qu, q);qu->qu_array[proot] = qroot;return 0;
}int qu_connected(QuickUnion qu, int p, int q)
{return root(qu, p) == root(qu, q);
}

算法效率:初始化、union和find均为N的操作

算法总结:

Quick-Union 算法对 union 操作进行了优化,即使是对 N 个元素执行 N 次 union,数组的访问次数最多也是 N。但是 union 和 find 都会从节点遍历到根元素,如果每次的 union 操作都是将一个大树的根元素连接到另一个只有单一元素(也就是自己本身就是根元素)的树,那么很容易出现“高树”的现象。最差的时候,两个都会是 N 的操作。

(3)Weighted-Quick-Union

数据结构:N个元素的一维数组,加上辅助的树大小的数组。

struct qu {int*    qu_array;int*    size;int     count;
};

算法描述:在Quick-union的基础上加以修改,记录树的大小,总是将较小树的根连接到较大树的根,避免出现“高树”现象
find:    查看p和q是否具有相同的根
union: 在Quick-union的基础上,加入一个记录树大小的数组,保证每次都是小树根连接到大树根上

算法实现图示:

算法实现(find和Quick-Union一样,只演示 union 操作):

int qu_union(QuickUnion qu, int p, int q)
{int proot, qroot;proot = root(qu, p);qroot = root(qu, q);if (qu->size[proot] < qu->size[qroot]) {qu->qu_array[proot] = qu->qu_array[qroot];qu->size[qroot] += qu->size[proot];} else {qu->qu_array[qroot] = qu->qu_array[proot];qu->size[proot] += qu->size[qroot];}return 0;
}

算法效率:初始化:2N,union:已知根元素的情况下,效率为恒定值,find:与树的深度成正比,但是树的深度最大也只是lgN(证明过程略)。因此最差的情况下,union和find也都是 lgN。

不过 Weighted-Quick-Union 还可以继续改进,压缩从某一个节点到根的路径,将树进行更为平坦的伸展:

把查找根元素 root 的实现进行优化,实现方式有两种:
a. 增加一个for循环,将从某个节点到根节点路上的所有节点都直接连接到根节点
b. 将路径上每个节点的爷爷节点连接到根节点,只将路径减半

以 b 为例,修改 root 的操作如下:

static int root(QuickUnion qu, int i)
{while (qu->qu_array[i] != i) {qu->qu_array[i] = qu->qu_array[qu->qu_array[i]];i = qu->qu_array[i];}return i;
}

这样每次 root 执行之后,路径都会减半,加快查找效率。

算法效率的演示在下篇总结。

普林斯顿大学算法第一周个人总结1相关推荐

  1. 普林斯顿大学算法公开课笔记

    第一章 Union-Find 01 Dynamic connectivity (动态连接性问题即 the model of union find 并查集模型) 问题: a set of N objec ...

  2. 普林斯顿大学算法课 Algorithm Part I Week 3 自我总结

    要熟练掌握比较器Comparator public final Comparator<T> MY_COMPARATOR = new myComparator(); //定义比较器 .... ...

  3. Coursera普林斯顿大学算法下Week4:Boggle 拼字游戏

    任务链接:http://coursera.cs.princeton.edu/algs4/assignments/boggle.html 这次任务给的需要实现的方法很少,完成本次任务关键在于理清思路,需 ...

  4. 「数据结构」普林斯顿算法课第一周作业

    「数据结构」普林斯顿算法课第一周作业 Algorithm I, Princeton 编程作业: Percolation 思路 第一部分代码展示 第二部分代码展示 编程作业: Percolation P ...

  5. 3目标检测的准确率_吊打YOLOv3!普林斯顿大学提出:CornerNetLite,基于关键点的实时且精度高的目标检测算法,已开源!...

    点击上方"CVer",选择"星标"和"置顶" 重磅干货,第一时间送达 前戏 最近目标检测方向,出了很多很棒的paper,CVer也立即跟进报 ...

  6. 腾讯广告算法大赛 | 复赛第一周周冠军心得分享

    腾讯广告算法大赛 | 复赛第一周周冠军心得分享 腾讯广告算法大赛复赛第一周周冠军揭晓, 熟悉的队伍,熟悉的配方! 没错,依然是你们熟悉的葛文强团队! 今天,他们将对FFM方法进行详细介绍. 小板凳儿排 ...

  7. 中国大学MOOC课程《Python语言程序设计》课后练习第一周

    中国大学MOOC课程<Python语言程序设计>课后练习第一周 1.字符串拼接 python从2.6版本后增加了format函数,用来代替%s,%r等格式化字符串: # -*- codin ...

  8. 【采访】腾讯社交广告高校算法大赛第一周周冠军——郭达雅 比赛经验及心得分享

    [采访]腾讯社交广告高校算法大赛第一周周冠军--郭达雅 比赛经验及心得分享 经过一周紧张又激烈的角逐 腾讯社交广告高校算法大赛产生了第一位周冠军 他的名字叫郭达雅 一个腼腆沉静的小男孩 低调的实力派, ...

  9. 第一周周冠军带你解析赛题,尝试广告算法新思路

    经过激烈的竞争,2019腾讯广告算法大赛迎来初赛第一周的周冠军.他的名字叫储灿,一个谦虚认真的男孩.作为广告算法界的一颗新星,他对于大赛又有着怎样的独到见解呢?搬好板凳,一大波干货内容即将来袭! 大家 ...

最新文章

  1. acm经典题Mark
  2. 基于uPC1677C射频功率放大
  3. php 跳转网页 变量,php变量与JS变量实现不通过跳转直接交互的方法
  4. 『PaddlePaddle X Wechaty』有颜又有才的Living_Bot
  5. 深入浅出讲解C语言#define宏定义应用及使用方法
  6. 使用BusyBox制作嵌入式Linux根文件系统
  7. app抢购脚本如何编写_如何用1个记事本文件征服全世界?——cmd批处理脚本编写...
  8. 2013吉林通化邀请赛 1004 D-City 并查集求连通分支数
  9. 推荐一个不错的plist拆解工具,untp
  10. 2018中国十大开源云领军企业评选,等你报名!
  11. 技术图文:基于“科比投篮”数据集学Pandas
  12. GPU并行运算与CUDA编程--基础篇
  13. 移动体验大作战,冰桶算法全盘点
  14. Android带动画进度条简单实现
  15. leetcode 36. 有效的数独 (将 9 * 9 数独划分成 9 宫格 )
  16. 【数字IC验证快速入门】45、UVM项目实践之APB_SPI(13)UVM 验证方法学总结
  17. 接受密码和用户名,若用户名为‘admin‘,密码为‘‘123456‘则显示用户登录成功,否则一直登录
  18. 计算机学院运动会方阵策划案,运动会方阵策划书模板
  19. html背景图片不完全填充,background-size为100% 100%时背景图填充不完整
  20. Ubuntu 14.10 安装 hadoop-2.6.0单机配置和伪分布式配置

热门文章

  1. java 操作excel jxl_java 中JXL操作Excel实例详解
  2. ansible的playbook配置及template模板的使用
  3. 安装和使用pyv8解析JavaScript
  4. 回首昨天,继往开来!
  5. 我的第一首诗——七言律诗《除夜作》
  6. 2010年春晚十大看点nbsp;nbsp;[转自人人网“…
  7. 安卓系统版本号关系表
  8. 心用matlab画出来的,用matlab画3D心(surf,mesh)
  9. redis集群清除数据
  10. 灵感学院:45款唯美的苹果 iOS 应用程序图标设计