是否有更快的"迭代二维数组比使用嵌套for循环的方法?

时间:2018-03-22 13:11:39

标签: java arrays for-loop

我编写了一个程序,用于加密和解密使用foursquare密码读入的文件。目前,我将文件存储到一个字符数组中,将其传递给一个将其分解为bigrams的函数,并使用另一个函数中的嵌套for循环对其进行加密。在这一点上,我基本上试图优化运行时间。有没有另一种方法来迭代二维数组我使用它不使用两个for循环,或者最多只使用一个for循环?以下是相关代码:

FileHandler.java

   import java.io.*;
    import java.util.*;

    public class FileHandler {
    private List<String> characters = new ArrayList<String>();
    public char fileToChar[];

    public void preEncryptionFile(String fileText) throws IOException {
        String line;

        FileInputStream fileReader = new FileInputStream(fileText);
        DataInputStream dataInputStream = new DataInputStream(fileReader);
        BufferedReader bufferedReader = 
               new BufferedReader(new InputStreamReader(dataInputStream));

        while ((line = bufferedReader.readLine()) != null) {
            characters.add(line);
        }

        String charsToString = characters.toString();

        charsToString = charsToString.replaceAll("[^a-zA-Z]", "").toUpperCase();

        fileToChar = charsToString.toCharArray();

        bufferedReader.close();
    }
}

FourSquareCipher.java

    import java.util.*;

    public class FourSquareCipher {
        List<Character> encryptionList = new ArrayList<Character>();
        List<Character> decryptionList = new ArrayList<Character>();

        private char[][] matrix = { 
                { 'A', 'B', 'C', 'D', 'E', 'Z', 'G', 'P', 'T', 'F' },
                { 'F', 'G', 'H', 'I', 'K', 'O', 'I', 'H', 'M', 'U' }, 
                { 'L', 'M', 'N', 'O', 'P', 'W', 'D', 'R', 'C', 'N' },
                { 'Q', 'R', 'S', 'T', 'U', 'Y', 'K', 'E', 'Q', 'A' }, 
                { 'V', 'W', 'X', 'Y', 'Z', 'X', 'V', 'S', 'B', 'L' },
                { 'M', 'F', 'N', 'B', 'D', 'A', 'B', 'C', 'D', 'E' }, 
                { 'C', 'R', 'H', 'S', 'A', 'F', 'G', 'H', 'I', 'K' },
                { 'X', 'Y', 'O', 'G', 'V', 'L', 'M', 'N', 'O', 'P' }, 
                { 'I', 'T', 'U', 'E', 'W', 'Q', 'R', 'S', 'T', 'U' },
                { 'L', 'Q', 'Z', 'K', 'P', 'V', 'W', 'X', 'Y', 'Z' } };

        public void encryptionBigram(char[] fileToText) {
            int i;
            char x, y;

            for (i = 0; i < fileToText.length - 1; i += 2) {
                x = fileToText[i];
                y = fileToText[i + 1];

                encryption(x, y);
            }
        }

        private void encryption(char x, char y) {
            int i, j;
            int a, b, c, d;

            a = b = c = d = 0;

            for (i = 0; i < 5; i++) {
                for (j = 0; j < 5; j++) {
                    if (x == matrix[i][j]) {
                        a = i;
                        b = j;
                    }
                }
            }

            for (i = 5; i < 10; i++) {
                for (j = 5; j < 10; j++) {
                    if (y == matrix[i][j]) {
                        c = i;
                        d = j;
                    }
                }
            }

            encryptionList.add(matrix[a][d]);
            encryptionList.add(matrix[c][b]);
        }
}

3 个答案:

答案 0 :(得分:2)

使用单个循环迭代2D数组。

更具体地说,此代码计算行&amp;基于当前指数和列的列子阵列的宽度。

这仅在子阵列具有固定长度/宽度时才有效。

我没有对此进行基准测试,因此我无法确定它是否比您目前的效率更高。检查第二个条件和开销的开销递增第二个变量可能与计算行和放大器相同(甚至更少)。列。

从不最少:

char[][] letters = {
    {'A', 'B', 'C'},
    {'D', 'E', 'F'},
    {'G', 'H', 'I'}
};

int width = 3;
int maxIndex = letters.length * width;
for(int i = 0; i < maxIndex; i++) {
    int row = i / width; // determines row
    int column = i % width; // determines column

    System.out.println("Value["+letters[row][column]+"] Row["+row+"] Column["+column+"]");
}

通过将索引(由i表示)除以宽度来确定行。由于上例中子数组的宽度为3

  • 如果索引为6,则行为2。
  • 如果索引为9,则行为3。
  • 如果索引为11,则行为3.66(仍为3)

该列由模运算确定。由于上例中的每个子数组的宽度都为3

  • 如果索引为6,则列为0。
  • 如果索引为9,则列为0。
  • 如果索引为11,则列为2。

答案 1 :(得分:1)

Asymptotically,没有什么可做的,因为你的程序仍有O(n)时间复杂度 - 它会读取每个字符并在每个字符的两个嵌套for循环中执行固定的50次迭代,加上其他一些固定时间的工作。由于你必须阅读所有输入,你不能渐渐变得更好。

但是,如果你想在某种程度上加速你的程序,那些嵌套for循环确实是开始的地方 - 在每一个中,你有效地执行查找 - 通过25个位置并寻找一个匹配,然后返回行和列。这可以通过创建Map来改进,该get()将每个字母映射到它的位置数据,并且 // assuming this fills the List List<Dictionary<string, string>> obj = this.getData(); List<Dictionary<string, string>> objCopy = new List<Dictionary<string, string>>(obj); 具有恒定的渐近时间复杂度。

答案 2 :(得分:1)

使用break;将允许您在匹配值时立即停止循环,而不是在找到并设置值后继续循环。当然,如果您的值在两个循环的末尾,则可能需要更长时间。如果您的值位于两个循环的前面,那么您基本上会删除所有额外的计算。您可以将映射更改为更高频率的字母,方法是将它们放置在循环中较早的位置。

    for (i = 5; i < 10; i++) {
        for (j = 5; j < 10; j++) {
            if (y == matrix[i][j]) {
                c = i;
                d = j;
                break; // Using break here allows you to do the minimum comparisons.
            }
        }
    }