并查集

这个概念参考中国大学MOOC浙大的数据结构,时间复杂度比它给的源码大,是因为代码中没有使用索引值作为数据值。

#include<bits/stdc++.h>
using namespace std;
/*
    并查集:
        并查集就是能进行合并和查找根运算的集合。
        集合就是数学上所指的集合。 
*/
/*
    分析:
        集合可以直接使用数组表示,即把数据存入数组中就行。但是这样会有一个问题,就是时间复杂度是线性的。
        了解BST就知道,BST可以做到log2n级的时间复杂度,线性时间复杂度太大。所以我们把数组元素按树构建, 
        也就是说在保存元素的同时保存它的父节点(注意:不是完全二叉树那样使用索引,而是同时保存它的父节点)。

    初始化:
        父节点全部初始化为 -1。

    查找根:
        查找某结点的父元素就是递归查找它的根结点的父元素,直至无父节点。
        看起来这已经是最简单的方法了。但是注意一下,在递归路径上的点都是同一个根,所以在递归退栈的时候
        可以把路径上结点的父结点都设置为本次返回的值,这样之后查询此路径上的点的根时递归操作只需要做一次就可以。

    合并:
        直接把一个结点的父节点设置为另一个结点的索引值就可以。但是需要注意的是每次应该把元素个数少的
        挂在元素个数多的下面,这样是为了防止这棵树变成线性的。 
*/ 
/*
    结点结构:
        数据;
        父结点索引;  //根的父结点为设置为此树规模的负数 
*/
class Node
{
    public:
        int val;
        int parent;
        Node(){ parent = -1; }
};

//二分法获得数据的索引,时间复杂度:logN
int getIndex(Node *data, int d) 
{
    int i = 0, j = 9;
    while(i <= j)
    {
        int middle = (i + j) / 2;
        if(data[middle].val < d)
            i = middle + 1;
        else if(data[middle].val > d)
            j = middle - 1;
        else
            return middle;
    }
    return -1;
}

//查找并返回根结点的值索引 
int findRoot(Node *data, int x)
{
    int index = getIndex(data, x);
    if(data[index].parent < 0)
        return data[index].parent;
    return data[index].parent = findRoot(data, data[index].val);
}

//合并集合 
void unionSet(Node *data, int n1, int n2)
{
    int root1 = findRoot(data, n1), root2 = findRoot(data, n2);
    int index1 = getIndex(data, n1), index2 = getIndex(data, n2);
    if(root1 < root2)   //root1树的规模大于root2树 
    {
        data[index1].parent += data[index2].parent;
        data[index2].parent = index1;
    }else{
        data[index2].parent += data[index1].parent;
        data[index1].parent = index2;
    }
} 
bool cmp(Node e1, Node e2){ return e1.val < e2.val; }
int main()
{
    srand(unsigned(time(NULL)));
    Node data[10];
    for(int i = 0; i < 10; i++)
        data[i].val = rand() % 100;
    sort(data, data + 10, cmp);     //NlogN 级复杂度 
    unionSet(data, data[1].val, data[2].val);
    for(int i = 0; i < 10; i++)
        cout << data[i].parent << "  " << data[i].val << endl;
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值