没有合适的资源?快使用搜索试试~ 我知道了~
基于Java的源代码识别:Scripthon动态属性定义和匹配算法的研究
© 2014年。出版社:Elsevier B.V.信息工程研究院可在www.sciencedirect.com在线获取ScienceDirectIERI Procedia 10(2014)119 - 1302014未来信息工程Java源代码识别的脚本语言Tomán Bublík*,Miroslav Virius布拉格捷克技术大学核科学与物理工程学院,捷克共和国,布拉格,Trojanova 13,120 00摘要本文介绍了Java源代码片段检测问题的一般结果。我们提出的工具,使用图和子图同构检测。在文献中已经提出了针对所有这些任务的许多解决方案。然而,尽管所有这些解决方案都非常快,但它们只是比较常数静态树。 我们的解决方案提供使用Scripthon语言动态输入输入样本,同时保持可接受的速度。我们使用了几个优化,以实现在匹配算法过程中非常低的比较次数。版权所有© 2014作者.出版社:Elsevier B.V. 这是一篇基于CC BY-NC-ND许可证的开放获取文章(http://creativecommons.org/licenses/by-nc-nd/3.0/)。信息工程研究院负责评选和同行评议关键词:AST; Java;树匹配;脚本;源代码识别1. 介绍通常,由大量源代码组成的程序变得混乱,并且很多时候描述的疾病开始出现(代码重复,弱可重用性等)。维护源代码是一个非常重要的问题。关于如何处理这个问题,有很多工具和指南。在这项工作中描述的工具,可编程Java源代码扫描。该工具基于Scripthon语言,在本工作的范围内,为这些目的而开发剧本, 其中描述了源代码结构以及它的属性,都可以用这种语言来写这允许定义搜索的动态属性* 通讯作者。联系电话:+420605155484。电子邮件地址:tomas.bublik@gmail.com。2212-6678 © 2014作者出版社:Elsevier B.V. 这是一篇基于CC BY-NC-ND许可证的开放获取文章(http://creativecommons.org/licenses/by-nc-nd/3.0/)。信息工程研究所负责的选择和同行评审120TomáBublík and Miroslav Virius/IERI Procedia 10(2014)119要求.接下来,从该脚本动态地创建抽象语法树(以下称为AST)。同时,从给定的Java源代码中创建相似树,并通过图匹配算法对这两棵树进行匹配。然而,不仅图的形状进行比较,也考虑树的属性。为了更快地获得结果,在此过程中使用了几种图形优化。并且可以在相对短的时间内扫描更高数量的源代码类。这种方法的典型用法如下:用户想要在一个大型程序中找到一些不容易描述的东西。但他或她知道它可能在那里。他或她可以使用我们的工具,并尝试找到至少类似的缩进代码片段。因此,用户执行搜索过程,并基于接收到的结果指定输入脚本。通过重复此过程,他或她过滤了非预期的结果,并最终获得所需的代码段。我们的工具不仅对快速Java源代码扫描有用,而且例如,对于更好地定义搜索条件。我们的工具的另一个使用领域可以是克隆的检测问题。通过使用其他克隆检测工具,可以收集进一步研究的材料。例如,非理想克隆很难检测,并且在许多情况下,这些程序的输出并不明确。然而,它可以被Sripthon分类,并且基于这样的输出的公共搜索脚本可以。2. 理论一个图是一个有序的对,其中n是一个有限的,非空的对象集,称为顶点,和n是一个(可能是空的)无序的不同顶点对的集合,即,2-边的子集。集合如果,我们说我们也会说,和是的。边被称为。我们写(或)来表示边,但并不意味着顺序。如果两个图但是,还有其他方法可以将两个图视为相同。例如,如果可以重命名一个图的顶点并获得另一个图,则可以将两个图视为“相同”。这些图除了顶点的名称之外,在所有方面都是相同的在这种情况下,我们称这些图为我知道了形式上,如果存在一个图的对应关系,则图和图同构这样的话,这个函数称为同构。树是没有环的连通图(即,连通非循环图)。图匹配问题实际上与图之间同构的问题相同。此外,将图的各部分与模式进行匹配与找到同构子图是相同的挑战。在Irniger等人的研究中,有许多方法可以解决这个问题,2005年子图同构对于确定一个给定对象是否是另一个对象的一部分,甚至是几个对象的集合的一部分很有用。两个图的最大公共子图是同构于两个图的子图的最大图。最大公共子图是衡量两个对象相似性的有效方法图同构、子图同构和最大公共子图检测的算法已经在McKay,1981,Ullmann,1976,Levi,1972,McGregor,1982中报道。度量两个图的相似性的一个更通用的方法是图编辑距离。它是字符串编辑距离的推广,也被称为Levenshtein距离Stephen 1994。另一种度量两个图的相似性的方法是基于两个图之间的最大公共子图的距离度量。随着在最大公共子图检测领域中所做的工作越来越多,这些措施越来越受欢迎。在Bunke等人的著作中,1998年,提出了一种基于两个图的最大公共子图的图距离测度。它表明,著名的概念,最大公共子图距离是一个特殊的情况下,特定的编辑费用图编辑距离。因此,最初为最大公共子图检测开发的算法可以用于编辑距离计算,反之亦然,对于所考虑的编辑Tomas Bublik和Miroslav Virius/IERI Procedia 10(2014)119121成本此外,在Fernandez等人案中,2001年,最大公共子图和最小公共超图的概念被组合以导出图距离度量,并且在Wallis等人中,2001年,讨论了基于最小公共超图的图距离,记为最小公共超图。从文献Sanfeliu等人,1983年,Tsai等人, 1979年,Eshera等人,1984年,黄,1990年。所有这些方法都能保证找到最优解,但需要指数级的时间和空间。另一方面,次优或近似方法在计算步骤的数量上受到多项式约束,但可能无法找到最优解。在Wilson等人的研究中,2004中,通过计算图的特征向量上的Levenshtein距离来执行不精确图匹配。另一种方法在Robles等人,2005将邻接矩阵转换为字符串,然后使用前导特征向量对字符串进行序列排序。然后通过将字符串匹配技术应用于它们的字符串表示来匹配图。在Caelli等人中追求不同的想法,2004年,Caelli等人,2004年,探索了特征(子)空间投影和顶点聚类方法。而在Caelli等人的研究中,2004年,该方法的目标是在图的特征空间中工作,在Caelli等人,2004子图的匹配基于它们在公共子空间中定义的顶点连通性。3. 其他解决方案存在许多可用于检测克隆的搜索类型Roy等人,2009.文本研究方法属于基本研究方法。另一方面,这些方法易于实现,因为 由于源代码中包含了大量非程序材料,因此它们患有一系列疾病。例如,通过使用文本比较来检查变量范围可能是非常具有挑战性的问题基于标记的比较是需要考虑的下一组方法。这种方法将源代码划分为令牌序列,并将令牌序列相互比较。这比文本的方法更健壮,因为它更有效的算法是基于树的算法。存在两种方法:基于度量的和基于树的。基于度量的方法使用Java源代码生成的度量。然后将这些指标与从原始源生成的度量。基于树的方法是基于抽象语法子树的比较。这些方法在我们的工作中使用。它们实现起来稍微困难一些,但它们非常有效,并且提供了更多的搜索选项。相反,基于这些方法的算法与其他类型的算法相比耗时更长。IRA D.巴克斯特是这一领域的先驱巴克斯特等人,1998.他提出了一个解决方案,使用子树哈希到桶中。只有相同的水桶树被比较。Wahler等人提出的另一种解决方案,2004.他将AST转换成XML,并在其上应用数据挖掘技术,剩下的问题是XML处理过程的速度。此外,Koschke等人提出了一个有趣的选择,2006.他们序列化生成的AST,只比较它的后缀树标记。该算法是非常快的。它能够在线性时间内检测克隆。这些算法的不足之处在于无法动态检测代码片段。他们假设一个恒定不变的原始模式。相反,我们的解决方案提供了基于脚本语言的动态输入的使用。这意味着输入可以被调节或迭代,搜索树根据搜索的树属性而改变。变量也可以使用。例如,用户可以声明Class类型的类 clazz 块 ( Stmtk=2)122TomáBublík and Miroslav Virius/IERI Procedia 10(2014)119if(clazz.Name==“HelloWorld”)...其他...这个例子意味着我们搜索类里面有两个语句,如果这个类的名字是4. Scripthon语言在这项工作中,开发了一种名为Scripthon的新编程语言,能够实现这些功能。使用这种语言,可以用属性来描述代码结构,甚至可以根据搜索到的片段属性来改变搜索样本的属性。Scripthon是一种动态类型、解释型和非过程语言。它被翻译成一种树形表达形式,它的用法与任何其他现代脚本语言的用法非常相似。Scripthon语言语义的完整定义超出了本文的范围,可以在Bublík etal. 2012中找到。因为该语言被设计为只是一种脚本语言,所以没有特殊的结构开始剧本这种语言既不是纯面向对象的语言。编译器的输入是带有命令序列的文本。这个序列描述了Java源代码中的连续语句。具有可变详细程度的命令对应于可变长度代码段。细节级别不是固定的,并且可以在每个命令中变化。一个命令可以对应一行源代码;另一个可以描述Java中的整个类。Scripthon的结构与其他当代动态编程语言的结构非常相似。各个命令由行分隔。Scripthon中没有命令分隔符。块的内部部分是制表符嵌套的。一个块不被任何符号分隔;只是使用了制表符的层次结构。正在寻找具有特定名称的方法假设我们有最常见的Java代码:public class HelloWorld {public static void main(String[] args){ System.out.println(args);}}让我们假设我们正在寻找名为“main”的方法。很简单的用户只需启动一个文本搜索对话框(通常通过CTLF + F快捷键)并执行搜索过程。不幸的是,这将发现很多杂项结果。使用Scripthon,我们可以只搜索方法:Meth(Name=“main”)此外,我们只需要公共的和静态的:Meth(Name=更重要的是,main方法的最具体的搜索标准是:Meth(Name=“main”; Rest=[public,static]; Ret=void; Parks =1;ParTypes=[String[]];ParNames=[“args”])使用Scripthon,我们可以在main方法中定义一个方法调用:Tomas Bublik和Miroslav Virius/IERI Procedia 10(2014)119123Meth(Name=“main”; Rest=[public,static])MethCall(Name=“System.out.println”;Params=[“args”])Scripthon还支持代码块描述。我们可以这样定义块的属性:Class(Name=“HelloWorld”)Meth(Name=“main”)块(Stmtk =1;Order=false)同样,这个例子对应于一个给定的“hello world”例子。在main方法中只有一个语句,语句的顺序并不重要。Scripthon的另一个有趣的关键字是“Any”。这对于不确定的搜索很有用。这意味着搜索的语句可以是任何东西,也可以是空的。为了描述上面的代码,我们可以这样写:Meth(Name=public static void main(String[] args){int i = 1;i++;System.out.println(args);}我们可以通过以下脚本找到它:Meth(Name=“main”)Any()MethCall(Name=“System.out.println”)Scripthon还支持其他几个关键字。例如,Init()用于变量初始化,Loop()用于公共循环等。最后,通过给出的示例,很容易在代码中找到一个单例Class()classBlock(Order=false; Concretive = false)MethCall(Ret= class.Name;Rest=[public,static])这里唯一没有提到的参数是“连续”参数。这意味着块中的语句不能是连续的。这些语句只需要包含在给定块中的某个地方5. 获得优化的树Java编译器API用于在第一次迭代中从给定的Java源代码中获取AST。这个API是它是免费的,包含在Java SDK中。它提供了对Java编译器的控制,编译输出之一是给定源代码的抽象语法树。只有一个条件需要满足。Java源代码必须是可编译的。在浏览Java源代码时,创建了树,其中节点增加了四个数字。这些数字是自然数命名左,右,水平和水平下。第一个和第二个数字(左,右)表示树前序遍历中节点的顺序索引。因此,祖先的左索引总是小于其子的左索引,而右索引总是大于任何子的右索引。级别编号表示顶点的树层次结构中的级别,编号下的级别表示124TomáBublík and Miroslav Virius/IERI Procedia 10(2014)119当前节点下的级别数(与Yao等人,2004年)。假设x1和x2是一棵树的两个节点;下面的规则对这些值有效该节点是一个nancest或的,而nances是一个desccen t的,如果一个nances t或的,则nodes是一个descc ent的,如果一个nances t或的,则nodes是一个descc e nt的, 该节点是p的租金,并且是如果1)和2)的子节点 Ǥ ͳ该节点具有多个 子节点。所有这些数据都是在通过树的单个过程中获得的。获取此信息不是一个耗时的操作,因为它是在树木生产过程中进行的。另一方面,使用这些数字可以显著减少比较的次数。图1.一、 带索引图二、带有一个子节点的节点有了这些信息(图1),我们就知道当前处理的节点中包含多少子节点,或者节点是否是叶子节点。由于它,很多比较不需要执行。例如,比较这个脚本:方法(名称=用这个Java代码:公共静态空main(String[] args){Tomas Bublik和Miroslav Virius/IERI Procedia 10(2014)119125System.out.println(args);}这意味着这两个节点进行比较(图。2.)的情况。但是左索引和右索引表明“主”节点确实只有一个子节点,然而,我们搜索一个有4个语句的方法。因此,此代码不对应于脚本,并且不需要任何其他比较。6. 解决方案的全面描述整个过程有点复杂,但顶部的概述很容易。在主要的比对程序之前,图3.第三章。完整过程图四、节点索引发生两个过程。第一个在用户输入Java源路径后立即启动,它编译并优化从源获得的AST。此过程只执行一次,因为在此过程的范围内源始终相同。它在背景上运行。第二个过程在用户输入搜索脚本。它编译脚本,如果没有完成,则等待第一个进程。接下来,执行第一次迭代。在此迭代期间,匹配与索引构建一起执行。之后,将结果呈现给用户。假设用户根据结果改进输入的脚本。然后算法再次运行,只有差异。 只考虑与已更改的Scripthon部件的索引对应的节点。126TomáBublík and Miroslav Virius/IERI Procedia 10(2014)119图4显示了索引是如何工作的。让我们从本文开始假设相同的“HelloWorld”示例。对应Java源代码组的索引被分配给所有非叶子节点。当用户改变输入脚本时,比较新的和旧的对应树。在我们的例子中(图4),“System.out.println”方法调用被改为初始化int类型的变量“i”。这用灰色表示。然后通过树匹配算法检测包含该变化的节点。很明显,这个节点对应的Java源代码集保持不变。因此,在下一次搜索迭代中只需要考虑这个集合。这些顶级列表显示了匹配算法的工作原理:1 for(Class c from classes)2 for(语句s from语句)3match =compare(c.node,s)4如果(!比赛)5打破6 if(match)7addToResults(c)89 compare(Node n,Statement s)10 match =optiMatch(n,s)11 if(match)12if(n.allProperties匹配s.allProperties)13return(n,n);14for(n.children,s.children)15match =compare(.)16如果(!比赛)17返回false18 else returnfalse 19 returnmatch2021 optiMatch(节点n,语句s)22 checkTreeSizes(n,s)23 checkLevels(n,s)24 checkChildrensNumber(n,s)25 returnresultOfChecks所有源类都在循环中迭代(第1行)。接下来,所有Scripthon语句都在这个循环中迭代(第2行)。在第二个此方法将所有子语句与外部循环中的节点进行比较。如果有匹配,则将找到的结果添加到结果组中(第7行),否则将内部循环取喙(第5行)。根据第15行,“compare”方法递归地调用自己。首先,它检查与准备好的优化的匹配(第10行)。“optiMatch”方法(第21行)检查树的结构,并尝试通过树大小不匹配、层数不匹配或子节点数不匹配来排除节点。如果“optiMatch”方法返回false,则该节点将被排除在进一步考虑之外(第18行)。相反,当优化不排除节点时,在“compare”递归调用中比较语句和节点的所有子级(第15行)。但在此之前,我们知道当前语句和当前节点之间的对应关系,因此它被保存到内存中的第13行。如果整个子节点集都匹配,则认为当前节点相等,并且“compare”方法返回true(第19行)。否则,返回false(第17行)。最后,如果节点等于所有Sripthon语句,则将其保存到结果集中(第7行)。7. 复杂性分析由于比较了非常数树,因此确定算法的复杂度不是一件容易的事情。二叉树总是有点不同,因为我们根据用户输入来比较节点的特征,所以比较总是不同的。首先,有可能从子树比较算法的复杂性中浮现出来。子树比较问题是NP难的。根据Valiente,2002,复杂度是第一个树节点的数量,而第二个树节点的数量还存在若干改进Shamir等人,一九九九年。然而,我们的算法是基于所需的样本树上的信息的使用。由于这些信息,可以节省大量的比较此外,在第一次遍历期间,整个树只遍历一次。Tomas Bublik和Miroslav Virius/IERI Procedia 10(2014)119127运行.在下一次运行期间,只考虑与包含更改的节点对应的数据。不幸的是,增加比较次数的命令也可以用Scripthon编写。举例来说:Any()MethCall(Name=“someName”)这个脚本必须在源代码中的所有语句上运行,直到“someMethod”方法。如果此方法之前的代码很大,则必须再进行几次比较。而且,即使在 如果没有这样的方法。这意味着在最坏的情况下进行更多的比较再举一个例子:Block(Order=false)此命令标识块中的语句。但是如果语句顺序无关紧要,算法必须比较“Block”节点的所有子节点。如果第一个语句对应于最后一个语句,孩子,会有更多的比较。如果第二个语句对应于倒数第二个孩子,就会有更多的比较。总之,在最坏的情况下,可能会有更多的比较。为了评估所实现的优化是否有意义,该算法具有全局关闭优化的能力。如果我们注意到在启用优化的情况下实际发生了多少次比较,我们就获得了评估优化是否有意义的基础我们选择了一个项目,800个Java类作为测试样本。然后对这个项目进行了几次搜索迭代在禁用优化的情况下进行测试时,执行了节点142 275比较。另一方面,启用优化后,第一次运行(使用索引收集功能)与后续轮次(使用此索引)之间存在很大差异。在第一宗个案中,有28 268项比较,而在第二宗个案中,则有6 800项比较。可以看出,第二次比较的数字要低得多8. 结果在Windows 7操作系统、2.4 GHz CPU和8 GB内存的普通计算机上测试了算法的时间复杂度。使用的Java版本是1.7.0_51。为了展示我们的解决方案的真正好处,我们在禁用和启用优化的情况下执行了几个搜索过程。我们试图确定几个重要的部分,这些部分在当时可以反映整个工作的实际贡献。在没有优化的情况下,该算法通过“蛮力”方法在所有输入类上运行。在本例中,没有使用结果缓存和索引。我们将获得的时间与表1中的优化算法版本的时间进行了比较。表1时间表首轮没有优化优化Java编译时间38 469毫秒39 542毫秒Scripthon编译时间35毫秒33 Ms搜索时间962毫秒170毫秒总时间39 441毫秒39 924毫秒二轮没有优化优化Java编译时间0毫秒0毫秒Scripthon编译时间48毫秒44毫秒128TomáBublík and Miroslav Virius/IERI Procedia 10(2014)119搜索时间使用变化检测888毫秒68毫秒151毫秒15 ms总时间1 062毫秒208毫秒更改检测118 Ms62毫秒从表中可以看出,测量分两个阶段进行。第一个表显示了总是在算法的第一次运行中接收的时间。这两个表都有两列来指示时间是有优化还是没有优化。第一个显著的区别是第二次运行中不使用的编译时间。它为零,因为它不会在以后的运行中发生。下一行表示Scripthon代码编译过程的时间。因为搜索脚本之间没有显著差异,所以这些时间几乎相同。另一行显示自己的匹配过程。这两个时代有很大的不同。优化版本大约快5倍,然而,根据第一个表,这个时间完全损失在编译时间上。更糟糕的是,总时间甚至比没有任何优化的时间还要长!第二个表包含多一行。这一行显示了在以前运行中创建的索引的帮助下匹配过程的时间。在这个例子中,我们使用了这个脚本:Class()Any()Meth(Name=“add”)Init(Name=“errors”)对于以后的运行,唯一的变化是“Init”语句中的名称。在这种情况下,算法仅使用与“Meth(Name=“add”)”对应的节点。换句话说,该算法只考虑具有名为“add”的方法的类。可以看出,如果不需要再次编译整个源代码,并且如果算法具有从先前运行创建的索引,则匹配时间加速是巨大的。然后,整个过程只运行了运行相同任务所需时间的一小部分,没有任何改进。9. 结论我们的项目表明,源识别可以大大加快。对速度的重要贡献是缓存与语句对应的节点。尽管这种方法加快了过程,但是,必须说这只适用于进一步的运行。在第一次运行的情况下,源代码的编译需要大量时间。但仍有许多改进之处。例如,编译可以在脚本编写期间就开始。该项目展示了在可接受的时间内可编程和动态代码识别的可用性。目前,该项目仅用于科学目的,但我们希望添加所有解决方案,使其成为其他用户。我们还考虑使用树索引方法,以实现更高的速度的匹配过程中的未来。确认这项工作得到了捷克共和国教育、青年和体育部SGS 11/167/OHK 4/3 T/14赠款的支持。Tomas Bublik和Miroslav Virius/IERI Procedia 10(2014)119129引用[1] 托马斯·布布里克米罗斯拉夫·维留斯搜索Java代码段的新语言。In:ITAT 2012.第12届全国会议ITAT。2012年9月17日至21日。科希策的帕沃尔·约瑟夫·萨夫里克大学。第35页- 40.[2] 克里斯托夫-安德烈·M.伊尼格尔图形匹配-使用机器学习技术过滤图形数据库。2005年,ISBN 1-58603-557-6。[3] B.D. 麦凯实用图同构In Congressus Numerantium,volume 30,1981,pages 45[4] J.R.乌尔曼子图同构的一个算法。Journal of Association for Computing Machinery,1976,pages 31-42.[5] G.李维关于两个有向或无向图的最大公共子图的推导的注记。Calcolo,1972,第341-354页。[6] J·麦格雷戈回溯搜索算法与最大公共子图问题。软件-实践和经验,1982年,第23-34页。[7]G.A.斯蒂芬字符串搜索算法。世界科学,1994年。[8] H. Bunke和K.希勒基于最大公共子图的图距离度量。Pattern Recognition Letters,1998,第255-259页。[9] M.- L. Fernandez和G. Valiente.结合最大公共子图和最小公共超图的图距离度量。PatternRecognition Letters,2001,第753-758页。[10]W.D. Wallis,P. Shoubridge,M. Kraetz和D. Ray.使用图并集绘制距离。Pattern RecognitionLetters,May 2001,pages 701-704.[11]A. Sanfeliu和K.S. Fu.模式识别中属性关系图之间的距离度量。IEEE Transactions on Systems,Man,and Cybernetics,1983,353-363.[12]W.H. Tsai和K.S. Fu.用于模式识别的属性关系图的纠错同构。IEEE Transactions onSystems,Man,and Cybernetics,1979,pages 757-768.[13] M.A. Eshera和K.S. Fu.一种用于图像分析的图距离测度。IEEE Transactions on Systems,Man,andCybernetics,1984,pages 398-408.[14] E.K.黄。基于属性图的三维物体识别。In H. Bunke和A. Sanfeliu,编辑,句法和结构模式识别-理论和应用,世界科学,1990,第381-414页。[15] R.威尔逊和急诊室汉考克图谱特征的Levenshtein距离。在J. Kittler,M. Petrou和M.尼克松,编辑,Proc.第十七届国际模式识别会议,第2卷,2004年,第489-492页。[16] A.罗伯斯-凯利和急诊室汉考克从光谱序列化的图形编辑距离。IEEE Transactions on PatternAnalysis and Machine Intelligence,2005,第365-378页。[17] T. Caelli和S.科西诺夫基于特征子空间投影聚类的不精确图匹配。Int. Journal of Pattern Recognitionand Artificial Intelligence,2004,pages 329-355.[18] T. Caelli和S.科西诺夫一种用于不精确图匹配的特征空间投影聚类方法。IEEE Transactions onPattern Analysis and Machine Intelligence,2004,第515-519页。[19] Ch.K.罗伊,J.R. Cordy和R.科施克2009.代码克隆检测技术和工具的比较和评估:定性方法。Sci. Comput. 程序. 74,7(2009年5月),pp.470-495[20] I. D. Baxter,A.雅欣湖M. Sant'Anna和L.啤酒1998.利用抽象树进行克隆检测。在软件维护国际会议(ICSM '98)上。IEEE计算机协会,华盛顿特区,美国,pp。368-377.[21] R. Koschke,R.Falke,P. Frenzel.使用抽象后缀树进行克隆检测,逆向工程。2006年。WCRE'06。第13次工作会议,ISBN 0-7695-2719-1,2006年,第253-262页。[22] J. T. Yao和M.张某2004.一种快速的XML查询树模式匹配算法。在2004年IEEE/WIC/ACM网络智能国际会议(WI '04)上。IEEE计算机协会,华盛顿特区,美国,pp。235-241。[23]G. Valiente. 树和图上的算法Springer,ISBN 3540435506,2002,第170页。130TomáBublík and Miroslav Virius/IERI Procedia 10(2014)119[24]V. Wahler,D. Seipel,J. W. von Gudenberg和G.费舍尔基于频繁项集技术的源代码克隆检测。《骗局》,2004年。[25]R. Shamir,D.苏快速子树同构。在Journal of Algorithms,第33卷第2期,1999年,第267-280页,doi:10.1006/jagm.1999.1044中
下载后可阅读完整内容,剩余1页未读,立即下载
安全验证
文档复制为VIP权益,开通VIP直接复制
信息提交成功