作者在 2011-04-25 10:27:45 发布以下内容
(转载)
计算机,顾名思义,是用来计算的机器,它本身并不具有思维能力,将它叫做电脑实在是
言过其实。无论多么复杂的程序,所从事的都是比较、赋值、循环等基本的运算。我们要
编程序解决实际问题,就是要将实际问题的解题步骤用这些基本运算描述出来,这种描述
就是算法。
如何才能将实际问题的解题步骤描述出来呢?这就要建立数学模型。有些问题的数学模型
非常明显,有些问题则比较含蓄。比如说,岗哨设置问题,这个问题可以建立明显的数学
模型,也就是图论模型。有了这个模型,就可以用图论中的相关定理来解决此问题,计算
机所起的作用不过是按照算法计算结果。对于像走迷宫之类的问题,看上去没有明显的数
学模型,只能用回溯法搜索,但实际上这种搜索法本身就是一个数学模型,这个模型叫做
状态空间模型,即在某一个状态空间(状态的集合)内,从某个初始状态开始,通过某种
规则或运算,转移到目标状态。如果状态A可以通过状态转移规则转移到状态B,则从A到B
连一条有向边,这样整个状态空间构成一个网络,只要找到从初始状态到目标状态的路径
即可,于是搜索法又转化为图论模型。也许对有些问题建立严格的数学模型并不能简化问
题的求解,但是可以通过该模型将特殊的问题转化为一般的问题,至少具有理论分析(比
如复杂性分析)上的意义。
要建立数学模型,首先要将问题中的对象以及它们之间的相互关系用数学语言描述,这就
涉及到对象如何表示的问题,也就是采用什么样的抽象数据类型(ADT)来描述对象。所采用
的ADT应该能够方便清晰地表现出对象之间的相互关系(包括显式的和隐式的)。然后在A
DT上定义一些运算(可以暂时不关心运算的实现),将问题的解决步骤转化为ADT的运算的
序列。至于ADT的运算,可以转化为更小的子ADT运算来实现。转化到最后,分解到最小了
,就必须考虑抽象数据类型ADT如何存储在计算机的存储器中,即数据的描述方法。最常见
的数据描述方法有:公式化描述、链接描述、间接寻址和模拟指针。
1。公式化描述借助数学公式来确定元素表中的每个元素分别存储在何处 (存储器地址)。
最简单的情形就是把所有元素依次连续存储在一片连续的存储空间中,这时采用的公式是
location(i)=location(1)+(i-1),其中location(i)表示第i个元素的地址,并假设每个元
素占用一个内存单元。这也就是通常所说的连续线性表,即数组。
2。在链接描述中,元素表中的每个元素可以存储在存储器的不同区域中,每个元素都包含
一个指向下一个元素的指针(即内存中的地址)。
3。在间接寻址方式中,元素表中的每个元素也可以存储在存储器的不同区域中,不同的是
,此时必须保存一张表,该表的第i项指向元素表中的第i个元素,所以这张表是一个用来
存储元素地址的表。
4。模拟指针非常类似于链接描述,区别在于它用整数代替了指针,整数所扮演的角色与指
针所扮演的角色完全相同。如果所有模拟指针分配的内存单元是一片连续的内存地址,则
称其为游标描述或静态链表描述。
所有的基本ADT,比如说图、树、线性表等,最后都要用以上四种描述方法中的一种或几种
描述方法存储在存储器中。至于选择哪一种描述方法,要根据ADT上定义的运算来确定,总
的原则是使运算易于实现并且占用的资源尽量少。对于某些复杂的ADT,比如堆、优先队列
等,则是用基本ADT来实现。因此ADT呈现出一种层次继承关系。
在构造算法的过程中还有一个难点,就是如何将解决问题的步骤用ADT的运算描述。这个过
程没有固定的方法,只能靠经验的积累和一时的灵感。但是一般可以采取以下几个策略:
递归策略,分治策略,贪心策略,动态规划策略,搜索策略,随机策略,模拟策略等。这
些算法设计策略只是一种算法设计思想,并非固定的法则。必须分清楚各种策略的适用条
件和相互间的联系区别,在考虑问题时才能够正确地选择算法策略。
另外,熟悉常用抽象数据类型的各种实现方法和一些常用算法也很大帮助。因为许多问题
可以转化为类似的经典问题,或者可以分解为若干子问题,而这些子问题可以用经典的算
法和抽象数据类型解决。其中,最常用的算法策略应该是搜索策略,几乎所有的问题都可
以用此策略解决(但是未必可行)。这种策略充分利用了计算机计算速度快的特性,在许
多情况下可以在合理的时间内找到问题的最优解。但是,对于有些问题,虽然可以用搜索
法解决,但是时间复杂性无法忍受,所以不可以滥用搜索法,在使用搜索法之前要先估计
时间复杂性。即使使用了搜索法,也要根据实际情况进行优化,通常采用启发式搜索、A算
法、A*算法或界限剪枝法,目的是为了减少搜索的时间复杂性。还有一些看上去只能用搜
索法或穷举法的问题可以考虑用动态规划法和贪心法。值得注意的是,对于有些问题,比
如NP-完全问题,用任何算法都无法在多项式时间内解决,这时可以考虑寻找近似解法,得
到较优解或最优解的上下界,一般是采用贪心算法策略构造近似解法。
以上是我的学习体会,下面说说我对学习算法和数据结构这门课的建议。
对于编程的初学者,可以先通过简单的排序算法了解最简单的ADT线性表的常用操作;然后
要重点掌握递归技术,包括递归和递推的相互转换。递归技术非常重要,可以通过递归技术
了解ADT栈的操作;接着学习搜索法的初步——回溯法,研究经典问题八皇后问题和走迷宫
问题,通过这些经典问题了解深度优先搜索法(DFS)和宽度优先搜索法(BFS)以及ADT栈、A
DT队列的操作,要学会利用人工设置堆栈模拟递归;接着可以学习分治法、贪心法这两种
常用的策略,并应用到排序、搜索等简单的算法中;这时再开始学习图和树这两种抽象数
据类型就应该没有什么难度了。在学习ADT图和ADT树时,要注意结合离散数学中的图论理
论知识和搜索法中的DFS,BFS方法,要学会将实际问题转化为图论模型;再下去可以学习
各种搜索法的优化算法,启发式搜索、A算法、A*算法或界限剪枝法等;然后是网络流算法
,要注意模型的建立;最后学习最优化问题的解法,包括线性规划、动态规划、非线性规
划等算法策略,这部分内容主要侧重模型的建立和分析,算法本身并没有难度。这样基本
的算法就学习完了。再深入一点可以学习问题的计算复杂性,计算模型,并行算法,神经
言过其实。无论多么复杂的程序,所从事的都是比较、赋值、循环等基本的运算。我们要
编程序解决实际问题,就是要将实际问题的解题步骤用这些基本运算描述出来,这种描述
就是算法。
如何才能将实际问题的解题步骤描述出来呢?这就要建立数学模型。有些问题的数学模型
非常明显,有些问题则比较含蓄。比如说,岗哨设置问题,这个问题可以建立明显的数学
模型,也就是图论模型。有了这个模型,就可以用图论中的相关定理来解决此问题,计算
机所起的作用不过是按照算法计算结果。对于像走迷宫之类的问题,看上去没有明显的数
学模型,只能用回溯法搜索,但实际上这种搜索法本身就是一个数学模型,这个模型叫做
状态空间模型,即在某一个状态空间(状态的集合)内,从某个初始状态开始,通过某种
规则或运算,转移到目标状态。如果状态A可以通过状态转移规则转移到状态B,则从A到B
连一条有向边,这样整个状态空间构成一个网络,只要找到从初始状态到目标状态的路径
即可,于是搜索法又转化为图论模型。也许对有些问题建立严格的数学模型并不能简化问
题的求解,但是可以通过该模型将特殊的问题转化为一般的问题,至少具有理论分析(比
如复杂性分析)上的意义。
要建立数学模型,首先要将问题中的对象以及它们之间的相互关系用数学语言描述,这就
涉及到对象如何表示的问题,也就是采用什么样的抽象数据类型(ADT)来描述对象。所采用
的ADT应该能够方便清晰地表现出对象之间的相互关系(包括显式的和隐式的)。然后在A
DT上定义一些运算(可以暂时不关心运算的实现),将问题的解决步骤转化为ADT的运算的
序列。至于ADT的运算,可以转化为更小的子ADT运算来实现。转化到最后,分解到最小了
,就必须考虑抽象数据类型ADT如何存储在计算机的存储器中,即数据的描述方法。最常见
的数据描述方法有:公式化描述、链接描述、间接寻址和模拟指针。
1。公式化描述借助数学公式来确定元素表中的每个元素分别存储在何处 (存储器地址)。
最简单的情形就是把所有元素依次连续存储在一片连续的存储空间中,这时采用的公式是
location(i)=location(1)+(i-1),其中location(i)表示第i个元素的地址,并假设每个元
素占用一个内存单元。这也就是通常所说的连续线性表,即数组。
2。在链接描述中,元素表中的每个元素可以存储在存储器的不同区域中,每个元素都包含
一个指向下一个元素的指针(即内存中的地址)。
3。在间接寻址方式中,元素表中的每个元素也可以存储在存储器的不同区域中,不同的是
,此时必须保存一张表,该表的第i项指向元素表中的第i个元素,所以这张表是一个用来
存储元素地址的表。
4。模拟指针非常类似于链接描述,区别在于它用整数代替了指针,整数所扮演的角色与指
针所扮演的角色完全相同。如果所有模拟指针分配的内存单元是一片连续的内存地址,则
称其为游标描述或静态链表描述。
所有的基本ADT,比如说图、树、线性表等,最后都要用以上四种描述方法中的一种或几种
描述方法存储在存储器中。至于选择哪一种描述方法,要根据ADT上定义的运算来确定,总
的原则是使运算易于实现并且占用的资源尽量少。对于某些复杂的ADT,比如堆、优先队列
等,则是用基本ADT来实现。因此ADT呈现出一种层次继承关系。
在构造算法的过程中还有一个难点,就是如何将解决问题的步骤用ADT的运算描述。这个过
程没有固定的方法,只能靠经验的积累和一时的灵感。但是一般可以采取以下几个策略:
递归策略,分治策略,贪心策略,动态规划策略,搜索策略,随机策略,模拟策略等。这
些算法设计策略只是一种算法设计思想,并非固定的法则。必须分清楚各种策略的适用条
件和相互间的联系区别,在考虑问题时才能够正确地选择算法策略。
另外,熟悉常用抽象数据类型的各种实现方法和一些常用算法也很大帮助。因为许多问题
可以转化为类似的经典问题,或者可以分解为若干子问题,而这些子问题可以用经典的算
法和抽象数据类型解决。其中,最常用的算法策略应该是搜索策略,几乎所有的问题都可
以用此策略解决(但是未必可行)。这种策略充分利用了计算机计算速度快的特性,在许
多情况下可以在合理的时间内找到问题的最优解。但是,对于有些问题,虽然可以用搜索
法解决,但是时间复杂性无法忍受,所以不可以滥用搜索法,在使用搜索法之前要先估计
时间复杂性。即使使用了搜索法,也要根据实际情况进行优化,通常采用启发式搜索、A算
法、A*算法或界限剪枝法,目的是为了减少搜索的时间复杂性。还有一些看上去只能用搜
索法或穷举法的问题可以考虑用动态规划法和贪心法。值得注意的是,对于有些问题,比
如NP-完全问题,用任何算法都无法在多项式时间内解决,这时可以考虑寻找近似解法,得
到较优解或最优解的上下界,一般是采用贪心算法策略构造近似解法。
以上是我的学习体会,下面说说我对学习算法和数据结构这门课的建议。
对于编程的初学者,可以先通过简单的排序算法了解最简单的ADT线性表的常用操作;然后
要重点掌握递归技术,包括递归和递推的相互转换。递归技术非常重要,可以通过递归技术
了解ADT栈的操作;接着学习搜索法的初步——回溯法,研究经典问题八皇后问题和走迷宫
问题,通过这些经典问题了解深度优先搜索法(DFS)和宽度优先搜索法(BFS)以及ADT栈、A
DT队列的操作,要学会利用人工设置堆栈模拟递归;接着可以学习分治法、贪心法这两种
常用的策略,并应用到排序、搜索等简单的算法中;这时再开始学习图和树这两种抽象数
据类型就应该没有什么难度了。在学习ADT图和ADT树时,要注意结合离散数学中的图论理
论知识和搜索法中的DFS,BFS方法,要学会将实际问题转化为图论模型;再下去可以学习
各种搜索法的优化算法,启发式搜索、A算法、A*算法或界限剪枝法等;然后是网络流算法
,要注意模型的建立;最后学习最优化问题的解法,包括线性规划、动态规划、非线性规
划等算法策略,这部分内容主要侧重模型的建立和分析,算法本身并没有难度。这样基本
的算法就学习完了。再深入一点可以学习问题的计算复杂性,计算模型,并行算法,神经