1

算法基础

程序设计 = 数据结构 + 算法

算法时为了解决实际问题而设计的,数据结构是算法需要处理的问题载体,数据结构只是静态的描述呢数据元素之间的关系,高效的程序需要再数据结构的基础上设计和选择算法

数据结构

数据元素相互之间存在的一种或多种特定关系的集合(数据结构指数据对象中数据元素之间的关系)。数据结构分为逻辑结构和物理结构。

逻辑结构:是指数据对象中数据元素之间的相互关系。

    (1)集合结构:数据元素除了同属于一个集合外,没有什么其他关系
    (2)线性结构:线性结构中的数据元素之间是一对一的关系
    (3)树形结构:元素之间存在一种一对多的层次关系
    (4)图形结构:元素是多对多的关系
    
物理结构:是指数据的逻辑结构在计算机中的存储形式。
    
    (1)顺序存储:把数据元素存放在地址连续的存储单元你,其数据间的逻辑关系和物理关系是一致的
    (2)链式存储:把数据元素存放在任意的存储单元里,这组存储单元可以是连续的,也可以是不连续的。链式存储结构的数据元素存储关系不能反映其逻辑关系,需要用一个指针存放数据元素的地址,这样通过地址就可以找到相关数据元素的位置.
Python的数据结构
内置数据结构:列表、元组、字典等
扩展数据结构:Python系统里面没有直接定义,需要我们自己取定义实现这些数据的组织方式,如栈、队列等
抽象数据类型(Abstract Data Type):

把数据类型和数据类型上的运算捆在一起,进行封装。如插入,删除,修改,查找,排序等.

算法

算法:是独立存在(不依赖特定的编程语言)的一种解决问题的方法和思想。算法有五大特性:

(1)输入:算法有0个或多个输入
(2)输出:算法至少有一个或多个输出
(3)有穷性:算法在有限的步骤之后会自动结束而不会无限循环,并且每一个步骤可以在可接受的时间内完成
(4)确定性:算法中的每一步都有确定的含义,不会出现二义性
(5)可行性:算法的每一步都是能够执行有限次数完成的
时间复杂度

假设存在函数g,使得算法A处理规模为n的问题所用时间为T(n)=O(g(n)),则O(g(n))为算法A的奖金时间复杂度,简称时间复杂度,记为T(n)

最优时间复杂度:算法完成工作最少需要多少基本操作 --- 没有什么参考价值
* 最坏时间复杂度:算法完成工作做多需要多少基本操作 --- 基本操作都能完成
平均时间复杂度:算法完成工作平均需要多少基本操作

数据结构

  • 数组
  • 栈,先进后出
  • 队列,先进先出
  • 双端队列,双端队列中的元素可以从两端弹出,插入和删除操作限定在队列的两边进行。
  • 环形队列,环形队列是一种特殊的队列结构,保证了元素也是先进先出的,但与一般队列的区别是,他们是环形的,即队列头部的上个元素是队列尾部,通常是容纳元素数固定的一个闭环。
  • 堆,一种特别的树状数据结构。堆总是一棵完全树。即除了最底层,其他层的节点都被元素填满,且最底层尽可能地从左到右填入。
  • 链表
  • 单向链表。
  • 双向链表。
  • 跳表,一种带多级索引的链表。
  • 散列表,是根据键而直接访问在内存存储位置的数据结构。它通过计算一个关于键值的函数,将所需查询的数据映射到表中一个位置来访问记录,这加快了查找速度。
  • 二叉树,二叉树是一个连通的无环图,并且每一个顶点的度不大于3。
  • 红黑树,是一种自平衡二叉查找树。
  • 字典树(Trie)
  • 图(Graph)是由顶点的有穷非空集合和顶点之间的边的集合组成。
  • TODO
  • 布隆过滤器,一个概率型数据结构,可以用来判断一个元素是否在一个集合中。判断某个元素在,可能会被误判;判断某个元素不在,那么一定不在。

算法思想

分治法

分治法是基于多项分支递归的一种很重要的算法范式。字面上的解释是“分而治之”,就是把一个复杂的问题分成两个或更多的相同或相似的子问题,直到最后子问题可以简单的直接求解,原问题的解即子问题的解的合并。

例子:快排、归并排序、MapReduce

贪心算法

贪心算法就是在每一步的选择中都按照当前最优的选择,从而希望最终结果得到最优解。贪心算法在有最优子结构的问题中尤为有效。最优子结构的意思是局部最优解能决定全局最优解。简单地说,问题能够分解成子问题来解决,子问题的最优解能递推到最终问题的最优解。
贪心算法与动态规划的不同在于它对每个子问题的解决方案都做出选择,不能回退。动态规划则会保存以前的运算结果,并根据以前的结果对当前进行选择,有回退功能。

例子:最小生成树、哈夫曼编码

动态规划(Dynamic Programming)

动态规划通过把原问题分解为相对简单的子问题的方式求解复杂问题的方法。常常适用于有重叠子问题和最优子结构性质的问题。
若要解一个给定问题,我们需要解其不同部分(即子问题),再根据子问题的解以得出原问题的解。通常许多子问题非常相似,为此动态规划法试图仅仅解决每个子问题一次,从而减少计算量:一旦某个给定子问题的解已经算出,则将其记忆化存储,以便下次需要同一个子问题解之时直接查表。这种做法在重复子问题的数目关于输入的规模呈指数增长时特别有用。

递归+记忆=递推

适用情况:

  1. 具有最优子结构性质。
  2. 无后效性,子问题确定后不会再改变。
  3. 子问题重叠的性质。

例子:背包问题

回溯法(backtracking)

回溯法采用试错的思想,它尝试分步的去解决一个问题。在分步解决问题的过程中,当它通过尝试发现现有的分步答案不能得到有效的正确的解答的时候,它将取消上一步甚至是上几步的计算,再通过其它的可能的分步解答再次尝试寻找问题的答案。回溯法通常用最简单的递归方法来实现,在反复重复上述的步骤后可能出现两种情况:

  1. 找到一个可能存在的正确的答案
  2. 在尝试了所有可能的分步方法后宣告该问题没有答案

在最坏的情况下,回溯法会导致一次复杂度为指数时间的计算。

例子:八皇后问题

分支界限法

与贪婪算法一样,这种方法也是用来为组合优化问题设计求解算法的,所不同的是它在问题的整个可能解空间搜索,所设计出来的算法虽其时间复杂度比贪婪算法高,但它的优点是与穷举法类似,都能保证求出问题的最佳解,而且这种方法不是盲目的穷举搜索,而是在搜索过程中通过限界,可以中途停止对某些不可能得到最优解的子空间进一步搜索(类似于人工智能中的剪枝),故它比穷举法效率更高。

概率算法

例子:
数值随机化算法
蒙特卡罗(Monte Carlo)算法
拉斯维加斯(Las Vegas)算法
舍伍德(Sherwood)算法
https://juejin.im/post/5dabfb...


SoapEye
89 声望6 粉丝

历史就是历史,它是客观存在的。