2021.1.7学习

本文深入探讨了并查集和归并排序两种经典算法。归并排序通过分治策略实现高效排序,而并查集则关注于集合操作的优化,如路径压缩和按秩合并,以实现快速查询和合并。文中提供了示例代码展示这两种算法的实现,并讨论了它们在实际问题中的应用,如数据文件归并和集合操作的高效管理。
摘要由CSDN通过智能技术生成

课程学习
关于并查集和归并排序
归并
将已有序的子序列合并,得到完全有序的序列;即先使每个子序列有序,再使子序列段间有序。
常用于多个有序的数据文件归并成一个有序的数据文件。
思想方法:
(1)假设已经有两个有序数列,分别存放在两个数组s,r中;并设i,j分别为指向数组的第一个单元的下标;s有n个元素,r有m个元素。
(2)再另设一个数组a,k指向该数组的第一个单元下标。

#include <stdlib.h>
#include <stdio.h>
 
void Merge(int sourceArr[],int tempArr[], int startIndex, int midIndex, int endIndex)
{
    int i = startIndex, j=midIndex+1, k = startIndex;
    while(i!=midIndex+1 && j!=endIndex+1)
    {
        if(sourceArr[i] > sourceArr[j])
            tempArr[k++] = sourceArr[j++];
        else
            tempArr[k++] = sourceArr[i++];
    }
    while(i != midIndex+1)
        tempArr[k++] = sourceArr[i++];
    while(j != endIndex+1)
        tempArr[k++] = sourceArr[j++];
    for(i=startIndex; i<=endIndex; i++)
        sourceArr[i] = tempArr[i];
}
 
//内部使用递归
void MergeSort(int sourceArr[], int tempArr[], int startIndex, int endIndex)
{
    int midIndex;
    if(startIndex < endIndex)
    {
        midIndex = startIndex + (endIndex-startIndex) / 2;//避免溢出int
        MergeSort(sourceArr, tempArr, startIndex, midIndex);
        MergeSort(sourceArr, tempArr, midIndex+1, endIndex);
        Merge(sourceArr, tempArr, startIndex, midIndex, endIndex);
    }
}
 
int main(int argc, char * argv[])
{
    int a[8] = {50, 10, 20, 30, 70, 40, 80, 60};
    int i, b[8];
    MergeSort(a, b, 0, 7);
    for(i=0; i<8; i++)
        printf("%d ", a[i]);
    printf("\n");
    return 0;
}

并查集
重点处理节点的连锁顺序和方向

#include <bits/stdc++.h>
using namespace std;
int fa[105];
int  find(int n)
{
    if(fa[n]==n) return n;
    else return fa[n]=find(fa[n]);
}
struct Node{
    int x,y;
}node[105];
bool check(Node a,Node b)
{
    if(a.x==b.x) return 1;
    else if(a.y==b.y)return 1;
    else return 0;
}
set<int> cnt;
int main()
{
    int n;
    cin>>n;
    for(int i=0;i<n;i++)
    {
        fa[i]=i;
        cin>>node[i].x>>node[i].y;
        for(int j=0;j<i;j++)
        {
            if(check(node[i],node[j])){
              
                fa[find(j)]=find(i);
               // cout<<fa[j]<<endl;
            }
        }
    }
    for(int i=0;i<n;i++)
    {
        //cout<<find(fa[i])<<endl;
        cnt.insert(find(i));
    }
    cout<<cnt.size()-1<<endl;
}

以下为引用课程内容

并查集 每个点保存其父节点的信息 合并两个集合、查询两个元素是否在同一个集合 暴力:开数组保存元素属于的集合编号,查询
O(1)O(1),合并 O(n)O(n) 并查集:用树形结构保存集合,根节点编号作为集合编号,保存每个节点的父节点信息 Q:如何判断树根?
Q:如何取得集合编号? Q:如何合并两个集合? 此时的复杂度,查询 O(n)O(n),合并 O(1)O(1),如何优化(即降低树的高度)?
注:合并操作前需要先查询根节点信息,此处的“合并”未计算查询复杂度 加入路径压缩优化,查询
O(logn)O(logn),合并O(1)O(1) 加入按秩合并优化,查询 O(logn)O(logn),合并O(1)O(1)
加入上述两种优化,查询 O(\alpha(n))O(α(n)),合并O(1)O(1) 近似认为其查询操作的时间复杂度
O(\alpha(n)) = O(5) = O(1)O(α(n))=O(5)=O(1)

  • 由于阿克曼函数 f (n) = A(n, n)f(n)=A(n,n) 的增加速率非常快,因此其反函数 f^{−1} = \alphaf −1 =α 会以非常慢的速度增加。阿克曼反函数常用 αα 表示。因为 A(4, 4)A(4,4) 的数量级约等于\large
    2{{2{{10^{{19729}}}}}}2 2 10 19729
    ,因此对于一般可能出现的数值 nn,α(n)α(n) 均小于等于 44。 字典树 高效的存储和查找字符串集合 最大异或对 树状数组

前缀和

  • 每个数组下标代表一个前缀, 值为前缀的和, 然后用数组元素间做减法算出某个区间的和.填例子
  • 填题目

差分

  1. 保存相邻值的差.例子:每个数组下标代表一个前缀和, 上一个数组下标代表的前缀和 与 当前数组下标代表的前缀和 之差, 作为当前数组元素的值.(区间插气球问题)
  2. 填题目

前缀和和差分是一对逆运算 前缀和 S_i=a_1+a_2+a_3+…S i ​ =a 1 ​ +a 2 ​ +a 3
​ +… 如何计算 S_iS i ​ 作用:快速求区间和 二维前缀和 差分:构造b数组使满足其前缀和是原数组 b 1 = a 1 b_1=a_1 b1=a1
b 2 = a 2 − a 1 b_2=a_2-a_1 b2=a2a1 区间增减 假定a数组初始为0,每次长度一区间增减 线段树

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值