铜仁市论坛

首页 » 分类 » 定义 » 数据结构和算法八精华总结
TUhjnbcbe - 2021/7/4 15:59:00
北京看白癜风一般多少钱 http://m.39.net/news/a_5218115.html

计算机数据结构和算法,以及大数据分析算法模型,是整个计算机和数字化业务的业务数据处理、加工、挖掘、提效的核心手段,结合网络、数据库和分布式技术服务组件就能构建强大的数字化应用。今天重点对相关的内容进行一个全局性的总结。

首先看一下数据结构和算法的知识概览图:

接下来看一下数据结构和算法的知识回顾:

一、数据

数据(Data)是信息的载体,它能够被计算机识别、存储和加工处理。它是计算机程序加工的原料,应用程序处理各种各样的数据。

计算机科学中,所谓数据就是计算机加工处理的对象,它可以是数值数据,也可以是非数值数据。数值数据是一些整数、实数或复数,主要用于工程计算、科学计算和商务处理等;

非数值数据包括字符、文字、图形、图像、语音等。

二、数据元素

数据元素(DataElement)是数据的基本单位。在不同的条件下,数据元素又可称为元素、结点、顶点、记录等。

例如,学生信息检索系统中学生信息表中的一个记录、八皇后问题中状态树的一个状态、教学计划编排问题中的一个顶点等,都被称为一个数据元素。

有时,一个数据元素可由若干个数据项(DataItem)组成,例如,学籍管理系统中学生信息表的每一个数据元素就是一个学生记录。它包括学生的学号、姓名、性别、籍贯、出生年月、成绩等数据项。

这些数据项可以分为两种:

一种叫做初等项,如学生的性别、籍贯等,这些数据项是在数据处理时不能再分割的最小单位;

另一种叫做组合项,如学生的成绩,它可以再划分为数学、物理、化学等更小的项。通常,在解决实际应用问题时是把每个学生记录当作一个基本单位进行访问和处理的。

三、数据对象

数据对象(DataObject)或数据元素类(DataElementClass)是具有相同性质的数据元素的集合。

在某个具体问题中,数据元素都具有相同的性质(元素值不一定相等),属于同一数据对象(数据元素类),数据元素是数据元素类的一个实例。例如,在交通咨询系统的交通网中,所有的顶点是一个数据元素类,顶点A和顶点B各自代表一个城市,是该数据元素类中的两个实例,其数据元素的值分别为A和B。

四、数据结构

数据结构研究的三个方面:

(1)数据集合中各数据元素之间所固有的逻辑关系,即数据的逻辑结构;

(2)在对数据进行处理时,各数据元素在计算机中的存储关系,即数据的存储结构;

(3)对各种数据结构进行的运算。

数据结构是指相互有关联的数据元素的集合。

数据的逻辑结构包含:

(1)表示数据元素的信息;

(2)表示各数据元素之间的前后置节点关系。

数据的存储结构有顺序、链接、索引等。

线性结构条件:

(1)有且只有一个根结点;

(2)每一个结点最多有一个前置节点,也最多有一个后置节点。

非线性结构:不满足线性结构条件的数据结构。

五、数据的逻辑结构

数据的逻辑结构有以下两大类:

线性结构:有且仅有一个开始结点和一个终端结点,且所有结点都最多只有一个直接前驱和一个直接后继。

线性表是一个典型的线性结构。栈、队列、串、数组等都是线性结构。

非线性结构:在该类结构中至少存在一个数据元素,它具有两个或者两个以上的前驱或后继。

如树和二叉树集合结构和多维数组、广义表、图、堆等数据结构都是非线性结构。

六、基本的数据结构

集合结构:数据元素的有限集合。数据元素之间除了“属于同一个集合”的关系之外没有其他关系。

线性结构:数据元素的有序集合。数据元素之间形成一对一的关系。

树型结构:树是层次数据结构,树中数据元素之间存在一对多的关系。

图状结构:图中数据元素之间的关系是多对多的。

七、数据的存储结构

数据的存储结构可采用顺序存储或链式存储的方法。

