我被赋予了按字母顺序将值添加到ArrayList中的任务(按姓氏,如果姓氏相同,则按名字),一旦给出所有输入,就不允许对ArrayList进行排序。我想做的是确定每次给出输入时值应位于的位置并将其放置在该位置。值示例:输入为{John Doe,Bryan Sully,Harry Ache,Ali Doe,Bry Dyre},输出应为{Harry Ache,Ali Doe,John Doe,Bry Dyre,Bryan Sully}。但是,在姓氏相同的情况下,{Harry Ache,Ali Doe,Bry Dyre,John Doe和Bryan Sully}会出现什么?
ArrayList<Person> list = new ArrayList<Person>();
public void addPerson(Person p){
if(list.size() == 0){
list.add(p);
} else{
for(Person pp: list){
int getIndex = list.indexOf(pp);
int lOrder = p.getLastName().compareTo(pp.getLastName());
if(lOrder > 0){
list.add(getIndex + 1, p);
break;
} else if(lOrder == 0){
int fOrder = p.getFirstName().compareTo(pp.getFirstName());
if(fOrder > 0){
list.add(getIndex, p);
break;
} else {
list.add(getIndex + 1, p);
break;
}
} else {
list.add(getIndex, p);
break;
}
}
}
}
答案 0 :(得分:0)
很少有改进。
如果您可以使用诸如
for(int i = 0; i < array.size(); i++)
您不必分别检查lastName
和firstName
。您可以将两者(p.lastName + p.firstName).compareTo(pp.lastName + pp.firstName)
进行比较,然后对结果采取行动。由于已经有了当前元素的索引,因此只需检查是否只是将新项目插入相同的索引即可。
这是示例实现
static void addPerson(Person person) {
for (int i = 0; i < sortedList.size(); i++) {
var existingPerson = sortedList.get(i);
var compareResult = compare(existingPerson, person);
if (compareResult > 0) {
sortedList.add(i, person);
return;
}
}
sortedList.add(person);
}
static int compare(Person p1, Person p2) {
return (p1.lastName + p1.firstName).compareTo(p2.lastName + p2.firstName);
}
答案 1 :(得分:0)
代码的一个问题是,您要在循环的单次迭代之后进行插入,仅与列表中的第一个Person
相比插入Person
p。
这是一个改进的实现:
public void addPerson(Person person) {
if (list.isEmpty()) {
list.add(p);
} else {
// the position where you will insert the Person;
// default value is list.size(), so it can be added to the end
int position = list.size();
Person p;
for (int i = 0; i < list.size(); i++) {
p = list.get(i);
// if the comparison result is > 0, you found the first Person
// in the list that comes alphabetically after;
// Insert person before it, at position i
if (compare(p, person) > 0) {
position = i;
break; // only break now that you've found the insert position
}
}
list.add(person, position);
}
}
/**
* @return 0 if both Persons p1 & p2 have the same names,
* a positive number if p1 is lexicographically greater than p2,
* or a negative number if p1 is lexicographically less than p2
*/
private int compare(Person p1, Person p2) {
int result = p1.getLastName().compareTo(p2.getLastName());
if (result == 0) {
result = p1.getFirstName().compareTo(p2.getFirstName());
}
return result;
}
正如其他人所建议的那样,在可能的情况下在Person
中实现Comparable接口也可以帮助创建更简洁的实现。
答案 2 :(得分:0)
算法的问题是,您总是查看目标列表中的第一个人,并且仅对该人做出决定,请注意所有“分支”的末尾都有一个break语句?
我了解您添加所有这些break语句的“原因”,这些确保新人总是在列表不匹配时插入列表,这与您首次检查列表是否为空的原因相同。 / p>
要正确实现“插入排序”系统,实际上您需要遍历列表的所有索引。
一个简单的“插入排序”算法如下所示:
ArrayList<Person> list = new ArrayList<Person>();
public void addPerson(Person p){
// Loop
int size = list.size();
for(int getIndex = 0; getIndex < size; getIndex++){
Person pp = list.get(getIndex);
// Compare
int compare = p.getLastName().compareTo(pp.getLastName());
if (compare > 0) {
continue;
} else if(compare == 0) {
if (p.getFirstName().compareTo(pp.getFirstName()) > 0) {
continue;
}
}
// Add in existing slot
list.add(getIndex, p);
return;
}
// Add at the end
list.add(p);
}
其中一个困难的部分是,我们必须对一个人进行两件事的比较,这使得比较逻辑的难度超出了需要。这可以通过将这部分分解为“辅助”比较器来解决,该比较器为我们完成此逻辑合并:
Comparator<Person> compare = Comparator
.comparing(Person::getLastName)
.thenComparing(Person::getFirstName);
// Then, inside the above loop:
...
// Compare
if (compare.compare(p, pp) > 0) {
continue;
}
...