算法

1. 冒泡排序

1.1 算法原理:

S1:从待排序序列的起始位置开始,从前往后依次比较各个位置和其后一位置的大小并执行S2。

S2:如果当前位置的值大于其后一位置的值,就把他俩的值交换(完成一次全序列比较后,序列最后位置的值即此序列最大值,所以其不需要再参与冒泡)。

S3:将序列的最后位置从待排序序列中移除。若移除后的待排序序列不为空则继续执行S1,否则冒泡结束。

1.2.2 算法优化:

若某一趟排序中未进行一次交换,则排序结束

2. 快速排序

2.1 算法原理:

快速排序是对冒泡排序的一种改进。基本思想是:通过一趟排序将要排序的数据分割成独立的两部分,其中一部分的所有数据都比另外一部分的所有数据都要小,然后再按此方法对这两部分数据分别进行快速排序,整个排序过程可以递归进行,以此实现整个数据变成有序序列。

3. 直接插入排序

3.1 算法原理:

插入排序的基本方法是:每步将一个待排序序列按数据大小插到前面已经排序的序列中的适当位置,直到全部数据插入完毕为止。

假设有一组无序序列 , , … , :

(1) 将这个序列的第一个元素R0视为一个有序序列;

(2) 依次把 , , … ,  插入到这个有序序列中;

(3) 将插入到有序序列中时,前 i-1 个数是有序的,将和 ~ 从后往前进行比较,确定要插入的位置。

4. Shell排序

4.1 算法原理:

希尔排序是一种插入排序算法,又称作缩小增量排序。是对直接插入排序算法的改进。其基本思想是:

先取一个小于n的整数作为第一个增量,把全部数据分成个组。所有距离为的倍数的记录放在同一个组中。先在各组内进行直接插入排序;然后,取第二个增量重复上述的分组和排序,直至所取的增量,即所有记录放在同一组中进行直接插入排序为止。该方法实质上是一种分组插入方法。

5. 直接选择排序

5.1 算法原理:

直接选择排序是一种简单的排序方法,它的基本思想是:

第一次从R[0]~R[n-1]中选取最小值,与R[0]交换,

第二次从R[1]~R[n-1]中选取最小值,与R[1]交换,

….,

第i次从R[i-1]~R[n-1]中选取最小值,与R[i-1]交换,

…..,

第n-1次从R[n-2]~R[n-1]中选取最小值,与R[n-2]交换,

共通过n-1次,得到一个从小到大排列的有序序列。

6. 堆排序

6.1.1 二叉堆定义:

二叉堆是完全二叉树或近似完全二叉树。二叉堆满足两个特性:

1)父结点的键值总是大于或等于(小于或等于)任何一个子节点的键值。

2)每个结点的左子树和右子树都是一个二叉堆。

当父结点的键值总是大于或等于任何一个子节点的键值时为大根堆。当父结点的键值总是小于或等于任何一个子节点的键值时为小根堆。下面展示一个小根堆:

算法_第1张图片

由于其它几种堆(二项式堆,斐波纳契堆等)用的较少,一般将二叉堆就简称为堆。

6.1.2 堆的存储:

一般都用数组来表示堆,i结点的父结点下标就为(i – 1) / 2。它的左右子结点下标分别为2 * i + 1和2 * i + 2。如第0个结点左右子结点下标分别为1和2。

算法_第2张图片

6.1.3 堆的插入:

每次插入都是将新数据放在数组最后。可以发现从这个新数据的父结点到根结点必然为一个有序的数列,然后将这个新数据插入到这个有序数据中。

6.1.4 堆排序:

堆排序(Heapsort)是指利用堆积树(堆)这种数据结构所设计的一种排序算法,它是选择排序的一种。可以利用数组的特点快速定位指定索引的元素。堆分为大根堆和小根堆,是完全二叉树。大根堆的要求是每个节点的值都不大于其父节点的值,即A[PARENT[i]] >= A[i],小根堆则相反。