顺序存储方法是把逻辑上相邻的元素存储在物理位置相邻的存储单元中,由此得到的存储表示称为顺序存储结构。顺序存储结构是一种最基本的存储表示方法,通常借助于程序设计语言中的数组来实现。

链式存储方法对逻辑上相邻的元素不要求其物理位置相邻,元素间的逻辑关系通过附设的指针字段来表示,由此得到的存储表示称为链式存储结构,链式存储结构通常借助于程序设计语言中的指针类型来实现。

除了通常采用的顺序存储方法和链式存储方法外,有时为了查找的方便还采用索引存储方法和散列存储方法。

八、算法

算法:是指解题方案的准确而完整的描述。

算法不等于程序,也不等计算机方法,程序的编制不可能优于算法的设计。

算法的基本特征:是一组严谨地定义运算顺序的规则,每一个规则都是有效的,是明确的,此顺序将在有限的次数下终止。特征包括:

(1)可行性;

(2)确定性,算法中每一步骤都必须有明确定义,不充许有模棱两可的解释,不允许有多义性;

(3)有穷性,算法必须能在有限的时间内做完,即能在执行有限个步骤后终止,包括合理的执行时间的含义;

(4)拥有足够的情报。

算法的基本要素:一是对数据对象的运算和操作;二是算法的控制结构。

指令系统:一个计算机系统能执行的所有指令的集合。

基本运算和操作包括:算术运算、逻辑运算、关系运算、数据传输。

算法的控制结构:顺序结构、选择结构、循环结构。

算法基本设计方法:列举法、归纳法、递推、递归、减斗递推技术、回溯法。

算法复杂度:算法时间复杂度和算法空间复杂度。

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

算法空间复杂度是指执行这个算法所需要的内存空间。

时间复杂度

定义:设问题的规模为n,把一个算法的时间耗费T(n)称为该算法的时间复杂度,它是问题规模为n的函数。

常用的算法的时间复杂度的顺序:(比较时只看最高次幂)

for(i=1,i=10,i++)x=x+c;=O(1)

for(i=1,i=n,i++)x=x+n;=O(n)

多嵌套一个for,则为=O(n^2)以此类推

真题难点:i=1,while(i=n)

i=i*3;=O(log3^n)

i=i*2;=O(log2^n)以此类推

九、线性表

线性表由一组数据元素构成,数据元素的位置只取决于自己的序号,元素之间的相对位置是线性的。

在复杂线性表中,由若干项数据元素组成的数据元素称为记录,而由多个记录构成的线性表又称为文件。

非空线性表的结构特征:

(1)且只有一个根结点a1,它无前置节点;

(2)有且只有一个终端结点an,它无后置节点;

(3)除根结点与终端结点外,其他所有结点有且只有一个前置节点,也有且只有一个后置节点。结点个数n称为线性表的长度,当n=0时,称为空表。

线性表的顺序存储结构具有以下两个基本特点:

(1)线性表中所有元素的所占的存储空间是连续的;

(2)线性表中各数据元素在存储空间中是按逻辑顺序依次存放的。

ai的存储地址为:adr(ai)=adr(a1)+(i-1)k,,adr(a1)为第一个元素的地址,k代表每个元素占的字节数。

顺序表的运算:插入、删除。

十、线性链表

数据结构中的每一个结点对应于一个存储单元,这种存储单元称为存储结点,简称结点。

结点由两部分组成:(1)用于存储数据元素值,称为数据域;(2)用于存放指针,称为指针域,用于指向前一个或后一个结点。

在链式存储结构中,存储数据结构的存储空间可以不连续,各数据结点的存储顺序与数据元素之间的逻辑关系可以不一致,而数据元素之间的逻辑关系是由指针域来确定的。

链式存储方式即可用于表示线性结构,也可用于表示非线性结构。

线性链表,head称为头指针,head=null(或0)称为空表,如果是两指针:左指针(llink)指向前置结点,右指针(rlink)指向后置节点。

线性链表的基本运算:查找、插入、删除。

单链表

指针域中存储的信息称做指针或链。N个结点链结成一个链表,由于此链表的每一个结点中包含一个指针域,故又称线性链表或单链表。

循环链表

循环链表是单链表的变形

