代码改变世界

学习数据结构 -> 算法的介绍

2012-11-23 17:42  wid  阅读(1165)  评论(0编辑  收藏  举报

学习数据结构 -> 算法的介绍


1. 算法的定义
    从广义上讲, 算法是指解决问题的方法和步骤。
    在计算机中, 算法是指令的有限集合, 而每一条指令表示一个或多个操作。
    
    例如解决将大象装冰箱里的算法为:
        第一步: 将冰箱门打开;
        第二步: 把大象装进去;
        第三步: 把冰箱门合上。
    这就是解决如何将大象装进冰箱的算法。

 


2. 算法的描述
    一个算法可以用多种描述方法进行表示, 常用的有以下4种:
        1>. 自然语言;
        2>. 流程图;
        3>. 伪代码;
        4>. 计算机语言。
    
    自然语言: 自然语言通常是指一种自然地随文化演化的语言。泛指人类语言, 汉语、英语、俄语等都是自然语言, 例如在上面提到的将大象装冰箱里的描述方式就是自然语言。
    
    流程图: "千言万语不如一张图", 在描述较为复杂的算法时, 使用自然语言描述时可能会出现表达的歧义、叙述不够清晰等各种问题。
        以特定的图形符号加上说明, 用于表示算法的图, 称为流程图。 流程图的优势在于能够直观地描述一个工作过程的具体步骤。
        
    伪代码: 伪代码是用介于自然语言和计算机语言之间的文字和符号(包括数学符号)来描述算法的一种方法, 伪代码也有自己的语法规则, 例如将大象装冰箱用伪代码可描述为:

        Begin
        If 冰箱门未打开 Then
            do 把冰箱门打开
            do 把大象装进入
            do 把冰箱门合上
        Else
            do 把大象装进入
            do 把冰箱门合上
        End

    这里多添加了一个条件, 就是先判断冰箱门是否已经打开, 若未打开就按照常规的三步将大象装进去, 否则只需要将大象装进去然后再关上冰箱门即可。
    
    计算机语言: 例如使用C语言、C++、JAVA、Python等各种计算机语言都可以用来描述算法, 以C语言为例:

        void OpenDoor()
        {
            //打开冰箱门的具体操作过程
        }
        int MoveElephant()
        {
            //装大象到冰箱的具体操作过程
        }
        void CloseDoor()
        {
            //关上冰箱门的具体操作过程
        }
        int main()
        {
            OpenDoor() ;        //执行打开冰箱门函数
            MoveElephant() ;    //执行装大象函数
            CloseDoor() ;        //执行关闭冰箱门函数
            
            return 0 ;
        }

 


3. 算法的特性
    一个完整的算法必须要具备以下5点重要特性才能说是一个可行的算法:
        1>. 有穷性: 指算法能够在人们能够接受的一定的时间内结束, 不会永远无止境的执行下去;
        2>. 确定性: 指算法中的每一条指令都具有明确的含义, 在人们的理解上不会产生二义性, 对于相同的输入, 只能得出相同的输出;
        3>. 可行性: 算法中描述的操作都是可以通过已经实现的基本运算执行有限次来实现的;
        4>. 输入: 一个算法有或多个输入, 所谓0个输入是指算法本身定出了初始条件;
        5>. 一个算法有一个或多个输出, 以反映对输入数据加工后的结果, 没有输出的算法是毫无意义的。

 


4. 算法的性能标准
    对算法设计的要求, 在不同的场合以及不同的应用领域要求是不同的, 通常来说一些较为常见的要求如下:
        1>. 正确性: 算法应当满足具体问题的要求;
        2>. 可计算性: 算法不能靠直觉或经验进行描述, 算法的每一步必须是严格定义的, 必须能够一步步精确执行;
        3>. 可读性: 算法的可读性是指一个算法可供人们阅读的容易程度, 不易读懂的算法易于隐藏错误, 难以进行实现和修改;
        4>. 健壮性: 输入非法数据时程序能够做出反应进行处理, 而不至于让整个系统崩溃掉。
        5>. 通用性: 设计的算法应该具有一般性, 不能仅仅对于某一个数值才能使用;
        6>. 高效性: 问题解决速度越快越好, 占用资源越少越好, 对于同一个问题具有多种算法的情况下应该优先选择效率高, 占用资源少的算法。

 


5. 算法的度量
    数据结构中, 在算法是正确的前提下, 评价一个算法主要有两个指标: 算法的时间复杂度与空间复杂度。
    
    1>. 时间复杂度
        时间复杂度是指将算法通过编码实现后在计算机中运行所消耗的时间。从理论上来说, 程序在运行时所消耗的时间是不能算出来的, 必须上机运行测试才能知道。但是全部上机测试费时费力, 正常的情况下是不会这么做的,  因为我们只需推算出哪种算法运行所用的时间少就可以了。 通常来说, 算法中基本操作重复执行的次数是问题规模n的某个函数f(n), 算法的时间量记作:

        T(n) = O(f(n))

        它表示随问题规模n的增大, 算法执行时间的增长率和f(n)的增长率相同, 称作算法的渐进时间复杂度, 简称时间复杂度。
        随着模块n的增大, 算法执行的时间的增长率和f(n)的增长率成正比, 所以当n一定时, f(n)越小, 算法的时间复杂度越低, 算法的效率越高。
        在一个算法中, 人们是按算法中重复执行次数最多的语句来确定算法的时间复杂度。语句的频度指的就是该语句重复执行的次数。 时间的复杂度一般用数量级来表示。常用的时间复杂度有:
            O(1)、O(log2n)、O(n)、O(n*log2n)、O(n2)、O(2^n)
            
        举例:
            1. for循环嵌套:

            int s = 0 ;
            for( i = 0; i < n; i++ )
                for( j = 0; j < n; j++ )
                    for( k = 0; k < n; k++ )
                        s++ ;

            整个算法的执行时间和基本操作重复执行的次数n3成正比, 记为: T(n) = O(n^3)
    
    2>. 空间复杂度
        算法空间复杂度是指将算法实现成程序后, 在计算机运行时所占的存储空间的大小。这个存储空间一般包括以下几个方面的内容: 指令、常量、变量、外部输入、辅助空间。
        
        将这几个内容划分两个部分, 静态空间和固定空间:
            ①. 固定部分: 主要包括指令空间、数据空间(常量、简单变量)等所占的空间。这部分属于静态空间;
        ②. 可变空间: 这部分空间的主要包括动态分配的空间, 以及递归栈所需的空间等。这部分的空间大小与算法有关。

        一个算法所需的存储空间用f(n)表示。

          S(n)= O(f(n))

      其中n为问题的规模, S(n)表示空间复杂度。

        举例:
            一维数组 a[n] 的空间复杂度为O(n) ;
            二维数组 a[m][n] 的空间复杂度为 O(m*n)。

--------------------

wid, 2012.11.23

 

上一篇: 学习数据结构 -> 数据结构的基本概念