基础性算法

⩕    排序

〇    快速排序  

1、原理  ( 升序 )

​            先在区间中寻找一基准元素,将区间中元素分别与之比较,并进行处理

​            以保证比基准元素小的在基准元素之前,比基准元素大的在基准元素之后

​            处理完毕后,数组即排序完成

 2、核心模板( 升序 )
 

void quick_sort( int q[] , int l , int r)
{
    if(l > r)    return;                        //当左右端点相遇,结束循环
    int    x = q[ l + r >> 1 ];                 //定义基准元素,用于与左右端点指向的
    int    i = l - 1 , j = r + 1;                 //定义左右端指针,分别有两端至中间移动
    while(i < j)                            //左右端指针未相遇时,继续循环
    {
        do    i++;while(q[i] < x);            //若i所指向的元素小于基准元素,则继续循环
        do    j--;while(q[j] > x);            //若j所指向的元素大于基准元素,则继续循环
        if(i < j)    swap( q[i] , q[j] );    //上述循环结束后,此时i所指元素大于基准元素,j所指元素小于基准元素,交换二者
    }
    quick_sort( q , l , j );                //递归重复上述过程
    quick_sort( q , j + 1 , r );
}

〇    归并排序

1、核心模板 ( 升序 )
 

void  merge_sort( int q[] , int l , int r)
{
    if(l > r)    return;                                            //中断条件:左右端相遇
    int    mid = l + r >> 1;                                        //取中点
    merge_sort( q , l , mid ),merge_sort( q , mid + 1 , r);           //划分区间
    int    k = 0;                                                   //定义辅助指针,指向辅助数组中元素
    int i = l , j = mid + 1;                                    //定义端点指针,从划分的区间的左端点开始向右循环    
    while(i <= mid && j <= r)                                    //中断条件:区间循环完毕
    if(q[i] <= q[j])    tmp[k++] = q[i++];                         //比较i,j所指元素,将符合单调性的元素输入辅助数组
    else    tmp[k++] = q[j++];
    while(i <= mid)    tmp[k++] = q[i++];                            //循环区间
    while(j <= r)    tmp[k++] = q[j++];
    
    for(i = l,k = 0 ; i <= r ; i++,k++)                            //将排序完毕的辅组数组赋给需要排序的数组
        tmp[k] = q[i]
}

⩕    二分

1、应用

​        给定一序列,搜索符合条件的元素

 2、原理

​        先取区间中点,将区间划分,再检查该中点所对元素是否符合搜索条件,再依据检查结果对半缩小区间,即缩小搜索范围

 3、核心模板
 

int    bsearch_l(int l,int r)
{
    while(l < r)                        //中断条件:l,r相遇
    {
        int    mid = l + r >> 1;            //取中点
        if(check(mid))    r = mid;        //check(mid)用于判断mid是否符合搜索条件
        else    l = mid + 1;             //是则去除右区间,保留左区间,否则去除左区间,保留右区间
    }
    return    l;                           //返回l,r相遇位置,即搜索结果
}
int    bsearch_r(int l,int r)
{
    while(l < r)
    {
        int    mid = l + r + 1 >> 1;
        if(check(mid))    l = mid;        //check(mid)用于判断mid是否符合搜索条件
        else    r = mid - 1;            //是则去除左区间,保留右区间,否则去除右区间,保留左区间
    }
    return l;
}

⩕    高精度计算

〇    高精度数的储存

​            高精度数输入时常用一字符数组进行接收,而后将每一位上的字符按由低位到高位的顺序转化为数字,而后存进一`int`行数组中

​            该int型数组常采用变长数组,即`vector<int>`进行定义

1、核心模板

string  s1,s2;                                                        //定义接收高精度数的字符数组
vector<int>  A,B;                                                    //定义储存高精度数的数组
cin >> s1 >> s2;                                                    //读入
for (int i = a.size() - 1; i >= 0; i -- ) A.push_back(a[i] - '0');        //将字符转化为数字,并倒序存储
for (int i = b.size() - 1; i >= 0; i -- ) B.push_back(b[i] - '0');   

     

〇    高精度加法

1、核心模板
 