循环链表最后一个结点的next指针不为空,而是指向了表的前端。为简化操作,在循环链表中往往加入表头结点。

循环链表的特点是:只要知道表中某一结点的地址,就可搜寻到所有其他结点的地址。

双向链表

双向链表是指在前驱和后继方向都能游历(遍历)的线性链表。

在双向链表结构中,每一个结点除了数据域外,还包括两个指针域,一个指针指向该结点的后继结点,另一个指针指向它的前趋结点。通常采用带表头结点的循环链表形式。

用指针实现表

用数组实现表时,利用了数组单元在物理位置上的邻接关系表示表元素之间的逻辑关系。

优点是:

无须为表示表元素之间的逻辑关系增加额外的存储空间。

可以方便地随机存取表中任一位置的元素。

缺点是:

插入和删除运算不方便,除表尾位置外,在表的其他位置上进行插入或删除操作都须移动大量元素,效率较低。

由于数组要求占用连续的存储空间,因此在分配数组空间时,只能预先估计表的大小再进行存储分配。当表长变化较大时,难以确定数组的合适的大小

顺序表与链表的比较

顺序表的存储空间可以是静态分配的,也可以是动态分配的。链表的存储空间是动态分配的。顺序表可以随机或顺序存取。

链表只能顺序存取。顺序表进行插入/删除操作平均需要移动近一半元素。链表则修改指针不需要移动元素。

若插入/删除仅发生在表的两端,宜采用带尾指针的循环链表。存储密度=结点数据本身所占的存储量/结点结构所占的存储总量。顺序表的存储密度=1,链表的存储密度1。

总结:顺序表是用数组实现的,链表是用指针实现的。用指针来实现的链表,结点空间是动态分配的,链表又按链接形式的不同,区分为单链表、双链表和循环链表。

十一、栈和队列

栈是限定在一端进行插入与删除的线性表,允许插入与删除的一端称为栈顶,不允许插入与删除的另一端称为栈底。

栈按照“先进后出”(filo)或“后进先出”(lifo)组织数据,栈具有记忆作用。用top表示栈顶位置,用bottom表示栈底。

栈的基本运算:(1)插入元素称为入栈运算;(2)删除元素称为退栈运算;(3)读栈顶元素是将栈顶元素赋给一个指定的变量,此时指针无变化。

队列是指允许在一端(队尾)进入插入,而在另一端(队头)进行删除的线性表。rear指针指向队尾,front指针指向队头。

队列是“先进行出”(fifo)或“后进后出”(lilo)的线性表。

队列运算包括(1)入队运算:从队尾插入一个元素;(2)退队运算:从队头删除一个元素。

循环队列:s=0表示队列空,s=1且front=rear表示队列满

十二、栈

是限定仅在表尾进行插入或删除操作的线性表。栈是一种后进先出(LastInFirstOut)/先进后出的线性表,简称为LIFO

用指针实现栈—链(式)栈链式栈

无栈满问题,空间可扩充插入与删除仅在栈顶处执行链式栈的栈顶在链头适合于多栈操作

链栈的基本操作

1)进栈运算

进栈算法思想:

1)为待进栈元素x申请一个新结点,并把x赋给该结点的值域。

2)将x结点的指针域指向栈顶结点。

3)栈顶指针指向x结点,即使x结点成为新的栈顶结点。

具体算法如下:

SNode*Push_L(SNode*top,ElemTypex)

{

SNode*p;

p=(SNode*)malloc(sizeof(SNode));

p-data=x;

p-next=top;

top=p;

returntop;

}

2)出栈运算

出栈算法思想如下:

1)检查栈是否为空,若为空,进行错误处理。

2)取栈顶指针的值,并将栈顶指针暂存。

3)删除栈顶结点。

SNode*POP_L(SNode*top,ElemType*y)

{SNode*p;

if(top==NULL)return0;/*链栈已空*/

else{

p=top;

*y=p-data;

top=p-next;free(p);

returntop;

}

3)取栈顶元素

具体算法如下:

voidgettop(SNode*top)

{

if(top!=NULL)

return(top-data);/*若栈非空,则返回栈顶元素*/

else

return(NULL);/*否则,则返回NULL*/

}

