将整数分为数字的最快方法是什么?
我进行了很多操作,将数字分为单独的数字,将数字放入arraylist中,然后将此数字逐个传递给另一个Arraylist,以进行进一步的操作,直到模板为空,然后将下一个比以前大的数字更大。
我想知道哪种方法更快。
两种方法共有的部分:
// 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 Mainlist,然后删除它们: 路1:
// 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);
}
路2:
// take the last elements
while (!tempList.isEmpty()) {
mainList.add(tempList.get(tempList.size()-1);
tempList.remove(tempList.get(tempList.size()-1);
}
哪种方式更快?考虑到这是数十亿美元的运营,并分配了数十亿美元的数字。我认为诸如collections.reverse()之类的方法需要更多的时间,但是每次使用下一个数字的新数字更新时,我只会称其为“它”。但是以2我调用.size()-1操作在每个操作中。
同样,数字越大 - 更新模板和从中获取数字之间的差距就越大,那么renverse()方法调用越小。 该数字从1开始,到达无穷大。
模板主义者是有原因的,所以请不要建议绕过它。
其他问题:测量此类事情的最佳实践是什么?
I do a lot of operations with splitting numbers into separate digits, putting digits in ArrayList and passing this digits one by one to other ArrayList for further operations until tempList is empty - then goes the next number which is bigger than previous.
I'd like to know which approach is faster.
The part that is common to both approaches:
// 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);
}
Then I can go 2 ways passing those digits to other ArrayList mainList one by one and deleting them after:
Way 1:
// 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);
}
Which way is faster? Taking into consideration, that it's billions of operations with billions of numbers being split and added. I supposed that method such as Collections.reverse() takes more time, but I only call it every time tempList is updated with new digits from next number. But in Way 2 I call .size()-1 operation on EVERY operation.
Also the bigger the number - the bigger the gap between updating the tempList and taking numbers from it (obviously), so less .reverse() method calling.
The number starts at 1 and goes to infinity.
tempList is there for a reason, so please, do not suggest to bypass it.
Additional question: what is the best practice of measuring such things?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
警告。这里有一些陷入困境。
实际上,有两个问题混合在一起:
biginteger
中创建数字列表?我同意:“从一个列表到另一个列表是没有用的” 。至少在这种情况下,它似乎没有用。但是,如果
femplist
发生了一些事情,并且以任何方式证明了从一个列表中删除元素并将其添加到另一个列表中的一般方法,那么提高此特定情况的性能仍然可能是可行的。关于如何将数据从一个列表传输到另一个列表的核心问题,以相反的顺序:
令人惊讶的是,以现在编写的形式,
...第二片片段比 far 慢第一个!
(遵循说明)
这样的简单测试都比较了这两种方法。 (当然,像这样的“ Micorbenchs”应该用一粒盐进行,但是由于此处的性能与渐近运行时间有关,因此这里是
合理
的
)进行错误的方法调用。第二种方法包含该行
,在这种情况下,这是罪魁祸首:您有
Integer
对象的列表。您正在调用删除
,以整数
对象传递。此方法将搜索整个列表,并删除参数的第一次出现。这不仅很慢,还导致结果显然是错误的!您实际想做的是使用最后一个元素的索引删除最后一个元素。 ,更改这条线以
给出完全不同的时序结果:
因此,当正确实现时,
...第一个片段 far 慢于第二个!!
因此 那 Eran在他的回答中提到。
关于如何从
biginteger
中创建数字列表的问题:有几种可能的性能改进。用
%= 10
和/= 10
调用的序列手动提取数字,非常慢。避免使用模型操作已经带来了很小的加速。因此,不是您可以做的
由于
biginteger
和昂贵的部门的不变性,而 ,这仍然比简单地将biginteger
转换为字符串并提取提取的数量级要慢。从那里开始的数字,如 dasblinkenlight在他的答案中建议使用。一个简单的比较:
输出将沿着这样的路线:
表明
toString
方法的速度比手动的方法快100倍以上。Caution. There are some gotchas involved here.
In fact, there are two questions mixed:
BigInteger
?I agree with the comment by Roman C: "Moving from one list to another is useless". At least, it seems to be useless in this case. But if there is something happening to the
tempList
, and the general approach of removing elements from one list and adding them to another list (one by one) is justified in any way, then the question of how to improve the performance for this particular case may still be feasible.Regarding the core question of how to transfer data from one list to another, in reverse order:
Surprisingly, in the form that it is written now,
...the second snippet is far slower than the first one!
(Explanation follows)
A simple test like this one compares both approaches. (Of course, "micorbenchmarks" like this one should be taken with a grain of salt, but as the performance here is related to asymptotic running times, this is reasonable here)
The output on my machine is
But....
This is due to a wrong method call. The second approach contains the line
and this is the culprit in this case: You have a list of
Integer
objects. And you are callingremove
, passing in anInteger
object. This method will search through the whole list, and remove the first occurrence of the argument. This is not only slow, it also causes the result to be plainly wrong!What you actually want to do is to remove the last element, using the index of the last element. So changing this line to
gives an entirely different timing result:
So, when implemented properly, then
...the first snippet is far slower than the second one!
For the reasons that Eran mentioned in his answer.
Regarding the question of how to create a list of digits from a
BigInteger
: There are several possible performance improvements.Extracting the digits manually, with a sequence of
%= 10
and/= 10
calls is very slow. Avoiding the modulo operation already brings a small speedup. So instead ofyou could do
But due to the immutability of
BigInteger
and the expensive division, this is still orders of magnitude slower than simply converting theBigInteger
into a string, and extracting the digits from there, as dasblinkenlight suggested in his answer.A simple comparison:
The output will be along the lines of this:
showing that the
toString
approach is more than a hundred times faster than the manual ones.第二个片段应该更快,原因有两个:
不必扭转阵列列表,正如您所认识的那样。
删除阵列列表的最后一个元素比删除第一个元素要快,因为删除第一个元素涉及减少所有剩余元素的索引(通过System.ArrayCopy完成)。
The second snippet should be faster for two reasons :
Not having to reverse the ArrayList, as you recognized yourself.
Removing the last element of an ArrayList is faster than removing the first element, since removing the first element involves decreasing the index of all the remaining elements (which is done via System.arraycopy).
两个片段都很慢。如果您想更快地做,请列出适当的尺寸,然后从背面填充。
此答案显示了如何获得所需的
arraylist&lteger&lteger&gt; gt;
。现在您可以执行此操作:这将立即以所需的顺序产生
arrayList
,因此反向例程变得完全不必要。注意:Java-8使您可以在一行中转换为整数数组:
demo。
Both snippets are slow. If you want to do it faster, make a list of the proper size, and fill it in from the back.
This answer shows how to obtain the length of the required
ArrayList<Integer>
. Now you can do this:This produces
ArrayList
in the desired order right away, so the reversing routines become completely unnecessary.Note: Java-8 lets you do the conversion to an array of integer in one line:
Demo.