C#算法设计之知识储备
前言
该文章的最新版本已迁移至个人博客【比特飞】,单击链接 https://www.byteflying.com/archives/669 访问。
算法的讨论具有一定的规则,其中也包含一些不成文的约定,本博文旨在为初学算法的同学指明一条通向算法的“不归路”。
渐近记号
1、Θ(big-theta)
若存在正常量
、
和
,使得当
时,不等式
恒成立,则称g(n)是f(n)的一个渐近紧确界,记作Θ。它包含渐近上界和渐近下界。
简单的理解为在 时,f(n)被夹在
和
之间,
为f(n)的渐近下界,
为f(n)的渐近上界。
2、O(big-oh)
若存在正常量 c和
,使得当
时,不等式
恒成立,则称g(n)是f(n)的一个渐近上界,记作O。
简单的理解为在 时,cg(n)总是在f(n)之上。
3、Ω(big-omege)
若存在正常量 c和
,使得当
时,不等式
恒成立,则称g(n)是f(n)的一个渐近下界,记作Ω。
简单的理解为在 时,cg(n)总是在f(n)之下。
其它几个记号在讨论算法的复杂度时极少用到,故本博文不予介绍。
以下给出这3种常用记号的函数图:
我们使用O表示算法在最坏的情况下所代表的时间复杂度,Ω表示算法在最好的情况下所代表的时间复杂度,Θ表示算法在平均情况下所代表的时间复杂度。
由于网络中很多文章均没有将这3个符号分清楚,比如我们讨论冒泡排序的时间复杂度时,其在最坏的情况下的时间复杂度为: ,在最好的情况下的时间复杂度为:
,在平均情况下的时间复杂度也为:
。这种记法是不正确的,但由于大家都这么写,本系列博文若未特殊说明,沿用此记法。
时间复杂度
在分析算法的时间复杂度时,我们一般分析其在最坏的情况下的关键代码的执行次数。还以冒泡排序为例,冒泡排序算法采用双循环比较相邻2个元素的值的大小,若符合预期则不管,若不符合预期则交换这2个元素的位置。设问题的规模为n,那么在最坏的情况下,即原数组逆序排列时,我们需要执行交换元素的代码次数为 次,所以我们认为冒泡排序的时间复杂度为:
。事实上冒泡排序在最坏的情况下执行的精确次数一般不是
次,而是略低于
次,因为内循环可以被优化。每次外循环执行完毕后内循环可以少执行一次,因为每次外循环执行完毕时,最大的值已经在最后面了(若我们需要升序排序),内循环无需处理后面的元素。具体分析可参考我的另一篇博文,C#算法设计排序篇之01-冒泡排序(附带动画演示程序)。
还有另外几个规则,在讨论算法的时间复杂度时,我们更关心的是高阶项,忽略低阶项。例如一个算法在最坏的情况下的执行次数为 次,那么这个低阶的 n 可以被忽略,其时间复杂度就是
。因为当 n 趋向于无穷大时,低阶的 n 对整体的执行次数没有多大影响。当一个算法执行的次数为 n 时,那么它的时间复杂度为
,也称这个算法的时间复杂度为线性的。n/2,n,2n,100000000n,都是线性的算法,均记为
。设一个算法的执行次数为 cn 次,常量c被忽略,因为当 n 趋向于无穷大时,常量对整体的执行次数没有多大影响。
你可能想到另外一个问题,线性的 100000000n 和 ,哪个效率更高?答案和你的问题规模有关。
若问题规模趋向于无穷大,线性的算法总是好于 ,因为高阶函数的增长速度快于低阶函数。对于
和 100000000n ,当问题的规模大于1亿时,
显著的超越线性的 100000000n ,但是若你的问题规模总是小于1亿,那么此时选择
的算法是个不错的选择,因为小于1亿时,
小于 100000000n 。不过现实开发中,你不可能设计出 100000000n 的线性算法,此处仅作讨论。
若一个算法总是在某一确定时间内完成其运算,我们记作 ,并称其时间复杂度为常量的(或常数的)。典型的算法是哈希算法。我们一般认为哈希算法的时间复杂度为常量的(本博文不讨论关键字冲突等问题)。
以下给出几种常见的时间复杂度曲线图以供参考:
空间复杂度
与时间复杂度基本类似,本博文不予赘述。
基于比较的排序算法的下界
基于比较的排序算法的下界为 ,《算法导论》第3版中文版第107~108页(英文版第191~192页)使用决策树模型证明了此下界,有兴趣的同学可以自行观摩。
常见的基于比较的排序算法有:冒泡排序、快速排序、直接插入排序、选择排序、归并排序、堆排序、希尔排序、二叉树排序等。
非基于比较的以空间换时间的排序算法有:计数排序、基数排序、桶排序等。
其中快速排序、归并排序、堆排序、二叉树排序4种排序算法都达到了比较排序算法的下界,我们一般称它们为基于比较的先进算法。
以上排序算法都可以在我的 C#算法设计概述 系列博文中找到,其中包含了时间复杂度的分析等。
排序算法的稳定性
假定在待排序的记录序列中,存在多个具有相同的关键字的记录,若经过排序,这些记录的相对次序保持不变,即在原序列中,r[i]=r[j],且r[i]在r[j]之前,而在排序后的序列中,r[i]仍在r[j]之前,则称这种排序算法是稳定的;否则称为不稳定的。
即保证排序前2个相等的数其在序列的前后位置顺序和排序后它们两个的前后位置顺序相同。
不稳定的排序算法有快速排序、直接选择排序、希尔排序、堆排序,简记为快、选、希、堆。其它的常见排序算法均为稳定性算法。
研究排序算法稳定性的意义是什么呢?
若你只想给一个无序数组排序,那么排序算法的稳定性没有任何意义。
若你要给一组对象排序,那么其可能是有意义的。例如一个学生对象包含学号和某次考试的总分2个字段,原来已经按学号排好序了(从小到大),现在让你按分数给这个学生对象的数组排序,但是若分数相同,那么学号小的依然排在前面,对于这种情况,你只能选择快、选、希、堆以外的排序算法。
内部排序与外部排序
内部排序:
待排序记录存放在计算机随机存储器中(内存)进行的排序过程。
外部排序:
待排序记录的数量很大,以致于内存不能一次容纳全部记录,所以在排序过程中需要对外存进行访问的排序过程。
假如你有1000亿条整数数据(无法一次载入内存),这些数据都是存在硬盘上的,现在你要写一个算法判定这1000亿条数据是不是升降排列的(nums[k+1] >= nums[k]),你可以每次从硬盘取出一批数据(内存可承受的),逐一判定相邻数据的大小关系,若不满足nums[k+1] >= nums[k]的关系直接判定false,如果1000条数据全部可以取出并没有被判定为false,则可以判定为true。
联机算法
联机算法是在任意时刻算法对要操作的数据只读入(扫描)一次,一旦被读入并处理,它就不需要在被记忆了。而在此处理过程中算法能对它已经读入的数据立即给出相应子序列问题的正确答案。
联机算法仅需要常量空间(不包含原数据)并以线性时间运行,因此联机算法几乎是完美的算法。
关于算法中的对数
该文章的最新版本已迁移至个人博客【比特飞】,单击链接 https://www.byteflying.com/archives/669 访问。
数学中的对数:
对数是对求幂的逆运算,正如除法是乘法的倒数,反之亦然。
如果a的x次方等于N(a>0,且a不等于1),那么数x叫做以a为底N的对数(logarithm),记作
。其中,a叫做对数的底数,N叫做真数。
- 特别地,我们称以10为底的对数叫做常用对数(common logarithm),并记为lg;
- 称以无理数e(e=2.71828...)为底的对数称为自然对数(natural logarithm),并记为ln;
- 零没有对数;
- 在实数范围内,负数无对数。 在复数范围内,负数是有对数的。
算法中的对数:
考虑到计算机是二进制的,并且在很多算法中均出现以2作为基数的思想,比如分治策略、二分查找、二叉树等。所以在算法的讨论中若没有特别的说明 是指以 2 为底的 n 的对数,即
,《算法导论》第3版中均记作
,一般图书或博文中记作
,它们都是指以 2 为底的 n 的对数。
总结
以上即为学习算法的前提知识储备,本博文没有讨论过于深奥的数学知识,仅为算法的初学者提供些许的帮助。
C#算法设计之知识储备的更多相关文章
- 【转载】FPGA算法设计随笔
FPGA设计算法依次需要完成MATLAB浮点仿真 MATLAB定点仿真 verilogHDL定点运算以及数据对比的流程.其中浮点到定点的转换尤为重要,需要在数据表示范围和精度之间做出权衡.另外掌握定点 ...
- Python数据结构与算法设计总结篇
1.Python数据结构篇 数据结构篇主要是阅读[Problem Solving with Python]( http://interactivepython.org/courselib/static ...
- 一个php技术栈后端猿的知识储备大纲
<h1 align="center">Easy Tips</h1><p align="center"><a href= ...
- python网络爬虫,知识储备,简单爬虫的必知必会,【核心】
知识储备,简单爬虫的必知必会,[核心] 一.实验说明 1. 环境登录 无需密码自动登录,系统用户名shiyanlou 2. 环境介绍 本实验环境采用带桌面的Ubuntu Linux环境,实验中会用到桌 ...
- 剑指Offer——中国银行面试知识储备
剑指Offer--中国银行面试知识储备+面试内容 事件介绍 时间:2016.11.23 08:30 地点:北京市海淀区永丰路299号南门(中国银行软件中心) 事件:中国银行面试(中英文面试) 注意事项 ...
- 想要开发自己的PHP框架需要那些知识储备?
作者:安正超链接:https://www.zhihu.com/question/26635323/answer/33812516来源:知乎著作权归作者所有.商业转载请联系作者获得授权,非商业转载请注明 ...
- 最大子段和的DP算法设计及其效率测试
表情包形象取自番剧<猫咪日常> 那我也整一个 曾几何时,笔者是个对算法这个概念漠不关心的人,由衷地感觉它就是一种和奥数一样华而不实的存在,即便不使用任何算法的思想我一样能写出能跑的程序 直 ...
- Python数据结构与算法设计(总结篇)
的确,正如偶像Bruce Eckel所说,"Life is short, you need Python"! 如果你正在考虑学Java还是Python的话,那就别想了,选Pytho ...
- 《PHP程序员面试笔试宝典》——如何回答算法设计问题?
如何巧妙地回答面试官的问题? 本文摘自<PHP程序员面试笔试宝典> 程序员面试中的很多算法设计问题,都是历年来各家企业的"炒现饭",不管求职者以前对算法知识掌握得是否扎 ...
随机推荐
- 从零开始学Electron笔记(六)
在之前的文章我们介绍了一下Electron如何通过链接打开浏览器和嵌入网页,接下来我们继续说一下Electron中的对话框 Dialog和消息通知 Notification. 在之前的文章中其实我们是 ...
- GPO - File Server Management
Creating disk space usage quotas: File Screening Generate Storage Report, including file edit audit. ...
- vue : 项目起手式 - router组件通用模板
每次新建文件都要找来找去,麻烦,干脆贴到这里好了. <template> <div id="page"> </div> </templat ...
- 解决nginx在Linux中已经正常启动,Windows端的浏览器却无法访问的问题
一:查看Linux中nginx已经正常启动 二:查看80端口,未被占用 三:检查防火墙的问题 关闭防火墙:chkconfig iptables off //失败 暂时关闭防火墙:service ipt ...
- java基础知识--数据类型
计算机时识别不了我们编写的代码语言,计算机中的数据全部采用二进制表示,即0和1表示的数字,每一个0或者1就是一个位,一个位叫做一个bit(比特).(实际上计算机只能识别高低电平,而不是0和1.) 字节 ...
- 【mysql】- 索引使用篇
回顾 每个索引都对应一棵B+树,B+树分为好多层,最下边一层是叶子节点,其余的是内节点.所有用户记录都存储在B+树的叶子节点,所有目录项记录都存储在内节点. InnoDB 存储引擎会自动为主键(如果没 ...
- three.js 数学方法之Matrix3
今天郭先生来说一说three.js的三维矩阵,这块知识需要结合线性代数的一些知识,毕业时间有点长,线性代数的知识大部分都还给了老师.于是一起简单的复习了一下.所有的计算都是使用列优先顺序进行的.然而, ...
- layui常用插件(二) 时间插件
日期和时间 html <div class="layui-inline"> <!-- 注意:这一层元素并不是必须的 --> <input type=& ...
- 读/写xlsx文件
安装 pip install openpyxl 1.创建Excel电子表格 建立新文档需要调用Workbook对象的save方法,一个Workbook对象代表一个Excel工作簿,该方法的参数是保存的 ...
- Java锁_读写锁
独占锁:是指锁一次只能被一个线程持有,ReentrantLock和Synchronized都是独占锁. 共享锁:是指锁可以被多个线程持有. 对于ReentrantReadWriteLock,其读锁是共 ...