十三、队列(Queue)

是只允许在表的一端进行插入,而在另一端进行删除的运算受限的线性表。其所有的插入均限定在表的一端进行,该端称为队尾(Rear);所有的删除则限定在表的另一端进行,该端则称为队头(Front)。

如果元素按照a1,a2,a3....an的顺序进入队列,则出队列的顺序不变,也是a1,a2,a3....an。所以队列具有先进先出(FirstInFirstOut,简称FIFO)/后进后出特性。

如车站排队买票,排在队头的处理完走掉,后来的则必须排在队尾等待。

在程序设计中,比较典型的例子就是操作系统的作业排队。队列的顺序存储结构称为顺序队列,顺序队列实际上是运算受限的顺序表,和顺序表一样,顺序队列也是必须用一个数组来存放当前队列中的元素。

由于队列的队头和队尾的位置是变化的,因而要设两个指针分别指示队头和队尾元素在队列中的位置。

循环队列是为了克服顺序队列中“假溢出”,通常将一维数组Sq.elem[0]到Sq.elem.[MaxSize-1]看成是一个首尾相接的圆环,即Sq.elem[0]与Sq.elem.[maxsize-1]相接在一起。这种形式的顺序队列称为循环队列。

用线性链表表示的队列称为链队列。链表的第一个节点存放队列的队首结点,链表的最后一个节点存放队列的队尾首结点,队尾结点的链接指针为空。另外还需要两个指针(头指针和尾指针)才能唯一确定,头指针指向队首结点,尾指针指向队尾结点

十四、树与二叉树

树是一种简单的非线性结构,所有元素之间具有明显的层次特性。

在树结构中,每一个结点只有一个前置节点,称为父结点,没有前置节点的结点只有一个,称为树的根结点,简称树的根。每一个结点可以有多个后后置节点,称为该结点的子结点。没有后置节点的结点称为叶子结点。

在树结构中,一个结点所拥有的后置节点的个数称为该结点的度,所有结点中最大的度称为树的度。树的最大层次称为树的深度。

二叉树的特点:(1)非空二叉树只有一个根结点;(2)每一个结点最多有两棵子树,且分别称为该结点的左子树与右子树。

二叉树的基本性质:

(1)在二叉树的第k层上,最多有2k-1(k≥1)个结点;

(2)深度为m的二叉树最多有2m-1个结点;

(3)度为0的结点(即叶子结点)总是比度为2的结点多一个;

(4)具有n个结点的二叉树,其深度至少为[log2n]+1,其中[log2n]表示取log2n的整数部分;

(5)具有n个结点的完全二叉树的深度为[log2n]+1;

(6)设完全二叉树共有n个结点。如果从根结点开始,按层序(每一层从左到右)用自然数1,2,….n给结点进行编号(k=1,2….n),有以下结论:

①若k=1,则该结点为根结点,它没有父结点;若k1,则该结点的父结点编号为int(k/2);

②若2k≤n,则编号为k的结点的左子结点编号为2k;否则该结点无左子结点(也无右子结点);

③若2k+1≤n,则编号为k的结点的右子结点编号为2k+1;否则该结点无右子结点。

满二叉树是指除最后一层外,每一层上的所有结点有两个子结点,则k层上有2k-1个结点深度为m的满二叉树有2m-1个结点。

完全二叉树是指除最后一层外,每一层上的结点数均达到最大值,在最后一层上只缺少右边的若干结点。

二叉树存储结构采用链式存储结构,对于满二叉树与完全二叉树可以按层序进行顺序存储。

二叉树的遍历:

(1)前序遍历(dlr),首先访问根结点,然后遍历左子树,最后遍历右子树;

(2)中序遍历(ldr),首先遍历左子树,然后访问根结点,最后遍历右子树;

(3)后序遍历(lrd)首先遍历左子树,然后访问遍历右子树,最后访问根结点。

十五、树

①结点的度:结点拥有子节点的个数

②树的度:该树中最大的度数

③叶子结点:度为零的结点

④分支结点:度不为零的结点

⑤内部结点:除根结点之外的分支结点

⑥开始结点:根结点又称为开始结点

结点的高度:该结点到各结点的最长路径的长度

