时间复杂度

dijkstra算法及其优化

不羁岁月 提交于 2020-01-22 20:02:52
dijkstra算法是经典的贪心算法。基本的想法是,有两个集合S和E,开始S集合中只有一个起点,E集合中有剩下的其他点。遍历E集合中的所有点,找出与起点距离最近的一个点,将其加入集合S,并用该点去更新起点到其他点的最短路径。 由动图结合上面的思路,我们可以看出,算法的基本框架是: 1 1.初始化 2 for i(0 -> n - 1) 3 { 4 2.找出距离起点最近的点 5 3.标记该点加入集合S 6 4.用新加入集合S的点去更新起点到其他点的最短距离 7 } 1.其中初始化包括了距离数组dis,将dis数组初始化为无穷大,将第一个点的距离置为0。 2.循环n - 1次是因为n个点只需添加n - 1个点到集合S,每做一次循环添加一个点,所以是循环n - 1次。 3.标记新点加入集合用一个st数组记录即可。 4.dis[i]表示的是起点s到i的点距离,所以用新点a去更新起点s到其他点(例如b点)的最短路径就是比较dis[a] + (a到b的距离)和 dis[b]的大小,将dis[b]置成两者中的最小值。 5.可以注意的是在伪代码中的2步:找出距离起点最近的点,要遍历剩下的所有点,所以时间复杂度是O(n),但是我们联想到,在一堆数字中找出一个最小值,可以用堆进行优化,时间复杂度是可以由O(n)降到O(logn)的。所以这就是dijkstra的堆优化,可以将时间复杂度为O(mn)降为O

时间复杂度Big O以及Python 内置函数的时间复杂度

痴心易碎 提交于 2020-01-22 19:36:00
声明:本文部分内容摘自 原文 本文翻译自Python Wiki 本文基于GPL v2协议,转载请保留此协议。 本页面涵盖了Python中若干方法的时间复杂度(或者叫“大欧”,“Big O”)。该时间复杂度的计算基于当前(译注:至少是2011年之前)的CPython实现。其他Python的实现(包括老版本或者尚在开发的CPython实现)可能会在性能表现上有些许小小的差异,但一般不超过一个O(log n)项。 本文中,’n’代表容器中元素的数量,’k’代表参数的值,或者参数的数量。 1. 列表(list) 以完全随机的列表考虑平均情况。 列表是以数组(Array)实现的。最大的开销发生在超过当前分配大小的增长,这种情况下所有元素都需要移动;或者是在起始位置附近插入或者删除元素,这种情况下所有在该位置后面的元素都需要移动。如果你需要在一个队列的两端进行增删的操作,应当使用collections.deque(双向队列) 操作 平均情况 最坏情况 复制 O(n) O(n) append[注1] O(1) O(1) 插入 O(n) O(n) 取元素 O(1) O(1) 更改元素 O(1) O(1) 删除元素 O(n) O(n) 遍历 O(n) O(n) 取切片 O(k) O(k) 删除切片 O(n) O(n) 更改切片 O(k+n) O(k+n) extend[注1] O(k) O(k)

浅谈程序优化

荒凉一梦 提交于 2020-01-22 19:15:24
   当初在学校实验室的时候,常常写一个算法,让程序跑着四处去晃荡一下回来,结果也就出来了。可工作后,算法效率似乎重要多了,毕竟得真枪实弹放到产品中,卖给客户的;很多时候,还要搞到嵌入式设备里实时地跑,这么一来真是压力山大了 ~~~ 。这期间,对于程序优化也算略知皮毛,下面就针对这个问题讲讲。   首先说明一下,这里说的程序优化是指程序效率的优化。一般来说,程序优化主要是以下三个步骤:    1. 算法优化    2. 代码优化    3. 指令优化 算法优化   算法上的优化是必须首要考虑的,也是最重要的一步。一般我们需要分析算法的时间复杂度,即处理时间与输入数据规模的一个量级关系,一个优秀的算法可以将算法复杂度降低若干量级,那么同样的实现,其平均耗时一般会比其他复杂度高的算法少(这里不代表任意输入都更快)。   比如说排序算法,快速排序的时间复杂度为O(nlogn),而插入排序的时间复杂度为O(n*n),那么在统计意义下,快速排序会比插入排序快,而且随着输入序列长度n的增加,两者耗时相差会越来越大。但是,假如输入数据本身就已经是升序(或降序),那么实际运行下来,快速排序会更慢。   因此,实现同样的功能,优先选择时间复杂度低的算法。比如对图像进行二维可分的高斯卷积,图像尺寸为MxN,卷积核尺寸为PxQ,那么     直接按卷积的定义计算,时间复杂度为O(MNPQ)    

