数组技术(共7篇)
数组技术 篇1
0 引言
随着全三维数字设计产品数据管理技术的日渐成熟,三维机加工艺设计模型在实际生产应用中将逐步取代传统二维机加工艺图纸,实现对现场进行生产作业指导。基于数字化的三维机加工艺模型数据载体通常以轻量化演示文件格式进行存储并在专业演示软件中进行浏览,而演示文件的大小往往影响到三维机加工艺模型演示文件的数据管理难度与网络传输的效率,对工艺模型演示文件进行数据压缩成为其在应用中迫切需要解决的问题。在三维机加工艺模型中,大部分存储空间由几何模型数据占用,因此对三维机加工艺的几何模型的数据压缩显得尤为关键。针对三维CAD几何模型的压缩问题,国内外学者已进行了许多相关研究,例如文献[1]即通过对几何模型网格与顶点进行的简化。这些方法都是针对常规CAD模型提出的优化方案,而考虑到三维机加工艺的工序间模型存在大量重复三角面片的特点,通过对这些面片进行合理的重用往往可以有效地压缩三维机加工艺几何模型文件的大小。因此,本文将提出一种基于后缀数组的三维机加工艺几何模型的压缩方案,解决机加工艺演示文件的压缩问题。
1 几何模型STL文件格式与压缩方案
STL文件是当前CAD系统下较常用一种通用格式文件,其主要有文本文件(ASCII)和二进制文件2种格式[2]。实际应用时,由于ASCII文件格式占用空间较大,不适合模型轻量化文件的编码。本文主要介绍STL的二进制文件的组成方式,在STL二进制文件中保存的是模型的一个个三角面片的信息。文件的具体格式中起始部分存储着零件名称占80字节,接着是一个表示三角面片个数的4字节整数N,之后会有N组三角面片信息,每组三角面片信息由3个顶点数据,1个法向量数据,和三角面片属性数据组成,这些数据一共占用50个字节[3]。
对STL文件的轻量化压缩,已有许多经典解决方法,以下为2种较为常见的解决方案。
第1种压缩方式,是通过将STL文件里三角面片数据中的法矢量数据去除,进而为每个三角面片数据节省12字节的空间,虽然去除面片的法矢量可能会导致复杂表面的图形渲染效果下降,但是鉴于机械制造的零部件通常表面较规整,因此其对展示效果的影响是可以接受的。当数据加载后,需要对三角面片的法矢量进行补全,补全法矢量的方式是采用三角面片的是3个顶点直接计算该面片的外法矢量。外法矢量计算公式如下:
其中,为三维空间的法矢量,v1、v2、v3为三角面片的3个顶点坐标,且按逆时针分布。
第2种压缩途径是采用低空间占用的顶点索引来标记顶点的重复顶点,以节约文件存储空间[4],该方法常应用于GPU图形渲染等场景中。其方法是先将所有顶点去重排序后,保存为一个顶点序列,这样每个三维顶点就有唯一的4字节序列号,三角面片不再记录3个顶点的具体信息,直接记录3个4字节的索引序号,需要处理具体顶点时,再用顶点的索引序号在顶点序列中取出使用。由于三维零部件模型都是由封闭的几何面片构成,每个图形表面的网格顶点会被不少于3个不同的三角面片网格共用。以平均3个共享平面的下限计算,原本需要使用9个4字节的数据来记录着3个相同的顶点,而现在只需要3个4字节的数据记录顶点信息,同时用3个4字节的索引记录模型顶点的标号。因此该方案至少能实现顶点数据66.7%的压缩率,实际使用中,这个途径往往能达到40%以下的压缩率,可见该方案能有效地节约存储空间。
2 后缀数组
后缀数组是一种为文本索引设计的数据结构,该结构由记录了字符串的各个后缀的字典序索引的数组构成[5]。利用后缀数组的字典序特性可以快速实现字符串内相同连续子串的查找匹配问题。首先引入后缀数组相关定义。
定义1:1个n长字符串S的i后缀Suffix(S,i)指字符串S以第i个元素为起始字符的后缀,即Suffix(S,i)=SiSi+1Si+2…Sn[6]936。
定义2:1个n长字符串S的后缀数组SA指S所有后缀字典序排序后其索引构成的数组,即SA是1个由1~n排列构成的数组,且i<j时,满足Suffix(S,SA(i))<Suffix(S,SA(j))[6]936。
定义3:排序数组rank(i)指后缀Suffix(S,i)在后缀数组中的排序位置,即有SA(rank(i))=i。
定义4:对字符串S1与S2,定义lcp(S1,S2)指字符串S1与S2的最长公共前缀的长度[6]936。
定义5:对字符串S,定义height(i)表示SA(S)的i与i+1索引指代后缀的最长公共前缀长度,即height(i)=lcp(Suffix(S,SA(i)),Suffix(S,SA(i+1)))[6]936。
如表1所示为字符串S=aazbcbbcbcaa的后缀数组。
后缀数据的构造求解算法有许多,包括倍增算法、诱导拷贝算法与分治和递归算法[7]。本文主要介绍后缀数组的倍增算法的主体思想。
后缀数组的倍增算法过程:首先以每个后缀的第一关键字按计数排序的方式排序;之后假设当前索引数组已经完成n个字符串后缀按L长前缀为关键字的排序过程,再构造2L长前缀为关键字排序的索引数组,由于所有后缀串的L长前缀的排序已经完成,因此对于任意后缀Suffix(S,i)将其L长前缀排序位置作为第一关键字,而将后缀Suffix(S,i+L)的L长前缀的排序位置作为Suffix(S,i)的第二关键字,进行基数排序,通过这次基数排序索引数组可以完成n个后缀串的2L长前缀为关键字的排序,通过反复这个倍增过程最终获得所有后缀串的排序。因为,基数排序过程可以在O(n)的时间复杂度内完成,加之倍增过程恰有[log2n]次,所以整个过程的时间复杂度为O(nlog n)。
文献[8]介绍一种线性时间复杂度求解height数组的算法。改算法基于一个关于height数组的性质,当height(rank(i))=h时,height(rank(i+1))≥h-1。该算法流程如图1所示,该算法时间复杂度为O(n)。
3 机加工艺工序间模型压缩
3.1 机加工艺工序间模型文件原始编码
机加工艺通常由多个工序过程构成,每个工序会对上一步工序产生的零件物理模型做进一步的再加工而产生新的零件物理模型,通常将这些在整个机加工艺过程间各个过渡零件物理模型称为机加工艺的工序间模型。因此,一个三维机加工艺模型所包含的所有物理几何模型集合是从毛坯模型到加工零件成品模型的一系列工序间模型构成的。
参考传统STL格式文件的编码方式,本文对机加工艺工序间模型数据轻量化文件采用如下编码格式如图2所示。文件中起始部分是文件头,其中记录模型名称与工序间模型数量N这2个信息;紧接着是顶点数据段,存放所有工序间模型所涉及的顶点信息,其起始由4个字节的整型数据储存所有工序间模型包含的不同顶点数量,若一共有K个不同的顶点,那么接下来文件中依次存放K个浮点数三元集表示各个顶点的空间位置;再紧接着是工序间模型三角面片数据段,由N段数据块组成,每段数据块即一个工序间模型的三角面片数据,其中每段数据的起始4个字节是一个整型数据表示接下来有多少组三角面片数据组,每个三角面片数据组由3个整型顶点索引构成,每个整型索引代表顶点信息段中的对应顶点,3个顶点构成一个三角面片。
由于机加工艺中,其每一步工序只会在上一步工序产生的工序间模型基础上改变部分几何表面特征,而几何模型的大部分表面信息并没有发生变化,这使得相邻的工序间模型间存在大量相同的三角面片段,因此上述轻量化文件中的工序间模型三角面片数据段存在大量重复的数据片段。如果对这些重复的三角面片段数据信息进行合并,可以实现对机加工艺模型轻量化文件的进一步压缩。
3.2 重复数据段匹配
实现工序间模型的重复三角面片数据段压缩,首先要解决的是如何快速查找并匹配出相邻工序间模型的重复三角面片段。由于在轻量化文件中工序间模型的三角面片数据信息是由一串串索引序列组成,因此,相邻工序间模型的重复三角面片段匹配问题可以转换为2个字符串之间查找匹配重复连续子串的问题。
3.2.1 朴素匹配方法
该问题最简单的朴素求解方法是采用逐一匹配的方式完成。其具体过程是通过枚举2个待匹配字符串的起始位置,用指针依次匹配以该起始位置开始的后续字符串位置,直到不能匹配为止。对于长度为L1和L2的2个字符串,一共有L1·L2个起始匹配位置,每个起始位置最坏匹配min(L1,L2)个字符,因此该暴力算法的时间复杂度为O(L1·L2·min(L1,L2))。虽然对字符串长度在几百范围内的情况,这个算法在现代计算机上完全可以在很短的时间内解决,但是考虑到本文中编码构成的字符串是由几何模型三角面片的节点生成的,且工艺模型的三角面片常常出现数千至上万的级别,而在103~104的数量级上,该暴力算法会出现十分严重退化,往往运算时间会上升至几分钟甚至更多。
为了有效优化匹配效率,下文将利用后缀数组的方式来降低匹配过程的时间复杂度,从而实现高效的重复三角面片数据段匹配。
3.2.2 基于后缀数组算法的重复数据片段快速匹配
利用后缀数组进行工序间模型的重复三角面片数据段的快速匹配。首先将工序间模型的顶点索引序列视为字符串,每次匹配发生于相邻2个工序间模型之间,即如果总共有k+1个工序间模型,则需进行k次重复面片模型匹配。同时,在匹配过程中为了能使用基数排序算法,将所有顶点索引序号重映射至[0,N)的连续区间上。
匹配前先将待匹配的2个顶点序列串前后相连,并在相连接处加入不在区间[0,N)内的特殊序号$进行分割,即如带匹配的工序间模型顶点序列为sa与sb,则进行后缀数组运算的序列为s=sa+$+sb。其中,之所以加入特殊符号$是由于s的连续子串中包含由sa后缀串与sb前缀串组成的序列串,而这个序列串在sa与sb中都不存在,但这种本不存在的字符串会影响2个字符串间height数组的结果;因此加入特殊序号符$以保证height数组匹配出的最长公共前缀不会出现跨越sa与sb的情况。然后利用上述后缀数组的相关算法计算获得顶点序列s的SA数组、rank数组以及height数组。
根据所计算出的后缀数组相关信息,利用贪心算法,寻找顶点序列sb中在序列sa中出现的重复子序列。设sa与sb序列的长度分别为la与lb,其具体算法流程如下:
根据上述方法进行复杂度分析,后缀数组相关计算在O(Nlog N)的时间复杂度内完成,而上述过程最坏情况下也可O(N2)的时间复杂度内完成,因此2个相邻工序间模型的重复顶点子序列匹配可在O(N2)复杂度内完成。
实际上,上述贪心的匹配过程还存在优化的空间,其中STEP 06与STEP 08对应的过程可以在贪心算法开始前对SA数组进行扫描并预处理出每个下标对应的最近满足SA(i)<la的位置,这样贪心过程的STEP 06与STEP08可以降为O(1)的时间复杂度,同时在STEP 07与STEP 09处采用线段树等高级数据结构,可以将STEP 07与STEP 09的单次计算时间复杂度降为O(log N)甚至更低。因此,进行适当优化,该贪心算法时间复杂度可降为O(Nlog N)。但是出于本课题的应用场景字符串长度只在一般不超过104的数量级上,O(N2)复杂度已经十分有效。
3.3 重复数据段压缩编码与解压
新的数据编码方式在文件头与定点信息段部分采用3.1节所述原始编码方式进行数据编码。对于工序间模型三角面片数据段进行如下压缩编码,首先第一组工序间模型数据段与原始编码方式一致,其内容不变;当第k组工序间模型编码完成后,对第k+1组工序间模型进行压缩编码,其初始4个字节的整型数据依旧是该工序间模型所包含三角面片数量,接下来的三角面片数据段依次检测每一个索引字符,如果该索引字符在匹配中没有出现则正常写入文件,否则检测匹配段在第k组工序间模型中对应的匹配区间时,就不再写入该区间数据,而是直接用该区间的起始终止索引代替这段数据,例如第k+1个工序间模型三角面片段中[L1,R1]区间与第k个工序间模型三角面片段中[L0,R0]区间相同,那么在构造压缩文件时第k+1组工序间模型的三角面片数据在写到[L1,R1]区间时直接以2个4字节整型数据{-L0,-R0}代替,之所以采用负数,是为了区分该数据是索引还是区间序号。通过这个方法扫描一遍原始轻量化文件数据,即可获得压缩后的数据文件。
利用该方式压缩的工序间模型三角面片数据解压缩过程非常简单,通过依次扫描各个工序间模型的三角面片数据段,将压缩后的三角面片数据中的代表区间序号的数据用上一个工序间模型三角面片段对应区间中的数据填充,即可完成解压过程。
4 实验论证
为了验证所述工序间模型三角面片段重用方案的有效性,本文挑选了5个轻量化机加模型案例,分别采用经典压缩方法与三角面片段重用方法进行实验测试。表2为实验结果。
从表中不难看出,本文方法能有效地对原模型文件进行压缩,平均能将原始模型压缩至16%左右,尤其是针对模型文件较大较复杂的情况下,其优化效果更加明显。进一步分析发现这些模型工序较多,重复三角面片段出现的概率更大,因此优化效果更佳。
通过实验结果可以判断,本文所述三角面片重用方法是有效的。
参考文献
[1]Schroeder William J.,Zarge Jonathan A.,Lorensen William E.Decimation of Triangle Meshes[J].ACM SIGGRAPH Computer Graphics.1997,26(2):65-70.
[2]张贞贞,陈定方.基于VC的STL文件读取[J].湖北工业大学学报,2008,23(2):44-46.
[3]严梽铭,钟艳如.基于VC++和Open GL的STL文件读取显示[J].计算机系统应用,2009(03):172-175.
[4]朱林,常名.计算机图形学[M].Lin Zhu,Ming Chang,译.武汉:华中科技大学出版社,2001.
[5]张长利,赫枫龄,左万利.一种基于后缀数组的无词典分词方法[J].吉林大学学报(理学版),2004(04):548-553.
[6]Manber Udi,Myers Gene.Suffix arrays:A new method for on-line string searches.SIAM Journal on Computing.1993,22(5):935-948.
[7]张喜娟.基于后缀数组的近似字符串匹配[D].西安:西安电子科技大学,2012.
[8]Cormen T.H.算法导论[M].北京:机械工业出版社,2006.
数组排序算法浅析 篇2
顺序排序的主要思想是每一轮比较结束后都可以确定某一元素;在一轮的比较过程中, 将要确定的位置上的元素与其后所有的元素进行比较;对于一个长为N的数组, 需进行N-1轮比较。其第一轮的比较过程如下:
该轮中, a[0]与a[1]~a[n-1]的所有元素进行比较, 比较过程中, 如果发现哪个元素比a[0]小, 则与a[0]进行交换。一轮比较之后, 确定a[0]为数组中最小的元素。相同方法, 依次确定a[1]、a[2]、a[3]…a[n-2]。
由上表, 可以写出其实现代码
可以发现当数组原有的顺序是降序, 要实现其升序排序时, 每一轮中的交换的次数将会非常多, 严重影响排序效率。所以对该方法进行改进:先找出数组中最小值, 再与相应位置上的元素进行交换, 这就是选择排序。
选择排序的主要思想是每次从待排序的数据元素中选出最小的一个元素, 放在待排序数列的起始位置, 直到全部待排序列的数据元素全部排列完毕。
第一轮的比较过程如下:
选择排序的实现代码
选择排序相较于顺序排序有更高的执行效率, 而且思想同样利于理解。
冒泡排序的主要思想是“相邻元素”之间的比较, 如果前面的元素大于后面元素就把他们互换。一轮比较之后可以确定最后一个元素为最大, 第二轮比较之后可以确定最后一个元素为第二大的元素……依次类推, 第N-1轮比较, 可以确定倒数第二个元素, 这个时候数组的排序完成。冒泡排序的过程如下:
冒泡排序的实现代码
顺序排序算法, 思想简单易于理解且适于任何的数组, 无论什么情况下都可以使用;但是顺序排序效率较低, 可以采用选择排序法进行改进;即使如此选择排序的效率依然受到比较次数的影响, 所以对于比较元素比较少的数组, 可以采用冒泡排序法。
如果数组中99%的数值已经排序好, 即只有很少的元素需要进行排序, 可以选择冒泡排序法;如果你所要排序的数据数目相对较少并满足100个以下, 你就可以采用选择排序法;如果上述几种情况都不满足, 那么就选普遍适用的排序算法即顺序排序法即可。
以上所述只是三种常见排序, 在众多的排序算法中各有优缺点, 每一种算法只有在某一种情况下才表现的最好, 我们应当合理的根据实际情况选择算法。
参考文献
[1]张巍.基于Page Rank算法的搜索引擎优化策略研究[D].四川大学, 2005.
[2]郭敏杰.基于云计算的海量网络流量数据分析处理及关键算法研究[D].北京邮电大学, 2014.
C语言数组状态研究 篇3
关键词:C语言,数组,元素
1 整型数组状态分析
1.1 整型数组初始化后的状态分析
以下代码在定义一维整型数组时初始化部分元素, 并输出全部单元的值。
在编译系统下运行, 输出结果如下:
1 2 0 0
结果分析:对一维整型数组中的部分元素初始化, 未初始化的元素自动赋为0值。
以下代码在定义二维整型数组时初始化部分元素, 并输出全部单元的值。
输出结果如下:
结果分析:二维数组和多维数组从本质上来说, 就是一维数组, 只不过这类一维数组的每个元素也是一个数组而已。比如此二维数组实际是含有三个元素的一维数组, 每一行是它的一个元素, 每个元素又是一个一维数组。
1.2 给整型数组元素赋值后的状态分析
给整型数组中的部分元素赋值后, 对其他未赋值元素不产生影响, 保持原值。
1.3 输入数据给整型数组元素后的状态分析
为整型数组中的部分元素输入数据后, 对其他元素不产生影响, 保持原值。
2 浮点型数组状态分析
2.1 浮点型数组初始化后的状态分析
以下代码在定义一维浮点型数组时初始化部分元素, 并输出全部单元的值。
结果分析:对一维浮点型数组中的部分元素初始化, 未初始化的元素自动赋为0.000000, 这和整型数组类似。
2.2 给浮点型数组元素赋值后的状态分析
给浮点型数组中的部分元素赋值后, 对其他未赋值元素不产生影响, 保持原值。
2.3 输入数据给浮点型数组元素后的状态分析
为浮点型数组中的部分元素输入数据后, 对其他元素不产生影响, 保持原值。
3 字符数组状态分析
3.1 字符数组初始化后的状态分析
以下代码在定义一维字符数组时初始化部分元素, 并输出全部单元的值。
结果分析:对一维字符数组中的部分元素初始化, 未初始化的元素自动赋为空字符 (即'