森林:m(m≥0)棵互不相交的树的集合。将一棵非空树的根结点删去,树就变成一个森林;

反之,给m棵独立的树增加一个根结点,并把这m棵树作为该结点的子树,森林就变成一棵树。

2.结点的层数和树的深度

①结点的层数:根结点的层数为1,其余结点的层数等于其双亲结点的层数加1。

②堂兄弟:双亲在同一层的结点互为堂兄弟。

③树的深度:树中结点的最大层数称为树的深度。

注意:要弄清结点的度、树的度和树的深度的区别。

树中结点之间的逻辑关系是“一对多”的关系,树是一种非线性的结构

树的遍历

先序遍历:访问根结点——先序遍历根的左子树——先序遍历根的右子数

中序遍历:中序遍历左子树——访问根结点——中序遍历右子树

后序遍历:后序遍历左子树——后序遍历右子树——访问根结点

最优二叉树(哈夫曼树):最小两结点数相加的值再与次小结点数合并。

已知一棵二叉树的前根序序列和中根序序列,构造该二叉树的过程如下:

1.根据前根序序列的第一个元素建立根结点;

2.在中根序序列中找到该元素,确定根结点的左右子树的中根序序列;

3.在前根序序列中确定左右子树的前根序序列;

4.由左子树的前根序序列和中根序序列建立左子树;

5.由右子树的前根序序列和中根序序列建立右子树。

-已知一棵二叉树的后根序序列和中根序序列,构造该二叉树的过程如下:

1.根据后根序序列的最后一个元素建立根结点;

2.在中根序序列中找到该元素,确定根结点的左右子树的中根序序列;

3.在后根序序列中确定左右子树的后根序序列;

4.由左子树的后根序序列和中根序序列建立左子树;

5.由右子树的后根序序列和中根序序列建立右子树。

十六、图

G=(V,E)=(顶点,边)

无向完全图有n(n-1)/2个边,有向完全图有n(n-1)个边。n表结点。

边无向(),弧有向

迪杰斯特拉(Dijkstra)算法

是典型的单源最短路径算法,用于计算一个节点到其他所有节点的最短路径。主要特点是以起始点为中心向外层层扩展,直到扩展到终点为止。Dijkstra算法是很有代表性的最短路径算法,在很多专业课程中都作为基本内容有详细的介绍,如数据结构,图论,运筹学等等。注意该算法要求图中不存在负权边。

弗洛伊德(Floyd)算法邻接矩阵求

是解决任意两点间的最短路径的一种算法,可以正确处理有向图或负权的最短路径问题,同时也被用于计算有向图的传递闭包。Floyd-Warshall算法的时间复杂度为O(N3),空间复杂度为O(N2)。

普里姆(Prim)算法

普里姆算法的基本思想:

从连通网络N={V,E}中的某一顶点u0出发,选择与它关联的具有最小权值的边(u0,v),将其顶点加入到生成树顶点集合S中。以后每一步从一个顶点在S中而另一个顶点不在S中的各条边中选择权值最小的边(u,v),把它的顶点加入到集合S中。如此继续下去,直到网络中的所有顶点都加入到生成树顶点集合S中为止。

克鲁斯卡尔(Kruskal)算法

克鲁斯卡尔算法的基本思想:

设有一个有n个顶点的连通网络N={V,E},最初先构造一个只有n个顶点,没有边的非连通图T={V,?},图中每个顶点自成一个连通分支。当在E中选到一条具有最小权值的边时,若该边的两个顶点落在不同的连通分支上,则将此边加入到T中;否则将此边舍去,重新选择一条权值最小的边。如此重复下去,直到所有顶点在同一个连通分支上为止。

十七、查找计数

顺序查找的使用情况:

(1)线性表为无序表;

(2)表采用链式存储结构。

二分法查找只适用于顺序存储的有序表,对于长度为n的有序线性表,最坏情况只需比较log2n次。

十八、排序计数

