使用Java,我有一个名为TestClass的类,它有一个名为Name的成员,它是一个字符串。我也有一个这种类型的ArrayList,它已经按名称字母顺序排序。我想要做的是找到放置TestClass新实例的最佳索引。到目前为止,我能想出的最佳方法是:
public static int findBestIndex(char entry, ArrayList<TestClass> list){
int desiredIndex = -1;
int oldPivot = list.size();
int pivot = list.size()/2;
do
{
char test = list.get(pivot).Name.charAt(0);
if (test == entry)
{
desiredIndex = pivot;
}
else if (Math.abs(oldPivot - pivot) <= 1)
{
if (test < entry)
{
desiredIndex = pivot + 1;
}
else
{
desiredIndex = pivot - 1;
}
}
else if (test < entry)
{
int tempPiv = pivot;
pivot = oldPivot - (oldPivot - pivot)/2;
oldPivot = tempPiv;
}
else
{
int tempPiv = pivot;
pivot = pivot - (oldPivot - pivot)/2;
oldPivot = tempPiv;
}
} while (desiredIndex < 0);
return desiredIndex;
}
基本上,将数组分成两半,检查您的值是在此之前,之后还是之后。如果是,请检查阵列的前半部分。其他明智的,检查下半场。然后,重复一遍。我知道这种方法只能通过第一个字符进行测试,但这很容易修复,与我的主要问题无关。对于某些情况,这种方法运行良好。对于大多数人来说,它的工作非常糟糕。我认为它没有正确找到新的枢轴点,如果是这样的话,我该如何解决?
编辑:为了澄清,我将其用于库存系统,因此我不确定LinkedList是否合适。我使用的是ArrayList,因为它们对我来说比较熟悉,因此如果需要,可能会更容易翻译成另一种语言(目前很可能会转移到C#)。我试图避免像Comparable这样的事情,因为如果C#缺乏它,我必须完全重写。
编辑部分Duex:弄清楚我做错了什么。我应该设置并更改我正在检查的区域的边界,而不是使用先前的轴点,并基于此创建新的轴。
答案 0 :(得分:3)
正如已经指出的那样,没有理由自己实现这个,简单的代码示例:
class FooBar implements Comparable<FooBar> {
String name;
@Override
public int compareTo(FooBar other) {
return name.compareTo(other.name);
}
}
TreeSet<FooBar> foobarSet = new TreeSet<>();
FooBar f1;
foobarSet.add(new FooBar("2"));
foobarSet.add(f1 = new FooBar("1"));
int index = foobarSet.headSet(f1).size();
答案 1 :(得分:2)
为此使用SortedSet(例如TreeSet)可能不是一个好主意,因为树不允许重复的元素。如果您有重复的元素(即具有相同名称的TestClass实例),则应使用列表。要将元素插入到已排序的列表中很简单:
void insert(List<TestClass> list, TestClass element) {
int index = Collections.binarySearch(list, element, Comparator.comparing(TestClass::getName));
if (index < 0) {
index = -index - 1;
}
list.add(index, element);
}
此代码需要Java 8或更高版本,但也可以重写以在较旧的Java版本中使用。
答案 2 :(得分:1)
您应该使用已经具有秩序感的PriorityQueue之类的东西。插入具有顺序感的集合将自动以最短的时间(通常为log(n)或更少)将元素放置在正确的位置。
如果你想在没有这个的情况下进行任意插入,那么我建议使用一个不必使用或完全复制的LinkedList来插入像你当前拥有的ArrayList这样的单个项目。虽然为LinkedList找到正确的插入位置将花费O(n)时间,但实际上它仍然比使用log(n)搜索ArrayList中的正确位置更快,但随后需要复制或排序它然后。
此外,在链表中查找插入位置的代码也更加简单。
if (next != null && next.compareTo(insertElement) > 0){
// You have the right location
}
答案 3 :(得分:1)
使用的其他数据结构可以使用而不是像树,优先级队列等列表。
答案 4 :(得分:1)
我认为问题出现在这段代码中:
else if (test < entry)
{
int tempPiv = pivot;
pivot = oldPivot - (oldPivot - pivot)/2;
oldPivot = tempPiv;
}
else
{
int tempPiv = pivot;
pivot = pivot - (oldPivot - pivot)/2;
oldPivot = tempPiv;
}
您正在执行相同的操作,并且测试&lt; <进入或湿试验>条目。当您搜索的项目位于数组的开头时,这将导致线性搜索。
我更喜欢使用(低和高)
high = list.size();
low = 0;
do {
pivot = (high + low) / 2;
if (test < entry) {
low = pivot;
} else if (test > entry) {
high = pivot
} else {
....
}
} while ...;
答案 5 :(得分:0)
创建一个自己的列表实现,并在你的add方法中有这些行:
wrappedList.add(object);
Collections.sort(wrappedList);