vector<int>    add(vector<int> &A , vector<int> &B)
{
    vector<int>    C;                                    //定义变长数组C,用于储存答案
    int    t = 0;                                        //定义t用于记录进位数,初始化为0
    for(int i = 0;i < A.size() || i < B.size();i++)     //中断条件:处理完A,B每一位上数字
    {
        if(i < A.size())    t += A[i];                  
        if(i < B.size())    t += B[i];                  //t进行上述步骤后,最终结果为 t+A[i]+B[i]
        C.push_back(t % 10);                         //t % 10得到相加后当前位上的数字并输进C数组
        t /= 10;                                    //t / 10 得到进位数
    }
    if(t)    C.push_back(1);                             //若最高位有进位数,则进1
    return    C;                                        //返回储存答案的数组C
}

 〇    高精度减法

1、核心模板
 

vector<int>    sub(vector<int> &A , vector<int> &B)               //传入时需注意,A应为被减数,B为减数
{
    vector<int>    C;                                            //定义变长数组C用于储存答案
    for(int i = 0,t = 0;i < A.size();i++)                      //中断条件:处理完被减数的每一位,
    {                                                       //并定义t用于记录借位数,初始化为0
        t = A[i] - t;                                        //当前位数字减去借位数
        if(i < B.size())    t -= B[i];                         //若B当前位上有数字,则减去,此时结果为A[i]-t-B[i]
        C.push_back((t + 10) % 10);                             //取得相减后当前位上数字,t+10是为了防止结果为负数
        if(t < 0)    t = 1;                                    //若t<0,说明向前借了一位,t更新为1
        else    t = 0;                                        //否则即未进行借位,t更新为0
    }
    while(C.size() > 1 && C.back() == 0)    C.pop_back();       //去除前导零
    return    C;                                                //返回储存答案的变长数组C
}

〇    高精度乘法c

1、注

​        此处高精度乘法仅实现一高精度数乘一较小的数

2、核心模板
 

vector<int>    mul(vector<int> &A , int B)
{
    vector<int>    C;                                //定义变长数组C用于储存答案
    int    t = 0;                                    //定义t用于记录进位数
    for(int i = 0;i < A.size() || t;i++)           //遍历每一位,分别乘以B
    {
        if(i < A.size())    t += A[i] * B;          //计算结果
        C.push_back(t % 10);                     //取计算后当前位上数字,并输入C中    
        t /= 10;                                //取进位
    }
    return    C;                                    //返回储存答案的变长数组C
}

〇    高精度除法

1、注

​        除法与加、减、乘法不同,计算时从高位开始向低位处理,因此在储存时应从高位到低位进行储存

​        但为了应对多种运算混合存在的情况,为了与其他运算一致,故采用与加、减、乘法相同的储存方式,即从低位向高位储存

​        在除法处理时,进行倒序遍历即可

​        且计算后的结果C,也是由高位到低位储存,因此最后需将C逆序,使其为由低位向高位储存

2、核心模板
 

vector<int>    div(vector<int> &A , int B , int &r )       //A是被除数,B是除数,r是余数
{
    vector<int>    C;                                    //定义变长数组C用于储存答案
    r = 0;                                           //余数初始化为0
    for(int    i = A.size() - 1;i >= 0;i--)              //倒序处理A
    {
        r = r * 10 + A[i];                            //将上次的余数*10在加上当前位的数字,便是该位需要除的被除数
        C.push_back(r / b);                            //所得即为商在这一位的数字
        r % b;                                       //取得这一位的余数
    }
    reverse(C.begin() , C.end());                     //将C数组逆序,使其由低位到高位储存
    while(C.size() > 1  && C.back() == 0)    C.pop_back();        //去除前导零
    return    C;                                        //返回储存答案的变长数组C
}

⩕    前缀和

〇    一维前缀和

1、概念

​            对于一数组a,其中元素为 `a[0] = 0 , a[1] , a[2] ...`

​            定义一新数组s,其中元素为 `s[0] = 0 , s[1] = a[1] + a[0] , s[2] = a[2] + a[1] + a[0] ...`

​            则将 数组s 称为 数组a 的前缀和数组

2、核心模板
 

for(int  i = 1;i <= n;i++)
    s[i] = s[i - 1] + a[i];

3、应用

​            可用于快速计算数组a中某区间的和

