算法和数据结构解析:1-算法简介

Posted 鮀城小帅

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了算法和数据结构解析:1-算法简介相关的知识,希望对你有一定的参考价值。

1.算法的基本概念

算法(Algorithm),就是“计算方法”,指解决一个问题具体的步骤和方法。

算法是计算机程序的核心。在一个计算机程序中,有两个非常重要的部分:数据结构和算法。数据结构决定了程序中数据组织和存储的形式,而算法决定了程序的功能和效率。算法在具体应用时,与数据结构密不可分,是一个程序的灵魂。

2.算法的特征

一个算法应具有一下五个重要特征:

  • 有穷性(Finiteness)

算法的有穷性,是指算法必须能在执行有限个步骤之后终止。

  • 确切性(Definiteness)

算法的每一步骤必须有确切的定义。

  • 输入项(Input)

一个算法有0个或多个输入,以刻画运算对象的初始情况。所谓0个输入,是指算法本身定出了初始条件。

  • 输出项(Output)

一个算法有一个或多个输出,以反映对输入数据加工后的结果。

  • 可行性(Effectiveness)

算法中执行的任何计算步骤都是可以被分解为基本的可执行的操作步骤,即每个计算步骤都可以在有限时间内完成(也称之为有效性)。

3.算法复杂度

3.1 算法复杂度

基于算法的有穷性,我们可以知道算法运行消耗的时间不能是无限的。而对于一个问题的处理,可能有多个不同的算法,它们消耗的时间一般是不同的;运行过程中占用的空间资源也是不同的。

这就涉及到对算法的性能考察。主要有两方面:时间和空间。在计算机算法理论中,用时间复杂度和空间复杂度来分别从这两方面衡量算法的性能。

3.2 时间复杂度(Time Complexity)

算法的时间复杂度,是指执行算法所需要的计算工作量。

一般来说,计算机算法是问题规模n 的函数f(n),算法的时间复杂度也因此记做:T(n)=Ο(f(n))

问题的规模n 越大,算法执行的时间的增长率与f(n) 的增长率正相关,称作渐进时间复杂度(Asymptotic Time Complexity)。

3.3 空间复杂度

算法的空间复杂度,是指算法需要消耗的内存空间。有时候做递归调用,还需要考虑调用栈所占用的空间。

其计算和表示方法与时间复杂度类似,一般都用复杂度的渐近性来表示。同时间复杂度相比,空间复杂度的分析要简单得多。

所以,我们一般对程序复杂度的分析,重点都会放在时间复杂度上。

3.4 时间复杂度的计算

代码的执行时间,可以用“基本指令”的数量来表示。计算机系统里,基本指令包括:算术指令(加减乘除、取余、向上向下取整)、数据移动指令(装载、存储、赋值)、控制指令(条件或无条件跳转,子程序调用和返回)

查看一些具体的代码,分析一下它们的时间复杂度:

int a = 1;

简单赋值操作,运行时间 1(1个单位)

if (a > 1)

简单判断操作、条件跳转,运行时间 1

for (int i = 0; i < N; i++) System.out.println(i);

有循环,运行时间 1(i赋初值)+ N+1(判断)+N(打印)+N(i自增)= 3N + 2

3.5 复杂度的大O表示法

不同的算法,运行时间随着输入规模 n 的增长速度是不同的。我们可以把执行时间,表示成输入规模 n 的函数 T(n) 。

在算法分析中,一般用大O符号来表示函数的渐进上界。对于给定的函数g(n),我们用O(g(n))来表示以下函数的集合:

O(g(n)) =  f(n): 存在正常量 c 和 n0,使对所有 n≥n0 ,有 0≤f(n) ≤ cg(n) 

这表示,当数据量达到一定程度时,g(n) 的增长速度不会超过 O(g(n))限定的范围。也就是说,大O表示了函数的“阶数”,阶数越高,增长趋势越大,后期增长越快。

下图画出了常见的算法复杂度:

     

O(1),O(log(n)),O(√n),O(n),O(nlog(n)),O(n²),O(e²).

3.6 空间复杂度的计算