堆排序利用了大根堆(或小根堆)堆顶记录的关键字最大(或最小)这一特征,使得在当前无序区中选取最大(或最小)关键字的记录变得简单。

(1)用大根堆排序的基本思想

① 先将初始数组建成一个大根堆,此堆为初始的无序区

② 再将最大的元素(即堆顶)和无序区的最后一个记录交换,由此得到新的无序区和有序区,且满足的值<=的值。

③由于交换后新的根可能违反堆性质,故应将当前无序区调整为堆。然后再次将中最大的元素和该区间的最后一个记录交换,由此得到新的无序区和有序区,且仍满足关系的值<=的值,同样要将调整为堆。

……

直到无序区只有一个元素为止。

(2)大根堆排序算法的基本操作:

①建堆,建堆是不断调整堆的过程,从len/2处开始调整,一直到第一个节点,此处len是堆中元素的个数。建堆的过程是线性的过程,从len/2到0处一直调用调整堆的过程,相当于o(h1)+o(h2)…+o(hlen/2) 其中h表示节点的深度,len/2表示节点的个数,这是一个求和的过程,结果是线性的O(n)。

②调整堆:调整堆在构建堆的过程中会用到,而且在堆排序过程中也会用到。利用的思想是比较节点i和它的孩子节点left(i),right(i),选出三者最大(或者最小)者,如果最大(小)值不是节点i而是它的一个孩子节点,那边交互节点i和该节点,然后再调用调整堆过程,这是一个递归的过程。调整堆的过程时间复杂度与堆的深度有关系,是lgn的操作,因为是沿着深度方向进行调整的。

③堆排序:堆排序是利用上面的两个过程来进行的。首先是根据元素构建堆。然后将堆的根节点取出(一般是与最后一个节点进行交换),将前面len-1个节点继续进行堆调整的过程,然后再将根节点取出,这样一直到所有节点都取出。

7. 归并排序

7.1 算法原理:

归并排序是建立在归并操作上的一种有效的排序算法,该算法是采用分治法的一个非常典型的应用。将已有序的子序列合并,得到完全有序的序列;即先使每个子序列有序,再使子序列段间有序。若将两个有序表合并成一个有序表,称为二路归并。

归并过程为:

比较a[i]和a[j]的大小,若a[i]≤a[j],则将第一个有序表中的元素a[i]复制到r[k]中,并令i和k分别加上1;否则将第二个有序表中的元素a[j]复制到r[k]中,并令j和k分别加上1,如此循环下去,直到其中一个有序表取完,然后再将另一个有序表中剩余的元素复制到r中从下标k到下标t的单元。

归并排序的算法我们通常用递归实现,先把待排序区间[s,t]以中点二分,接着把左边子区间排序,再把右边子区间排序,最后把左区间和右区间用一次归并操作合并成有序的区间[s,t]。

归并操作的工作原理如下:

S1: 申请空间,使其大小为两个已经排序序列之和,该空间用来存放合并后的序列

S2: 设定两个指针,最初位置分别为两个已经排序序列的起始位置

S3: 比较两个指针所指向的元素,选择相对小的元素放入到合并空间,并移动指针到下一位置

S4: 重复S3,直到某一指针超出序列尾

S5: 将另一序列剩下的所有元素直接复制到合并序列尾

8. 基数排序

8.1 算法原理:

基数排序的原理如下:将所有待比较数值(正整数)统一为同样的数位长度,数位较短的数前面补零。然后,从最低位开始,依次进行一次排序。这样从最低位排序一直到最高位排序完成以后, 数列就变成一个有序序列。

基数排序的方式有以下两种:

最高位优先(Most Significant Digit first)法,简称MSD法:先按排序分组,同一组中记录,关键码相等,再对各组按排序分成子组,之后,对后面的关键码继续这样的排序分组,直到按最次位关键码对各子组排序后。再将各组连接起来,便得到一个有序序列。