​            要计算 `a[l]` 到 `a[r]` 的和,即计算 `s[r] - s[l - 1]`;

〇二维前缀和

1、概念

​        对于一数组a,其中元素为`a[0][0] = 0,a[0][1],a[0][2] ...`

​        定义一新数组s,其中元素为`s[0][0] = 0,s[0][1] = a[0][0] + a[0][1]...s[1][1] = a[0][0] + a[0][1] +a[1][0] + a[1][1] ...`

​        则将 数组s 称为 数组a 的前缀和数组

2、核心模板
 

for(int i = 1;i <= n;i++)
    for(int j = 1;j <= m,j++)
        s[i][j] = s[i - 1][j] + s[i][j -1] + a[i][j] + a[i - 1][j - 1];

3、应用

​        可用于快速求矩阵中以 ( x1 , y1 ) , ( x2 , y2 )为对角线的矩形区域的和

​        和即`s[x2][y2] - s[x1 - 1][y2] - s[x2][y1 - 1] + s[x1 - 1][y1 - 1]`

⩕    差分

〇    一维差分

1、概念

​            对于一 数组a,其中元素为 `a[1] , a[2] , a[3] ...`

​            构造一新 数组b,其中元素满足,`b[1] = a[1],b[1] + b[2] = a[2],b[1] + b[2] + b[3] = a[3] ...`

​            即 数组a 是 数组b 的前缀和数组,将 数组b 称为 数组a 的差分

2、原理

​            将 数组a 初始全视为0,再执行一插入操作,即可达成差分的效果

3、核心模板
 

void    insert(int l,int r,int c)
{
    b[l] += c;
    b[r + 1] -= c; 
}
... ...
for(int i = 1;i <= n;i++)    insert( i , i , a[i]);

4、应用

​        可快速完成将 [ l , r ] 区间的元素均加上 c 的操作,执行 insert 函数即可

​        对 数组b 做前缀和,即可得到 数组a

〇    二维差分

1、核心模板
 

void    insert(int x1,int y1,int x2,int y2,int c)
{
    b[x1][y1] += c;
    b[x2 + 1][y1] -= c;
    b[x1][y2 + 1] -= c;
    b[x2 + 1][y2 + 1] += c;
}
... ...
for(int i = 1;i <=n ;i++)
    for(int j = 1;j <= n;j++)
        insert( i , j , i , j , a[i][j]);

2、注

​    其余内容与一维差分同理

⩕    离散化

1、概念

​            对一 数组a ,其中元素范围较,但元素分布较为分散,    

​            定义一元素连续的新数组,将 数组a 中元素映射到该新数组上,此过程即为离散化

2、核心模板
 

vector<int>    alls;
sort(alls.begin() , alls.end());
alls.erase(unique(alls.begin() , alls.end()) , alls.end());
int    find(int x)
{
    int    l = 0,r = alls.size() - 1;
    while(l < r)
    {
        int    mid = l + r >> 1;
        while(l < r)
        {
            if(alls[mid] >= x)    r = mid;
            else    l = mid + 1;
        }
    }
    return    r + 1;
}

# ——————————————————————————————

⩕    区间合并

1、概念

​        给定n个区间,将所有有交集的区间合并

2、原理

​        维护一新区间,对n个区间依左端点进行排序,再对n个区间进行遍历,有以下三种情况

​        1、与维护区间无交集,不处理

​        2、与维护区间由交集,合并

​        3、包含于维护区间,合并

3、核心模板
 

typedef    pair<int,int>    PII;
vector<PII>    segs;
void    merge(vector<PII> &segs)
{
    vector<PII> res;
    sort(segs.begin() , segs.end());
    int    st = -2e9 , ed = -2e9;
    for(auto seg:segs)
    if(ed < seg.first)
    {
        if(st != -2e9)    res.push_back({st,ed});
        st = seg.first,ed = seg.second;
    }
    else    ed = max(ed , seg.second);
    if(st != -2e9)    res.push_back({st,ed})
    segs = res;
}

欢迎订阅专栏,数据结构实验,期末大作业,前端后端,算法都有哦,想我发哪个方面的资源或文章可以私信我,免费的哦

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

然然超绝肌肉线条

你的鼓励将是创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值