算法设计与分析期末复习不挂科

news2024/12/27 15:28:37

算法的基本概念

算法概念

通俗讲:算法是解决问题的一种方法或一个过程
严格讲:算法是解某一特定问题的一组有穷规则的集合
且满足以下性质:

  • 有限性:算法在执行有限步之后必须终止
  • 确定性:算法的每一个步骤都有精确的定义,要执行的每一个动作都是清晰的,无歧义的
  • 输入:一个算法有0个或多个输入,他是由外部提供的,作为算法执行前的初始值或初始状态
  • 输出:一个算法有一个或多个输出,这些输出与输入有着特定的关系,实际上是输入的某种函数
  • 能行性:指的是算法中有待实现的运算都是基本运算,原则上可以由人们用纸笔在有限时间里精确的完成

算法的时间复杂性分析

有几种方法可以用来分析算法的时间复杂性,如循环次数的统计,基本操作频率的统计,计算步的统计等

  • 循环次数的统计:计算多项式O(n),排序(冒泡排序) O(n^2),选手竞技淘汰比赛O(n),洗牌O(nlogn)
  • 基本操作频率统计:赋值操作,比较操作,四则运算操作,这些都可以看做基本操作,选取的基本操作执行的频率必须和算法中的任何其他操作一样多
    例如冒泡中的比较操作,可以看成基本操作: 归并排序中的赋值操作O(n),收割白菜O(n)
  • 计算步的统计: 统计算法中所有部分的时间花费 计算步和问题规模n无关,我们可以把一个语句的执行看成一个计算步,或者把连续200个乘法操作看做一个计算步,不能把n次操作看做一个计算步! 可以将 flag = (a+b+c==n)&&(5*a+3*b+c/3==n)&&(c%3==0);看做一个计算步,或者a=b;看做计算步,然后用conut统计次数!

最好情况/最坏情况和平均情况分析

有些算法因为不同输入实例,运行时间可能差别输入规模n的某个阶

  • 最好情况: 例如排序算法排升序,输入实例已经是升序,冒泡,插排最好时间复杂性为O(n)
  • 最坏情况:例如排升序,输入实例是降序,冒泡,插排最坏时间复杂度为O(n^2)
  • 平均情况: 算法运行时间选取算法所有可能输入的平均运行时间

渐进复杂性

算法的输入规模和运行时间的阶
在这里插入图片描述

通俗点讲就是保留最大阶,就是我们要求的渐进复杂性
在这里插入图片描述

渐进记号

运行时间的上界O记号
在这里插入图片描述
运行时间的下界
在这里插入图片描述
运行时间的准确界
在这里插入图片描述
在这里插入图片描述

递归方程解的渐进阶求法

在这里插入图片描述
在这里插入图片描述

合并排序

  • 算法思想:
    先将元素划分多组,直到不能划分为止,然后进行区间的合并,合并成有序序列,直到合并成一整个有序序列!
  • 代码
void merge_sort(int a[],int l,int r,int tmp[])
{
	if(l>=r) return;
	int mid = l+r>>1;
	//递归区间拆分
	merge_sort(a,l,mid);
	merge_sort(a,mid+1,r);
	//进行区间合并
	int i = l,j = mid+1,k = 0;
	while(i<=mid&&j<=r)
	{
		if(a[i]<a[j]) tmp[k++] = a[i++];
		else tmp[k++] = a[j++];
	}
	while(i<=mid) tmp[k++] = a[i++];
	while(j<=r) tmp[k++] = a[j++];
	//拷贝回原数组
	for (i = l, j = 0; i <= r; i ++, j ++ ) a[i] = tmp[j];
}

合并过程:
eg: 8 5 3 9 11 6 4 1 10 7 2

在这里插入图片描述
时间复杂度:O(nlogn)
空间复杂度:O(n)

递归和分治法

递归

  • 基于归纳的递归算法的思想方法

对于一个规模为n的问题P(n),归纳法的思想如下:

  • 基础步:a1是问题P(1)的解
  • 归纳步:对所有的k,1<k<n,若ak是问题P(k)的解,则p(ak)是问题 P(k+1)的解.其中,p(ak)是对ak的某种运算或处理.这里可以将p()看成递归函数!

分治

分治算法思想