排序是指将一个无序序列整理成按值非递减顺序排列的有序序列。交换类排序法:(1)冒泡排序法,需要比较的次数为n(n-1)/2;(2)快速排序法。插入类排序法:(1)简单插入排序法,最坏情况需要n(n-1)/2次比较;(2)希尔排序法,最坏情况需要o(n1.5)次比较。选择类排序法:(1)简单选择排序法,最坏情况需要n(n-1)/2次比较;(2)堆排序法,最坏情况需要o(nlog2n)次比较。

排序小结

1、就平均时间性能而言,快速排序最佳。但在最坏情况下不如堆排序和归并排序。(归并排序对n较大时适用)

2、当序列中的记录“基本有序”或n值较小时,直接插入排序是最佳的方法,因此常将它与其他排序方法结合使用,如快速排序、归并排序等。

3、基数排序的时间复杂度也可写成O(d*n),因此它最适用于n值很大而关键字较小的序列。

4、稳定的排序方法:简单排序。不稳定的排序方法:快速排序、堆排序。

一般来说,排序过程中的“比较”是在相邻的两个记录的关键字之间进行的排序方法是稳定的。

接下来我们看下:

常见算法的复杂度:

最后我们再次回顾下,算法思想合集:

关于算法设计常用的算法思想方法

1、递推法

递推是序列计算机中的一种常用算法。它是按照一定的规律来计算序列中的每个项,通常是通过计算机前面的一些项来得出序列中的指定项的值。其思想是把一个复杂的庞大的计算过程转化为简单过程的多次重复,该算法利用了计算机速度快和不知疲倦的机器特点。

2、递归法

程序调用自身的编程技巧称为递归(recursion)。一个过程或函数在其定义或说明中有直接或间接调用自身的一种方法,它通常把一个大型复杂的问题层层转化为一个与原问题相似的规模较小的问题来求解,递归策略只需少量的程序就可描述出解题过程所需要的多次重复计算,大大地减少了程序的代码量。递归的能力在于用有限的语句来定义对象的无限集合。一般来说,递归需要有边界条件、递归前进段和递归返回段。当边界条件不满足时,递归前进;当边界条件满足时,递归返回。

注意:

(1)递归就是在过程或函数里调用自身;

(2)在使用递归策略时,必须有一个明确的递归结束条件,称为递归出口。

3、穷举法

穷举法,或称为暴力破解法,其基本思路是:对于要解决的问题,列举出它的所有可能的情况,逐个判断有哪些是符合问题所要求的条件,从而得到问题的解。它也常用于对于密码的破译,即将密码进行逐个推算直到找出真正的密码为止。例如一个已知是四位并且全部由数字组成的密码,其可能共有种组合,因此最多尝试次就能找到正确的密码。理论上利用这种方法可以破解任何一种密码,问题只在于如何缩短试误时间。因此有些人运用计算机来增加效率,有些人辅以字典来缩小密码组合的范围。

4、贪心算法

贪心算法是一种对某些求最优解问题的更简单、更迅速的设计技术。

用贪心法设计算法的特点是一步一步地进行,常以当前情况为基础根据某个优化测度作最优选择,而不考虑各种可能的整体情况,它省去了为找最优解要穷尽所有可能而必须耗费的大量时间,它采用自顶向下,以迭代的方法做出相继的贪心选择,每做一次贪心选择就将所求问题简化为一个规模更小的子问题,通过每一步贪心选择,可得到问题的一个最优解,虽然每一步上都要保证能获得局部最优解,但由此产生的全局解有时不一定是最优的,所以贪婪法不要回溯。

贪婪算法是一种改进了的分级处理方法,其核心是根据题意选取一种量度标准,然后将这多个输入排成这种量度标准所要求的顺序,按这种顺序一次输入一个量,如果这个输入和当前已构成在这种量度意义下的部分最佳解加在一起不能产生一个可行解,则不把此输入加到这部分解中。这种能够得到某种量度意义下最优解的分级处理方法称为贪婪算法。

对于一个给定的问题,往往可能有好几种量度标准。初看起来,这些量度标准似乎都是可取的,但实际上,用其中的大多数量度标准作贪婪处理所得到该量度意义下的最优解并不是问题的最优解,而是次优解。因此,选择能产生问题最优解的最优量度标准是使用贪婪算法的核心。