定义:算法执行所占用的空间。

  • Array[100]: O(100)
  • Array[N: O(N)
  • int val = 1; 空间复杂度 O(1)

有时候递归调用,需要计算调用栈所占用的空间。

4. 算法的分类

算法的分类有以下两种原则:

  • 按照应用的目的来划分

    搜索算法、排序算法、字符串算法、图算法、最优化算法、数学(数论)算法

  • 按照具体实现的策略划分

    暴力法、增量法、分治法、贪心、动态规划、回溯、分支限界法

     

4.1暴力法

暴力法,也叫穷举法。它要求设计者找出所有可能的方法,然后选择其中的一种方法,若该方法不可行则试探下一种可能的方法。该方法逻辑清晰、简单,编写程序简洁。

在某些情况下,算法规模不大时,使用优化的算法没有必要,而且某些优化算法本身较为复杂,在规模不大时可能因为复杂的算法浪费时间,反而不如简单的蛮力搜索。暴力破解法对计算机资源耗费严重,如果条件太复杂,运算速度缓慢。

使用暴力法的几种情况:

  • 搜索所有的解空间和路径;
  • 直接进行计算;
  • 在问题规模不是很大的情况下,现实问题的模拟与仿真。

4.2 增量算法

增量法(Incremental Algorithm)的思想与第一数学归纳法类似,它的本质是将一个问题化为规模刚好小一层的子问题。解决子问题后加入当前的对象。写成递归式是:

                T(n) = T(n-1) + g(n)

增量法常常结合随机化,以避免最坏情况的出现。

增量法在解决排序问题时典型的实例就是直接插入排序。

4.3 分治算法

(1)分而治之:

  • 问题的规模越小,越容易解决
  • 把复杂问题不断分成多个相同或相似的子问题,知道每个子问题可以简单地进行求解
  • 讲所有子问题的解合并起来,就是原问题的解

(2)分治和递归:

  • 产生的子问题形式往往和原问题相同,只是原问题的较小规模表达。
  • 使用递归手段求解子问题,可以很容易地将子问题的解合并,得到原问题的解

(3)基本步骤

  • step1:将原问题分解为若干个规模较小,相互独立,与原问题形式相同的子问题
  • step2:若子问题规模较小而容易被解决则直接解,否则递归地解各个子问题
  • step3:将各个子问题的解合并为原问题的解

(4)应用场景

  • 二分搜索、大整数乘法、归并排序、快速排序
  • 期盼覆盖问题、循环赛日程表问题、汉诺塔问题等

4.4 贪心算法

(1)定义

贪心(Greedy) —— 总是做出在当前看来是最好的选择。不从整体考虑,只考虑眼前,得到 局部最优解。

(2)局部最优解和全局最优解

要保证最终得到的是全局最优解,贪心策略必须具备 无后效性(前面做的影响对后面没影响

(3)适用场景

  • 用贪心算法直接求解全局最优,条件比较苛刻;
  • 哈夫曼( Huffman )编码

(4)具体实现框架

        从问题的某一初始解出发;

        while (能朝给定总目标前进一步)
        
        

            利用可行的决策,求出可行解得一个解元素;        

        

        由所有解元素组合成问题的一个可行解;

4.5 动态规划

(1)动态决策的过程

  • 把原问题划分成多个“阶段” , 依次来做 “决策”,得到当前的局部解;
  • 每次决策依赖于当前的“状态”,随即引起状态的转移;
  • 一个决策序列就是在变化的状态中产生出来的;
  • 这种多阶段决策最优化,解决问题的过程就成为 动态规划.

(2)最优化问题

  • 动态规划通常用来求解最优化问题
  • 可以有很多可行解,每个解都对应一个值,我们希望找到具有最优值的解

(3)动态规划的过程

在求解过程的的时候,中间会经历很多的阶段,然后每一个阶段,后面阶段需要计算的结果和状态可能需要依赖之前的状态和决策。比如前面做了决策1,不同的决策1会导致后面会采取不同的决策2;比如当决策1 的结果是最优的,但是基于决策1的结果的决策2的结果很少或者不是最优的。所以,需要综合决策1和决策2来的得到具有最优值的结果。

(3) 应用场景

最优二叉搜索树、最长公共子序列、背包问题等等。

4.6 回溯法

(1)选优搜索法

  • 按照一定的选优条件,不停向前搜索,直到到达目标;
  • 如果搜索到某一步,发现之前的选择并不优,就退回一步重新选择;
  • 这是一种通用解题方法

(2)深度优先搜索(DFS)策略

在包含问题所有解的解空间树中,按照深度优先搜索的策略,从根节点出发,深度搜索解空间树;回溯法就是对隐式图的深度有限搜索算法。

4.7 分支限界法

(1)广度有限搜索(BFS)策略

  • 所谓“分支”,就是采用广度优先的策略,依次搜索当前节点的所有分支
  • 抛弃不满足约束条件的相邻节点,其余节点加入“活节点表”
  • 然后从表中选择一个节点作为下一个扩展节点,继续搜索

(2)限界策略

  • 为了加速搜索的进程,一般会在每一个活节点处,计算一个函数值;
  • 根据这些已计算出的函数值,从当前活节点表中选择一个最有利的节点作为扩展节点,使搜索朝着解空间树上最优解的分支推进,以便尽快地找出一个最优解

4.8 比较

     回溯法分支限界法
对解空间树的搜索方式DFSBFS
存储节点常用数据结构堆栈队列
应用场景找出满足约束条件的所有解;找出全局最优解找出满足约束条件的一个解;找出局部最优解

5. 经典算法

在实际应用中,有一些经典算法和策略,都可以作为解决问题的思路:

  • 二分查找

  • 快速排序、归并排序

  • KMP算法

  • 快慢指针(双指针法)

  • 普利姆(Prim)和 克鲁斯卡尔(Kruskal)算法

  • 迪克斯特拉(Dijkstra)算法

  • 其它优化算法:模拟退火、蚁群、遗传算法

以上是关于算法和数据结构解析:1-算法简介的主要内容,如果未能解决你的问题,请参考以下文章

算法与程序设计:分支限界法

算法和数据结构解析:1-算法简介

算法和数据结构解析:1-算法简介

浅谈分支限界算法

分枝限界算法

计算机算法与分析——7.1分枝-限界法