排序算法概述

news/2024/6/16 4:33:54 标签: 排序算法, 算法, 数据结构, c++, 动态规划

1.算法>排序算法分类

  • **比较类算法排序:**通过比较来决定元素的时间复杂度的相对次序,由于其时间复杂度不能突破 O ( n l o g n ) O(nlogn) O(nlogn),因此也称为非线性时间比较类算法

  • **非比较类算法排序:**不通过比较来决定元素间的相对次序,它可以突破基于比较排序的时间下界,以线性时间运行。

算法>排序算法

2.算法>排序算法性能指标

排序方法时间复杂度(平均)时间复杂度(最坏)时间复杂度(最好)空间复杂度稳定性
插入排序 O ( n 2 ) O({n^2}) O(n2) O ( n 2 ) O({n^2}) O(n2) O ( n ) O(n) O(n) O ( 1 ) O(1) O(1)稳定
希尔排序 O ( n 2 / 3 ) O(n^{2/3}) O(n2/3) O ( n 2 ) O({n^2}) O(n2) O ( n ) O(n) O(n) O ( 1 ) O(1) O(1)不稳定
选择排序 O ( n 2 ) O({n^2}) O(n2) O ( n 2 ) O({n^2}) O(n2) O ( n 2 ) O({n^2}) O(n2) O ( 1 ) O(1) O(1)不稳定
堆排序 O ( n l o g 2 n ) O(n{log_2}n) O(nlog2n) O ( n l o g 2 n ) O(n{log_2}n) O(nlog2n) O ( n l o g 2 n ) O(n{log_2}n) O(nlog2n) O ( 1 ) O(1) O(1)不稳定
冒泡排序 O ( n 2 ) O({n^2}) O(n2) O ( n 2 ) O({n^2}) O(n2) O ( n ) O({n}) O(n) O ( 1 ) O(1) O(1)稳定
快速排序 O ( n l o g 2 n ) O(n{log_2}n) O(nlog2n) O ( n 2 ) O({n^2}) O(n2) O ( n l o g 2 n ) O(n{log_2}n) O(nlog2n) O ( n l o g 2 n ) O(n{log_2}n) O(nlog2n)不稳定
归并排序 O ( n l o g 2 n ) O(n{log_2}n) O(nlog2n) O ( n l o g 2 n ) O(n{log_2}n) O(nlog2n) O ( n l o g 2 n ) O(n{log_2}n) O(nlog2n) O ( n ) O(n) O(n)稳定

2.分治算法

二分: binarySearch 又叫 折半查找 是对有单调性质的数列进行查找
二分的复杂度很低,达到了 O ( l o g n ) O({log_n}) O(logn) 的复杂度

模板1:

int lb=MIN,rb=MAX;
int ans=-1;
while(lb<=rb)
{
    int mid=(lb+rb)/2;
    if(check(mid))
    {
        ans=mid;
        lb=mid+1;
    }
    else
    {
        rb=mid-1;
    }
    printf("%d\n",ans);
}

模板2:

int lb=MIN,rb=MAX;
int mid;
while(l<r)
{
    mid=(lb+rb)/2;
    if(check(mid))
    {
        lb=mid;
    }
    else
    {
        rb=mid-1;
    }
}
return lb;

满足最小值的模板:

模板一:

int lb=MIN,rb=MAX;
int ans=-1;
while(lb<=rb)
{
    int mid=(lb+rb)/2;
    if(check(mid))
    {
        ans=mid;
        rb=mid-1;
    }
    else
    {
        lb=mid+1;
    }
    printf("%d\n",ans);
}

模板二:

int lb=MIN,rb=MAX;
int mid;
while(l<r)
{
    mid=(lb+rb)/2;
    if(check(mid))
    {
        rb=mid;
    }
    else
    {
        lb=mid+1;
    }
}
return rb;

3.倍增算法

(1)快速幂

最常见的 x y   m o d   m {x^y}\bmod m xymodm

typedef long long ll;
ll mypow(ll x,ll y,ll m)
{
    ll ans=1%m;
    for(;y;y>>1)
    {
        if(y&1) ans=ans%x*m;
        x=x*x%m;
    }
    return ans;
}

5.搜索

(1)深度优先搜索

深度优先搜索算法(英语:Depth-First Search,简称DFS)是一种用于遍历或搜索树或搜索图的算法