一般情况下,要选出最优量度标准并不是一件容易的事,但对某问题能选择出最优量度标准后,用贪婪算法求解则特别有效。

5、分治法

分治法是把一个复杂的问题分成两个或更多的相同或相似的子问题,再把子问题分成更小的子问题……直到最后子问题可以简单的直接求解,原问题的解即子问题的解的合并。

分治法所能解决的问题一般具有以下几个特征:

(1)该问题的规模缩小到一定的程度就可以容易地解决;

(2)该问题可以分解为若干个规模较小的相同问题,即该问题具有最优子结构性质;

(3)利用该问题分解出的子问题的解可以合并为该问题的解;

(4)该问题所分解出的各个子问题是相互独立的,即子问题之间不包含公共的子子问题。

6、动态规划法

动态规划是一种在数学和计算机科学中使用的,用于求解包含重叠子问题的最优化问题的方法。其基本思想是,将原问题分解为相似的子问题,在求解的过程中通过子问题的解求出原问题的解。动态规划的思想是多种算法的基础,被广泛应用于计算机科学和工程领域。

动态规划程序设计是对解最优化问题的一种途径、一种方法,而不是一种特殊算法。不象前面所述的那些搜索或数值计算那样,具有一个标准的数学表达式和明确清晰的解题方法。动态规划程序设计往往是针对一种最优化问题,由于各种问题的性质不同,确定最优解的条件也互不相同,因而动态规划的设计方法对不同的问题,有各具特色的解题方法,而不存在一种万能的动态规划算法,可以解决各类最优化问题。因此读者在学习时,除了要对基本概念和方法正确理解外,必须具体问题具体分析处理,以丰富的想象力去建立模型,用创造性的技巧去求解。

7、迭代法

迭代法也称辗转法,是一种不断用变量的旧值递推新值的过程,跟迭代法相对应的是直接法(或者称为一次解法),即一次性解决问题。迭代法又分为精确迭代和近似迭代。“二分法”和“牛顿迭代法”属于近似迭代法。迭代算法是用计算机解决问题的一种基本方法。它利用计算机运算速度快、适合做重复性操作的特点,让计算机对一组指令(或一定步骤)进行重复执行,在每次执行这组指令(或这些步骤)时,都从变量的原值推出它的一个新值。

8、分支界限法

分枝界限法是一个用途十分广泛的算法,运用这种算法的技巧性很强,不同类型的问题解法也各不相同。

分支定界法的基本思想是对有约束条件的最优化问题的所有可行解(数目有限)空间进行搜索。该算法在具体执行时,把全部可行的解空间不断分割为越来越小的子集(称为分支),并为每个子集内的解的值计算一个下界或上界(称为定界)。在每次分支后,对凡是界限超出已知可行解值那些子集不再做进一步分支,这样,解的许多子集(即搜索树上的许多结点)就可以不予考虑了,从而缩小了搜索范围。这一过程一直进行到找出可行解为止,该可行解的值不大于任何子集的界限。因此这种算法一般可以求得最优解。

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

9、回溯法

回溯法(探索与回溯法)是一种选优搜索法,按选优条件向前搜索,以达到目标。但当探索到某一步时,发现原先选择并不优或达不到目标,就退回一步重新选择,这种走不通就退回再走的技术为回溯法,而满足回溯条件的某个状态的点称为“回溯点”。

其基本思想是,在包含问题的所有解的解空间树中,按照深度优先搜索的策略,从根结点出发深度探索解空间树。当探索到某一结点时,要先判断该结点是否包含问题的解,如果包含,就从该结点出发继续探索下去,如果该结点不包含问题的解,则逐层向其祖先结点回溯。(其实回溯法就是对隐式图的深度优先搜索算法)。若用回溯法求问题的所有解时,要回溯到根,且根结点的所有可行的子树都要已被搜索遍才结束。而若使用回溯法求任一个解时,只要搜索到问题的一个解就可以结束。

最后推荐一个可视化算法工具:

数据结构:超好用的数据结构与算法可视化工具(USFCA旧金山大学)

这是旧金山大学的一个网站,该网站以可视化的交互模式介绍数据结构和算法,非常有利于理解!

1
查看完整版本: 数据结构和算法八精华总结