一个更有效的方法来编写这个程序
这个程序是功课。我们已经完成了它,并且很好去。我想知道是否有更简化的写这个程序的方式?该程序被称为Interleave,它所做的是将两个ArrayLists组合起来,以便第一个ArrayList中的每个其他元素都来自第二个ArrayList。听起来很简单,就是我们使用迭代器来添加必要的元素。但代码是BLOCKY。在我看来,必须有更好的方式来写这个,对吧?提前致谢。一个更有效的方法来编写这个程序
import java.util.*;
public class Interleave
{
public static void main(String[] args)
{
ArrayList<Integer> a1 = new ArrayList<Integer>();
Collections.addAll(a1, 10, 20, 30);
ArrayList<Integer> a2 = new ArrayList<Integer>();
Collections.addAll(a2, 4, 5, 6, 7, 8, 9);
System.out.println(a1);
System.out.println(a2);
System.out.println(interleave(a1, a2));
ArrayList<String> list = new ArrayList<String>();
String[] words =
{ "how", "are", "you?" };
for (String s : words)
{
list.add(s);
}
}
public static ArrayList<Integer> interleave(ArrayList<Integer> a1,
ArrayList<Integer> a2)
{
Iterator<Integer> it = a2.iterator();
int i = 1;
while (it.hasNext())
{
int val = it.next();
if (a1.size() >= i)
{
a1.add(i, val);
} else
{
a1.add(val);
}
i += 2;
}
return a1;
}
}
效率比代码看起来更重要。每次在索引i处添加元素时,该索引之后的每个元素都需要由ArrayList向上移动一个索引,因为它使用数组作为其基础数据结构。如果使用避免这个问题的LinkedList,或者如果您创建了第三个数组(第一个数组+第二个数组),并将这些元素添加到该数组中,则此代码效率会更高。再次,你还必须考虑空间,所以制作另一个阵列会增加空间需求。
即使您坚持使用您当前的方法,您应该在添加所有元素之前增加数组的容量。这样,数组的容量已经足够大,可以添加另一个数组中的所有元素,并且不会(可能)需要多次增加。
希望有所帮助。
编辑:
你也可以重新配置阵列提前使得每个第二名已经是空的,这将节省您从我前面描述的阵列转移问题。
效率远不如代码的外观重要。干净的代码不太可能是错误的代码,并且更容易维护。如果你的代码没有足够的效率去完成它的工作,那么对它进行分析并修复重要的部分。 [过早优化是万恶之源。](http://en.wikiquote.org/wiki/Donald_Knuth) – nmichaels 2011-05-18 18:43:57
@nmichaels - 你滥用早熟优化报价。每种情况都有所不同,因此有自己的一套准则。此外,我们任何人都不可能说出什么是“足够有效地完成工作”,因为这是一次学校练习,而且OP没有详细讨论要求。因此,我们只是不提全面更好的解决方案。 – KyleM 2011-05-18 20:25:50
@nmichaels - 我还应该补充一点,过早的优化不是使用糟糕的编程习惯的借口,这正是你所倡导的。在可能的情况下,程序员应该明智地选择数据结构,并且应该进行编码,使其代码具有可读性,可维护性和高效性。这些事情应该根据情况来平衡;过早优化是无关紧要的。 – KyleM 2011-05-18 20:28:08
现在,你interleave
函数假定一个具体列表实现(ArrayList
)和特定类型,它必须包含(Integer
)。您可以通过使用泛型概括此功能:
public static <T> List<T> interleave(List<T> first, List<T> second)
{
Iterator<T> it = second.iterator();
int i = 1;
while (it.hasNext()) {
T val = it.next();
if (first.size() >= i)
first.add(i, val);
else
first.add(val);
i += 2;
}
return first;
}
虽然这仍然强制两个列表包含相同的类型。 – Santa 2011-05-18 18:43:06
public static ArrayList<Integer> interleave(ArrayList<Integer> a1, ArrayList<Integer> a2)
{
Iterator<Integer> it1 = a1.iterator();
Iterator<Integer> it2 = a2.iterator();
ArrayList<Integer> output = new ArrayList<Integer>();
while (it1.hasNext() || it2.hasNext())
{
if (it1.hasNext()) { output.add(it1.next()); }
if (it2.hasNext()) { output.add(it2.next()); }
}
return output;
}
while条件应该是'||'而不是'&&'以允许不同的长度列表。 – WhiteFang34 2011-05-18 18:52:23
啊,是的。感谢您的支持。 – Lucas 2011-05-18 19:12:10
+1。简洁易读 – patros 2011-05-18 19:22:24
我不认为你可以减少代码量很大。它可能无法做得太快。但是,我会提出一些其他改进建议:
- 如果您要返回另一个对象,那么对您传入的对象进行变异不是一个好习惯。
- 你可以只使用
List
代替ArrayList
所以任何类型的List
可以传递。 - 你可以使用泛型不能使其具体到
Integer
列表。
这些组合会产生这样的:
public static <T> List<T> interleave(List<T> a1, List<T> a2) {
List<T> list = new ArrayList<T>(a1.size() + a2.size());
Iterator<T> it1 = a1.iterator();
Iterator<T> it2 = a2.iterator();
while (it1.hasNext() || it2.hasNext()) {
if (it1.hasNext()) {
list.add(it1.next());
}
if (it2.hasNext()) {
list.add(it2.next());
}
}
return list;
}
好点,但因为它是作业,我将不得不留在项目的规则。 – kreeSeeker 2011-05-19 04:53:46
@ kreeSeeker它可以做得更快,正如我在我的文章中所述。随着元素数量的增加,只需使用LinkedList就可以提高速度。 – KyleM 2011-05-19 13:01:44
的Java,作为一种语言,是相当冗长和 “块状”。习惯它。 ;-) – Santa 2011-05-18 18:31:26
@Santa,好吧,至少他的项目不涉及乐高积木,那会变得混乱。也许甚至'块';) – FreeSnow 2011-05-18 18:32:59
你可以用一个for each-loop替换Iterator-while循环,这将为你节省一条高高的线!;) – Jacob 2011-05-18 18:34:17