算法之道
主要用c实现了《算法导论》一书的绝大多数算法
nineheaded_bird
这个作者很懒,什么都没留下…
展开
-
【图解例说机器学习】K最近邻 (KNN)
kNN (k-nearest neighbor)的定义针对一个测试实例,在给定训练集中,基于某种距离度量找到与之最近的k个实例点,然后基于这k个最邻近实例点的信息,以某种决策规则来对该测试实例进行分类或回归。由定义可知,kNNkNNkNN模型包含三个基本要素:距离度量、k值选择以及决策规则。再详细描述这三要素之前,我们先用一个样图来简单描述kNNkNNkNN分类模型的效果。我们以二维平面...原创 2020-01-12 22:12:55 · 797 阅读 · 0 评论 -
【算法导论】多项式求和
一般情况下,一元n次多项式可写成:其中,pi是指数为ei的项的非零系数,且满足因此,我们可以采用线性表(定义:线性表是由n个数据元素构成的有限序列,比如数组、向量、链表等等)来表示:其中,每一项的指数i可以用其系数pi的序号表示。在通常的应用中,多项式的次数比较大,使得线性表的长度很难确定,因此我们可以考虑链表,向量也可以(c++中)。举原创 2014-10-26 15:18:31 · 7902 阅读 · 0 评论 -
【Qt编程】3D迷宫游戏
说起迷宫想必大家都很熟悉,个人感觉迷宫对人的方向感是很大的考验,至少我的方向感是不好的,尤其是在三维空间中。由于这段时间帮导师做项目用到了三维作图,便心血来潮想做个三维迷宫玩玩。要想画出三维的迷宫游戏,我们需要先从二维开始。二维迷宫:迷宫的程序描述: 现实生活中,我们经常将问题用数学的方法来描述并解决(数学建模)。同样的,我们想用程序来解决问题,就得把问题程序原创 2014-10-18 18:30:38 · 7965 阅读 · 1 评论 -
【算法导论】最大二分匹配
最大二分匹配问题在现实生活中比较普遍,常常出现在任务分配上。例如,有5个员工,4个不同的任务,而不同员工能够完成不同或相同的任务。也就是说,有的员工只会做这个任务,有的员工会做那个任务,有的员工会做一些任务。图解如下:左边代表员工,右边代表任务,连线代表有能力完成。 我们的问题是合理安排员工,尽可能地完成最多的任务数。上图中阴影部分为一种最好的分配方式。前一篇文章中,我们介绍了最大流问题,原创 2014-01-04 20:37:04 · 3551 阅读 · 0 评论 -
【算法导论】最大流算法
最大流问题就是在容量容许的条件下,从源点到汇点所能通过的最大流量。1 流网络网络流G=(v, E)是一个有向图,其中每条边(u, v)均有一个非负的容量值,记为c(u, v) ≧ 0。如果(u, v) ∉ E则可以规定c(u, v) = 0。网络流中有两个特殊的顶点,即源点s和汇点t。与网络流相关的一个概念是流。设G是一个流网络,其容量为c。设s为网络的源点,t为汇点,那么G的流是一个原创 2014-01-02 21:23:56 · 19164 阅读 · 5 评论 -
【算法导论】幻方算法
说起幻方,大家应该在小学时候就已经接触过了,最简单的就是九宫格,射雕英雄传中的那段至今还记得:戴九履一,左三右七,二四为肩,六八为足。下面我们就来看看这个有趣的问题。幻方可以分为:奇数阶幻方、双偶阶幻方、单偶阶幻方。奇数阶幻方上面所说的九宫格就是典型的奇数阶幻方,奇数阶幻方值得是阶数为奇数的幻方。其最经典的填法是罗伯法。具体步骤为:把1(或最小的数)放在第一行正中;按以下规律排列剩原创 2013-12-30 20:39:26 · 9129 阅读 · 1 评论 -
【算法导论】地图染色算法
地图染色问题可以根据四色定理来解决。所谓四色定理,就是指可以用不多于四种的颜色对地图着色,使相邻的行政区域不重色,因此我们可以用四色定理的结论,用回溯算法对一幅给定的地图染色。算法的基本思想是:从第(1)号行政区域开始染色,每个区域逐次用颜色1#、2#、3#、4#进行试探,若当前所取的颜色与周围已染色的行政区域不重色,则用栈记下该区域的颜色序号,否则依次用下一颜色进行试探;若出现用1#到4#颜原创 2013-12-28 22:54:29 · 18110 阅读 · 1 评论 -
【算法导论】有向图的可达矩阵
有时候,我们关注的不是从一个地点到另一个地点的费用,而是能否从一个顶点到达另一个顶点。因此我们可以假设所有边的权值为单位1,在下面的算法中,我们可以在O(n*n*n)的时间内计算出图中任意两点是否可达,我用可达矩阵来表示有向图中两者是否可达。如果可以从i到j,则定义tij=1,否则tij=0。因此我们可以得到下式:我们以下面的有向图进行具体实现:下图给出了计算所得的每一个T原创 2013-12-27 11:05:07 · 34986 阅读 · 3 评论 -
【算法导论】每对顶点之间的最短路径算法
对于一个顶点数为N的有向网路图,我们可以通过前面所提到的单源最短路径算法执行N次来获得每一对顶点间的最短路径。这种方法的时间复杂度为O(N*N*N)。如果网络中有负权值的边,则需要使用前面提到的单源最短路径算法之Bellman—Floyd算法。总之,总可以通过单源最短路径来求得每对顶点间的最短路径。这里我就不再用程序实现上述方法,下面介绍Floyd解决这一问题的另一种算法,它形式简单,利于理解,而原创 2013-12-26 10:52:57 · 5610 阅读 · 0 评论 -
【算法导论】单源最短路径之Dijkstra算法
Dijkstra算法解决了有向图上带正权值的单源最短路径问题,其运行时间要比Bellman-Ford算法低,但适用范围比Bellman-Ford算法窄。、迪杰斯特拉提出的按路径长度递增次序来产生源点到各顶点的最短路径的算法思想是:对有n个顶点的有向连通网络G=(V, E),首先从V中取出源点u0放入最短路径顶点集合U中,这时的最短路径网络S=({u0}, {}); 然后从uU和vV-U中原创 2013-12-23 20:25:10 · 5157 阅读 · 0 评论 -
【算法导论】单源最短路径之Bellman-Ford算法
单源最短路径指的是从一个顶点到其它顶点的具有最小权值的路径。我们之前提到的广度优先搜索算法就是一种无权图上执行的最短路径算法,即在所有的边都具有单位权值的图的一种算法。单源最短路径算法可以解决图中任意顶点间的最短路径。 对于单源最短路径问题,一般有两种经典解法:1.对于有权值为负的图,采用Bellman-Ford算法;2.对于权值全为正的图,常采用Dijkstra算法。本文介绍Be原创 2013-12-20 18:10:13 · 7857 阅读 · 5 评论 -
【算法导论】最小生成树之Prime法
关于最小生成树的概念,在前一篇文章中已经讲到,就不在赘述了。下面介绍Prime算法:其基本思想为:从一个顶点出发,选择由该顶点出发的最小权值边,并将该边的另一个顶点包含进来,然后找出由这两个顶点出发的最小边,依此类推,直至包含所有的顶点。如果期间构成环,就舍弃该边,继续寻找最小边。下面以具体实例来说明算法的过程:具体的程序实现如下:#include#define N 6 /原创 2013-12-19 19:45:45 · 2509 阅读 · 0 评论 -
【算法导论】最小生成树之Kruskal法
在图论中,树是指无回路存在的连通图。一个连通图的生成树是指包含了所有顶点的树。如果把生成树的边的权值总和作为生成树的权,那么权值最小的生成树就称为最小生成树。因为最小生成树在实际中有很多应用,所以我们有必要了解怎样生成最小生成树。构造最小生成树的两种常用方法:Kruskal算法、Prim算法。本文介绍Kruskal算法,Prim算法在下篇文章中介绍。Kruskal算法是从另一条途径来求网络的的原创 2013-12-17 17:41:15 · 3202 阅读 · 5 评论 -
【算法导论】有向图的深度优先搜索遍历
在前面的文章中,我已经讨论了无向图的遍历,现在发现在有向图中,可能会发生无法遍历到所有节点的情况。因此在经历一次深度优先搜索遍历后,如果还存在未被搜索到的节点,则需要再从新的节点开始进行深度优先搜索遍历,直到访问完所有节点。以下面的有向图为例:如果从a开始进行深度优先搜索遍历,则会得到 a b c d h g f 后结束,因此我们还要 从未访问到的节点e进行第二次深度优先搜索遍历原创 2013-12-15 18:32:31 · 25658 阅读 · 0 评论 -
【算法导论】邻接表存储的拓扑排序
上一篇文章中讲述了用邻接矩阵存储的图的拓扑排序,下面本文介绍用邻接表存储的图的拓扑排序。关于拓扑排序的概念及基本思想,我在上一篇文章中已经较为详细的描述了,这里不在介绍。我们知道利用邻接矩阵进行拓扑排序时,程序实现较为简单,但是效率不高,算法的复杂度为O(n^3).而利用邻接表会使入度为0的顶点的操作简化,从而提高算法的效率。在邻接表存储结构中,为了便于检查每个顶点的入度,可在顶点表中增加原创 2013-12-13 16:50:52 · 8627 阅读 · 1 评论 -
【算法导论】邻接矩阵存储的拓扑排序
在很多应用中,很多事情都是按照一定的次序来进行的,比如说起床穿衣时,不可能先穿鞋再穿袜子,但是穿袜子和穿裤子可以不分先后次序。这种按照一定顺序进行的活动,可以使用顶点表示活动,顶点之间的有向边表示活动间的先后关系,这种有向无回路图说明了活动的先后次序。当活动只能单个进行时,如果可以将图中的所有顶点排列成一个线性序列vi1, vi2, …, vin,并且这个序列同时满足关系:若从顶点vi到顶点v原创 2013-12-11 17:31:18 · 10209 阅读 · 1 评论 -
【算法导论】图的深度优先搜索遍历(DFS)
关于图的存储在上一篇文章中已经讲述,在这里不在赘述。下面我们介绍图的深度优先搜索遍历(DFS)。深度优先搜索遍历实在访问了顶点vi后,访问vi的一个邻接点vj;访问vj之后,又访问vj的一个邻接点,依次类推,尽可能向纵深方向搜索,所以称为深度优先搜索遍历。显然这种搜索方法具有递归的性质。图的BFS和树的搜索遍历很类似,只是其存储方式不同。 其基本思想为:从图中某一顶点vi出发原创 2013-12-10 19:24:50 · 4379 阅读 · 0 评论 -
【算法导论】图的广度优先搜索遍历(BFS)
图的存储方法:邻接矩阵、邻接表 例如:有一个图如下所示:则上图用邻接矩阵可以表示为:用邻接表可以表示如下:邻接矩阵可以很容易的用二维数组表示,下面主要看看怎样构成邻接表: 邻接表存储方法是一种顺序存储与链式存储相结合的存储方法。在这种方法中,只考虑非零元素,所以在图中的顶点很多而边很少时,可以节省存储空间。 邻接原创 2013-12-09 20:50:15 · 6897 阅读 · 0 评论 -
【算法导论】链表队列
链表队列很简单,之前看到过,没有用程序实现。其原理就是遵循FIFO原则,只能从队首取元素,从队尾插入元素,就和排队模型一样。因此只需要队首指针和队尾指针就可以方便的进行队列操作。因为在最近看的图论算法中,经常用到队列,在这里就先用程序实现链表队列。和单链表一样,为了运算方便,我们也在队头节点前附加一个头结点,且头指针指向头结点。其链表队列的示意图如下:下面是具体的程序实现:#i原创 2013-12-06 17:52:50 · 2140 阅读 · 0 评论 -
【算法导论】B树
一棵B树T是具有如下性质的有根树(设根为root):1.每个节点x有一下域:(a)num,当前存储在节点x的关键字个数,关键字以非降序存放,因此key[i] (b)isleaf,是一个bool值,如果x为叶子节点,则isleaf=true. (c)每个节点包括num+1个指向其子女的指针p原创 2013-12-04 20:21:25 · 2537 阅读 · 0 评论 -
【算法导论】贪心算法之背包问题
在讨论贪心算法时,我们先了解贪心算法与动态规划之间的区别与联系,后面我们将发现可以用0、1背包问题和部分背包问题来比较贪心算法和动态规划的关系。我们知道,对于一个最优解问题,贪心算法不一定能够产生一个最优解。因为,如果想要采用贪心算法得到最优解需要满足两个条件:贪心选择性质、最优子结构。贪心选择性质:一个全局最优解可以通过局部最优解来得到。that is to say,当考虑如何做选择时,原创 2013-12-01 11:32:39 · 8770 阅读 · 1 评论 -
【算法导论】贪心算法之活动安排问题
对于许多最优化问题来说,采用动态规划来求解最优解有点大材小用了,只需要采用更简单有效的贪心算法就行了。贪心算法就是所做的每一步选择都是当前最佳的,通过局部最佳来寻求全局最佳解。就像砝码称重一样,总是优先选择大的砝码。贪心算法对大多数优化问题来说能产生最优解,但也不一定总是这样的。能用贪心算法解的典型问题包括活动选择问题、最小生成树、最短路径问题等等。下面我们来讨论活动活动选择问题:对于原创 2013-11-27 22:18:09 · 5876 阅读 · 0 评论 -
【算法导论】动态规划之最优二叉查找树
如果我们想写一个单词查询的软件的话,我们的目的就是让查询的总时间最短,我们首先想到用之前的二叉查找树。我们可以用红黑树或者其它的平衡二叉树来保证每个单词的搜索时间。但是每个单词出现的频率一般不同,因此我们希望把频率较大的单词放在离根比较近的地方,频率较小的放在离叶子较近的地方。而且,我们所要查询的单词词库中没有,这也值得考虑。 由上文可知,ki表示单词,di表原创 2013-11-26 22:00:02 · 9643 阅读 · 0 评论 -
【算法导论】动态规划之最长公共子序列
子序列:一个给定序列的子序列就是该给定序列去掉零个或者多个元素后的序列。例如:Z={B,C,D,B}是X={A,B,C,B,D,A,B}的一个子序列。注意顺序不能改变公共子序列:既是序列X的子序列,又是序列Y的子序列。例如:X={A,B,C,B,D,A,B},Y={B,D,C,A,B,A},则序列{B,C,A}是X和Y的一个公共子序列,长度为4;序列{B,C,B,A}是X和Y的一个最长公共子序原创 2013-11-25 21:02:54 · 2321 阅读 · 0 评论 -
【算法导论】动态规划之矩阵链乘法
所谓矩阵链乘法是指当一些矩阵相乘时,如何加括号来改变乘法顺序从而来降低乘法次数。例如有三个矩阵连乘:A1*A2*A3,其维数分别为:10*100,100*5,5*50.如果按照((A1*A2)*A3)来计算的话,求(A1*A2)要10*100*5=5000次乘法,再乘以A3需要10*5*50=2500次乘法,因此总共需要7500次乘法。如果按照(A1*(A2*A3))来计算的话,求(A2*A3)要原创 2013-11-24 18:54:38 · 9447 阅读 · 1 评论 -
【算法导论】动态规划算法之装配线调度
动态规划算法之装配线调度和分治算法一样,动态规划是通过组合子问题的解而解决整个问题的。但是与分治算法不同的是,动态规划算法适用于子问题不是独立的情况,也就是各子问题包含公共的子子问题。动态规划通常用于最优化问题的求解。看一个问题是否适合采用动态规划算法,主要有两个标志:最优子结构和重叠子问题。最优子结构:问题的一个最优解包含了子问题的最优解。重叠子问题:当一个递归算法不断地调用同一问题原创 2013-11-23 18:41:24 · 3323 阅读 · 0 评论 -
【算法导论】红黑树
红黑树在了解红黑树之前,我们必须先了解二叉搜索树(又称二叉排序树,我在上一篇文章中有介绍),因为红黑树是一种特殊的二叉排序树:在每个节点上增加一个存储位来表示节点的颜色,因此红黑树共有五个域:color,key,lchild,rchild,p。红黑树的提出:一个高度为h的二叉排序树可以实现任何一种基本的动态集合操作:插入、删除、查找等操作,但是当树才高度比较高时,二叉树就会退化成链表。而红原创 2013-08-09 20:25:53 · 1682 阅读 · 0 评论 -
【算法导论】二叉排序树
二叉排序树二叉排序树的性质:每个节点的左子树中的所有节点的关键字都小于该节点的关键值,而右子树中的所有节点的关键字都大于该节点的关键值。二叉排序树的构造二叉排序树的构造是指将一个给定的数据元素构造为相应的二叉排序树。基本思想为:对于任给的一组数据元素{ R1, R2, …, Rn } , 可按以下方法来构造二叉排序树: (1) 令R1为二叉树的根;原创 2013-08-09 11:32:47 · 2421 阅读 · 0 评论 -
【算法导论】哈夫曼树及编译码
哈夫曼树及编译码哈夫曼树,又称二叉树,是一类带权路径长度最短的树。所谓路径长度,就是节点到树根之间的路径长度与节点权值的乘积。哈夫曼本人曾在MIT的信息论研究生班学习。Robert Fano教授让学生们自己决定是参加期未考试还是做一个大作业。而哈夫曼选择了后者,原因很简单,因为解决一个大作业可能比期未考试更容易通过。Robert Fano教授也是信息论的先驱,学过信息论的都知道有Fano不原创 2020-05-10 15:20:52 · 19864 阅读 · 0 评论 -
【算法导论】求二叉树的叶子数和深度
二叉树的叶子数和深度二叉树的遍历算法是许多二叉树运算的算法设计的基础,因此遍历算法的应用很广泛。下面以遍历算法求二叉树的叶子数和深度为例,来加深对于二叉树遍历算法的理解。1. 统计二叉树中的叶子结点数因为叶子结点是二叉树中那些左孩子和右孩子均不存在的结点,所以可在二叉树的遍历过程中,对这种特殊结点进行计数,来完成对叶子结点数的统计。这个统计可在任何一种遍历方式下给出,下面是利用中序遍历原创 2013-08-06 15:31:48 · 5092 阅读 · 1 评论 -
【算法导论】二叉树的广度优先遍历
二叉树的广度优先遍历广度优先遍历:又称按层次遍历,也就是先遍历二叉树的第一层节点,然后遍历第二层节点……最后遍历最下层节点。而对每一层的遍历是按照从左至右的方式进行的。基本思想:按照广度优先遍历的方式,上一层中先被访问的节点,它的下层孩子也必然先被访问,因此在算法实现时,需要使用一个队列。在遍历进行之前先把二叉树的根结点的存储地址入队,然后依次从队列中出队结点的存储地址,每出队一个结点的存原创 2013-08-06 15:01:50 · 2013 阅读 · 0 评论 -
【算法导论】二叉树的深度优先遍历
二叉树的深度优先遍历二叉树的遍历可以分为深度优先遍历和广度优先遍历。本篇介绍深度优先遍历,下一篇介绍广度优先遍历。 根据二叉树的递归定义可知,二叉树是由根结点(D)、左子树(L)和右子树(R)三个基本部分组成。只要能依次遍历这三个基本部分,便可遍历整个二叉树。这三个部分的排列组合为3!=6种,若限定按照先左后右进行遍历,则只有三种遍历方式:DLR(先序)、LDR(中序)、LRD(后序)。原创 2013-08-06 10:22:39 · 1509 阅读 · 0 评论 -
【算法导论】二叉树的建立
二叉树的建立基本概念: 有序树与无序树:若将树中的每个节点的各个子树都看成是从左到右有次序的,则称该树为有序树,否则为无序数。 顺序存储:从根节点起,自上而下,从左至右的方式对节点进行顺序编号,编号即对应为要存储的数组的下标。于是节点与数组元素就一一对应了。 满二叉树、完全二叉树、非完全二叉树的区别:原创 2013-08-06 09:58:13 · 3364 阅读 · 0 评论 -
【算法导论】排序算法总结
排序算法总结从六月初开始看算法导论,陆陆续续看了有2个月了,但实际看的时间只有半个月左右。这期间都忙着找导师、期末考试,同时还回家修养了十来天。真正专心的看算法是在离家返校后,由于没有考试和作业的烦恼,天天都沉浸在算法中,感觉效率较高。这段时间学到的东西较多,下面来总结一下:学到的排序算法可以分为两类:比较排序、非比较排序。(这些排序算法的详细介绍及c程序实现在本文末都给出了链接,欢迎参考原创 2013-08-02 12:15:58 · 2447 阅读 · 2 评论 -
【算法导论】桶排序
桶排序时间复杂度为:O(n)基本思想:将要排列的序列分成n组,每组分别进行排序,然后在合并到一起,这里面有分而治之的思想。实例说明:大家学c语言肯定学过switch-case结构,最常见的题型就是对成绩进行分类,但是这里我们是对其进行排名。假设有十个学生的成绩如下:78,17,39,26,72,94,21,12,23,68。我们可以把成绩先进行分段(称为桶),每十分分为一段,共分为10段。原创 2013-08-02 10:15:54 · 2570 阅读 · 0 评论 -
【算法导论】选择排序法
选择排序法选择排序其实是冒泡法的一种改进,其基本思路也是:先确定最小元素,再找次最小元素,最后确定最大元素。 它与冒泡排序的最大区别在于:冒泡排序是只要碰见比它大的元素就交换,而选择排序是直接将元素放在最终的确定位置,从而避免了多次交换过程。 举例说明:数组a[5]={3,4,2,5,1}.通过一轮比较知1应当放在数组a[0]上。所以我们可以直接将a[0]与a[4]进行交换,从原创 2013-08-01 21:15:37 · 1880 阅读 · 0 评论 -
【算法导论】冒泡排序法
冒泡排序法时间复杂度:O(n*n)基本思想:从数组最后一个元素开始,依次与前一个元素比较,若比前一个元素小,则与之交换位置,然后再与当前前一个元素比较,直到遇到比它大的元素为止。例如:假设数组为:a[5]={3,4,2,5,1};则运算过程为:首先1与5比较,由于1342513421534125原创 2013-08-01 21:00:43 · 2298 阅读 · 2 评论 -
【算法导论】基数排序
基数排序时间复杂度:O(n).基本思路:两个数比较大小,我们的直观感觉是先比较高位,若相同则比较低位。但是这样做需要记录额外的数据,浪费空间。而基数排序则是先比较低位,再比较高位。通过各个位的比较进行排序,如果数组元素最大有N位,则总共需要N次排序。注意:按位排序必须是稳定排序,所以在这我选择了计数排序。具体操作见下图:具体实现如下:#include#includ原创 2013-07-31 17:05:58 · 1772 阅读 · 0 评论 -
【算法导论】第i小的元素
第i小的元素 时间复杂度:n. 基本思想:和快速排序的思想相似,也是对数组进行递归划分,但是有所差别的是,快速排序会递归处理划分的两边,而随机化的选择算法只选择一边。 具体步骤为:首先,随机选择一个数组元素作为主元,从而将数组分解为两个子数组,并得到主元在元素中的位置q,假设较小子数组元素的个数为k-1;然后比较i与k的大小,来确定下一次递归选择哪一边原创 2013-07-31 15:46:31 · 1582 阅读 · 0 评论 -
【算法导论】最大值和最小值
最大最小值时间复杂度:3*floor(n/2)基本思想:成对地处理元素。先将一对输入元素相互比较,然后把较小的与当前最小值比较,较大的与当前最大值比较,因此每两个元素比较三次。注意分情况:当n为奇数时,将最大值和最小值都设置为第一个元素值;当n为偶数时,将前两个元素较大的元素设置为最大值,较小的设置为最小值。其具体实现如下:原创 2013-07-31 12:15:59 · 2370 阅读 · 0 评论