在求解一个输入规模为n,而n的取值有很大的问题时,直接求解往往非常困难.这时,可以先分析问题本身所具有的某些特性,然后从这些特性出发,选择某些适当的设计策略来求解.
例如:把n个输入划分成k个子集,分别对这些子集进行求解,再把所有得到的解组合起来,从而得到整个问题的解,这样,有时可以收到很好的效果.这种方法就是所谓的分治法

eg 最大最小问题:

输入:整数数组a,数组的起始边界和结束边界lr
输出:最大运算l,最小元素e_min

void maxmin(int a[],int &e_max,int &e_min,int l,int r)
{
	if(r-l<=1) //元素少直接求解
	{	
		if(a[l]<a[r])
		{
			e_max = max(a[r],e_max);
			e_min = min(a[l],e_min);
		}
		else
		{
			e_max = max(a[l],e_max);
			e_min = min(a[r],e_min);
		}
		return;
	}
	int mid,x1,y1,x2,y2;
	mid = (l+r)>>1; //划分成2个子区间
	maxmin(a,x1,y1,l,mid); //求2个子区间的最大最小值
	maxmin(a,x2,y2,mid+1,r);
	e_max = max(x1,x2); //合并原数组的最大最小值
	e_min = min(y1,y2);
}

求解过程如下图:

在这里插入图片描述
时间复杂度:O(n)
空间复杂度:O(logn) 递归深度

分治法设计步骤

  • 划分步:将输入的问题划分成k个子问题
  • 治理步:当问题规模大于某个预定义的阀值n0时,治理步由k个递归调用组成
  • 组合步:这一步把各个子问题组合起来

上面3个步骤对应归并排序:
划分步-> 划分子区间
治理步 -> 对区间合并
组合步 -> 拷贝数组

快速排序

算法思想:
把一个序列划分成2个子序列,使得第一个序列的元素都小于第二个序列的所有元素,不断进行划分直到最后构成n个序列,每个序列只有一个元素.这时他们就是有序序列了!

划分步:划分序列
治理步:选择一个基准位置,将区间进行划分,使左边的元素小于基准值,右边元素大于基准值
组合步:这里划分成n个区间后,就已经有序了,也就是整个序列的解

//按枢纽元素划分序列 采用快慢指针
int split(int A[], int low, int high)
{
	int k, i = low;
	int x = A[low];
	//这里的i指向待划分区间的第一个元素,k指向第二个元素!
	//这里的k一直往后遍历
	for (k = low + 1; k < high; k++)
	{
		if (A[k] <= x) //这里我们排升序,所以当 A[k]大于x的时候,说明这个位置,符号升序,我们不进入if语句,k指针继续往后
		{
			//进入了if说明 A[k]比我们选择的基准值x小,应该放在基准值的左边,所以让指针i++,如果k和i不是指向同一个元素就进行交换
			i++;
			if (i != k)
				swap(A[i], A[k]);
		}
	}
	//完成了上述交换后,我们在将基准值和i指向的元素交换,这样也就完成了一次划分
	swap(A[low], A[i]);
}
void quick_sort(int A[], int low, int high)
{
	int k;
	if (low < high) //有区间未划分就会进入if进行划分
	{
		k = split(A, low, high); //这里返回的k位置,这个元素已经有序,也就是完成了一次划分!
		quick_sort(A, low, k - 1);//对 k左边区间进行划分
		quick_sort(A, k + 1, high);//对k右边区间进行划分
	}
}

算法执行过程
第一次划分:
在这里插入图片描述

在这里插入图片描述
时间复杂度最坏情况: O(n)每次划分都划分成空区间和另一个区间,解决方案基准元素3数取中!
平均复杂度: O(nlogn)

贪婪法

  • 设计思想:

贪婪法通常用来解决具有最大值或者最小值优化问题.他犹如登山一样,一步步向前推进,从某一个初始状态出发,根据当前局部的而不是全局的最优决策,以满足约束方程为条件,以使得目标函数的值增加的最快或最慢为准则,选择一个能够最快到达要求的输入元素,以便尽快的构成问题的可行解

适合贪婪法求解的问题满足下面2个重要性质:

  • 选择性质

是指所求问题的全局最优解,可以通过一系列局部最优选择来达到.每进行一次选择,就得到一个局部的解,并把所求的问题简化为一个规模更小的类似子问题

  • 最优子结构性质

是指一个问题的最优解中包含子问题的最优解

背包问题

这里的背包问题物体可分解,就不介绍了,就是将性价比最高的物品放入到背包中,直到背包放不下此时性价比最高的物品,那就将物品进行分解,然后计算总价值!

