将整数拆分为数字的最快方法是什么?

2023-12-06

我做了很多操作,将数字分割成单独的数字,将数字放入 ArrayList 中,并将这些数字一个接一个地传递到其他 ArrayList 进行进一步操作,直到 tempList 为空 - 然后进入下一个比前一个更大的数字。

我想知道哪种方法更快。

两种方法的共同部分:

// Split number into digits and put into array
BigInteger number; // the number can be very big => BigInteger
ArrayList<Integer> tempList = new ArrayList<>();
while (number.compareTo(BigInteger.ZERO) == 1) {
   tempList.add((number.mod(BigInteger.TEN)).intValue());
   number = number.divide(BigInteger.TEN);
}

然后我可以通过两种方式将这些数字一一传递到另一个 ArrayList 主列表,然后删除它们: 方式一:

// reverse the tempList (as digits are put there backwards) and take the first elements
Collections.reverse(tempList);
while (!tempList.isEmpty()) {
    mainList.add(tempList.get(0);
    tempList.remove(0);
}

Way 2:

// take the last elements
while (!tempList.isEmpty()) {
    mainList.add(tempList.get(tempList.size()-1);
    tempList.remove(tempList.get(tempList.size()-1);
}

哪种方式更快?考虑到这是数十亿次操作,数十亿个数字被拆分和相加。我认为像 Collections.reverse() 这样的方法需要更多时间,但我只在每次用下一个数字的新数字更新 tempList 时调用它。但在方式 2 中,我对每个操作都调用 .size()-1 操作。

而且数字越大 - 更新 tempList 和从中获取数字之间的差距就越大(显然),因此 .reverse() 方法调用就越少。 数字从 1 开始,一直到无穷大。

tempList 的存在是有原因的,所以请不要建议绕过它。

附加问题:测量此类事物的最佳实践是什么?


警告。这里涉及一些问题。

事实上,有两个问题混合在一起:

  • 如何以相反的顺序将数据从一个列表传输到另一个列表?
  • 如何从 a 创建数字列表BigInteger?

我同意罗曼·C 的评论: “从一个列表移动到另一个列表是没有用的”。至少,在这种情况下,似乎没有什么用处。但如果有什么事情发生tempList,并且从一个列表中删除元素并将它们添加到另一个列表(一个接一个)的一般方法在任何方面都是合理的,那么如何提高这种特定情况下的性能的问题可能仍然是可行的。


关于如何将数据从一个列表传输到另一个列表的核心问题,以相反的顺序:

令人惊讶的是,按照现在写的形式,

...第二个片段是far比第一个慢!

(解释如下)

像这样的简单测试可以比较这两种方法。 (当然,像这样的“微基准测试”应该持保留态度,但由于这里的性能与渐近运行时间相关,所以这是合理的)

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Locale;
import java.util.Random;

public class BigIntegerDigitsPerformanceLists
{
    public static void main(String[] args)
    {
        testListConversion();
    }

    private static void testListConversion()
    {
        long before = 0;
        long after = 0;

        for (int size = 10; size <= 1000000; size *= 10)
        {
            List<Integer> inputA = createRandomList(size);
            List<Integer> inputB = createRandomList(size);

            before = System.nanoTime();
            List<Integer> resultA = convertA(inputA);
            after = System.nanoTime();
            System.out.printf(Locale.ENGLISH,
                "A: size %8d time %8.2fms result %d\n",
                size, (after-before)/1e6, resultA.get(0));

            before = System.nanoTime();
            List<Integer> resultB = convertB(inputB);
            after = System.nanoTime();
            System.out.printf(Locale.ENGLISH,
                "B: size %8d time %8.2fms result %d\n",
                size, (after-before)/1e6, resultB.get(0));
        }
    }

    private static List<Integer> createRandomList(int size)
    {
        List<Integer> result = new ArrayList<Integer>();
        Random random = new Random(0);
        for (int i=0; i<size; i++)
        {
            result.add(random.nextInt(10));
        }
        return result;
    }


    private static List<Integer> convertA(List<Integer> list)
    {
        List<Integer> result = new ArrayList<Integer>();
        Collections.reverse(list);
        while (!list.isEmpty())
        {
            result.add(list.get(0));
            list.remove(0);
        }
        return result;
    }

    private static List<Integer> convertB(List<Integer> list)
    {
        List<Integer> result = new ArrayList<Integer>();
        while (!list.isEmpty())
        {
            result.add(list.get(list.size() - 1));
            list.remove(list.get(list.size() - 1));
        }
        return result;
    }
}

我的机器上的输出是

A: size       10 time     0.08ms result 4
B: size       10 time     0.05ms result 4
A: size      100 time     0.13ms result 1
B: size      100 time     0.39ms result 1
A: size     1000 time     1.27ms result 6
B: size     1000 time     2.96ms result 6
A: size    10000 time    39.72ms result 1
B: size    10000 time   220.82ms result 1
A: size   100000 time  3766.45ms result 7
B: size   100000 time 21734.66ms result 7
...

But....

这是由于方法调用错误造成的。第二种方法包含行

list.remove(list.get(list.size() - 1));

这就是本例中的罪魁祸首:你有一个列表Integer对象。而你正在呼唤remove,传入一个Integer目的。此方法将搜索整个列表,并删除第一次出现的参数。这不仅很慢,而且还会导致结果明显错误!

你真正想要做的是删除最后一个元素,使用index最后一个元素的。所以将这一行更改为

list.remove((int)list.size() - 1);

给出了完全不同的计时结果:

A: size       10 time     0.08ms result 4
B: size       10 time     0.03ms result 4
A: size      100 time     0.13ms result 1
B: size      100 time     0.10ms result 1
A: size     1000 time     1.28ms result 6
B: size     1000 time     0.46ms result 6
A: size    10000 time    39.09ms result 1
B: size    10000 time     2.63ms result 1
A: size   100000 time  3763.97ms result 7
B: size   100000 time     9.83ms result 7
...

因此,如果实施得当,那么

...第一个片段是far比第二个慢!

由于以下原因Eran在他的回答中提到.


关于如何从a创建数字列表的问题BigInteger:有几个可能的性能改进。

手动提取数字,使用一系列%= 10 and /= 10通话速度很慢。避免模​​运算已经带来了小幅加速。所以而不是

digit = number % 10;
number = number / 10;

你可以做

nextNumber = number / 10;
digit = number - (nextNumber * 10);
number = nextNumber;

但由于其不变性BigInteger和昂贵的除法,这仍然比简单地转换要慢几个数量级BigInteger到一个字符串中,并从那里提取数字,如dasblinkenlight 在他的回答中建议.

一个简单的比较:

import java.math.BigInteger;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
import java.util.Random;

public class BigIntegerDigitsPerformance
{
    public static void main(String[] args)
    {
        testListCreation();
    }

    private static void testListCreation()
    {
        long before = 0;
        long after = 0;

        for (int size = 10; size <= 100000; size *= 10)
        {
            BigInteger number = createRandomBigInteger(size);

            before = System.nanoTime();
            List<Integer> resultA = createA(number);
            after = System.nanoTime();
            System.out.printf(Locale.ENGLISH,
                "A: size %8d time %8.2fms result %d\n",
                size, (after-before)/1e6, resultA.get(0));

            before = System.nanoTime();
            List<Integer> resultB = createB(number);
            after = System.nanoTime();
            System.out.printf(Locale.ENGLISH,
                "B: size %8d time %8.2fms result %d\n",
                size, (after-before)/1e6, resultB.get(0));

            before = System.nanoTime();
            List<Integer> resultC = createC(number);
            after = System.nanoTime();
            System.out.printf(Locale.ENGLISH,
                "B: size %8d time %8.2fms result %d\n",
                size, (after-before)/1e6, resultC.get(0));
        }
    }


    private static BigInteger createRandomBigInteger(int size)
    {
        StringBuilder sb = new StringBuilder();
        Random random = new Random(0);
        for (int i=0; i<size; i++)
        {
            sb.append(String.valueOf(random.nextInt(10)));
        }
        return new BigInteger(sb.toString());
    }


    private static List<Integer> createA(BigInteger number)
    {
        ArrayList<Integer> list = new ArrayList<Integer>();
        while (number.compareTo(BigInteger.ZERO) == 1)
        {
            list.add((number.mod(BigInteger.TEN)).intValue());
            number = number.divide(BigInteger.TEN);
        }
        return list;
    }

    private static List<Integer> createB(BigInteger number)
    {
        ArrayList<Integer> list = new ArrayList<Integer>();
        while (number.compareTo(BigInteger.ZERO) == 1)
        {
            BigInteger next = number.divide(BigInteger.TEN);
            BigInteger diff = number.subtract(next.multiply(BigInteger.TEN));
            list.add(diff.intValue());
            number = next;
        }
        return list;
    }

    private static List<Integer> createC(BigInteger number)
    {
        String s = number.toString();
        ArrayList<Integer> list = new ArrayList<Integer>(s.length());
        for (int i=s.length()-1; i>=0; i--)
        {
            list.add(s.charAt(i) - '0');
        }
        return list;
    }
}

输出将类似于:

...
A: size     1000 time     9.20ms result 6
B: size     1000 time     6.44ms result 6
C: size     1000 time     1.96ms result 6
A: size    10000 time   452.44ms result 1
B: size    10000 time   334.82ms result 1
C: size    10000 time    16.29ms result 1
A: size   100000 time 43876.93ms result 7
B: size   100000 time 32334.84ms result 7
C: size   100000 time   297.92ms result 7

表明toString方法比手动方法快一百倍以上。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

将整数拆分为数字的最快方法是什么? 的相关文章

随机推荐

  • 为什么“ps”中没有出现“echo”?

    我很难理解 ps 命令上显示的内容 为了测试我的理解 我创建了下面的虚拟脚本 bin bash for i in 1 100000 do date u date u date u done 运行此脚本时 我打开了一个新终端并重复执行 ps
  • Ajax 响应:[readyState:0,responseText:“”,状态:0,statusText:“错误”]

    我的 ajax 调用导致错误 这是我可以在错误回调中获得的信息 readyState 0 responseText status 0 statusText error 这意味着什么 我究竟做错了什么 这是我的 ajax 调用 var aja
  • 使用where条件创建唯一索引

    现在我有下面的用户表 并且希望电子邮件列在 id 有前缀时唯一auth0 column id text email text not null 所以我尝试了这个CREATE UNIQUE INDEX陈述 CREATE UNIQUE INDE
  • 如何使图像适合框架,保持纵横比并在缩略图列表中居中

    我想将列表缩略图框显示为数据网格 每个缩略图必须放置在具有特定宽度和高度的框架中 为了一致性 如下所示 div class frame img src img1 jpg div div class frame img src img2 jp
  • PHP 中如何将数组元素转换为字符串?

    如果我有一个包含对象的数组 a array objA objB 每个对象都有一个 toString method 如何将所有数组元素转换为字符串 以便数组 a除了它们的字符串表示之外不再包含任何对象 是否有单行或我必须手动循环数组 一行 a
  • Golang 写入输入并从终端进程获取输出

    我有一个关于如何从终端子进程 例如 ssh 发送输入和接收输出的问题 python 中的一个例子是这样的 如何为子进程提供密码并同时获取标准输出 我在 Golang 中找不到与上述工作方式类似的简单示例 在 Golang 中 我想做这样的事
  • Delphi 10.3.3 未能通过 macOS 公证

    我的程序在Delphi 10 3 2中经过公证 但在10 3 3中失败 PAClient 退出并显示代码 1 是否有日志可以帮助我诊断问题 如果是这样 我该如何找到它 这是之后的整个错误 Connecting to 192 168 1 23
  • 为什么 int[] 上的 Arrays.asList 返回 List,而不是 List

    考虑这段代码 int tcc 1 2 3 ArrayList
  • Javascript 设置打印样式表

    如何修改打印样式表对象的样式 我正在使用 jQuery 如果这有帮助的话 我基本上想设置一个对象的 css 属性 但该属性仅适用于打印 而不适用于屏幕 例如 myobject css background white print 这个问题有
  • 如何使用timeit模块

    我该如何使用timeit比较我自己的功能的性能 例如 insertion sort and tim sort 如果你想使用timeit在交互式 Python 会话中 有两个方便的选项 Use the IPython壳 其特点是方便 time
  • 从轮廓中删除图例

    这是从R获得的图片 代码如下 我想将其导出为 PDF 格式 不过 我想首先删除右侧的图例栏 据我所知 没有可选参数来控制这个条形图例 你会怎么做 library gplots f lt function x y theta num lt x
  • SimpleDateFormat 抛出 ParseException 错误偏移量为 0

    下面的代码有什么问题 它抛出一个 ParseException 错误偏移量为 0 final DateFormat df new SimpleDateFormat EEE MMM dd HH mm ss yyyy df parse Thu
  • PrimeFaces p:editor 基于什么?

    我想向 PrimeFaces 添加一些客户端功能p editor 但由于某种原因 我无法发现他们用来构建组件的 JavaScript 客户端代码 有人能指点我吗 附 我想做的两件事是使组件可调整大小 PrimeFaces 不支持 并且我想添
  • 多态性和接口 - 澄清?

    迂腐的问题 根据维基百科多态性有 3 种类型 特设多态性 指的是可以应用于参数的多态函数 不同的类型 但根据类型的不同 其行为也不同 它们所适用的论点 换句话说 重载 function Add x y Integer Integer fun
  • 减去 Pandas 或 Pyspark Dataframe 中的连续列

    我想在 pandas 或 pyspark 数据框中执行以下操作 但我仍然没有找到解决方案 我想从数据框中的连续列中减去值 我所描述的操作如下图所示 请记住 输出数据帧的第一列不会有任何值 因为输入表中的第一列不能被其前一列减去 因为它不存在
  • 如何使用 gfortran-10 构建 MPICH?

    TL DR 如何使用 gfortran 10 gcc 10 和 g 10 构建 MPICH 背景 我想用 grortran 10 构建 MPICH以便能够使用最新的 MPI 绑定 但我还没能做到 尝试在 Ubuntu 上通过 apt 安装
  • 是否有相当于“az rest”的PowerShell?

    我最近发现了az rest命令 它允许我执行经过身份验证的 REST 命令 而不必担心获取令牌 https www codeisahighway com native azure rest api calls now available i
  • Google OAuth Android 的重定向 url

    从未真正使用过 OAuth 现在尝试实现它 我想从 google 和 facebook 获取访问令牌和配置文件数据 使用 Xamarin Auth 使用 Facebook 没有问题 我指定 http www facebook com con
  • boost图形库定向多图edge_range错误

    我有一个有向多重图 其顶点为 A C 边为 E1 E4 A E1 gt B A E2 gt B A E3 gt B B E4 gt C 我想迭代连接 A 和 B 的边 在 BGL 中 我将其表达为 include
  • 将整数拆分为数字的最快方法是什么?

    我做了很多操作 将数字分割成单独的数字 将数字放入 ArrayList 中 并将这些数字一个接一个地传递到其他 ArrayList 进行进一步操作 直到 tempList 为空 然后进入下一个比前一个更大的数字 我想知道哪种方法更快 两种方