
数据结构
changyuanchn
这个作者很懒,什么都没留下…
展开
-
链表
链表由一系列不必再内存中相连的结构组成,每一个结构都含有表元素和指向该元素后继元的结构的指针。这个是定义,看着比较晕。其实链表就是一个表,表中有两个内容,一个是一些基本元素,另外一个是指针,顺着这个指针,可以找到下一个表。如图所示:链表分有头结点的链表,和没有头结点的链表,上图是有头结点的链表,没有头结点的链表就是把头部分去掉。即一般来说带有头结点的链表比较常用,在检查是否原创 2013-11-02 16:18:39 · 999 阅读 · 0 评论 -
冒泡排序(BubbleSort)
这里来介绍一个应该算是最简单的排序算法--冒泡排序。冒泡排序的思想就是一次比较两个元素,如果元素的顺序错误,就交换着两个元素的位置,重复这一步骤直到没有错误的顺序为止。因为冒泡排序会使值比较小的元素从底部一步步的向上,知道顶部,就像小气泡从水中向上冒一样,因此取名冒泡原创 2013-11-24 11:31:17 · 840 阅读 · 0 评论 -
递归
递归的定义是:A function defined in terms of itself is called recursive. 也就是说一个函数的定义需要用到这个函数的本身。递归是一个很奇妙的思想,从上面的定义看去,递归貌似一个死循环,这个当然是不对的,递归总会有一个结束的条件,也就是基准情况,这个基准情况规定了递归什么时候结束。下面来看一个例子:计算阶乘n! = n*(n-1)*...*原创 2013-11-29 16:10:32 · 983 阅读 · 1 评论 -
拓扑排序(Topological Sort)
0)拓扑排序拓扑排序是对有向无圈图的顶点的一种排序,这个排序的结果是如果存在一条vi到vj的路径,那么排序中vi在vj的前面。下图是一个有向无圈图的例子:在这个有向无圈图中,1,6,5,7,4,2,3;1,6,5,7,2,4,3;这两组都是拓扑排序,我们可以看到这两种排序都满足拓扑排序的要求,比如说1-4的路径,可知1,7,4;1,6,5,4;1,6,7,4;1,6,5,7,4原创 2013-12-02 11:05:34 · 20489 阅读 · 1 评论 -
图的一些基本概念
0)图的定义图是由点和边组成的一种结构。也就是说,图G=(V,E),V表示点的集合,E表示边的集合。而边也可以用点对来表示,即(v,w),其中v,w属于V。如果点对(v,w)是有序的,也就是说(v,w)!=(w,v),那么我们就称图为有向图。点v和w邻接,当且仅当(v,w)属于E。 1)图的附加概念路径:路径由一系列点组成,这些点要原创 2013-12-01 20:35:41 · 1476 阅读 · 0 评论 -
分治算法(divide and conquer)
0) 引论正如名字divide and conquer所言,分治算法分为两步,一步是divide,一步是conquer。Divide:Smaller Problems are solved recursively except base cases.Conquer:The solution to the original problem is then formed from the原创 2013-12-09 12:07:42 · 18186 阅读 · 1 评论 -
最短路径算法(Shortest-path Algorithms)
0) 引论正如名字所言,最短路径算法就是为了找到一个图中,某一个点到其他点的最短路径或者是距离。最短路径算法一般分为四种情况:a) 无权重的最短路径b) 有权重的最短路径c) 边的权重为负的图d) 无环的图ps:上面的情况针对的都是有向图。1) 无权重的最短路径下图是一个例子:假设我们取点v3作为初始点,计算点v3到图中所有点的路径以及距离(包括点v3)原创 2013-12-03 11:43:50 · 18980 阅读 · 2 评论 -
网络流(Network Flow)
0) 引论网络流问题是有实际应用来源的。个人觉得网络流应该是网络流量的意思,它限制了一个网络的最大流量问题。举个例子,对于一个给水网络,每条管道的最大流量是确定的,这就要求我们解决整个给水网络的流量问题;或者是交通网络,可以对每条道路的交通流量进行计算,使其不能超多最大的道路流量。1) 数学模型对于一个网络流我们可以用一个有向图G = (V,E,C)表示;V表示顶点的集合,E表原创 2013-12-03 17:45:55 · 11758 阅读 · 1 评论 -
关于深度优先和广度优先的问题
Depth-First Search和Breadth-First Search,即深度优先和广度优先是图的两种搜索的方法。其实与其说是方法,不如说是两种思想。下面我们就来介绍这两种思想。1) Depth-First Search深度优先是指在图的查找中,对每一个分支深入到不能再深入为止,如果到达了终点,则选择另一个未访问的顶点,继续查找,知道每个节点都被访问到,并且每个节点只能被访原创 2013-12-03 22:21:05 · 11979 阅读 · 0 评论 -
最小生成树
0) 引论这里的最小生成树是图论中的概念,是指在图中找到一个最小的树,这棵树包含所有的点,并且总的边的权重要最小。这里我们说的图是指无向图。下图所示为一个无向图的最小生成树。下面我们看看解决这个问题的两种算法。1) Prim’s algorithm这个算法有点类似于Dijkstra algorithm。是一步一步的增长树。依次处理每一个顶点,选取最短原创 2013-12-03 21:12:14 · 972 阅读 · 0 评论 -
动态规划(Dynamic Programming)
0) 引论动态规划通过把原问题分解为相对简单的子问题的方式求解复杂的方法。动态规划常常用于有重叠子问题和最优子结构性质的问题。动态规划可以取得全局最优质的,他所耗费的时间远小于朴素的解法。动态规划的思想是:要解决一个问题,往往需要求解其不同部分(子问题),再合并不同的子问题以解出原问题的解。这里的子问题是非常相似的,动态规划仅仅处理每个子问题一次,把结果存储,当需要再次使用这个子问题时,则原创 2013-12-10 20:32:22 · 1453 阅读 · 1 评论 -
NP 简介
NP是non-deterministic polynomial time的缩写,也就是说在多项式时间内无法完成的一系列问题。也就是人们常说的NP-Hard问题。NP Complete是NP问题的一个子集,这个子集包含NP中最难的问题。已经证明,NP中的任何问题都可以多项式的归纳为NP Complete问题。遗憾的是到目前为止,尚没有有效的解决方法。常用的方法有近似算法,逐层贪婪,启发死算法原创 2013-12-04 12:10:43 · 2645 阅读 · 0 评论 -
欧拉回路(Euler Circuits)
首先介绍一下什么是欧拉回路,这个是一个图问题,也就是说假设我们拿着一只笔,在纸上画一个图,在这个期间笔不能离开纸,同时每一个边只能画一次。也就是人们常说的一笔完成。如下面例子所示图a,图b可以一笔画出来,而图c不可以。欧拉回路就是研究这个问题:什么样的图能够一笔画成。我先先来分析上面的图a,可以发现对于图a,虽然可以一笔画成,但是却无法在结束时回到最初的起始点,也就是说假设我们从左原创 2013-12-04 11:48:28 · 3908 阅读 · 0 评论 -
贪婪算法
0) 引论贪婪算法是分阶段进行的一种算法,每一个阶段,我们只取最好的决策,而不管以后。贪婪算法是“take what you can get now”策略。贪婪算法的结果一般会取到的是局部最优值而非全局最优的,一般情况下这两个值是不相等的,但是很多情况下,可以用局部最优值来模拟近似全局最优值。常用的图论中的Dijkstra算法以及Kruskal算法都利用了贪婪算法的思想。贪婪算法的原创 2013-12-05 17:30:00 · 7825 阅读 · 1 评论 -
Huffman 编码
1) 问题引入Huffman 编码也也是贪婪算法的一种应用,它在文件压缩中有较强的应用。对于计算机来说,它只认识两个数0,1 。而对于字符,计算机需要对其进行二进制编码来表示。假设对于128个字符,常规的编码方式利用8个位来表示(其中1位为奇偶校验位)。假设我们的文件只有7种不同的字符组成,那么我们需要3个位来表示这7个字符,可以有下面的编码方式:如果我们用等长的位来编码时,我原创 2013-12-05 20:56:23 · 1122 阅读 · 0 评论 -
随机化算法
0) 引论随机是很有用的一个东西,先不去管什么随机化算法,至少随机数是个很好的东西,就像掷骰子,总可以帮组我们决定一些犹豫不决的并且无关紧要的事。在机器学习中,一般我们都是要在整个数据集中随机抽取一定的数据做训练,另外一些做测试,这样结果才能有说服力,这里也将用到了随机数。因此下面我们首先来讲解一下伪随机数发生器。1) 伪随机数发生器真正意义上的随机数是很难产生的,大多数的随机原创 2013-12-14 21:21:00 · 13608 阅读 · 0 评论 -
回溯算法(BackTracking)--八皇后问题
0) 回溯算法:回溯算法也算是遍历算法的一种,回溯算法是对Brute-Force算法的一种改进算法,一个典型的应用是走迷宫问题,当我们走一个迷宫时,如果无路可走了,那么我们就可以退一步,再在其他的路上尝试一步,如果还是无路可走,那么就再退一步,尝试新的路,直到走到终点或者退回到原点。1) 皇后问题:N皇后问题是指在N*N的棋盘上放置N个皇后,使这N个皇后无法吃掉对方(也就是说两原创 2013-12-16 22:17:40 · 23030 阅读 · 2 评论 -
字符串的模式匹配
0) 引论这里主要想讨论一下字符串的模式匹配,主要是KMP算法。假设我们有一个字符串S,称之为原始串;另一个字符串T,称之为模式串;字符串匹配是指找出原始串S中是否含有模式串T,如果含有,则返回S中第一个匹配项的位置;例如S=“abcabcabdef”;T=“abcabd”;那么我们可以得到S中含有模式串T,我们返回S中第一个匹配项的位置,即3。1) Brute-Force原创 2013-11-25 08:31:59 · 1209 阅读 · 0 评论 -
左堆(Leftist Heaps)
0)引论为什么要提出左堆这么一个概念呢?有了二插堆还不够么。这是因为前面提到的数据结构在支持合并(merge)操作的时候是比较差的。比如对于一个二叉查找树来说,要把两个二叉查找树合并,那么可能需要把一个二叉树的结点一个一个的插入到另一个二叉树中,这个的时间消耗是一个很恐怖的事情。因此我们引入左堆。1) 左堆的一些基本概念零路径长(null path length)Npl(X):结点X到原创 2013-11-09 16:09:32 · 6276 阅读 · 0 评论 -
堆栈
堆栈就是插入和删除都在一个方向的一种表的数据结构,也就是所谓的“先进后出”,其实就像一个瓶子,只有一面是能够打开的,要想拿出最里面的东西,就要先吧上面的东西移开。下图形象的显示了什么是堆栈。其实这个图说明了一切 对堆栈的操作比原创 2013-11-02 20:01:17 · 951 阅读 · 0 评论 -
队列
队列与堆栈不同,队列是一边进,另一边出的表,如下图所示:队列的主要操作也比较少,主要的有入队,出队,检查队列是否为空,队列一般会有两个标志位,即Front和Rear,表示对头和队尾,通过对这两个标志位进行操作,可以对队列进行适当的操作。0) 链表声明与实现struct QueueModel{ int Capacity; int Front; int Re原创 2013-11-02 22:49:32 · 925 阅读 · 0 评论 -
B 树
0)引论大多数的查找树都是二叉树,这个可以理解,因为二叉树相对来说比较简单,易行,用递归方式编程也较易实现。这里介绍一种非二叉的树,即B树。1)B树一个M阶的B树,应该具有以下的性质:(1)根节点要么是叶子,要么具有2-M个子节点(2)非叶节点(根节点除外)具有[M/2]-M个子节点(3)所有的叶节点具有相同的深度(4)所有的数据都存储在叶节点上也就是说与二叉树不同原创 2013-11-04 21:46:28 · 909 阅读 · 0 评论 -
不相交集(The Disjoint Set ADT)
0)引论不相交集是解决等价问题的一种有效的数据结构,之所以称之为有效是因为,这个数据结构简单(几行代码,一个简单数组就可以搞定),快速(每个操作基本上可以在常数平均时间内搞定)。首先我们要明白什么叫做等价关系,而在这个之前要先有一个关系(relation)的定义Relation:定义在数据集S上的关系R是指,对于属于数据集S中的每一对元素(a,b),a R b要么是真要么是假。如果a原创 2013-11-19 10:03:05 · 10680 阅读 · 3 评论 -
二叉树
0)首先回顾一些树的基本概念:根节点(root):没有父亲的结点。树叶(leaf):没有儿子的结点。路径(path):是一个结点到另一个结点的序列表示,这些结点都应该是父子关系。路径的长(length): 路径上边的条数。为序列个数减一。深度(depth):根结点到某一结点的唯一路径的长。高(height):某一结点到树叶的最长路径的长。如图所示: 树的遍原创 2013-11-04 10:46:42 · 960 阅读 · 0 评论 -
伸展树
伸展树是一种相对简单的树结构,它保证从空树开始任意M次对树的操作最多花费O(MlogN)的时间。这种保证并不能排除某次操作的时间为O(N)的可能,但是能保证每次操作平均的时间为O(logN)。对于一系列的操作,有的可能花费时间多些,有的少些。伸展树基于这样的一个事实:“对于时间花费为O(N}的二叉树操作是可以接受的,只要这种操作相对比较不频繁发生。”对于一个二叉查找树,可能有的操作原创 2013-11-05 20:02:45 · 1262 阅读 · 1 评论 -
AVL树
前面介绍了二叉查找树,二叉查找树的平均时间复杂度为O(logN),是相当低的,因此是一种非常优异的模型。但是这只是对一个随机输入的二叉查找树有效(平衡的二叉树)。当我们进行一定次数的插入(或删除)后,可能会导致二叉树不平衡,甚至退化成链表,这样会重新使时间复杂度变为O(logN).为此,引入AVL树。AVL树是Adelson-Velskii和Landis于1962年发明的自平衡二叉树。在一个二原创 2013-11-05 15:49:46 · 1105 阅读 · 0 评论 -
插入排序
0)引论下面的几篇要集中整理一下排序算法。排序算法有很多种,思想各不相同,时间复杂度也不一样。这里先对要排序的数据做一些约束:1)待排序的数据存放在数组中,且索引为从0开始2) 待排序的数据均为正数之所以有这两个约束是为了简化算法,非整数数据只需做些许改动即可应用。下面介绍一种相当简单的排序----插入p原创 2013-11-20 16:53:52 · 1010 阅读 · 0 评论 -
归并排序(MergeSort)
Merge是左堆哪里引入的一个概念,意思是把两个堆合并成一个堆。这里我们把归并的思想引入到排序中,通过把两个已排序的数据表合并来对数据进行排序。堆排序利用了递归的思想,它的最坏时间复杂度为O(NlogN)。如下图所示,由上图可知,归并排序需要3个游标,每个游标指向数组的起始位置,通过比较A[Aptr]与B[Bptr]的大小,然后将较小的值拷贝到数组C中,然后进行相应的游标的位置移动原创 2013-11-21 15:04:50 · 2138 阅读 · 0 评论 -
堆排序
0)引论这里我们介绍一下堆排序。堆是一种优先队列,它的性质很简单:树的最小值在根节点上,对于子树依旧成立。因此堆排序的思想也就明确了:把数据以堆的方式存储,然后依次输出根节点。这样就可以把数据按照从小到大的顺序排列出来了。如果需要从大到小排列,则只需要在构建堆的时候,使树的根节点为最大值就可以了。由堆的性质我们可以得出,堆排序的时间复杂度为O(NlogN)。1)堆排序由引论知道,我原创 2013-11-21 09:34:54 · 1084 阅读 · 0 评论 -
希尔排序(Shellsort)
0) 引论希尔排序时Donald Shell于1959年发明的一种改进插入排序的排序算法。对于插入排序我们知道,要想打破插入排序的时间界,那么必须要交换向距离比较远的元素。希尔排序通过引入增量序列,首先排序距离较远的元素,大大缩小逆序的数量,进而提高了插入排序的执行效率。1) 希尔排序希尔排序利用一个增量序列,h1,h2,...,ht,任何增量序列只需要满足h1=1即可。在使用增量hk原创 2013-11-20 21:22:35 · 1301 阅读 · 0 评论 -
哈希(Hashing)
0)引论哈希(Hashing)是以一种能以常数平均时间进行插入,查找,删除的技术。常数时间一般意义上是指O(1)。是的,Hashing是一种技术,从英文名也可以看出,这是动名词,一般动名词大多表示的不是一个静态的东西。就像抽象数据结构(ADT),ADT是一系列的操作的集合。而不应该是一般以为的抽象的一种数据结构。可见不同语言的表示以及翻译是一件很重要的事情。扯远了,回到正题。不同于二叉原创 2013-11-07 11:50:14 · 10848 阅读 · 0 评论 -
快速排序(Quicksort)
0)引论人如其名,快速排序之所以称之为快速排序就是因为在实践中,这个算法是最快的排序算法。它的平均运行时间为O(NlogN)。最坏的时间复杂度为O(N^2)。虽然像堆排序,归并排序的时间复杂度比较低,但是他们的实际运行时间并不比快速排序快,反而由于有一些拷贝的进程,使运行时间变得很慢。快速排序也是一种divide-and-conquer策略。1)快速排序基本步骤:a) 如果数据集S中的原创 2013-11-21 20:37:19 · 4039 阅读 · 0 评论 -
选择排序
选择排序也是一种非常简单的排序算法,它的思想是:依次找出无序数组中的最小值,然后把它放到已排序的数据的后面。算法的时间复杂度为O(N^2)。另外选择排序是不稳定的。排序算法的不稳定是指,当待排序的数组中有相等元素时,当运行排序算法后,这组相等元素的位置发生改变,则称算法为不稳定的。当然稳不稳定对最终结果没多大意义1) 例子未排序序列:【39,28,51,62,78,9,25,36】原创 2013-11-24 11:56:02 · 719 阅读 · 0 评论 -
二项队列
0)引论左堆的合并,插入,删除最小的时间复杂度为O(logN)。二项队列就是为了对这些结果进一步提高的一种数据结构。利用二项队列,这三种操作的最坏时间复杂度为O(logN),但是插入的平均时间复杂度为O(1)。1)二项队列二项队列不是一棵树,它是一个森林,由一组堆序的树组成的深林,叫做二项队列。二项队列有几个性质比较重要(a) 每一颗树都是一个有约束的堆序树,叫做二项树(b原创 2013-11-09 22:54:15 · 9470 阅读 · 9 评论 -
Priority Queue(Heaps)--优先队列(堆)
0)引论前面已经有了链表,堆栈,队列,树等数据结构,尤其是树,是一个很强大的数据结构,能做很多事情,那么为什么还要引进一个优先队列的东东呢?它和队列有什么本质的不同呢?看一个例子,有一个打印机,但是有很多的文件需要打印,那么这些任务必然要排队等候打印机逐步的处理。这里就产生了一个问题。原则上说先来的先处理,但是有一个文件100页,它排在另一个1页的文件的前面,那么可能我们要先打印这个1页的文件原创 2013-11-09 13:44:53 · 33333 阅读 · 10 评论 -
深度优先和广度优先的Python实现
#coding=utf-8 class Gragh(): def __init__(self,nodes,sides): ''' nodes 表示点 sides 表示边 ''' # self.sequense是字典,key是点,value是与key相连接的点 self.sequense =原创 2018-01-09 05:09:40 · 23724 阅读 · 11 评论