单源最短路径问题

Dijkstra狄斯喹诺算法解最短路径

视频链接这是求最短路径的一种算法
算法思想:
多个节点多个连接的边组成的图,我们需要求一个节点到另一个节点的最短路径
我们可以先从第一个节点出发求临近最短的路径的节点,然后确定路径后,再到最短路径节点处重复之前操作,如果当前节点的路径值比之前路径值小就更新路径值,否则不变,直到到达目标节点

在这里插入图片描述
书上例题:

在这里插入图片描述
时间复杂度O(n^2) 空间复杂度: O(n)

最小花费生成树问题

最小花费生成树问题应用场景: 例如用图的顶点代表城市,顶点与顶点之间的边代表城市之间的道路或通信线路,用边的权代表道路的长度或通信路线的费用,最小花费生成树问题,就表示城市之间最短的道路或费用最少的通信线路问题.

最小生成树概念:
在这里插入图片描述

Kruskal克鲁斯卡尔算法

算法思想俗称避环法

开始时将图的所有节点都作为孤立顶点,每个顶点都构成了一颗只有根节点的书,构成了森林T.
然后将所有边按照权值排升序,每次从边集中选择最小权值边,然后加入到到T中,并且不会使当前T构成回路,就加入,否则就丢弃该边,重复上述操作,直到把n-1条边加入后就生成了最小花费生成树
在这里插入图片描述
时间复杂度: 完全图O(n^2logn) 平面图 O(nlogn) 空间复杂度: O(n)

Prim普利姆算法

算法思想:

该算法有点类似狄斯喹诺算法
先从起点位置开始,然后加入与起点相连的最短权值的点,然后将当前树看成一个整体,再加入与当前树相连权值最小的顶点,依次进行直到所有顶点都加入

在这里插入图片描述
适用于顶点少,边数多的情况
时间复杂度:O(n^2) 空间复杂度:O(n)

霍夫曼编码问题

在这里插入图片描述
通俗点讲哈夫曼树就是一个带权的二叉树,相同的叶节点可以构造出不同哈夫曼二叉树

前缀码和最优二叉树

最优二叉树,就是刚刚哈夫曼树构造WPL为最小
也就是权值越大的越靠近根节点,权值越小的越远离根节点
前缀码就是将哈夫曼树二叉树的每条边编码,左边为0,右边为1进行
到叶子节点,有唯一的前缀码,并且前缀码唯一,任意节点的前缀码不会是另一叶子节点的前缀码
在这里插入图片描述
解题步骤

  • 构造最优二叉树
  • 编码
  • 得出每个叶节点的前缀码

在这里插入图片描述
哈夫曼算法时间复杂度:O(nlogn)

动态规划

动态规划思想方法

动态规划的最优决策原理:

对于具有n个输入的最优解问题,它们的活动过程往往划分为若干个阶段,每一个阶段的决策依赖于前一个阶段的状态,由决策所采取的动作使状态发送转移,成为下一阶段的决策依据.

多段树的最短路径问题

多段树的决策过程

多段树的最短路径问题,是求源点s到达收点t的最小花费通路
决策的第一阶段,确定图中第k-1段的所有顶点到达收点t的花费最小通路
决策的第二阶段,确定图中第k-2段所有节点到达收点t的花费的最小通路

详细过程如图所示
在这里插入图片描述
在这里插入图片描述

0/1背包问题

0/1背包问题中,物体或者被装入背包,或者不装入背包,只有这2种选择,不能分割物体!

在这里插入图片描述
代码实现:

#include<bits/stdc++.h>

using namespace std;

const int MAXN = 1005;
int v[MAXN];    // 体积
int w[MAXN];    // 价值 
int f[MAXN][MAXN];  // f[i][j], j体积下前i个物品的最大价值 

int main() 
{
    int n, m;   
    cin >> n >> m;
    for(int i = 1; i <= n; i++) 
        cin >> v[i] >> w[i];

    for(int i = 1; i <= n; i++)
    {
        for(int j = 1; j <= m; j++)
        {
            //  当前背包容量装不进第i个物品,则价值等于前i-1个物品
            if(j < v[i]) 
                f[i][j] = f[i - 1][j];
            // 能装,需进行决策是否选择第i个物品
            else    
                f[i][j] = max(f[i - 1][j], f[i - 1][j - v[i]] + w[i]);
        } 
     }          
    cout << f[n][m] << endl;

    return 0;
}