最低位优先(Least Significant Digit first)法,简称LSD法:先从开始排序,再对进行排序,依次重复,直到对排序后便得到一个有序序列。


排序,感觉这个写的很好(http://blog.csdn.net/hguisu/article/details/7776068/),每一个点都要懂,直接插入,选择,冒泡,归并,快排要会写,面试问的最多的是快排(时间复杂度,最好和平均都是O(nlgn),最差是O(n*n),当数据几乎有序时是最差的,这是退为冒泡,空间复杂度O(nlgn))。


1)判断一个链表有无环,一个快指针(走2 步),一个慢指针(走1 步),都从头开始,若有环,则它们相撞(设碰撞点为x);若无环,则快指针遇到空就跳出循环。2)有环,则求环的长度:从碰撞点x 开始,又走(一个走一步,一个两步),当再次碰撞时,他们走的次数为环的长度。3)求连接点,记住结论:碰撞点到连接点的距离等于头接点到连接点的距离。两个指针(都一次一步),一个从头节点走,一个从碰撞点走,第一次碰撞的节点就是连接点。


一致性算法:1)平衡性:哈希的结果能够尽可能分布到所有缓存中去。2)单调性:如果已经有一些内容通过hash 分派到了相应的缓冲中,又有新的缓冲区加入到系统中,那么

hash 的结果应该能保证原有已分配的内容可以被映射到新的缓冲区中,或原来的缓冲区中。

3)分散性:在分布式环境中,终端有可能看不到所有缓冲区,而只能看到其中一部分,当终端希望通过哈希过程将内容映射到缓冲区上时,由于不同终端所见的缓冲范围有可能不同,可能导致相同的内容被不同的终端映射到不同的缓冲区上,这种情况应该避免。4)负载:既然不同的终端可能将相同的内容映射到不同缓冲区中,那么对于一个特定的缓冲区而言,也可能被不同的用户映射为不同的内容。

在分布式集群中,对机器的添加和删除或机器故障后自动脱离集群,这些操作是分布式集群管理最基本的功能,若采用常用的hash(object)%N 算法,那么在有机器添加或删除以后,很多原有的数据就无法找到,所以出现一致性哈希算法——1)环形hash 空间:按照常用的

hash 算法来将对应的key 哈希到一个具有232 个桶的空间,即(0-232-1)的数字空间中,现在我们将这些数字头尾相连,想象成一个闭合的环形。2)把数据通过一定的hash 算法映射到环上。3)将机器通过一定的hash 算法映射到环上。4)节点按顺时针转动,遇到的第一个机器,就把数据放在该机器上。

堆排序空间复杂度O(1) 建堆的时间复杂度O(n) 调整堆的时间复杂度O(logn)

快速排序若以左边元素为基准,则先where(arr[high]>=key&&low


桶排序:把数组分组放在一个个的桶中,然后对每个桶里的再进行排序。当n=m 时,可以实现O(n),n 个数字m 个桶,缺点:1)空间复杂度高;2)待排序的元素要在某一个范围。

邮件,——1)当用户需要发送电子邮件时,首先利用客户端的电子邮件应用程序,编辑一封邮件,利用smtp 将邮件送往发送端的邮件服务器;2)发送端的邮件服务器,接收到用户送来的邮件后,通过smtp 将邮件送到接收端的邮件服务器,接收端的邮件服务器根据地址中的账号将邮件投递到对应的邮箱;3)利用pop3 或imap,接收端的用户可以在任何时间、地址,利用电子邮件应用程序从自己邮件中读取邮件。 

一个绳子烧完要一个小时,怎么计出1 小时15 分钟?绳子无限多。答案:要三条绳子

