2016-12-27 带权并查集与子树自检

带权的必要性

并查集的性能劣化最主要的是来源于子树过于庞大合并和判断需要时间过长,那么就需要通过带权来使得并查集在合并的时候变得更棒一点。使得子树深度变短而广度增加。


非带权并查集.png
int FindRoot(int i)
{
  while (i != id[i]) i = id[i];
  return i;
}

void union(int p, int q)
{
  int i = FindRoot(p);
  int j = FindRoot(q);
  id[i] = j;
}

这段就是比较普遍的并查集入门的时候所写的合并和查找代码,问题出在哪里呢?如果一棵树过于瘦长的话,每一次回溯根节点都可能会是一个噩梦,因为树形结构如果没有合格的筛选的话可能会变成一条非常耿直的线段,这样子每一次合并之后回溯都会可能产生n的复杂度,如果进行m次合并操作,那么就可能会出现m*n的时间消耗。

带权并查集的代码

虽然说加入带权之后会带来非常大的性能提升,实际上它的代码量非常的短。首先,我们需要一个新的数组size来标记一开始的所有的节点的大小,因为其实一开始所有的节点都可以算作一棵独立的树,那么size的空间大小开和节点数一样就够了。然后在合并操作里面这样进行

void union(int p, int q)
{
  int i = FindRoot(p);
  int j = FindRoot(q);
  if (i == j) return;
  else if (size[i] > size[j]) {size[i] += size[j];id[j] = i;}
  else {size[j] += size[i];id[i] = j;}
}

即可,因为这样子的话,其实每一次回溯的最坏情况也只会有lgN的时间消耗。

带权并查集时间复杂度的证明

在带权并查集里面,两棵树合并如果需要深度增长,当且仅当第二棵树的深度大于等于第一棵树,这样子的话就会需要到将第一棵树并入第二棵树中,其实相当于是将N棵树二分掉了一样,能够一直保持这相等或大于在N个大小的数里面最大只可能是lgN棵,所以在合并之后至多只可能便利lgN次,因此整个并查集的搭建只会需要N+M*lgN的时间复杂度,最后的结果图应该如此。


带权并查集结果图.png

并查集的展开

既然我们可以通过进行附加权的方式使得他们在合并的时候呈现一个接近好的树形结构,那么如果我们在将这样子的一棵并查集树展开会是怎么样的?只能说,那真的非常非常棒。在之前的回溯里面我们已经只需要进行lgn次操作就可以查找到了祖父节点,那么如果我直接在回溯的时候不断将它指向祖父节点呢?就会变成lglgn也就是lg*n这样一种复杂度,在进行2的65535次方次操作的时候,也就是lgx2的65535次方,仅仅需要五次就能够解决,这是一个接近于1的常数量级!

并查集的展开.png

这样的状态压缩的代码

非常非常非常简单,我知道之前带权并查集的代码仅仅两行已经非常简单了,但是这样一个会更加简单!

void FindRoot(int i)
{
  while (i != id[i]) i = id[i];
  return i;
 }

void ExFindRoot(int i)
{
  while(i != id[i])
  {
    id[i] = id[id[i]];//只有这一行。
    i = id[i];
   }
  return i;
}

路径压缩的证明

其实我觉得聪明的读者们已经能够猜出为什么会变成一个lg*n的复杂度了。
很简单,因为在查询它的祖父的时候,用它的父亲又查询了一次,这样子又再一次调用了在带权之后已经转成了多叉树形式数据结构的并查集,因此在每一次操#作进行的时候实际上就会产生lg*的这样子的结果。

2016-12-27结语

实话说之前没有想过这方面的优化,总认为能用就可以了,优化是一种非常麻烦的事情,没有那么好的大脑是无法进行的。直到看到这玩意。。。。如果说正确的算法是将不可能的问题化成可能,将可能的问题尽量优化的话。那么“优雅”的算法更像是能将问题解决的同时调用最少的资源和最简短的语句。。我是真服了这个优化了。。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,547评论 6 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,399评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,428评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,599评论 1 274
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,612评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,577评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,941评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,603评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,852评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,605评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,693评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,375评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,955评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,936评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,172评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,970评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,414评论 2 342

推荐阅读更多精彩内容

  • 1 序 2016年6月25日夜,帝都,天下着大雨,拖着行李箱和同学在校门口照了最后一张合照,搬离寝室打车去了提前租...
    RichardJieChen阅读 5,071评论 0 12
  • 树的概述 树是一种非常常用的数据结构,树与前面介绍的线性表,栈,队列等线性结构不同,树是一种非线性结构 1.树的定...
    Jack921阅读 4,432评论 1 31
  • 从并查集Union Find算法谈算法解决实际问题的过程算法并查集算法寻找路径 从并查集Union Find算法谈...
    代号027阅读 1,736评论 0 1
  • kuangbin专题 模板 关于并查集的一点心得 大家都说带权并查集的起点是食物链( POJ - 1182 ),但...
    染微言阅读 1,488评论 0 3
  • 老师,人类的灵魂工程师。话的确没错,问题是灵魂工程师出现了灵魂扭曲,那么培育出来的灵魂能正常吗? 跟仇视老师无关,...
    蝉翼呵呵阅读 303评论 0 3