验证结果

在这里插入图片描述

回溯

回溯法的思想方法

问题的解空间和状态空间树

状态空间树的动态搜索

回溯法的效率问题

分支于限界

分支与限界法的基本思想TSP 图 8.9

随机算法

随机算法的类型和特点

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/54565.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

关于nodejs调用c/c++代码的一些感悟

帮客户解决问题&#xff0c;他们做的业务涉及到硬件&#xff0c;但是桌面端程序员离职&#xff0c;临时接手的人员&#xff0c;只会node&#xff0c;于是希望通过node调用c 基本套路&#xff0c;使用ffi和ref插件&#xff0c;打开设备正常&#xff0c;但就是无法读取数据。 接…

【Python游戏】用Python实现一个测试你智商的小游戏——24点,过不了三关的都是细狗 | 附带源码

前言 好咯&#xff0c;包子们下午好 今天小编主要是过来测试一下大家的智商&#xff0c;没别的意思&#xff0c;不是看不起大家&#xff0c;我感觉今天实现的小游戏&#xff0c;可能大家真的过不了三关&#xff01; 哈哈哈&#xff0c;废话不多说吧 直接开始我们的游戏实现功能…

五、【React-Router6】路由表 useRoutes() + Outlet

文章目录1、useRoutes() 介绍2、简单 CODING2.1、项目结构2.2、routes.js2.3、App.js2.4、Result3、嵌套 Outlet CODING3.1、项目结构3.2、routes.js3.3、Home.js3.4、App.js3.5、Result1、useRoutes() 介绍 原来写的路由管理如下 <Routes><Route path/about elemen…

codeforces:C. Almost All Multiples【构造 + 贪心】

目录题目截图题目分析ac code总结题目截图 题目分析 现在p1 x, pn 1如果我们一开始按1234…这样放字典序是最小的所以根据这个思路&#xff0c;我们还是按这个构造&#xff1a;那么我们的n被挤出来了&#xff0c;只能放到px上所以如果一开始x不能整除n的话&#xff0c;就直接…

Linux安装MySQL【Ubuntu20.04】

操作系统&#xff1a;Ubuntu20.04 使用工具&#xff1a;xshell7、xftp7 MySQL版本&#xff1a;5.7 一、删除Linux系统下自带的mariadb &#xff08;因为centos自带一个老版Mariadb 与MySQL冲突&#xff09; 如果没有找到Mariadb直接跳过 #查找Mariadb rpm -qa | grep maria…

面试总结2

用时&#xff1a;40min 自我介绍hashset存储对象怎么进行判断是否重复 Synchronized底层实现原理 Synchronized锁的升级过程 讲讲开发中常用到的spring注解spring事务&#xff0c;传播机制&#xff0c;隔离级别说一说你常用的git命令说一说你对IOC、AOP的理解1、hashset存储对…

[Linux打怪升级之路]-秒懂进程地址空间

前言 作者&#xff1a;小蜗牛向前冲 名言&#xff1a;我可以接受失败&#xff0c;但我不能接受放弃 如果觉的博主的文章还不错的话&#xff0c;还请点赞&#xff0c;收藏&#xff0c;关注&#x1f440;支持博主。如果发现有问题的地方欢迎❀大家在评论区指正。 目录 一、C/C下…

【GIT】常用操作总结

一、在本地仓库及远程仓库创建分支&#xff0c;并建立关联关系。 1、创建本地分支&#xff0c;如图&#xff1a; 2、填写分支名称&#xff0c;勾选Checkout branch&#xff1a; 3、提交本地分支到远程分支&#xff1a; 右键选择Git -- Repository -- push&#xff1a; push的时…

Python爬取的网页,需要解码怎么办

前言 本文是该专栏的第26篇,后面会持续分享python的爬虫干货知识,记得关注。 很多时候,在用爬虫采集数据的时候,采集到的源码内容并非我们想要的正确信息,使用正则或者Xpath匹配到的信息也需要我们再次解码才能拿到精准的数据。最近也正是球迷朋友们非常关注卡塔尔世界杯…

[操作系统笔记]基本分段存储管理

内容系听课复习所做笔记&#xff0c;图例多来自课程截图 分段原理 与“分页”最大的区别就是&#xff1a;离散分配时所分配地址空间的基本单位不同 分页是不管程序的逻辑的&#xff0c;规定了页大小就是这么多&#xff0c;但是分段是依据程序自身逻辑来划分的&#xff08;分页的…

