数据结构与算法
文章平均质量分 90
苏叔叔
Isolation is not good for me!
展开
-
二分检索
二分检索二分检索(Binary Search)也叫二分查找,是应用于有序表上的一种检索方法。二分检索的思想是:由于序列已经有序,故不需要顺序遍历,每次只需和序列中间位置的元素进行比较即可,以此确定下次查找的位置。显然每次都可以排除一半的元素,很高效。原创 2014-07-13 15:20:32 · 3574 阅读 · 0 评论 -
数据结构:外排序-多路归并
外排序 外排序问题的出现,主要是因为内存不够。当需要排序的数据量过多,以至于无法一次性把所有的数据都放入内存,这导致了外排序问题的出现。解决大数据量排序的方法是:先分块排序,后进行块合并。外排序步骤把原数据分成几段读入内存,以至于每一块都可以完整的在内存中进行排序,排序好后,写入外部存储设备。归并已排序好的数据块。这就是归并排序在外排序中的应用。 对每块数据进行排序,可以使用各种内排序方法:快速排序、归并排序、堆排序等。这个比较简单,下面模拟一个对排序好的数据块进行归并的过程。原创 2014-08-23 17:56:24 · 3774 阅读 · 1 评论 -
选择排序:简单选择、树形选择
选择排序(Selection Sort):经过一趟排序,可以从n-i+1(i=1,2...)个记录中选取关键字最小的记录作为有序序列中第i个记录。也就是说,每一趟排序,都会排好一个元素的最终位置。其中最简单的是简单选择排序(Simple Selection Sort)简单选择排序的思想是 在每一趟排序中,通过n-i次关键字的比较,从n-i+1个记录中选出关键字最小的记录,并和第i个记录原创 2014-06-10 17:21:33 · 7189 阅读 · 2 评论 -
数据结构:最小生成树--Kruskal算法
Kruskal算法 求解最小生成树的另一种常见算法是Kruskal算法,它比Prim算法更直观。从直观上看,Kruskal算法的做法是:每次都从剩余边中选取权值最小的,当然,这条边不能使已有的边产生回路。手动求解会发现Kruskal算法异常简单,下面是一个例子算法说明 为了判断环的出现,我们换个角度来理解Kruskal算法的做法:初始时,把图中的n个顶点看成是独立的n个连通分量,从树的角度看,也是n个根节点。我们选边的标准是这样的:若边上的两个顶点从属于两个不同的连通分量,则此边可取原创 2014-08-07 11:45:37 · 10032 阅读 · 1 评论 -
插入排序:表插入
所谓插入排序之表排序,是利用静态链表的形式,分两步完成排序。一,对一个有序的循环链表,插入一新的元素,修改每个节点的后继指针的指向,使顺着这个指针的指向,元素是有序的。在这个过程中,我们不移动或交换元素,只是修改指针的指向。二,顺着指针的指向调整元素的位置,使其在链表中真正做到物理有序。思路:构建一新的结构体类型,使其封装了值域和指针域。并增加一节点,当做头节点,为循环终止原创 2014-06-02 20:44:44 · 3960 阅读 · 1 评论 -
二叉树前序、中序、后序遍历非递归写法的透彻解析
前言在前两篇文章二叉树和二叉搜索树中已经涉及到了二叉树的三种遍历。递归写法,只要理解思想,几行代码。可是非递归写法却很不容易。这里特地总结下,透彻解析它们的非递归写法。其中,中序遍历的非递归写法最简单,后序遍历最难。我们的讨论基础是这样的:原创 2014-07-06 22:14:43 · 131251 阅读 · 47 评论 -
交换排序:冒泡排序
交换排序:两两比较待排序记录的关键码,若是逆置,则交换,直到无逆置。其中最简单的交换排序是:冒泡排序。冒泡排序(Bubble Sort,也叫起泡排序):不断地比较相邻的记录,若是不满足排序要求,则交换。交换时,可从前向后,也可从后向前。看一个从前向后的排序过程:原创 2014-06-12 18:24:08 · 1934 阅读 · 0 评论 -
基数排序
前言当序列中元素范围比较大时,就不适合使用计数排序。针对这种情况,就有了基数排序,这是一种按位排序。它仍然是以计数排序为基础。基数排序基数排序的基数:十进制数的基数自然是10,二进制的基数自然是2。通常有两种按位排序策略:1.高位优先法(most significant digit first,MSD):简单讲就是从高位排起。2.低位优先法(least significant digit first,LSD):它与高位优先相反,从低位排起。从排序效果上看,高位优先比较直观,但却涉及到递归的过程,故原创 2014-07-10 21:39:29 · 3416 阅读 · 0 评论 -
链表的应用:单元多项式的加法、减法、乘法
使用链表来实现单元多项式的加法、减法、乘法。一个单元多项式的节点结构无非是这样的:系数域、指数域、链域。我们使用链表来模拟单元多项式的常见运算。其中,加法是其它运算的基础,减法:poly1-poly2=poly1+(-poly2),乘法:poly1*poly2,可用poly1乘以poly2的每一项,相加其乘积结果。原创 2014-06-17 10:42:11 · 7487 阅读 · 7 评论 -
堆
堆的概述堆作为一种树形结构,也是二叉树的一种应用。二叉搜索树是规定了节点之间的大小关系:左孩子<根节点<右孩子。而堆中规定的节点之间的次序是:根节点<左孩子,根节点<右孩子;根节点>左孩子,根节点>右孩子。前者我们称之为小顶堆,后者是大顶堆。不同的逻辑定义,会得到不同的性质。关于堆的一些性质描述,我们在选择排序:堆排序中已详细介绍过。堆的存储结构堆是一种特殊的完全二叉树。通常所说的堆,就是指二叉堆。特殊是指它的节点大小次序是有规定的,但其本质还是一棵完全二叉树。而完全二叉树最常用的是顺序存储结构。原创 2014-07-08 14:02:11 · 2224 阅读 · 0 评论 -
插入排序:表折半插入
在前一篇插入排序:表插入中,我们用静态链表的存储方式,直接插入的策略,构建了一种新的插入排序算法:表插入。有人可能会想到:同样是静态链表的形式,为什么不使用更高效的折半插入的策略呢?这种想法真的很好,如果做到了,显然是极大的优化。 我在网上还真看到了相关的内容,大家可看下《表插入方法的改进》,里面有此想法的介绍。这篇博客就是介绍表插入的另一种实现:表折半插入。看完一定让你彻底理解它。原创 2014-06-05 17:26:57 · 2215 阅读 · 0 评论 -
二分查找的改进--差值查找
差值查找 在二分查找中,我们每次比较都可以排除一半的数据量,这个已经是很高效了。如果利用关键字本身的信息,每次排除的数据量充分依赖于关键字的大小,则查找会更高效,这就是差值查找的思想。下面通过示例代码,比较二分查找和差值查找的不同,在不同中领略差值查找的改良之处。原创 2014-09-21 00:31:09 · 4380 阅读 · 8 评论 -
线性检索:顺序检索
当我们对所检索序列中元素的分布一无所知或元素本身就是随机分布的时候,顺序检索是常用的方法。 常用的返回值策略是,若用数组array,从下标0开始存储元素,检索成功则返回相应下标,失败则返回-1。另一种返回策略是:若从下标1开始存储元素,0号位置作为sentinel(哨兵),返回0则表示检索失败。使用这种返回策略会减少循环条件的判断,提高效率。直接看代码原创 2014-08-15 20:32:31 · 3696 阅读 · 1 评论 -
集合的检索:位图法
位图法是一种逻辑上很巧妙的描述集合的方法。如集合S={2,4,1,5,12},它用位图描述就是 0110 1100 0000 1000,两个字节即可描述S,左边是低阶位。用bitset<16>存储的话就是{[15]、[14]、...[1]、[0]}={0001000000110110}。用位图对集合进行描述后,就很方便进行集合的运算,如交、并和差。原创 2014-08-15 19:53:30 · 2663 阅读 · 1 评论 -
选择排序:堆排序
堆排序(Heap Sort):使用堆这种数据结构来实现排序。先看下堆的定义:最小堆(Min-Heap)是关键码序列{k0,k1,…,kn-1},它具有如下特性:ki<=k2i+1,ki<=k2i+2(i=0,1,…)简单讲:孩子的关键码值大于双亲的。同理可得,最大堆(Max-Heap)的定义:ki>=k2i+1,ki>=k2i+2(i=0,1,…)简单讲:孩子的关键码值大于双亲的。同理可得,最大堆(Max-Heap)的定义:ki>=k2i+1,ki>=k2i+2(i=0,1,…)同样的:对于最大堆,双亲的关原创 2014-06-11 20:56:42 · 2640 阅读 · 0 评论 -
哈夫曼树
哈夫曼树给定n个权值作为n个叶子结点,构造一棵二叉树,若带权路径长度达到最小,称这样的二叉树为最优二叉树,也称为哈夫曼树(Huffman tree)。哈夫曼树是带权路径长度最短的树,权值较大的结点离根较近。节点的带权长度是这样定义的:节点的权值*根节点到该节点的路径长度。树的带权路径长度(Weighted Path Length of Tree,简记为WPL)则是指所有节点的带权长度和。哈夫曼树就是使WPL最小的一种树,并且哈夫曼树是满二叉树。它的构造方法是哈夫曼方法。哈夫曼树是这样构造的:原创 2014-07-12 00:03:35 · 4548 阅读 · 7 评论 -
前缀、中缀、后缀表达式
前缀、中缀、后缀表达式1.定义所谓的前、中、后,是指表达式中运算符相对于运算对象的位置。中缀运算符位于运算对象中间,即是中缀表达式。如(1+2)*3-4最普遍的、最易被人脑理解的是中缀表达式。前缀运算符位于运算对象之前,即是前缀表达式。如-*+1234后缀运算符位于运算对象之后,即是后缀表达式。如12+3*4-2.总结前缀、后缀不易被人脑理解,但易于被计算机解析。只有对中缀表达式进行合理的转换,才可得到相应的前、后缀表达式。原创 2015-06-23 16:13:09 · 3443 阅读 · 0 评论 -
数据结构与算法目录
数据结构与算法系列先看这里,有助于你更好地获取内容。首先明白一个问题:为什么要研究数据结构? 这是因为所有的程序本质上是对数据进行处理,如何高效的处理数据,这依赖于数据本身的结构(如类型(整型、浮点型等)、维数、是否为复杂类型(结构体类型、类类型)等)以及数据之间的逻辑关系(线性、非线性等)。我们所学的数据结构这门课程就是研究这些内容的,只有弄清楚了这些,我们才可以用高效的算法与之结合,产生高效率的程序。掌握好数据结构的内容也是一个程序员的基本功,特别对于c/c++程序员。原创 2014-05-12 13:48:23 · 15386 阅读 · 2 评论 -
归并排序:二路归并
归并排序(Merge Sort)是将两个(或两个以上)有序表合并成一个新的有序表,即把待排序序列分为若干个有序的子序列,再把有序的子序列合并为整体有序序列。归并排序的具体做法:把原序列不断地递归等分,直至每等份只有一个元素,此时每等份都是有序的。相邻等份合并,不断合并,直至合并完全。二路归并归并排序是建立在归并操作上的一种有效的排序算法。该算法是采用分治法(Divide and Conquer)的一个非常典型的应用。归并排序最常用的是二路归并,即把两个小的有序的序列和并成一个大的有序序列:合二为一原创 2014-06-26 17:40:33 · 9744 阅读 · 0 评论 -
交换排序:快速排序
快速排序(Quick Sort)也是一种交换排序,它在排序中采取了分治策略。快速排序的主要思想是:从待排序列中选取一元素作为轴值(也叫主元)。将序列中的剩余元素以该轴值为基准,分为左右两部分。左部分元素不大于轴值,右部分元素不小于轴值。轴值最终位于两部分的分割处。对左右两部分重复进行这样的分割,直至无可分割。原创 2014-06-14 13:47:47 · 4614 阅读 · 0 评论 -
插入排序:二路插入
在上一篇博客中:插入排序:直接插入、交换插入、折半插入。提到了三种插入排序的具体实现。不过仍有改进的地方。例如序列 2 1 3,当把1往前插入时,由于1<2,则应当把1插入到2的前面。在上述三种插入排序方法的实现中,都是把1、2位置交换。于是,我们想有没有可能不进行交换,因为交换总是相当耗时的。但是1必须要排到2的前面,可2的前面没有位置了啊?嗯,初看是这样的。试想这是一个循环的数组呢?这就是二路插入最核心的想法。原创 2014-06-01 15:47:26 · 6733 阅读 · 6 评论 -
栈的实现:顺序栈
栈(stack)是一种很常见的线性结构。它是只允许在一端进行插入和删除操作的线性表,这一端我们称为栈顶。栈的特点常被称为:先进后出(filo-first int last out),或者是后进先出(lifo-last in first out)。这个描述从它的操作特点可以看出,只许在一端进行插入,那么显然,先进的肯定后出。栈的应用,比如系统应用栈来实现递归,图的深度遍历使用了栈,递归要用到栈……。说到它的实现就有两种形式:顺序栈、链栈。其中以顺序栈最为常见。栈的常见操作:原创 2014-05-24 12:17:24 · 6864 阅读 · 1 评论 -
约瑟夫问题的数组解法
约瑟夫问题的数组、动态链、静态链解法。原创 2014-05-05 17:55:59 · 4941 阅读 · 5 评论 -
串的匹配:朴素匹配&KMP算法
引言字符串的模式匹配是一种常用的操作。模式匹配(pattern matching),简单讲就是在文本(text,或者说母串str)中寻找一给定的模式(pattern)。通常文本都很大,而模式则比较短小。典型的例子如文本编辑和DNA分析。在进行文本编辑时,文本通常是一段话或一篇文章,而模式则常常是一个单词。若是对某个指定单词进行替换操作,则要在整篇文章中进行匹配,效率要求肯定是很高的。模式匹配的朴素算法最简单也最容易想到的是朴素匹配。何为朴素匹配,简单讲就是把模式串跟母串从左向右或从右向左一点一点比较:原创 2014-07-23 22:30:13 · 4386 阅读 · 1 评论 -
插入排序:希尔排序
我们知道当一个序列基本有序时,直接插入会变得很高效。因为此时只需少量的移动元素,操作集中在元素的比较上。基于这种想法,我们就试图把一个序列在进行直接插入前调整得尽量有序。这就是希尔排序(Shell Sort)的核心思路。(Shell只是算法发明者的名字,无特殊含义)那到底该怎么做呢? 希尔排序一反以前的做法,插入为何只在相邻的元素之间进行,不相邻的同样可以进行。于是,希尔排序也被形象原创 2014-06-07 21:15:28 · 1970 阅读 · 1 评论 -
队列的应用:优先队列
优先级队列:如果我们给每个元素都分配一个数字来标记其优先级,不妨设较小的数字具有较高的优先级,这样我们就可以在一个集合中访问优先级最高的元素并对其进行查找和删除操作了。这样,我们就引入了优先级队列 这种数据结构。 优先级队列(priority queue) 是0个或多个元素的集合,每个元素都有一个优先权,对优先级队列执行的操作有(1)查找(2)插入一个新元素 (3)删除 一般情况下,查找操原创 2014-06-12 11:26:17 · 3536 阅读 · 0 评论 -
链表常见操作:环、倒数第k个、是否相交
链表常见操作:判断是否有环链表中很常见的一问题是,是否有环?如下图:怎么办呢?正常链表的尾节点的链域是NULL,有环就不存在NULL了!对了,用一指针轮询,不断地 p=p->next; 若是看到了p为NULL,则表明无环!否则,就是有环。这个想法挺好,但是有环,会进入死循环的。有人说,那就设置一时间点,过了时间还没结束,就是有环。我想说,那万一链表真的很长呢,时间点设置多少才够了?……办法是有的:使用两指针,一快一慢,都从头开始轮询,若有环,则慢的肯定可以被快的反超,因为此时大家都像是在围绕着环形跑原创 2014-05-24 17:27:37 · 2100 阅读 · 1 评论 -
插入排序:直接插入、交换插入、折半插入
插入排序:把一个数插入到一个有序的序列中,并要求插入后此数据序列仍然有序。这种排序思想就是插入排序。 那么对于一个原始无序的序列,哪里找有序的部分呢?这个很简单,可以把序列分为两个部分,第一个元素是第一部分,其余元素是第二部分。第一个部分只有一个元素,当然是有序的!对于如何把其余元素插入到第一部分中去,按插入策略,可分为如下几种插入方法:原创 2014-05-28 21:13:38 · 17229 阅读 · 2 评论 -
数据结构:点对之间最短距离--Floyd算法
Floyd算法 Dijkstra算法是用于解决单源最短路径问题的,Floyd算法则是解决点对之间最短路径问题的。Floyd算法的设计策略是动态规划,而Dijkstra采取的是贪心策略。当然,贪心算法就是动态规划的特例。算法思想 点对之间的最短路径只会有两种情况:两点之间有边相连,weight(Vi,Vj)即是最小的。通过另一点:中介点,两点相连,使weight(Vi,Vv)+weight(Vv,Vj)最小。Min_Distance(Vi,Vj)=min{weight(Vi,Vj)原创 2014-08-04 13:06:24 · 4835 阅读 · 0 评论 -
数据结构:单源最短路径--Dijkstra算法
单源最短路径 给定一带权图,图中每条边的权值是非负的,代表着两顶点之间的距离。指定图中的一顶点为源点,找出源点到其它顶点的最短路径和其长度的问题,即是单源最短路径问题。Dijkstra算法 求解单源最短路径问题的常用方法是Dijkstra(迪杰斯特拉)算法。该算法使用的是贪心策略:每次都找出剩余顶点中与源点距离最近的一个顶点。算法思想 带权图G=<V,E>,令S为已确定了最短路径顶点的集合,则可用V-S表示剩余未确定最短路径顶点的集合。假设V0是源点,则初始 S={V0}。原创 2014-08-03 21:28:06 · 10081 阅读 · 0 评论 -
链表常见操作:逆置(反转)
链表中的一个很常见的操作是:链表的逆置,也叫链表的反转。如:1->3->5->7->9 反转后是 9->7->5->3->1原创 2014-05-20 00:17:25 · 12236 阅读 · 9 评论 -
数据结构:图的实现--邻接矩阵
为了表现图中顶点之间的关联,我们可以使用邻接矩阵来实现图结构。所谓的邻接矩阵,就是一个反应边与边之间联系的二维数组。这个二维数组我们用matrix[numV][numV]表示,其中numV是顶点数。对于无权图若顶点Vi和Vj之间有边,则matrix[Vi][Vj]=1;否则matrix[Vi][Vj]=0。对于有权图若顶点Vi和Vj之间有边,且权值为weight,则matrix[Vi][Vj]=weight;否则matrix[Vi][Vj]=0或MAXWEIGHT(取最小权值或最大权值)。原创 2014-07-31 23:29:34 · 23309 阅读 · 1 评论 -
数据结构:图的遍历--深度优先、广度优先
图的遍历是指从图中的某一顶点出发,按照一定的策略访问图中的每一个顶点。当然,每个顶点有且只能被访问一次。在图的遍历中,深度优先和广度优先是最常使用的两种遍历方式。这两种遍历方式对无向图和有向图都是适用的,并且都是从指定的顶点开始遍历的。先看下两种遍历方式的遍历规则:深度优先深度优先遍历也叫深度优先搜索(Depth First Search)。它的遍历规则:不断地沿着顶点的深度方向遍历。顶点的深度方向是指它的邻接点方向。原创 2014-08-02 11:20:15 · 66547 阅读 · 11 评论 -
数据结构:图--拓扑排序
拓扑排序 在实际应用中,有向图的边可以看做是顶点之间制约关系的描述。把顶点看作是一个个任务,则对于有向边<Vi,Vj>表明任务Vj的完成需等到任务Vi完成之后,也就是说任务Vi先于任务Vj完成。对于一个有向图,找出一个顶点序列,且序列满足:若顶点Vi和Vj之间有一条边<Vi,Vj>,则在此序列中顶点Vi必在顶点Vj之前。这样的一个序列就称为有向图的拓扑序列(topological order)。步骤从有向图中选取一个没有前驱(入度为0)的顶点输出。删除图中所有以它为起点的弧。原创 2014-08-03 01:10:21 · 8182 阅读 · 0 评论 -
索引排序
索引排序在排序时,若是数据很复杂,对数据的移动显然是费时的。若把数据移动改为指针移动,则减少了操作复杂度。索引排序,也叫地址排序,就是这种排序思想。索引含义根据索引的含义不同,索引排序的算法上也主要分为两种。一、index[i]为array[i]最终在有序序列中的位置。二、index[i]为位置i上最终应存放元素的下标。即最终元素按array[index[0]]、array[index[1]]……有序。原创 2014-07-17 00:30:50 · 10441 阅读 · 0 评论 -
单链表,单循环链表,约瑟夫问题
线性表 线性表中的线性一词说的是一种逻辑结构,它表示除了首尾节点外,其它节点都只有一个前驱和一个后继,这是一对一的关系。要想实现线性表得考虑它的物理结构,即选用何种存储结构。线性表主要有两种存储结构:1.顺序存储这即是我们常用的数组,很多语言都内置了这种数据类型,可见它即基础又常用。它的特点是:按位置访问很容易,它是O(1)的;插入和删除相对比较麻烦,因为这普遍要移动元素,它是O(n)的;按内容查找对于无序的表是O(n)的。2.链式存储,原创 2014-05-12 13:49:02 · 4677 阅读 · 2 评论 -
链表常见操作:有序链表合并去重
两个升序链表合并,并要求去掉重复元素 。分析:如何使链表本身是有序的,这个我们可以在加入元素的过程中做到合并,并去掉重复元素,这个是难点思路:主要思想类似于直接插入排序和归并排序。指针p指向list1,指针q指向list2,由于list1已经有序,我们只需要把q指向的节点插入一个原本有序的表,这不就是直接插入排序算法吗?当然,得把p移动到合适位置。再由于list2也已经有序,因此插入过程中p不需回溯,只需不断地往后移动,这不就是归并排序吗?如果q指向节点的值域和p指向节点的值域相同,则应该丢掉此原创 2014-05-20 09:43:38 · 6218 阅读 · 1 评论 -
栈的应用:解析算术表达式
类似于 1*2-3+4-(5-6)-2/4 的式子,我们称为算术表达式。下面我们利用栈这种数据结构来解析它,即用栈来辅助计算算术表达式。首先我们得明确计算规则:先左后右:从左算到右先乘除,后加减先括号内,后括号外原理:原创 2014-05-27 14:06:54 · 6364 阅读 · 3 评论 -
树、二叉树基础
前面介绍的栈、队列都是线性结构(linear structure)。而树是非线性结构(non-linear structure)。因此,树中的元素之间一般不存在类似于线性结构的一对一的关系,更多地表现为多对多的关系。直观地看,它是数据元素(在树中称为节点)按分支关系组织起来的结构。显然,树形结构是比线性结构更复杂的一种数据结构类型。树的定义:树是含有n个节点的有穷集合,其中有一个节点比较特殊称为根节点。在图示树时,用一条边连接两个有逻辑关系的节点,这个关系被称为父子关系。二叉树(Binary Tree)由节原创 2014-07-02 12:37:01 · 4856 阅读 · 0 评论 -
二叉树
在计算机科学中,树是一种重要的非线性数据结构,直观地看,它是数据元素(在树中称为结点)按分支关系组织起来的结构。二叉树(Binary Tree)是每个节点最多有两个子树的有序树。通常子树被称作"左子树"(left subtree)和"右子树"(right subtree)。二叉树常被用于实现二叉查找树和二叉堆。值得注意的是,二叉树不是树的特殊情形。在图论中,二叉树是一个连通的无环图,并且每一个顶点的度不大于3。有根二叉树还要满足根结点的度不大于2。有了根结点后,每个顶点定义了唯一的根结点,和最多2个子结点。原创 2014-07-03 19:09:49 · 11168 阅读 · 1 评论