深度优先搜索是一种在开发爬虫早期使用较多的方法。它的目的是要达到被搜索结构的叶结点(即那些不包含任何超链的HTML文件) 。在一个HTML文件中,当一个超链被选择后,被链接的HTML文件将执行深度优先搜索,即在搜索其余的超链结果之前必须先完整地搜索单独的一条链。深度优先搜索沿着HTML文件上的超链走到不能再深入为止,然后返回到某一个HTML文件,再继续选择该HTML文件中的其他超链。当不再有其他超链可选择时,说明搜索已经结束。

代码框架:

void dfs(int k)//k:当前顶点
{
    if(/*找到解 或者 没有可访问的顶点*/)
    {
        printf("%d",/*输出解*/);
        return ;
    }
    for(int i=1;i<=/*搜索分枝*/;i++)
    {
        /*标记该顶点已访问*/;
        dfs(/*下一个顶点*/);
        /*还原该顶点的状态*/;
    }
}

(2)广度优先遍历

广度优先搜索算法(Breadth-First Search,BFS)是一种通过逐层遍历所有访问对象,从而通过最短节点数到大目标的算法

代码框架:

void bfs()
{
    /*初始节点入队*/;
    while(/*队列非空*/)
    {
        /*队头元素出队*/,/*赋给 current*/;
        while(/*current 还可以扩展*/)
        {
            /*由节点 current 扩展出新节点 new*/;
            if(/*new 重复于已有的节点状态*/) continue;
            /*new 节点入队*/
            if(/*new 节点是目标状态*/)
            {
                /*置 flag=true*/;
                break;
            }
        }
    }
}

6.动态规划(DP)

(1)线性动态规划

  • 最大子段和

给出一段序列,选出其中连续且非空的一段使得这一段和最大。

输入格式

第一行是一个整数 n n n ,表示了序列的长度

第二行是包含 n n n 个绝对值不大于 10000 10000 10000 的整数 a i {a_i} ai ,描述了这段序列。

输出格式

一个整数,为最大的字段和是多少。

字段的最小长度为1.

样例输入

7

2 -4 3 -1 2 -4 3

样例输出

4

核心代码:

int a[N];
int dp[N];
for(int i=1;i<=n;i++)
{
    dp=max(dp[i-1]+a[i],a[i]);
    ans=max(ans,dp[i]);
}
  • 最长上升子序列

一个树的序列 b i {b_i} bi ,当 b 1 < b 2 < b 3 < . . . < b s {b_1}<{b_2}<{b_3}<...<{b_s} b1<b2<b3<...<bs 的时候,我们称这个序列是上升的。

对于给定的一个序列( a 1 , a 2 , a 3 , . . . , a n {a_1},{a_2},{a_3},...,{a_n} a1,a2,a3,...,an)我们可以得到一些上升子序列 a i 1 , a i 2 , a i 3 , . . . , a i k {a_{i1}},{a_{i2}},{a_{i3}},...,{a_{ik}} ai1,ai2,ai3,...,aik ,这里 1 ≤ i 1 < i 2 < i 3 < . . . < i q ≤ N 1 \leq {i_1}<{i_2}<{i_3}<...<{i_q} \leq N 1i1<i2<i3<...<iqN

你的任务,就是对于给定的序列,求出最长上升序列的长度。

输入格式

输入的第一行是序列的长度 n ( 1 ≤ n ≤ 1000 ) n(1 \leq n \leq 1000) n(1n1000)

第二行给出的序列中的 n n n 个整数,这些整数的取值范围都在0到10000.

输出格式

最长上升子序列的长度。

样例输入

7

1 7 3 5 9 4 8

样例输出

4

核心代码:

int a[N];
int dp[N];
for(int i=1;i<=n;i++)
{
    dp[i]=1;//附初值
    for(int j=1;j<i;j++)
    {
        if(a[j]<a[i])//dp找最大值
        {
            dp[i]=max(dp[i],dp[j]+1);
        }
    }
    ans=max(ans,dp[i]);
}
  • 最长公共子序列

给定两个字符串 x , y x,y x,y ,长度不超过5000,求出两个序列的最长公共子序列。

**注意:**子序列不是字串,不要求连续。

输入格式

第一行一个字符串,表示字符串 x x x ,第二行一个字符串,表示字符串 y y y

输出格式

一个整数,表示最长的公共子序列长度。

样例输入

cnblogs

belong

样例输出

4

核心代码:

