随笔分类 -  算法与数据结构

摘要:前面做了栈的基本操作总感觉需要做一个实际的例子来检验一下。这里我将用栈来做一个简单的四则运算。目标比较简单:做一个带小括号(“()”)的四则运算,如果要加入到中括号(“[]”)或者大括号(“{}”),依次类推。求一个表达式:用下面这个算是做例子,程序最后应该可以算出任何带小括号的运算。3+(32-6... 阅读全文
posted @ 2014-08-05 18:43 sjdang 阅读(1397) 评论(0) 推荐(0)
摘要:AVL:本章参考了严蔚敏的《数据结构》,程杰《大话数据结构》 上一章的排序二叉树对于我们寻找无序序列中的元素的效率有了大大的提高。查找的最差情况是树的高度。这里就有问题了,将无序数列转化为二叉排序树的时候,树的结构是非常依赖无序序列的顺序,这样会出现极端的情况。【如图1】: 这样的一颗二叉排序树就是一颗比较极端的情况。我们在查找时候,效率依赖树的高度,所以不希望这样极端情况出现,而是希望元素比较均匀的分布在根节点两端。问题提出: 能不能有一种方法,使得我们的二叉排序树不依赖无序序列的顺序,也能使得我们得到的二叉排序树是比较均匀的分布。引入: 平衡二叉树(Self-Balancing B... 阅读全文
posted @ 2013-12-17 13:58 sjdang 阅读(781) 评论(0) 推荐(0)
摘要:二叉排序树 也称为 二叉查找数。它具有以下性质:若它的左子树不空,则左子树上所有结点的值均小于它的根结点的值。若它的右子树不空,则右子树上所有结点的值均大于它的根结点的值。它的左、右子树也分别为二叉排序树。 之前的查找折半查找、斐波那契查找、插值查找的前提条件就是序列为有序,为顺序存储结构。我们在查找一章提过,查找还有动态查找,比如插入和删除操作,进行这些操作对顺序存储结构效率不那么高。能不能有一种既静态查找效率高,动态查找效率也高呢? 联想之前的堆排序,人们创造出一个堆这样的结构来提高排序效率。(佩服他们的思维)堆结构建立在二叉树上,之前一直都不知道二叉树是怎么用的,看到这里二叉树的作用.. 阅读全文
posted @ 2013-12-12 15:50 sjdang 阅读(1048) 评论(1) 推荐(1)
摘要:以前有个游戏,一方写一个数字,另一方猜这个数字。比如0-100内一个数字,看谁猜中用的次数少。这个里面用折半思想猜会大大减少次数。步骤:(加入数字为9)1.因为数字的范围是0-100,所以第一次猜50(100的一半)2.缩小范围到0-50,根据对方回应数大了,再猜25(50的一半)3.缩小范围到0-25,对方回应数大了,再猜134.缩小范围到0-13,对方回应数大了,再猜75.缩小范围到7-13,对方回应数小了,再猜106.缩小范围到7-10,对方回应数大了,再猜9,中真是比较差的情况,最差的情况这样逐次缩小到最后一个数,应该是需要猜7次。这就是折半查找思想,非常的简单,但是有个前提,所要查找 阅读全文
posted @ 2013-12-10 10:23 sjdang 阅读(755) 评论(0) 推荐(0)
摘要:查找:操作有(1).查询某个“特定的”数据元素是否在查找表中; (2).检索某个“特定的”数据元素的各种属性; (3).在查找表中插入一个元素 (4).删除某一个元素若只完成前两个操作,称为“静态查找表”。若在查找过程中同时插入查找表中不存在的数据元素,或者从查找表中删除已经存在的某个数据元素,则称为“动态查找表”查找操作性能:查找中一般将以其关键字与给定值比较的个数的平均值作为衡量算法好坏的依据。平均查找长度:为了确定在查找表中的位置,需和给定值进行比较的关键字个数的期望值。 阅读全文
posted @ 2013-12-10 10:08 sjdang 阅读(167) 评论(0) 推荐(0)
摘要:快速排序快速排序由图灵奖获得者Tony Hoare26岁设计出来,这个大牛有兴趣的可以google下。前面讲过 直接插入排序、简单选择排序、冒泡排序 这几个我们能够最直接想出来的排序方法。(时间复杂度都是 O(N2))后来人们一直寻找能够打破时间复杂度O(N2)的限制。先后有 希尔排序,它是直接插入排序的升级。(每趟插入的步长从大到小)堆排序,它是简单选择排序的升级。(应用堆这个结构来存储数据的大小关系)而快速排序则是冒泡排序的升级。(冒泡排序是比较两个相邻的数大小,交换)快速排序:基本思想是:通过一趟排序将要排序的数据分割成独立的两部分,其中一部分的所有数据都比另外一部分的所有数据都要小,然 阅读全文
posted @ 2013-12-09 18:05 sjdang 阅读(1116) 评论(0) 推荐(0)
摘要:归并排序 利用了完全二叉树的堆排序在效率上提高了不少。但是堆排序主要耗费时间在调整堆上,算法效率也不够稳定。对于二叉树的应用,还有没有其他方法能够保持算法的效率,也能够使其是一个稳定的算法。(堆排序不够稳定)具体效率可以查看《算法导论》、《数据结构与算法》(严蔚敏) 想想二叉树的结构,如果我们比较两个数,我们想想将两个树作为叶子,比较结果存放在根中。如果是四个数呢?四个数分别为四个叶子,通过两两比较形成一个小集合,然后小集合再比较最后形成最终的结果。这就是归并的思想。开始不理解为什么叫归并,后来看到有人写过:先递归分解,再合并成数组归并算法用了 分治法(Divide and Conquer.. 阅读全文
posted @ 2013-12-07 11:40 sjdang 阅读(351) 评论(0) 推荐(0)
摘要:堆排序问题提出: 前面写过 简单选择排序 讲过,要找出n个数据中最小的值,那么需要比较n-1次。仔细想想,比较第一趟的时候,第一个哨兵下标元素与每一个元素比较,如果哨兵元素不是最小的,那么会发生交换,记交换后的元素下标为swap。继续比较第二趟 到 第n趟时候,每一趟都会有元素与swap下标元素比较,但是这个比较之前就已经比较了,只是没有保存下来。能不能通过方法能够记录这些比较,使其重复比较的次数减少? 堆排序就是对简单选择排序的一种改进,通过一种数据结构来保存比较之后的元素关系,在大量数据比较时候,效率非常高。 堆具有的性质:n个元素序列{k1,k2,k3,...,kn}满足如下关系:... 阅读全文
posted @ 2013-12-06 15:10 sjdang 阅读(722) 评论(0) 推荐(0)
摘要:希尔排序: 直接插入排序在在本身数量比较少的时候情况下效率很高,如果待排数的数量很多,其效率不是很理想。 回想一下直接插入排序过程,排序过程中,我们可以设置一条线,左边是排好序的,右边则是一个一个等待排序,如果最小的那个值在最右边,那么排这个最小值的时候,需要将所有元素向右边移动一位。 是否能够减少这样的移位呢? 我们不希望它是一步一步的移动,而是大步大步的移动。希尔排序就被发明出来了,它也是当时打破效率O(n2)的算法之一。希尔排序算法通过设置一个间隔,对同样间隔的数的集合进行插入排序,此数集合中的元素移位的长度是以间隔的长度为准,这样就实现了大步位移。但是最后需要对元素集合进行一次... 阅读全文
posted @ 2013-12-05 15:26 sjdang 阅读(35649) 评论(1) 推荐(0)
摘要:插入排序:在《算法导论》中是这样描述的这是一个对少量元素进行排序的有效算法。插入排序的工作机理与打牌时候,整理手中的牌做法差不多。在开始摸牌时,我们的左手是空的,牌面朝下放在桌子上。接着,一次从桌子上摸起一张牌,并将它插入到左手一把牌中的正确位子上。为了找到这个正确的位置,要将它与手中已有的每一张牌从右到左进行比较,无论什么时候,左手的牌都是排好序的。算法思想:将一个记录插入到已经排好序的有序表中,从而得到一个新的,记录数加1的有序表。图解:每一张图都是一个for循环。红色和绿色的表示 左手的牌(排好序的数组)。以此类推。。。代码: 1 void insertionSort(myDataTyp 阅读全文
posted @ 2013-12-04 17:20 sjdang 阅读(479) 评论(0) 推荐(0)
摘要:之前在冒泡排序的附录中提到可以在每次循环时候,不用交换操作,而只需要记录最小值下标,每次循环后交换哨兵与最小值下标的书,这样可以减少交换操作的时间。这种方法针对冒泡排序中需要频繁交换数组数字而改进。以此类推。。。代码: 1 void selectionSort(myDataType *ary,int len) 2 { 3 int i,j; 4 int mymin; //记录最小值下标 5 for (i=0;i ary[j])11 {12 mymin = j;13 14 ... 阅读全文
posted @ 2013-12-04 16:20 sjdang 阅读(285) 评论(0) 推荐(0)
摘要:冒泡排序应该是最常用的排序方法,我接触的第一个排序算法就是冒泡,老师也经常那这个做例子。冒泡排序是一种交换排序,基本思想:通过两两比较相邻的记录,若反序则交换,知道没有反序的记录为止。例子:依次类推。这里可以看出,每次比较从最后一个开始,向前比较,若反序则交换;每次都保证了是两两相邻的记录比较。冒泡排序的代码: 1 void bubble_sort (myDataType *ary,int len) 2 { 3 int i,j; 4 for (i=0;i=i;j--) 7 { 8 if (ary[j] > ary[j+1]) 9 ... 阅读全文
posted @ 2013-12-04 16:04 sjdang 阅读(477) 评论(0) 推荐(0)
摘要:排序是非常基本的一个操作。排序也分许多方法,可能会有人想,为什么不用最一种最快最好的方法而非要搞出那么多方法呢?因为各种方法有各种方法的用处,适用于不同的情况。排序分:内排序 和 外排序内排序:在排序整个过程中,所有的欲排序记录都存放在内存中。外排序:欲排序的个数多,不能同时放置内存,整个排序过程需要在内外存之间多次交换。内排序:在排序过程中,所有元素调到内存中进行的排序,称为内排序。内排序是排序的基础。内排序效率用比较次数来衡量。按所用策略不同,内排序又可分为插入排序、选择排序、交换排序、归并排序及基数排序等几大类。外排序:在数据量大的情况下,只能分块排序,但块与块间不能保证有序。外排序用读 阅读全文
posted @ 2013-12-04 14:40 sjdang 阅读(215) 评论(0) 推荐(0)
摘要:之前我们介绍过,在一个工程中我们关心两个问题:(1)工程是否顺利进行(2)整个工程最短时间。之前我们优先关心的是顶点(AOV),同样我们也可以优先关心边(同理有AOE)。(Activity On Edge Network)看看百度百科上解释:AOE网:Activity on edge network若在带权的有向图中,以顶点表示事件,以有向边表示活动,边上的权值表示活动的开销(如该活动持续的时间),则此带权的有向图称为AOE网。 如果用AOE网来表示一项工程,那么,仅仅考虑各个子工程之间的优先关系还不够,更多的是关心整个工程完成的最短时间是多少;哪些活动的延期将会影响整个工程的进度,而加速这些 阅读全文
posted @ 2013-12-02 17:29 sjdang 阅读(36984) 评论(1) 推荐(9)
摘要:这一篇写有向无环图及其它的应用:清楚概念:有向无环图(DAG):一个无环的有向图。通俗的讲就是从一个点沿着有向边出发,无论怎么遍历都不会回到出发点上。有向无环图是描述一项工程或者系统的进行过程的有效工具,比如办公室,到工商局里面注册的时候,他会提示你一个流程,这个流程就是一个有向无环图。第一步不做,第二步就做不了。在其期间关心两个问题:1.工程是否顺利?(拓扑排序)2.估算整个工程所必须的最短时间。(关键路径)拓扑排序:数学语言:某个集合上的一个偏序得到该集合上的一个全序的操作过程。(迷糊中。。。看下离散数学。。。)百度百科:拓扑序列通常,这样的线性序列称为满足拓扑次序(Topological 阅读全文
posted @ 2013-11-25 12:18 sjdang 阅读(2496) 评论(0) 推荐(0)
摘要:floyd算法:解决任意两点间的最短路径的一种算法,可以正确处理有向图或负权的最短路径问题,同时也被用于计算有向图的传递闭包。设为从到的只以集合中的节点为中间节点的最短路径的长度。若最短路径经过点k,则;若最短路径不经过点k,则。因此,。在实际算法中,为了节约空间,可以直接在原来空间上进行迭代,这样空间可降至二维。我的理解为:folyd算法是每次选定一个点,查看任意两个顶点的距离是否都小于经过这个点之和的距离。即:假如ABC三个顶点相连,选定C的时候,查AB的距离是否大于 AC + CB 的距离之和,如果大于说明找到了一个更短的路径,即A->C->B。下面是我的例子:floyd算法 阅读全文
posted @ 2013-11-18 19:08 sjdang 阅读(492) 评论(0) 推荐(0)
摘要:在网图中,最短路径的概论:两顶点之间经过的边上权值之和最少的路径,并且我们称路径上的第一个顶点是源点,最后一个顶点是终点。维基百科上面的解释:这个算法是通过为每个顶点v保留目前为止所找到的从s到v的最短路径来工作的。初始时,原点 s 的路径长度值被赋为 0 (d[s]= 0),若存在能直接到达的边(s,m),则把d[m]设为w(s,m),同时把所有其他(s不能直接到达的)顶点的路径长度设为无穷大,即表示我们不知道任何通向这些顶点的路径(对于V中所有顶点v除s和上述m外d[v]= ∞)。当算法退出时,d[v]中存储的便是从s到v的最短路径,或者如果路径不存在的话是无穷大。Dijkstra 算法的 阅读全文
posted @ 2013-11-17 14:22 sjdang 阅读(790) 评论(0) 推荐(0)
摘要:之前的Prim算法是基于顶点查找的算法,而Kruskal则是从边入手。通俗的讲:就是希望通过 边的权值大小 来寻找最小生成树。(所有的边称为边集合,最小生成树形成的过程中的顶点集合称为W) 选取边集合中权值最小的边,查看边的两个顶点是否能和集合W构成环路,若能构成环路,则舍去;否则选取下一条最小权值边重复上一步。 这里需要注意一个问题,我们从最小权值的边开始寻找最小生成树, 判断当即将选入的边的两个顶点是否会和已经在集合中的顶点构成环路,这个是我们需要解决的问题。先说下Kruskal算法的数学语言:假设连通网N={V,{E}},则令最小生成树的初始状态只有n个顶点而无边的非连... 阅读全文
posted @ 2013-11-14 21:31 sjdang 阅读(646) 评论(0) 推荐(0)
摘要:一个连通图的生成树是一个极小的连通子图,它包含图中全部的顶点(n个顶点),但只有n-1条边。最小生成树:构造连通网的最小代价(最小权值)生成树。prim算法在严蔚敏树上有解释,但是都是数学语言,很深奥。最小生成树MST性质:假设N=(V,{E})是一个连通网,U是顶点集V的一个非空子集。若(u,v)是一条具有最小权值(代价)的边,其中u∈U,v∈V-U,则必存在一颗包含边(u,v)的最小生成树。prim算法过程为:假设N=(V,{E})是连通图,TE是N上最小生成树中边的集合。算法从U={u0}(u0∈V),TE={}开始,重复执行下述操作:在所有u∈U,v∈V-U的边(u,v)∈E中找一条代 阅读全文
posted @ 2013-11-14 00:20 sjdang 阅读(2001) 评论(0) 推荐(0)
摘要:图:目录:1.概念2.邻接矩阵(结构,深度/广度优先遍历)3.邻接表(结构,深度/广度优先遍历)图的基本概念:数据元素:顶点1.有穷非空(必须有顶点)2.顶点之间为边(可空)无向图:边没有方向,用(vi,vj)表示,(vj,vi)也可。有向图:边有方向,称为弧,用表示。vi尾,vj头简单图:不存在顶... 阅读全文
posted @ 2013-11-12 17:11 sjdang 阅读(866) 评论(0) 推荐(0)