数据结构与算法之美-链表

风流意气都作罢 提交于 2020-01-22 01:09:58
什么是链表 和数组一样,链表也是一种线性表。 从内存结构来看,链表的内存结构是不连续的内存空间,是将一组零散的内存块串联起来,从而进行数据存储的数据结构。 链表中的每一个内存块被称为节点Node。节点除了存储数据外,还需记录链上下一个节点的地址,即后继指针next。 链表的特点 插入、删除数据效率高,时间复杂度为O(1),只需更改指针指向即可。 随机访问效率低,时间复杂度为O(n),需要从链头至链尾进行遍历。 和数组相比,链表的内存空间消耗更大,因为每个存储数据的节点都需要额外的空间存储后继指针。 常见的链表结构 单链表 每个节点只包含一个指针,即后继指针。 单链表有两个特殊的节点,即首节点和尾节点。 用首节点地址表示整条链表,尾节点的后继指针指向空地址null。 性能特点,插入和删除节点的时间复杂度为O(1),查找的时间复杂度为O(n)。 循环链表 除了尾节点的后继指针指向首节点的地址外均与单链表一致。 适用于存储有循环特点的数据,比如约瑟夫问题。 双向链表 节点除了存储数据外,还有两个指针分别指向前一个节点地址(前驱指针prev)和下一个节点地址(后继指针next)。 首节点的前驱指针prev和尾节点的后继指针next均指向空地址。 性能特点,和单链表相比,存储相同的数据,需要消耗更多的存储空间。 插入、删除操作比单链表效率更高,时间复杂度为O(1)。以删除操作为例

算法:计算十进制数字在二进制表示1的个数

天涯浪子 提交于 2020-01-21 01:18:13
题目一 计算十进制数字在二进制表示 1 的个数 举个例子: 十进制数字为 1 时,它的二进制表示是 001,二进制表示 1 的个数为 1; 十进制数字为 2 时,它的二进制表示是 010,二进制表示 1 的个数为 1; 十进制数字为 3 时,它的二进制表示是 011,二进制表示 1 的个数为 2; 十进制数字为 4 时,它的二进制表示是 100,二进制表示 1 的个数为 1; 十进制数字为 5 时,它的二进制表示是 101,二进制表示 1 的个数为 2; 十进制数字为 6 时,它的二进制表示是 110,二进制表示 1 的个数为 2; 十进制数字为 7 时,它的二进制表示是 111,二进制表示 1 的个数为 3; 时间复杂度 O(logn) 的解法 对于这个题目比较容易想到的是如下代码: int count = 0; while(n != 0) { if(n % 2 == 1) { count++; } n = n >> 1; } 上述代码主要做了两个步骤: n % 2 表示对数字求模运算,也就是计算 二进制的末尾 是 1 还是 0,如果二进制的末尾是 1 ,则 count 自增,count 表示的是二进制表示 1 的个数; n = n >> 1 表示把二进制 往右移走一位 ,比如十进制数字 7 的二进制表示是 111 ,那么通过右移一位后,则变成 011。

python之算法

安稳与你 提交于 2020-01-20 22:28:37
1.什么叫算法 算法:可以理解为是解决问题方法的一个计算过程。 2.时间复杂度 用来评估算法运行效率的一个东西。时间复杂度常用 大O符号 表述,如O(1)。 n = 10 print('Hello World') # 时间复杂度:O(1) ---------------------------------------------------------------- for i in range(n): print('Hello World') # 时间复杂度:O(n) ---------------------------------------------------------------- for i in range(n): for j in range(n): print('Hello World') # 时间复杂度:O(n^2) ---------------------------------------------------------------- for i in range(n): print('Hello World') for j in range(n): print('Hello World') # 时间复杂度:O(n^2) ---------------------------------------------------------------

线段树

邮差的信 提交于 2020-01-20 22:15:02
文章目录 1. 概念 1.1 定义 1.2 使用场景 1.2.1 时间复杂度 2. 线段树——区间求和及更新 3. 线段树——区间最值 4. 碎碎念 5. 参考资料 1. 概念 1.1 定义 线段树使用一个完全二叉树来存储每个区间(segment) 的数据。线段树所使用的二叉树是用一个数组保存的。 完全二叉树:除了最后一层之外的其他每一层都被完全填充,并且所有结点都保持向左对。参考 https://www.zhihu.com/question/19809666/answer/13029983 对于长度为 n 的线段数组有如下性质: 树的高度 log(n) 节点的个数 2n -1「 (n) 叶子节点 +( n -1 ) 内部节点」 <=> 2 ⌈ L o g 2 n ⌉ + 1 2^{⌈ Log_2^n ⌉ + 1} 2 ⌈ L o g 2 n ​ ⌉ + 1 -1 根据完全二叉树的性质,树高 h = ⌈ L o g 2 n Log_2^n L o g 2 n ​ ⌉ +1 ,节点个数 n = 2 h 2^h 2 h - 1 由此节点个数 2 ⌈ L o g 2 n ⌉ + 1 2^{⌈ Log_2^n ⌉ + 1} 2 ⌈ L o g 2 n ​ ⌉ + 1 -1 => 2 ∗ 2 ⌈ L o g 2 n ⌉ 2*2^{⌈ Log_2^n ⌉} 2 ∗ 2 ⌈ L o g 2 n