int c[N][N];
int len1,len2;
len1=strlen(x+1);
len2=strlen(y+1);
for(int i=1;i<=len1;i++)
{
    for(int j=1;j<len2;j++)
    {
        if(x[i]==y[i])
        {
            c[i][j]=a[i-1][j]+1;
        }
        else
        {
            c[i][j]=max(c[i-1][j],c[i][j-1]);
        }
    }
}

(2)矩阵类动态规划

  • 数字三角形

观察下面的数字金字塔。

写一个程序来查看从最高点到最低部任意处结束路径,使路径经过数字的和最大。每一步可以走到左下方的点也可以走到右下方的点。

 7

3 8

8 1 0

2 7 4 4

4 5 2 6 5

在上面的样例中,从 7→3→8→7→5 的路径产生了最大和,为30.

输入格式

第一行一个正整数 r r r ,表示行的数目。

后面每一行为这数字金字塔特定包含的整数。

输出格式

单独一行,包含那可能得到的最大的和。

样例输入:

5

7

3 8

8 1 0

2 7 4 4

4 5 2 6 5

样例输出:

30

核心代码:

int dp[N][N];
for(int j=1;j<=r;j++)
{
    dp[r][j]=a[r][j];
}
for(int i=r-1;i>=1;i--)
{
    for(int j=1;j<=i;j++)
    {
        dp[i][j]=max(dp[i+1][j],dp[i+1][j+1])+a[i][j];
    }
}

(3)背包问题

背包问题(Knapsack problem)可以描述为:给定一组物品,每种物品都有自己的重量和价格,在限定的总重量内,我们如何选择,才能使得物品的总价格最高。

背包问题又分为:01背包、完全背包、多重背包。此外,还存在一些其他考法,例如恰好装满、求方案总数、求所有的方案等。

  • 01背包

01背包的特点就是一个物品要不就选,要不就不选,分别表示1和0,所以叫01背包。

用 dp[i][j] 表示将前 i i i 个物品放入载重为 j j j 的背包能获得的最大价值,w[i] 表示第 i i i 件物品的重量,v[i] 表示第 i i i 件物品的价值,则可以用一下状态转移式来表示这个过程:

当 w[i]>j (也即第 i i i 件物品不能放入载重为 j j j 的背包)时:

dp[i][j]=dp[i-1][j];

否则(也即第 i i i 件物品能放入载重为 j j j 的背包)

dp[i][j]=max(dp[i-1][j],dp[i-1][j-w[i]]+v[i]);

注意到 dp 数组和第 i i i 行的值更新只跟 i − 1 i-1 i1 行有关,因此可以通过滚动数组结合反向更新的方式优化一下空间复杂度,在动态规划解题的时候这是一种常用的空间复杂度优化方式

二维写法

for(int i=1;i<=n;i++)
{
    for(int j=0;j<=c;j++)
    {
        if(j<w[i])
        {
            dp[i][j]=dp[i-1][j];
        }
        else
        {
            dp[i][j]=max(dp[i-1][j],dp[i-1][j-w[i]]+v[i]);
        }
    }
}

滚动数组优化

for(int i=1;i<=n;i++)
{
    for(int j=c;j>=0;j++)
    {
        if(j>=w[i])
        {
            dp[j]=max(dp[j],dp[j-w[i]]+v[i]);
        }
    }
}
  • 完全背包