1、2、3。1)1 点一头,2 点两头,同时点。2 烧完用了30 分钟2)2 一烧完,马上点1 的另一头,则1 烧完用了15 分钟。3)1 一烧完,马上点3,两头点,3 烧完,用了30 分钟。所以:30+15+30=1 小时15 分钟。


最短路径算法,迪杰斯特拉算法。1 背包问题 自己网上去看,一定要懂。

对于一个给定的问题,若具有以下两条性质,可用动态规划1)最优子结构:若一个问题的最优解包含了其子问题的最优解,就说明该问题具有最优子结构。2)重叠子问题。

空间复杂度 归并 O(n) 快速 O(logn) 其余 5 种 O(1)。

选择排序:1)从n 个记录中找出关键字最小的记录与第一个记录交换。2)从第二个记录开始的n-1 个记录中再选出关键码最小的记录与第二个交换。以此类推。

对冒泡排序常见的改进方式是加入一个标志变量exchange,用于标志某一趟排序过程中是否有数据交换,若进行某一趟排序时并没有数据交换,则说明数据已经按要求排好,可立即结束排序,避免不必要的比较过程。

如何快速查找链表的中间节点?只遍历一次。答案:建立两个指针,一个指针一次遍历两个节点,一个指针一次遍历一个节点,当快指针遍历到控节点时,慢指针指向的位置为链表中间位置。

快排改进:1)和插入排序组合,由于快速排序在处理小规模数据时表现不好,因此在数据规模小到一定程度时,改用插入排序,具体小到何种程度,一般文章说5-10.(SCISTL 硅谷标准模块采用10)2)中轴元素(左边比他小,右边比他大),可以取最左边、最右边、中间这三个位置的元素中的中间值。3)分成三堆,一方面避免相同元素,另一方面降低了子问题规模(一堆小于一堆等于一堆大于)。

百度时,一输入“北京”,搜索框下面就会出现“北京爱情故事”,“北京公交”,“北京语言大学”等,实现这类技术用的数据结构是什么?答案:trie 树,又称为单词查找树,字典树,是一种树形结构,是一种哈希树的变种,是一种用于快速检索的多叉树结构。其核心思想是:空间换时间。利用字符串的公共前缀来降低查询时间的开销以达到提高效率的目的。Trie 树的性质:1)根节点不包含字符,除了根节点以外的每个节点包含一个字符2)从根节点到某一个节点,路径上经过的字符连接起来,为该节点对应的字符串3)每个节点的

all 子节点包含的字符串不同。

哈夫曼编码。哈夫曼树不好画就自己百度吧,反正也不难。

辗转相除法:用来求两个自然数的最大公约数(已知a,b,c 为正数,若a 除以b 余数是c,则[a,b]=[b,c],其中[a,b]表示a 和b 的最大公约数)代码见p14 反时间复杂度O(nlogn)

a*b=最大公约数*最小公倍数。

数组中有一个数字出现的次数超过了数组长度的一半,找出他,没有就返回-1?先排序,找中间那个,遍历一次数组,统计中间那个元素出现的次数,若超过一半则返回,否则返回

-1.

斐波拉契数列

1)采用递归的方法

2)采用非递归

基数排序稳定O(n) 1)当n 较小时,比如n<50,可以采用直接插入排序or 直接选择排序。2)若文件初始状态基本有序(指正序),则应该使用直接插入,冒泡,or 随机的快速排序。3)堆排序所需要的辅助空间少于快速排序,并且不会出现快速排序可能出现的最坏情况。

 有序队列数据的时间复杂度无序队列数据的时间复杂度

寻找最小值O(1)O(n)

估算平均值O(n)O(n)

找出中间值O(1)O(n)

找出最大出现的可能性值 O(n) O(nlogn)

一个包含n 个节点的四叉树,每个节点都有4 个指向孩子的指针,这个4 叉树有多少个控制在?答案:4*n-(n-1)=3n+1,解释:n 个节点,一共有4n 个指针,除了root 根节点外,all 节点都用了一个指针,其父节点用来指向他的,用了n-1 个,则剩下的null 指针为4*n-(n-1)=3n+1 个。

