在previous question中讨论了部分代码优化问题并获得了一些底层改进之后,@ SergGr建议我创建一个新问题以尝试进行高层改进并达到我的主要目标目标。
在我的代码中,我必须在“加扰的” square-1 puzzle对象中应用一些动作,然后检查它是否已解决。当我发现better implementation of a square-1 puzzle object around internet时,便将其用于我的Android应用程序中。
然后,如您所见,class由四个简单数字(integer
)字段构成:
var ul = 0x011233
var ur = 0x455677 //continuation of ul
var dl = 0x998bba
var dr = 0xddcffe //continuation of dl
这些字段表示Square-1拼图的“部分”,其中hexadecimal
表示形式中的每个数字都是这些部分之一(两位数字,例如11
,33
, bb
...表示多维数据集的相同“部分”,其中“较大”部分)。
正如你所看到的那样,一些通过拼图来表示真实动作的操作是使用该数字进行的,但最多只能通过其位进行排列。
在我的应用程序中,我必须检查难题是否已解决,但就我的情况而言,已解决状态不一定等于原始字段。当我们谈论Rubik的Cube变体时,可以移动面孔,我们可以拥有一个已解决的状态,例如(ul +“” + ur):[112334 556770]
,[233455 677011]
,[455677 11233*]
等上。
Obs .:注意前导零...
然后,我想到了一种简单的算法,可以通过使用固定的求解序列(但使用Strings
)查找循环排列来检查求解状态。但是,经过一些测试后,我意识到使用Strings
进行这项工作会使我的应用程序运行得如此缓慢,以至于我不得不在一个大循环中多次调用此检查。
String
(在本例中为十六进制字符串); ul+ur
):s = "011233"+"455677"
; ul+ur
):t = "233455"+"677011"
; s+s
,则检查是否可以在t
内找到"011{233455677011}233455677"
,然后isSolved()
检查是否返回true
。基本上,我的应用程序的核心代码是这个,然后检查是否像这样解决难题:
for (sequence in sequences) { //814*814 elements
auxCube.applySequence(sequence.seq) //applies the current sequence to the auxiliary cube
if (auxCube.isSolved()) { //checks if it was solved
searches.add(Search(sequence.seq)) //adds the sucess in a list
}
auxCube.copy(oldCube) //back test cube to initial state to continue finding sequences
}
如您所见,这里仅使用了我创建的2个功能。我将在下面介绍方法applySequence()
。
applySequence()
方法我自己制作了此方法,将格式化的序列应用于Square-1拼图对象。一旦这个谜题的正式序列由一些字符组成(看起来像:“ (1, 2) / (6, -3) /
”,我就采取了一些步骤来提取数字,然后移动立方体。看起来像:
fun applySequence(sequence: String) {
//remove all "(", ")", "," and " " characters and split in each "/"
val pairs = sequence.replace(" ", "").replace("\\(", "").replace("\\)", "").split("/")
//if starts with / then perform respective move
if (sequence.startsWith("/")) slashMove()
//iterate over pairs
for (pair in pairs) {
//checks if pair is not empty
if (pair != "") {
//split pair in the "," character
val pairMoves = pair.split(",")
//perform top and bottom moves with extracted numbers
move(true, Integer.parseInt(pairMoves[0]))
move(false, Integer.parseInt(pairMoves[1]))
slashMove()
}
}
//if sequence not ends with / then applies respective move
if (!sequence.endsWith("/")) slashMove()
}
这种方法非常简单,但是考虑到它使用了String
和concat()
之类的contains()
操作,因此在Android中的循环性能降低了60万倍。
尝试优化之后,我意识到最好的方法之一是按位操作,这种操作是作者对原始代码进行的操作,但是我无法弄清楚。
作为有关该问题的额外信息,如果我删除对isSolved()
方法的调用,那么最终的搜索时间将在20~30 seconds
中减少。
然后,如何通过比特比特化来执行isSolved()
操作,以便在大的for循环中更轻便地工作(针对Android)?
答案 0 :(得分:0)
您可以通过按位运算检查两个值是否彼此循环移位。
您的值是6个字节(48位长度)的值,因此我们可以将它们打包在64位long
中,然后对一个值进行低48位的循环旋转,并检查与另一个值的一致性。
import java.util.*;
import java.lang.*;
import java.io.*;
class Ideone
{
public static void main (String[] args) throws java.lang.Exception
{
long a = (0x011233l) << 24 | 0x455677;
long b = (0x233455l) << 24 | 0x677011;
System.out.printf("a: %x b: %x \n", a, b);
if (b == a)
System.out.printf(" bingo at zero digits shift \n");
for (int sh=4; sh<48; sh+=4) {
long bb = (b >> sh)|((b << (64 - sh))>>16);
System.out.printf("rotated %d bits bb: %x \n", sh, bb);
if (bb == a)
System.out.printf(" bingo at %d digits shift \n", sh/4);
}
}
}
a: 11233455677 b: 233455677011
rotated 4 bits bb: 123345567701
rotated 8 bits bb: 112334556770
rotated 12 bits bb: 11233455677
bingo at 3 digits shift
rotated 16 bits bb: 701123345567
skipped
rotated 44 bits bb: 334556770112