完全背包的特点是每个东西都可以随便拿(指数量: ∞ \infty

用 dp[i][j] 表示将前 i i i 个物品放入载重为 j j j 的背包能获得的最大价值,w[i] 表示第 i i i 件物品的重量, v[i] 表示第 i i i 个物品的价值,则可以用以下的状态转移方程式来表示这个过程:

当 w[i]>j (也即第 i i i 件物品不能放入载重为 j j j 的背包)

dp[i][j]=dp[i-1][j];

否则(也即第 i i i 件物品能放入载重为 j j j 的背包)

dp[i][j]=max(dp[i-1][j],dp[i][j-w[i]]+v[i]);

注意如果用滚动数组的话,我们需要使用正向更新方式,这是唯一和上面的01背包问题的区别的地方。

二维写法

for(int i=1;i<=n;i++)
{
    for(int j=0;j<=c;j++)
    {
        if(j>=w[i])
        {
            dp[i][j]=max(dp[i-1][j],d[i][j-w[i]]+v[i]);
        }
        else
        {
            dp[i][j]=dp[i-1][j];
        }
    }
}

滚动数组优化

for(int i=1;i<=n;i++)
{
    for(int j=0;j<=c;j++)
    {
        if(j>=w[i])
        {
            dp[j]=max(dp[j],dp[j-w[i]]+v[i]);
        }
    }
}
  • 多重背包

多重背包的特点是每种物品的数量不知一个,但有限。

用 dp[i][j] 表示将前 i i i 件物品放入载重为 j j j 的背包能获得的最大价值,w[i] 表示第 i i i 件物品的重量,v[i] 表示第 i i i 件物品的价值,s[i] 表示第 i i i 种物品的数量,则可以用以下的状态转移方程式来表示这个过程:

dp[i][j]=max(dp[i-1][j-k*w[i]]+k*v[i],0<=k<=s[i]);

在多重背包的计算中,可以使用二进制优化来减小时间复杂度。

for(int i=1;i<=n;i++)
{
    for(int j=0;j<=c;j++)
    {
        for(int k=0;k<=s[i];k++)
        {
            if(j>=k*w[i])
            {
                dp[i][j]=max(dp[i][j],dp[i-1][j-k*w[i]]+k*v[i]);
            }
        }
    }
}

http://www.niftyadmin.cn/n/4966568.html

相关文章

2023 CCPC 华为云计算挑战赛 D-塔

首先先来看第一轮的 假如有n个,每轮那k个 他们的高度的可能性分别为 n 1/C(n,k) n1 C(n-(k-11),1)/C(n,k) n2 C(n-(k-21),2)/C(n,k) ni C(n-(k-i1,i)/C(n,k) 通过概率和高度算出第一轮增加的期望 然后乘上m轮增加的高度加上初始高度&#xff0c;就是总共增加的高度 下面是…

Docker搭建elasticsearch+kibana测试

最近需要做大数据画像&#xff0c;所以先简单搭建一个eskibana学习使用&#xff0c;记录一下搭建过程和遇到的问题以及解决办法 1.拉取es和kibana镜像 在拉取镜像之前先搜索一下 elasticsearch发现是存在elasticsearch镜像的&#xff0c;我一般习惯性拉取最新镜像&#xff0c…

Linux网络编程:线程池并发服务器 _UDP客户端和服务器_本地和网络套接字

文章目录&#xff1a; 一&#xff1a;线程池模块分析 threadpool.c 二&#xff1a;UDP通信 1.TCP通信和UDP通信各自的优缺点 2.UDP实现的C/S模型 server.c client.c 三&#xff1a;套接字 1.本地套接字 2.本地套 和 网络套对比 server.c client.c 一&#xff1a;线…

单词搜索:在二维网格中寻找单词的存在

题目连接 链表主页 在本篇文章中&#xff0c;我们将深入探讨 LeetCode 题目 "203. 移除链表元素" 的解题方法&#xff0c;从问题的分析、解题思路、代码实现到核心知识点的罗列&#xff0c;带你逐步理解如何使用C来删除链表中所有满足指定值的节点&#xff0c;并返…

设计模式 07 桥接模式

桥接模式&#xff08;Bridge Pattern&#xff09;属于结构型模式 概述 桥接模式是将抽象部分与它的实现部分分离&#xff0c;使它们都可以独立地变化。它是一种对象结构型模式&#xff0c;又称为柄体&#xff08;Handle and Body&#xff09;模式或接口&#xff08;Interface&…

Java可视化物联网智慧工地SaaS平台源码:人脸识别考勤

基于微服务JavaSpring Cloud Vue UniApp MySql实现的智慧工地云平台源码 智慧工地是指利用云计算、大数据、物联网、移动互联网、人工智能等技术手段&#xff0c;为建筑施工现场提供智能硬件及物联网平台的解决方案&#xff0c;以实现建筑工地的实时化、可视化、多元化、智慧化…

在c++ 20下使用微软的proxy库替代传统的virtual动态多态

传统的virtual动态多态&#xff0c;经常会有下面这样的使用需求&#xff1a; #include <iostream> #include <vector>// 声明一个包含virtual虚函数的基类 struct shape {virtual ~shape() {}virtual void draw() 0; };// 派生&#xff0c;实现virtual虚函数 str…

68、使用aws官方的demo和配置aws服务,进行视频流上传播放

基本思想&#xff1a;参考官方视频&#xff0c;进行了配置aws&#xff0c;测试了视频推流&#xff0c;rtsp和mp4格式的视频貌似有问题&#xff0c;待调研和解决 第一步&#xff1a;1) 进入aws的网站&#xff0c;然后进入ioT Core 2)先配置 Thing types & Thing&#xff0c…