两个栈实现队列?见《剑指offer》P59,插入的元素都放在stack1 中,pop 时,若stack2 不为空,则直接弹出stack2 的栈顶,若stack2 为空,则把stack1 的元素弹入stack2,再pop 出stack2 的栈顶。

用筛选法求100 以内的素数?见《面试宝典》P81,筛选法就是从小到大筛取一个已知素数的所有倍数,例如,根据2,我们可以筛去4,8,16。。。根据3,我们可以筛去9,15,由于4 被筛去了,下一个用于筛选的素数为5,以此类推最后剩余的就是100 以内的额素数。

若系统有5 台绘图仪,有多个进程均需要使用2 台,规定每个进程一次仅允许申请1

台,则至多有多少个进程参与竞争而不发生死锁?答案:4 个

哲学家就餐问题,最多允许4 个哲学家同时进餐,以保证至少有一个哲学家能够进餐,最总总会释放出他们所使用过的2 只筷子,从而可以使更多的哲学家进餐。

选择排序:每扫描一遍数组,只交换一次。

基于比较的排序算法:插入、希尔、选择、冒泡、归并、快速链地址法的平均查找长度

H(k)=k mod 7 有一个数组32 24 15 27 20 13

下标 0 1 2 3 4 5 6

15(1) 24(1) 32(1) 27(1)

20(2)

13(3)

所以平均查找长度为(1+1+1+1+2+3)/6=1.5

算法的基本概念

输出、输入,有穷性,确切性,可行性


红黑树—使二叉搜索树更加平衡:他是一种二叉搜索树,但在每个节点上增加一个存储位表示节点的颜色,可是 red 或 black,红黑树的查找、

插入、删除的时间复杂度最坏为 O(lgn)。因为由n

个节点随机生成的二叉搜索树的高度为lgn,所以二叉搜索树的一般操作的执行时间为O(lgn)。如何保证一颗n

个节点的红黑树的高度始终为lgn,因为红黑树的5 个性质:1)每个节点,要么红的,要么黑的2)根节点是黑的3)叶节点都是黑的,指的是NIL 指

针4)若一个节点时红的,则它的两个儿子都是黑的。5)对于任意节点而言,其到叶节点数尾端NIL 指针的每条路径都包含相同数目的叶节点。

直接插入排序是从当前位置往前插

N-S 图是用于取代传统流程图的一种方式,去掉了流程线,可在总体设计时使用。

计数排序:基于统计时间复杂度O(n) 空间复杂度O(n),采用计数排序法的辅助数组长度为max-min+1,(max 和min 分别为待排序数组的最大值和最小值),比如数组为1,0,3,1,0,1,1,max-min+1=3-0+1=4.

一个AOV 网的拓扑排序可能不唯一。对aov 网进行排序的基本思想:1)从aov 网中选择一个没有前驱的顶点输出他 2)从 aov 网中删去该节

点,并且删去 all 以该节点为尾的弧 3)重复上述步骤,直到all 点输出or aov 网中不存在没有前驱的点。

Hash 表的做法其实很简单,就是把key 通过一个固定的算法函数,即所谓的hash 函数转换为一个整形数字,then 将该数字对数组长度进行取余,取余结果就当做数组下标,将

value 存在在以该数字为下标的数组空间里。

要找最大的k 个数,建小顶堆。

AOV 网:用顶点表示活动,用弧表示活动间的优先关系,在网中,若从顶点i 到j 有一条有向路径,则i 为j 前驱。对于一个aov 网,从源点到终点的路径称为关键路径(错的),因为最早完成时间=最晚完成时间的点构成的路径为关键路径。

进程调度算法:1)先来先服务2)短作业优先3)时间片轮转4)最高优先权-抢占式和非抢占式。

你可能感兴趣的:(算法)