
数据结构
PYB不开心
这个作者很懒,什么都没留下…
展开
-
简单五子棋AI
五子棋AI这个项目参考了网上的五子棋源码,并且做出了自己的修改与一定的优化。基本思路:首先我们知道棋类AI的基本框架就是博弈树,使用最大最小搜索算法和alpha/beta剪枝。这是基本的框架。然后因为存在的解太多,所以我们需要考虑一个评估函数来进行选择。[1]评估:这里主要采用状态分析的办法来进行打分。我们首先统计所有的棋形状态(冲二,冲三,活三等等),然后根据双方的状态来打分:具体来说,就是轮到我原创 2017-02-23 18:16:47 · 1455 阅读 · 0 评论 -
图论:拓扑排序
摘要:拓扑排序是有向无圈图的一种定点序列. 如果存在i到j的路径,那么i就必须出现在j的前面;这个理论有很多的应用. 那么我们就来看看如何实现这种排序. (1)图的基本数据结构:图是使用邻接矩阵实现的.#include "stdafx.h"#include "malloc.h"#include"队列-数组实现.h"#define Number 10typedef struct List原创 2015-09-03 15:29:37 · 362 阅读 · 0 评论 -
线索树的基本例程:(2)
摘要:(1)如何删除一个线索树中的节点,并且不影响线索的指向。 (2)基本框架是普通二叉树的删除办法,有一些细节要处理: 【1】依然是注意不要陷入死循环 【2】判断节点儿子的情况相对较为复杂: 首先,如果该节点有两个儿子,那么它的没有线索指针。同样,除了整棵线索树只有一个节点的情况(它没有前继与后继),没有线索指针就意味原创 2015-09-01 18:49:37 · 332 阅读 · 0 评论 -
利用深度优先搜索算法寻找割点
摘要:利用深度优先搜索去寻找割点.(1)定义:什么叫做割点?割点的定义是针对无向连通图的.如果删除某一个节点后该图仍然是连通的,那么这个图是双连通的.否则被删除的节点叫做割点.(2)寻找割点的基本思路:[1]首先利用深度优先搜索给图进行编号.对每一个节点我们称它的编号为先序编号Num[v]。然后对深度搜索优先树每一个定点v计算它能够通过一条背向边或者树的零边或其他边达到的先序编号最低的顶点,称为Lo原创 2015-09-03 21:34:30 · 1998 阅读 · 0 评论 -
Kruskal算法求解最小生成树
摘要:本文用Kruskal算法求解最小生成树,算法本身是很简单的,但是用到了比较多的数据结构.该算法由堆操控,时间界是O(|E|log|E|)(1)基本思路:[1]每次都选择所有没有被选择过的边中最小的一条边,如果这条边不与已经选择的边构成一个圈,那么这条边就被选中,否则,删除.[2]当被选中的边数量达到|V|-1终止算法.(2)所用的数据结构:[1]堆:用来存放边,每次找到最小的边[2]相交/不想原创 2015-09-03 19:43:32 · 1200 阅读 · 0 评论 -
最大流通路
摘要:将每条边看成容量,寻找起始点到每一个点的能通过的最大值.(1)基本思路:[1]基本思路还是Dijkstra算法,首先将起始点的相邻点遍历一遍,找到起始点到该节点容量最大的一个,将它标记为已知.[2]在所有未知节点里面重复[1]的过程,每找到一个节点,都要访问它所有的邻接节点,并且更新距离,如果连接两个节点的边的容量比起始点到已知节点的最大容量要小,那么就要更新该容量.[3]直到所有节点被访问.原创 2015-09-03 19:03:00 · 485 阅读 · 0 评论 -
对具有负值边的图进行最短路搜索
(1)为什么要采取其他算法?Dijkstra算法在这里是行不通的.因为经过某条负值边会使得以前找到的节点不是最短路径.比如:(2)新算法的基本思路:[1]我们采用计算无权边时候的算法,稍加改进.首先将起始节点放入队列。[2]每次出队一个节点k,将它所有的相邻节点更新距离(Cij+Dk),如果k到初始点的距离加上相邻边的长比该相邻节以前到初始节点的距离小,就更新距离,并且将该相邻节点入队;[3]无论该原创 2015-09-03 18:39:55 · 1063 阅读 · 0 评论 -
不相交数据结构
摘要: (1)不相交数据结构是一种非常有用的数据结构,它类似于一种集合,高效的支持某两个元素是否在同一个元素中的查找操作,也支持合并两个集合,在集合中删除某个元素等操作. 【1】基本数据结构:不相交数据结构常用的一种形式是由树的构成的.树被储存在一个数组中(非显式的存储).集合的名字由树的根给出.假如该数组元素的值大于0,那么它不是根,否则它就是根(大小的负值由该数组元素的值)是否进行路径压缩是原创 2015-09-03 14:53:30 · 407 阅读 · 0 评论 -
利用散列函数进行字符串匹配
摘要:(1)假定给了我们一个长字符串L,给了一个我们已知长度的短字符串s,要求进行匹配,判断该s(长度k)是否在L(长度N)中,位置在哪里。 基本思路:对所有符合长度的短字符串T进行遍历(N-k+1次),求出该字符串的散列函数并且与s的散列函数进行比较,如果一致,那么就逐个字符的进行检查.(散列函数一致而不是同一字符的概率很小). 细节:关键是要迅速的求出散列函数值,对于字符串一般的思路是将所有原创 2015-09-01 20:01:33 · 765 阅读 · 0 评论 -
散列操作的基本例程(1)
摘要:散列表是一种很有用的数据结构,特别是对于Find操作只需要常数时间.本文的散列表利用空间避免冲突,利用率很高. (1)散列的基本数据结构,由一个大小变量和一个指针数组(指针指向一个链表)构成.#define Num 100#define MinTableSize 5typedef struct Hashtbl *HashTable;typedef struct ListNode *原创 2015-09-01 19:33:46 · 377 阅读 · 0 评论 -
优先队列的基本数据结构(2)
摘要:本次提供另外一些优先队列的基本操作 【1】 对二叉堆进行下滤,就是让某个元素降至到使得它符合二叉堆优先结构的节点.void PerLocateDown(Heap H,int i) //对二叉堆进行下滤{ int child; int FirstElement = H->Element[i]; for(;i*2<= H->heapsize; i = chil原创 2015-09-02 10:40:06 · 366 阅读 · 0 评论 -
散列表在多项式计算上的应用
摘要:计算一个多项式的乘法(大小为M,N)大概有两种办法:【1】记录所有的结果,然后排序再合并,这大概需要对MN项进行排序至少要O(MNlog(MN))的时间界。但是很多情况下最终不同的项只有M+N的量级,大多数被合并了。因此我们可以考虑另外一种办法【2】在用计算的时候进行合并,最后排序,这只需要对大约M+N(很多时候,比如一个多项式自乘)项记录排序,时间界为(O(M+N)log(M+N))。 对原创 2015-09-01 21:38:37 · 363 阅读 · 0 评论 -
左式堆的基本操作
摘要:二叉堆并不支持高效率的合并,因为这需要把一个数组拷贝到另外一个数组里面,这需要消耗O(N)的时间.实际上,所有高效支持合并的操作都是用指针来进行的.左式堆也是一种二叉堆,它与普通二叉堆唯一的区别就是它是不平衡的二叉堆,实际上是非常不平衡.把一个节点的零路径(Npl)长定义为一个节点到一个没有两个儿子的节点的最短路径,因此具有一个儿子或者没有儿子的树的零路径长是0.而NULL节点的npl是-1.原创 2015-09-02 12:08:14 · 2626 阅读 · 2 评论 -
优先队列(堆)的基本结构(1):
摘要:优先队列是指的队列可以提高最高优先级的信息,并且它的删除与插入操作都可以保证这个结构不被破坏;(1)基本数据结构:由一个代表堆大小的变量,堆容量的变量,还有一个可以动态分配的数组. (2)数组的第一个元素不用,编号从1开始.,该队列可以看成一棵二叉树,父节点总是比子节点要小.。同时堆是一个被完全填满的二叉树,有可能的例外是在最后一层. (3)可以用一个数组来存放堆,因为很容易证明(数学原创 2015-09-02 10:12:39 · 307 阅读 · 0 评论 -
对加权(无负值边)的图进行最短路径搜索
摘要:本次对加权边的图进行单源最短路径搜索.(1)与无权搜索有什么不一样?以前的算法在加权边上行不通了,这是因为从最短路径为k的点到相邻的点的路径不一定是最短路径,因为这条连接的边可能很长.(2)基本思路:利用Dijkstra算法-[1]首先访问起始点的所有邻接定点,找到到起始点最短的一个,将它标记为已访问.[2]将该节点设置为当前节点,访问它的所有节点,并更新它们到起始点的最短路径距离.(一开始除原创 2015-09-03 18:24:37 · 636 阅读 · 0 评论 -
删除子序列问题
给定一个序列,要求从里面删除一个连续的子序列,使得剩下的序列里含有一个最长的连续递增子序列。这个题目有O(nlogn)的解法,但是比较复杂,我也没有研究清楚,就先说O(n^2)的算法吧:最容易想到的是枚举算法(i,j),然后检测能够拼接的最长子序列。当然检测这个步骤需要O(n),我们有两种方式来解决这个问题.(1)预处理计算出所有的f(i),g(i),f(i)代表以第i个元素开始的递增序列,g(i)原创 2016-11-19 19:26:42 · 3123 阅读 · 1 评论 -
Leetcode-Sudoku Solver(数独)
这道题的解题思路如下:(1):维护一个list,里面保存所有未确定元素的取值集合(1):维护一个list,里面保存所有未确定元素的取值集合(2):每次从list里面取集合长度最小的集合,然后开始进行dfs(2):每次从list里面取集合长度最小的集合,然后开始进行dfs(3)每确定一个元素,就要更新对应的行,列,block所在的所有元素对应的集合(3)每确定一个元素,就要更新对应的行,列,block原创 2016-10-11 20:42:32 · 445 阅读 · 0 评论 -
Maigc Cubes:2017 Works Application笔试
给定一个M*M*M的魔方,和N个小魔方,将每一个小魔方融合到大魔方里(小魔方的大小不确定,但是一定小于大魔方),融合的部位将将加起来再对P取余,要求最后的结果一定是全部为0。求出所有小魔方的位置。思路如下,这个题目似乎没有找到巧妙的解法,所以采用暴力搜索.但是搜索也是有技巧的,我思考之后发现:这个问题很适合双向BFS搜索加减枝。从最终状态全0出发,我们可以每次减去一个魔方的值然后取余(-1%3 =原创 2016-10-31 11:00:11 · 2095 阅读 · 0 评论 -
如何确定一个链表中有闭环,如果有怎么确定起始点?
这个问题很有趣,首先我第一个直觉是用图论的知识来解决,但是这是不可行的.因为我们没有办法将每一个节点的信息保存起来(这样的代价过于巨大,每一个节点标志唯一的就是它本身的地址,但是地址这个信息不能直接映射为容器的下标,它的值过于巨大,所以很难存储).其次的一个思路就是联想生活中的知识了,两个人追着跑,如果有圈的话一定会相遇的.那么我们可以利用两个指针p1,p2(每次分别增1和2)来进行判断.这里又有一原创 2015-12-26 22:42:50 · 5770 阅读 · 0 评论 -
算法竞赛入门经典第三章总结(python实现)
#开灯问题def N_lamps(n,k): L = [0]*(n+1) for i in range(1,k+1): factor = 1 while(factor*i<=n): L[factor*i] = 1-L[factor*i]#1代表开 factor += 1 for k,i in e原创 2016-04-27 20:36:31 · 1536 阅读 · 1 评论 -
算法竞赛入门经典(1,2章的python实现)
可以说几乎没有什么难题,但是有几个地方还是值得注意.关乎一些编程的技巧.首先对于最大最小值,注意最好还是用第一个数组里的值作为初始值,避免了人为的假设最大值和最小值.对于浮点数的运算,一定要注意误差,比如转换成整数的时候要采用四舍五入的办法比如调用round函数或者int(f+0.5)。要求四舍五入的时候注意要多求一位.用好双端队列.def average(a,b,c): print('%.原创 2016-04-26 20:22:48 · 1805 阅读 · 0 评论 -
随机化算法:跳跃表
摘要:跳跃表主要是用来减少查找的代价,作为单向链表,如果搜寻一个数据需要O(N)的时间代价,但是如果采用随机化跳跃表则可以大大减少搜寻代价.(1)注意几个特点:[1]跳跃表m阶指针所连接的元素至少具有m阶的指针.[2]主要难点集中在查询,插入,以及删除操作.这比普通链表要复杂的多.[3]首先看基本数据结构.#include "stdafx.h"#include "malloc.h"#includ原创 2015-09-07 17:17:03 · 1748 阅读 · 0 评论 -
标题:利用动态规划求解最优二叉树
摘要:二叉查找书所要查找的目标出现的频率可能不一样,因此它们在二叉查找树上的位置不同,查找的代价也不同.(1)基本思路:[1]因为二叉查找树的左儿子一定要小于右儿子,这里用单词作为元素.首先按照首字母的顺序排序,当首字母相同时,按照字符串的长度排序。[2]假设对于单词wLeft……wRight进行构建二叉查找树,设F[Left][Right]以该单词集合中某个单词为根的最小查找代价.则可以写出递归关原创 2015-09-06 19:50:21 · 2031 阅读 · 0 评论 -
欧拉回路
摘要:欧拉回路的基本定义是从一个起点出发,遍历所有的边最后回到起点.欧拉通路则不要求回到初始点.基本思路:[1]首先给出两个定理,如果一个无向图存在欧拉回路,那么它一定每一个节点的度数都是偶数.这很容易理解,假如某个节点的出度与入度不等,那么终究有某次访问该点导致不能出去.[2]如果一个无向图存在欧拉通路,要么它每个节点的度数都是偶数,要么存在两个节点的度数是奇数.而且如果有两个节点是奇数,那么该回原创 2015-09-05 16:40:42 · 374 阅读 · 0 评论 -
强连通分支
摘要:寻找强连通分支,利用构造深度搜索优先树的办法,找到有向图的强连通分支.(1)基本思路:[1]首先利用深度搜索优先找到一颗深度搜索优先树.如果该树不包含所有的节点,那么对剩下的节点继续进行搜索.直到所有节点都被访问,这时候得到深度优先搜索树形成的森林.[2]在搜索过程中对所有的节点进行编号(后序遍历).[3]将该图进行反向,然后重新进行搜索,每次搜索的起点都找一个没有被访问的顶点中编号最低的点.原创 2015-09-05 15:06:02 · 1200 阅读 · 0 评论 -
欧拉通路的求解
摘要:同样利用深度优先搜索的办法.与欧拉回路求解的思路相似.基本思路:【1】首先从图中找到一条从奇数度数节点1到达奇数度数节点2的通路.方法,利用深度优先搜索直到找到另外一个奇数节点.[2]很显然,删除所有遍历过的边,剩下的图就是一个欧拉回路的图.[3]利用寻找欧拉回路的基本框架继续寻找.【4】利用链表Newvertex记录路径和拼接.【5】关于链表的数据结构和相关函数省略List FindEule原创 2015-09-05 21:05:08 · 1035 阅读 · 0 评论 -
对于无权边的最短路径搜索
摘要:在一个无权图中,寻找某个节点到其它所有节点的最短路径. 基本思路:(1)首先找到与起始节点相邻接的所有节点,那么它们的最短路径就是1.并且将这些访问过的节点标志为已经访问.容易知道,其余所有没有访问的节点中存在的最短路径是2.而且这些节点都是第一批访问的节点的邻接节点…..,如果最短路径为k的节点已经被访问,那么剩下节点中最短路径就是K+1,而且一定由路径长是k的节点连接到它们的。这很容易证原创 2015-09-03 15:56:08 · 376 阅读 · 0 评论 -
利用散列结构查找字谜
摘要:曾经我们用最基本的查找方法查找过字谜问题,如果字谜用二维数组存放(R*C),要查找的单词个数为w,则时间界是O(RCW). 现在改用散列存放要查找的单词,由于散列的查找时间为常数,那么时间界在理论上可以降至O(RC), 注意细节:(1)可以添加一个前缀变量,当搜索方向的上的字符串不属于某个单词的前缀,就停止对该单词的匹配.(这可以显著提高效率,但是需要加很多额外代码)#include "s原创 2015-09-01 22:35:17 · 441 阅读 · 0 评论 -
数据结构:线索树之基本例程(1)
摘要:由于具有N个节点的二叉树具有N+1个NULL指针,因此在二叉查找中有一半的空间被浪费掉了.假设节点x有一个左NULL指针,则将NULL指针指向它的中缀前驱,若有一个右NULL指针,则将其指向中缀后继,这就叫线索树. (1)使用两个个变量区分该节点的指针是否是左、右线索(注意线索也可能没有后继或前驱,也可能指向NULL). (2)搜索一个节点的前驱:基本思路: [1]进行一次中序遍历(左中原创 2015-09-01 18:12:01 · 487 阅读 · 0 评论 -
B树的基本例程:删除
摘要:删除操作与插入基本相似,但是比较复杂(算法部分取自算法导论)。 (0)因为删除操作可以从任意内部节点删除,这导致必须安排它的子女; (1)除了根节点,一定要保证删除不会使得该节点的元素个数少于t-1个. (3)因此在递归降至某个节点之前,一定要保证它的父节点有t个子女.下面分几种情况讨论B树删除的操作: (1)如果关键字k在节点x中,且x是个叶子节点,则删除x; (2)如果关键字k在原创 2015-09-01 10:12:14 · 872 阅读 · 0 评论 -
栈的应用:后缀表达式到中缀表达式的转换
摘要:(1)后缀表达式是给计算机看的,有些情况下我们需要将它转换成中缀表达式。 (2)这是一个重构的过程。 【1】首先考虑一些细节问题。作为表达式输入时要用空格将数字分开(1 2+),不能是(12+),因为数字没有用操作符隔开。那么在读入到的时候就要将空格给去掉,然后放入一个链表之中(放入数组不能区分间隔)。 【2】其次要考虑小数点的存在要将字符原创 2015-08-31 12:01:03 · 628 阅读 · 0 评论 -
标题:伸展树的基本操作:
摘要: (1):基本思想:当访问到一个节点并进行操作后,它一定被移动到根处(通过类似于AVL树的一系列旋转的操作:展开)。 (2)伸展树的花费:它能够保证任意M次对树的基本操作只花费O(MlogN)的时间.s=虽然这不能保证每一次的操作都很好,但实际效果是很好的。 (3)展开操作类似旋转,但是在如何旋转的问题上我们有所修改.令x是旋转路径(从底部到顶部)上的一个非根节点. {1}情况1原创 2015-08-31 16:47:20 · 617 阅读 · 0 评论 -
B树的基本例程(1)插入
摘要:B树的基本定义:每个节点x都有以下域: a)n[x],当前存储在节点x中的关键字数 b)n[x]个关键字本身,以非降序存放; c)leaf[x],是一个布尔值,标志是否是叶子. (2)每个节点内还包含n[x]+1个指向其子女的指针; (3)每个节点都具有相同的深度h。 (4)每个节点能包含的关键字数有一个上界和下界,这些界可以用一个称作B数的最小度数的固定整数t来表示.t>=2;原创 2015-09-01 09:12:59 · 619 阅读 · 0 评论 -
标题:AVL树的基本操作例程(1)
摘要(1)AVL树是带有平衡条件的二叉平衡树。它要求左子树和右子树的高度之差不能超过1; (2)当插入一个新的节点后,可能会造成新的不平衡;因此要通过一定的操作来修正;我们将它称为旋转; (3)不同的不平衡情况对应不同的旋转:对于一个平衡的节点有四种情况:对它的左儿子的左子树,左儿子右子树,右儿子左子树,右儿子的右子树;这对应了四种旋转; (4)单旋转原创 2015-08-31 16:44:21 · 498 阅读 · 0 评论 -
利用栈可以进行平衡符号的检测
摘要:当我们输入(,),{,},[,],等符号时,经常要检查它们的正确性。 (1)利用栈可以完成这个问题,当遇到一个左括号(,{,[,入栈,遇到右符号,出栈,如果出栈的元素不满足匹配,则说明不平衡. (2)尽管基本思路简单,但是考虑的如果要判断不平衡的原因(比如“(”多了),或者输入了一些错误的符号也要处理,以及像/* */等有两个字符的符号等细节问题,代码还是不容易写的太简洁.// chap3原创 2015-08-31 12:16:46 · 764 阅读 · 0 评论 -
中缀表达式到后缀表达式的转换
摘要: (1)中缀表达式就是我们平常所说的计算表达式 如 1+2+3; (2)后缀表达式就是将操作符号置于数的后面 1 2 + 3 +; (将中缀表达式转换成后缀表达式的好处),计算机可以不用关心运算符号的优先级,直接按顺序读取。 (3)一个简单的算法用到数据结构:栈,将中缀表达式转换为后缀表达式: {1}当读到一个操作数时,将它直接输出,当读到一个操作符号时,不将它输出,而是存放原创 2015-08-31 11:38:50 · 650 阅读 · 0 评论 -
数据结构:表达式树
摘要: (1)表达式树的树叶是操作数。其他节点为操作符。 (2)通过递归产生一个带括号的左表达式,然后打出根的操作符号,再递归的产生右表达式。这是一种中缀表达(也是中序遍历) (3)另一种方式是进行后序遍历,产生一个后缀表达式。 (4)现在给出一种教材上的构造表达式树的算法: 【1】首先输入一个后缀表达式(如果不是需要转换) 【2】依次读入元素,如果是操作数,则建立一个单节点树,并将原创 2015-08-31 13:29:09 · 1344 阅读 · 0 评论 -
单链表的基本结构与操作(1)
摘要:(1)链表基本上市最基本也最重要的数据结构之一了,下面简单分析一下基本结构与操作 (2)单链表(还有其它类项后面分析)有一个元素(任意类型)和一个指针组成。(可以视情况加一些附加结构) (3)查插入操作:(1)插入操作,非常简单,找到要插入位置的前一个元素,然后断开它与后一个元素的指针,连接到新元素上。然后将新元素指针指向后一个元素(所以这里需要保留原来的节点). (2)原创 2015-08-30 21:46:03 · 554 阅读 · 0 评论 -
队列的数组实现
摘要:(1)QueeRecord,队列的基本结构,queue指向它的指针 (2)初始化的时候,Front = 1,rear = 0;注意,为什么队列没有元素的时候队尾队首要不同呢?因为队列只有一个元素是队尾队列才一样,因此出队一个元素,队首Front加1,从而得到该结果. (3)为了便于理解,可以将队列理解为一个初始时队首面向数组第一个元素,进队时原创 2015-08-30 21:15:48 · 2608 阅读 · 0 评论 -
循环链表的基本理解
摘要:本身的结构很简单,在这里我取消了表头.最后一个节点指向第一个就好了.struct Node3//循环链表{ int Port; PtrtoNode3 Next;};List Create3(int N)//用来创建一个循环链表,没有表头{ List P,L ; L = (List)malloc(sizeof( struct Node)); L->原创 2015-08-30 22:28:02 · 370 阅读 · 0 评论