micro-app-源码解析4-数据通信篇-终篇

沙箱篇官方讲解地址 https://github.com/micro-zoe/micro-app/issues/21 1. 带着问题进行阅读 在做框架的时候&#xff0c;没法避免的遇见父子通信和兄弟通信的问题&#xff0c;但是如何实现通信这是个每个框架需要解决的问题。1.1 如何选择父子通信的方式 最好的方式应该是…

IOC操作Bean管理(基于注解方式)

IOC 控制反转&#xff0c;把创建对象过程交给Spring进行管理。 目录 什么是注解 Bean 管理注解方式&#xff08;创建对象&#xff09; 基于注解方式实现对象创建 第一步&#xff1a;引入依赖 第二步&#xff1a;开启组件扫描 创建类&#xff0c;在类上面添加创建对象注解…

Python爬虫实战,request+Matplotlib模块,Python绘制一个足球运动员的数据可视化图表

前言 用Python和Matplotlib绘制一个足球运动员的数据可视化图表。 Let’s start happily 开发工具 Python版本&#xff1a; 3.6.4 相关模块&#xff1a; bs4模块 requests模块 pandas模块 matplotlib模块 json模块 numpy模块 环境搭建 安装Python并添加到环境变量…

Sqoop数据导入 第2关:Mysql导入数据至HDFS上

为了完成本关任务,你需要掌握: 1、数据库( MySQL )建表。 2、Mysql 数据导入至 HDFS 中。 数据库( MySQL )建表 用命令进入 MySQL 客户端。 mysql -uroot -p123123 -h127.0.0.1 创建数据库hdfsdb(格式默认为utf8),并在数据库内建立表student,其表结构如下: mys…

通过求解数学模型来选择编码节点的最佳数量和位置(Matlab代码实现)

&#x1f352;&#x1f352;&#x1f352;欢迎关注&#x1f308;&#x1f308;&#x1f308; &#x1f4dd;个人主页&#xff1a;我爱Matlab &#x1f44d;点赞➕评论➕收藏 养成习惯&#xff08;一键三连&#xff09;&#x1f33b;&#x1f33b;&#x1f33b; &#x1f34c;希…

【✨十五天搞定电工基础】电阻电路的分析方法

本章要求1. 掌握支路电流法、叠加原理和戴维宁定理等电路的基本分析方法; 2. 了解实际电源的两种模型及其等效变换; 3. 了解非线性电阻元件的伏安特性及静态电阻、动态电阻的概念&#xff0c;以及简单非线性电阻电路 的图解分析法。 目录 一、电阻串并联连接的等效变换 1、…

企业如何有效的防爬虫?

防爬虫&#xff0c;简单来说&#xff0c;就是在尽量减少对正常用户的干扰的情况下尽可能的加大爬虫的成本。 而反防爬虫&#xff0c;或者说制造隐蔽性强的爬虫&#xff0c;就是尽量模拟正常用户的行为。 这两者是动态博弈的。大公司基本都有防爬的项目&#xff0c;以保护数据…

一图了解es6常用数据迭代函数map,filter,fill,reduce

一、一图胜千言 前端开发中&#xff0c;js数组处理是最常用的&#xff0c;除了for循环外&#xff0c;随着es6的普及&#xff0c;像reduce()、filter()、map()、some()、every()以及…展开属性都是最常用到的。 今天偶然从网上看到这张图&#xff0c;真是眼前一亮&#xff0c;真…

盘点JAVA中延时任务的几种实现方式

场景描述 ①需要实现一个定时发布系统通告的功能&#xff0c;如何实现&#xff1f; ②支付超时&#xff0c;订单自动取消&#xff0c;如何实现&#xff1f; 实现方式 一、挂起线程 推荐指数&#xff1a;★★☆ 优点&#xff1a; JDK原生(JUC包下)支持&#xff0c;无需引入新…

RabbitMQ之集群管理

1、在node2、node3、node4三台Linux虚拟机中安装RabbitMQ。 2、从node2拷贝.erlang.cookie到node3、node4的相应目录 如果没有该文件&#xff0c;手动创建/var/lib/rabbitmq/.erlang.cookie &#xff0c;生成Cookie字符串&#xff0c;或者启动一次RabbitMQ自动生成该文件。生产…