![](/img/trans.png)
[英]What's the most efficient way to insert a string into an already-sorted array list of strings?
[英]Insert into an already-sorted list
使用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:弄清楚我做錯了什么。 我應該設置並更改我正在檢查的區域的邊界,而不是使用先前的軸點,並基於此創建新的軸。
為此使用SortedSet(例如TreeSet)可能不是一個好主意,因為Set不允許重復元素。 如果您有重復的元素(即具有相同名稱的TestClass實例),則應使用List。 將元素插入已排序的列表就像這樣簡單:
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版本中工作。
正如已經指出的那樣,沒有理由自己實現這個,簡單的代碼示例:
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();
(基於如何在TreeSet中查找元素的索引? )
您應該使用已經具有秩序感的PriorityQueue之類的東西。 插入具有順序感的集合將自動以最短的時間(通常為log(n)或更少)將元素放置在正確的位置。
如果你想在沒有這個的情況下進行任意插入,那么我建議使用一個不必使用或完全復制的LinkedList來插入一個像你當前擁有的ArrayList這樣的項目。 雖然為LinkedList找到正確的插入位置將花費O(n)時間,但實際上它仍然比使用log(n)搜索ArrayList中的正確位置更快,但隨后需要復制或排序它然后。
用於在鏈表中查找插入位置的代碼也更加簡單。
if (next != null && next.compareTo(insertElement) > 0){
// You have the right location
}
使用的其他數據結構可以使用而不是像樹,優先級隊列等列表。
我認為問題出在這段代碼中:
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;
}
您正在執行相同的操作,進入測試<進入或測試>進入。 當您搜索的項目位於數組的開頭時,這將導致線性搜索。
我更喜歡使用(低和高)喜歡
high = list.size();
low = 0;
do {
pivot = (high + low) / 2;
if (test < entry) {
low = pivot;
} else if (test > entry) {
high = pivot
} else {
....
}
} while ...;
制作一個自己的列表實現,並在你的add方法中有這些行:
wrappedList.add(object);
Collections.sort(wrappedList);
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.