并查集
来源:互联网 发布:深圳java工程师招聘 编辑:程序博客网 时间:2024/05/22 17:06
并查集
并查集能很好地解决网络中两个节点是否连接的问题,但并查集不会给出节点之间的路径。正因为如此,并查集在判断节点的连通性时效率很高。其时间复杂度为O(1)。
并查集实现
思路:
- 相连的节点具有相同的id值
- 要实现p,q两个节点的合并,就需要将所有与p节点id值相同的节点的id改为q的id。
function unionFind(n){ this.id = []; for (var i = 0; i < n; i++) { //初始化时,每个节点的id值都不相同 this.id[i] = i; } this.find = function(p){ if (p >= 0 && p < this.id.length) { return this.id[p]; } } this.isConnected = function(p,q){ return this.find(p) == this.find(q); } this.unionElements = function(p,q){ var pId = this.id[p]; var qId = this.id[q]; if (pId == qId) { return; } for (var i = 0; i < this.id.length; i++) { if (this.id[i] == pId) { this.id[i] = qId; } } }}
并查集优化(1)
思路:
- 为每个元素指定父节点, 初始化时每个元素的父节点都指向自身
- 两个元素相连可以看做是一个元素是另一个元素的父节点
function unionFind2(n){ this.parent = []; for (var i = 0; i < n; i++) { //初始化时父节点等于自身 this.parent[i] = i; } this.find = function(p){ if (p < 0 || p >= this.parent.length) { return -1; } //获得元素p的根节点 while(parent[p] != p ){ p = parent[p]; } return p; } this.isConnected = function(p,q){ //两个元素根节点相等即代表相连 return this.find(p) == this.find(q); } this.unionElements = function(p,q){ int pParent = find[p]; int qParent = find[q]; if (pParent == qParent) { return; } //将一个元素的父节点设置为另一个元素,则代表两个元素相连 this.parent[pParent] = qParent; }}
并查集优化(2)
思路:
- 如果节点之间相连所形成的树层数太高的话,查到元素的根节点所耗费的时间会增加
- 增加一个数组,用于记录以每个节点为根节点的树中子节点的数量
- 每次合并元素之前,先判断一下待合并的元素所在的根节点哪个节点数量多,将数量少的根节点的父节点设置为数量多的根节点,并维护子节点数量数组
function unionFind2(n){ this.parent = []; this.size = []; for (var i = 0; i < n; i++) { this.parent[i] = i; //初始化时,每个节点的根节点都是自身,因此,size数量都为1 this.size[i] = 1; } this.find = function(p){ if (p < 0 || p >= this.parent.length) { return -1; } while(parent[p] != p ){ p = parent[p]; } return p; } this.isConnected = function(p,q){ return this.find(p) == this.find(q); } this.unionElements = function(p,q){ int pParent = find[p]; int qParent = find[q]; if (pParent == qParent) { return; } //合并时判断哪个分支数量多,将数量少的父节点设置为数量多的 if (this.size[pParent] > this.size[qParent]) { this.parent[qParent] = pParent; this.size[pParent] += this.size[qParent]; }else{ this.parent[pParent] = qParent; this.size[qParent] += this.size[pParent]; } }}
并查集优化(3)
思路:
- 用节点数量判断应该怎样连接两个分支是不准确的,因为节点数量不能代表一个分支的节点层数
- 用节点层数来判断怎样合并两个分支更加合理
function unionFind2(n){ this.parent = []; //rank表示以每个节点为根节点的分支树的高度 this.rank = []; for (var i = 0; i < n; i++) { this.parent[i] = i; //初始化时每个分支的高度都为1 this.rank[i] = 1; } this.find = function(p){ if (p < 0 || p >= this.parent.length) { return -1; } while(parent[p] != p ){ p = parent[p]; } return p; } this.isConnected = function(p,q){ return this.find(p) == this.find(q); } this.unionElements = function(p,q){ int pParent = find[p]; int qParent = find[q]; if (pParent == qParent) { return; } //将层数少的分支的父节点设置为层数大的分支的父节点,此时,分支层数不会发生变化 if (this.rank[pParent] > this.rank[qParent]) { this.parent[qParent] = pParent; }else if(this.rank[pParent] < this.rank[qParent]){ this.parent[pParent] = qParent; } else{ //当两个分支层数相同时,连接在一起之后,其中一个分支的层数将+1 this.parent[pParent] = qParent; this.rank[qParent] += 1; } }}
并查集优化(4)
思路:
- 每一个分支的层数越小,查询的效率越高
- 在find寻找某一元素的根节点的过程中,可以同时对分支的路径进行压缩,减少分支层数
function unionFind2(n){ this.parent = []; this.rank = []; for (var i = 0; i < n; i++) { this.parent[i] = i; this.rank[i] = 1; } this.find = function(p){ if (p < 0 || p >= this.parent.length) { return -1; } while(parent[p] != p ){ parent[p] = parent[parent[p]];//路径压缩 p = parent[p]; } return p; } this.isConnected = function(p,q){ return this.find(p) == this.find(q); } this.unionElements = function(p,q){ int pParent = find[p]; int qParent = find[q]; if (pParent == qParent) { return; } if (this.rank[pParent] > this.rank[qParent]) { this.parent[qParent] = pParent; }else if(this.rank[pParent] < this.rank[qParent]){ this.parent[pParent] = qParent; } else{ this.parent[pParent] = qParent; this.rank[qParent] += 1; } }}
并查集优化(5)
思路:
- 路径压缩是减少分支层数的有效方法,最理想的路径压缩效果是:在每个分支中,所有子节点的父节点都为根节点,即分支的层数为2。
function unionFind2(n){ this.parent = []; this.rank = []; for (var i = 0; i < n; i++) { this.parent[i] = i; this.rank[i] = 1; } this.find = function(p){ if (p < 0 || p >= this.parent.length) { return -1; } //第二种路径压缩方法,通过递归的方式将所有节点的父节点都设置为根节点 if (this.parent[p] != p ) { this.parent[p] = find(this.parent[p]); } return this.parent[p]; } this.isConnected = function(p,q){ return this.find(p) == this.find(q); } this.unionElements = function(p,q){ int pParent = find[p]; int qParent = find[q]; if (pParent == qParent) { return; } if (this.rank[pParent] > this.rank[qParent]) { this.parent[qParent] = pParent; }else if(this.rank[pParent] < this.rank[qParent]){ this.parent[pParent] = qParent; } else{ this.parent[pParent] = qParent; this.rank[qParent] += 1; } }}
阅读全文
0 0
- HDU3938 并查集 并查集
- 并查集(集并查)
- HDU1232 并查集<并>
- 并查集
- 数据结构-并查集
- 并查集
- 并查集!
- 并查集
- 并查集
- 并查集
- 并查集
- 并查集总结
- 并查集学习
- 并查集
- 并查集
- 并查集
- 所谓并查集
- 并查集
- c语言学习知识点(五)scanf函数应用以及问题
- Openmeetings4.0.0二次开发日志(三)使用webservice调用OM接口(2)
- 一个程序员的职业定位
- C++容器博客
- 一禅小和尚的人生哲学
- 并查集
- 关于HTML5中auto剖析
- MySQL错误:You can't specify target table 'tablename' for update in FROM clause
- C/C++ 混合编程
- mybatis 批量更新update详解
- java12周第2题
- windows下升级R
- Java 8 新特性概述
- 利用intellijidea创建maven多模块项目