《算法神探》之算法笔记

一、搜索问题:任何需要我们在可能的空间范围内(搜索空间)找到一个特定值(即目标)的问题。

搜索算法:用于进行搜索的一组具体的步骤或指令。

1、穷举搜索算法目标值是要在整个搜素空间范围内尝试每一种可能性。

最常见的穷举搜索是线性搜索:即按照顺序简单的检查所有不同的可能性。

线性搜索算法的优势是它们在任何领域都容易实现,即使要处理的是非结构化数据。

扫描二维码关注公众号,回复: 1508517 查看本文章

穷举算法的缺点是:在已经结构化的数据中这种方式不够高效。

2、数组:存储多个值的简单数据结构。

数组结构的意义在于,可以通过指定一个位置或者索引的方法来存储或读取数组中的任何值。

二分搜索算法:用于高效地在有序数组A中查找一个目标值V。

二分搜索算法的工作原理:不断地将搜索空间分成两半,并且把搜索空间限制在其中的一半,通过改变上下界限有效的限制了搜索空间。       A[Indexlow]<=V<=A[Indexhigh]           (数组A按升序排列)

中间值  IndexMid = (Indexlow+Indexhigh)/2      将中间值与目标值V比较确定搜索空间。

对于二分搜索,我们须了解有待排序的相关信息以便知道数据是按照什么方式排列的。

为了排除(或缩小)较大查找范围,所使用的算法必须能够保证我们要找的而目标值不在被去除的范围内。

解决新问题,必须理解每个算法背后的原理,从而知道如何调整它,适用一个新问题。

二分搜索算法背后的基本思想:利用数据中的规律去不断将搜索的范围减半。

3、广度优先搜索是一个按顺序依次尝试可能的搜索选项的算法。(它每次都会选择尝试最先发现的但还没有尝试过的选项)

图: 一个图是由点和边组成的数据结构, 两个点由一条边相连,则领地啊是相邻的。

广度优先搜索会沿着一个不断延申的边界展开,这个算法会检查所有离起点X步的点,然后才会继续坚持离起点X+1步的点,在广度优先搜索的每一步,都要查看当前的点是不是我们的最终目标。

*仔细记录下已经检查过的点,会给我们带来巨大的好处,在搜索问题中,如果任意相邻的两个点之间移动的代价是相等的,那么广度优先搜索可以保证找到一条花费最小代价的路径。广度优先搜索只有在相邻点之间移动的代价都一样时才会给出最优方案。

一般,找出两点步数最少的历经和找出两点之间代价最小的路径是不一样的。

4、深度优先搜索:

深度优先搜索会优先考虑最近新遇到的搜索状态,所有算法会沿着一条路往下走,直到遇到目标状态或者一条死路。

使用优先搜索时,也可以去维护一个栈,里面存放着所有已知但还未探索的状态。与广度优先搜索不同的是:深度优先搜索会将新的状态加到栈的顶端,而不是尾部。

深度优先搜索优先考虑的是搜索的深度,而不是广度。

和广度优先搜索一样,需要记录已经搜索过的点,可避免重复搜索一个点,甚至陷入死循环。

5、栈和队列

栈和队列是用来存放数据的两种简单的数据结构,栈是后进先出的数据结构。

栈:可以用一个数组A和一个记录当前栈顶位置的变量(Top)来实现一个栈,当推入一个新的元素时就会把它加入到下一个空位置A[Top+1]里。当从栈里弹出一个元素时,可以用Top来找到应该弹出的元素(A[Top])同时将Top的值减1.

注: 如果数组大小固定,在推入新元素时应检查数组是否还有剩余空间。

队列:是一个先进先出的数据结构。新的元素被加到队列的最后,而删除的元素会从队列的最前面删除。

队列也可以用数组来实现,你需要两个变量记录目前队列的第一个元素(Front)和最后一个元素(Back)在哪里. 当加入一个格子(A[Back+1]), 并把Back+1, 相反,在弹出一个元素时,我们把目前处于队列最前端的元素(A[Front])弹出,并将Front+1。

¥¥广度优先搜索使用 的是队列,深度优先搜索用的则是栈¥¥

我们存储信息的方式和使用的数据结构,不仅会影响到算法的效率,也会决定算法的工作原理,选择数据结构应符合算法要求。

6、并行算法

并行算法将一个问题分解成数个小块,并同时在这些小块上执行计算,最后再将结果组合起来。

设计一个高效的并行算法,有两点很重要:

①如何高效地将计算任务分割成互相独立的单元。

②如何在最后将结果组合起来。

当考虑是否应该使用并行计算时,另一个需要考虑的方面是:并行计算带来的效率提升是否大于它所带来的额外工作量。

7、迭代加深:

迭代加深是深度优先搜索的一种改版,它限制了每次搜素的深度,在第K轮搜素时,这个算法会执行一次深度限制为K的深度优先搜索。

迭代加深的有点:①它具有深度优先搜索的节省内存的有点。②它也像广度优先搜索那样,找到最短路径,并能够避免在一些最坏情况下被困在一条长的死路上。

8、逆向索引

逆向索引是计算要用的一种数据结构,它和书的索引类似, 对于每一个值,逆向索引可以告诉这个值在数据中的哪些地方出现过,如果一个值会在数据中反复出现,这一点就格外有用。

逆向索引是一个典型的需要在运行时间和内存占用之间取舍的例子。

添加一个逆向索引会占掉更多内存,但它也让我们在一个新的维度上进行搜索的效率得到了极大提升。

9、二叉搜索树

树中的每一个节点存放一个值,并且在每个节点最多有两个子节点:一个左子节点和一个右子节点,节点的位置根据其中存放的值的大小来决定,所有左子节点和它的左子节点中存放的值都比当前节点中的值小;类似的,所有右子节点和它的右子节点中存放的值都比当前节点的值大。

如果对于每个节点,其左子树中的节点的数目都和其右子树中的节点数目一致,此二叉树是完全平衡的。在此情况下,如果将树中的节点数量翻倍,整棵树的高度只会增加1。

在二叉搜索树中查找一值,可以从最上面的节点(根节点)往下查找,每查找一步就比较要找的值和当前节点的值的大小,以决定向左查找还是向右查找。






猜你喜欢

转载自blog.csdn.net/qq_33690342/article/details/80453467