【数据结构】时间复杂度的计算

与世无争的帅哥 提交于 2020-01-20 22:09:54
作者:raymondCaptain 链接:https://www.jianshu.com/p/f4cca5ce055a 来源:简书 我们假设计算机运行一行基础代码需要执行一次运算。 int aFunc ( void ) { printf ( "Hello, World!\n" ) ; // 需要执行 1 次 return 0 ; // 需要执行 1 次 } 那么上面这个方法需要执行 2 次运算 int aFunc ( int n ) { for ( int i = 0 ; i < n ; i ++ ) { // 需要执行 (n + 1) 次 printf ( "Hello, World!\n" ) ; // 需要执行 n 次 } return 0 ; // 需要执行 1 次 } 这个方法需要 (n + 1 + n + 1) = 2n + 2 次运算。 我们把 算法需要执行的运算次数 用 输入大小n 的函数 表示,即 T(n) 。 此时为了 估算算法需要的运行时间 和 简化算法分析,我们引入时间复杂度的概念。 定义:存在常数 c 和函数 f(N),使得当 N >= c 时 T(N) <= f(N),表示为 T(n) = O(f(n)) 。 如图: 当 N >= 2 的时候,f(n) = n^2 总是大于 T(n) = n + 2 的,于是我们说 f(n) 的增长速度是大于或者等于 T

二分查找时间复杂度推断

生来就可爱ヽ(ⅴ<●) 提交于 2020-01-20 13:09:34
主要还是从算法所占用的「时间」和「空间」两个维度去考量。 时间维度:是指执行当前算法所消耗的时间,我们通常用「时间复杂度」来描述。 空间维度:是指执行当前算法需要占用多少内存空间,我们通常用「空间复杂度」来描述。 二分查找分析: 二分查找每次排除掉一半的不适合值,所以对于N个元素的情况: 一次二分剩下:N/2 两次二分剩下:N/2/2 = n/4 三次二分查找剩下:N/2/2/2 = N/8 ..... M次二分剩下:n / (2^M) 在最坏情况下是在排除到只剩下最后一个值之后得到结果,即 N / (2^m) = 1 所以由上式可得:2^m = N 推出时间复杂度是以2为底的对数公式: m = log2(N) 注意:m为查找次数, N为元素个数. 例如:求0-10000个元素中最多几次查找到73? m = log2(10000) m = 13次 来源: CSDN 作者: 慢慢的燃烧 链接: https://blog.csdn.net/u010164190/article/details/104049014

数据结构与算法

点点圈 提交于 2020-01-20 04:53:34
1. 时间复杂度计算 基本操作,即只有常数项,认为其时间复杂度为O(1) 顺序结构,时间复杂度按加法进行计算 循环结构,时间复杂度按乘法进行计算 分支结构,时间复杂度取最大值 判断一个算法的效率时,只需关注操作数量的最高次项,其他次要项和常数项可以忽略 常见时间复杂度大小判断 O(1) < O(logn) < O(n) < O(nlogn) < O(n^2) < O(n^3) < O(2^n)< O(n!) < O(n^n) 2.顺序表 定义 :将元素顺序地存放在一块连续的存储区里,元素间的顺序关系由它们的存储顺序自然表示。 2.1顺序表的两种基本实现方式 max :元素存储区的容量 num :元素存储区的当前已有元素个数 2.2元素存储区替换 一体式结构需要整体搬迁,而分离式结构只需将表信息区中的数据链接地址更新,而该顺序表对象不变。 2.3增加元素、删除元素 3.链表 链表 :是一种常见的基础数据结构,是一种线性表,但是不像顺序表一样连续存储数据,而是在每一个节点(数据存储单元)里存放下一个节点的位置信息(即地址)。 3.1 单向链表 是链表中最简单的一种形式,它的每个节点包含两个域,一个信息域(元素域)和一个链接域。这个链接指向链表中的下一个节点,而最后一个节点的链接域则指向一个空值。 3.2 双向链表 每个节点有两个链接:一个指向前一个节点,当此节点为第一个节点时,指向空值