![](/img/trans.png)
[英]How does Java's Collections.sort overwrite the List to be sorted
[英]How can I get Sorted List behavior in Java without using Collections.sort()?
我了解Java出於各種概念上的原因不具備排序列表,但是考慮到我需要擁有一個類似於Priority Queue但還允許我進行隨機訪問(可索引)的集合的情況,換句話說,我需要一個遵循特定順序的列表。 我寧願不使用Collections.sort()
首選操作約束:
檢索-O(1)(基於索引的隨機訪問)
搜索-O(log n)
插入-O(log n)
刪除-O(log n)
集合上的迭代器應按排序順序為我提供所有元素(基於在數據結構實例化時提供的預定義Comparator
)
我寧願使用Java的內置庫來完成此操作,但也可以建議外部庫。
編輯:TreeSet不會做,因為基於索引的訪問很困難,使用包裝器集合也不是我的最佳選擇,因為刪除意味着我需要從兩個集合中刪除。
EDIT2:我無法找到indexable skip list
的實現和/或文檔,這似乎有些相關,有人可以幫助我找到它嗎? 也歡迎對提議的數據結構提出或反對的任何評論。
EDIT3:雖然這可能不是最完美的答案,但是我想添加這段代碼,以便任何有類似問題但需要排序列表的人都可以使用它,如果他們覺得有用的話。
請檢查是否有錯誤(如有),並提出改進建議(尤其是對sortedSubList
方法)
import java.util.ArrayList;
import java.util.Collection;
import java.util.Comparator;
public class SortedList<E> extends ArrayList<E> {
private final Comparator<? super E> comparator;
public SortedList(Comparator<? super E> comparator) {
this.comparator = comparator;
}
public SortedList(int initialCapacity, Comparator<? super E> comparator) {
super(initialCapacity);
this.comparator = comparator;
}
@Override
public boolean add(E e) {
if (comparator == null)
return super.add(e);
if (e == null)
throw new NullPointerException();
int start = 0;
int end = size() - 1;
while (start <= end) {
int mid = (start + end) / 2;
if (comparator.compare(get(mid), e) == 0) {
super.add(mid, e);
return true;
}
if (comparator.compare(get(mid), e) < 0) {
end = mid - 1;
}
else {
start = mid + 1;
}
}
super.add(start, e);
return true;
}
@Override
public boolean contains(Object o) {
if (comparator == null)
return super.contains(o);
if (o == null)
return false;
E other = (E) o;
int start = 0;
int end = size() - 1;
while (start <= end) {
int mid = (start + end) / 2;
if (comparator.compare(get(mid), other) == 0) {
return true;
}
if (comparator.compare(get(mid), other) < 0) {
end = mid - 1;
}
else {
start = mid + 1;
}
}
return false;
}
@Override
public int indexOf(Object o) {
if (comparator == null)
return super.indexOf(o);
if (o == null)
throw new NullPointerException();
E other = (E) o;
int start = 0;
int end = size() - 1;
while (start <= end) {
int mid = (start + end) / 2;
if (comparator.compare(get(mid), other) == 0) {
return mid;
}
if (comparator.compare(get(mid), other) < 0) {
end = mid - 1;
}
else {
start = mid + 1;
}
}
return -(start+1);
}
@Override
public void add(int index, E e) {
throw new UnsupportedOperationException();
}
@Override
public boolean addAll(int index, Collection<? extends E> c) {
throw new UnsupportedOperationException();
}
@Override
public E set(int index, E e) {
throw new UnsupportedOperationException();
}
public SortedList<E> sortedSubList(int fromIndex, int toIndex) {
SortedList<E> sl = new SortedList<>(comparator);
for (int i = fromIndex; i < toIndex; i++)
sl.add(get(i));
return sl;
}
}
在同一數據結構中很難獲得O(1)索引和O(log n)插入/刪除。 O(1)索引意味着我們無法負擔對樹,列表,跳過列表或其他基於鏈接的數據結構建立索引所涉及的鏈接跟蹤,而O(log n)修改意味着我們無法負擔一半的移位每次插入時數組的元素。 我不知道是否有可能同時滿足這些要求。
如果我們放寬這些要求之一,事情就會變得容易得多。 例如,所有操作的O(log n)都可以通過可索引的跳過列表或具有節點的自平衡BST來實現,該節點跟蹤以該節點為根的子樹的大小。 但是,這些都不能建立在Java標准庫的跳過列表或BST之上,因此您可能需要安裝另一個庫或編寫自己的數據結構。
可以通過保留排序的ArrayList並使用Collections.binarySearch
搜索元素或插入/刪除位置來完成O(1)索引編制,O(log n)搜索以及O(n)插入和刪除操作。 您不需要調用Collections.sort
,但仍然需要調用ArrayList的O(n)插入和刪除方法。 這可能是在Java內置工具之上構建的最簡單的選擇。 請注意,在最新的Java版本中, Collections.sort
是一種自適應mergesort,將花費O(n)
時間對僅最后一個元素不按排序順序排列的數組進行排序,因此您可以擺脫依賴Collections.sort
。 但是,這是實現細節,其他Java實現不必遵循。
如果您的主要目標是索引查找( get()
)的O(1),則可以使用Arrays.binarySearch()
實現自己的類,該類實現List
,並由數組支持。
retrieve: get(int) - O(1) - array index
search: contains(Object) - O(log n) - binarySearch
indexOf(Object) - O(log n) - binarySearch
insert: add(E) - O(n) - binarySearch + array shift
delete: remove(int) - O(n) - array shift
remove(Object) - O(n) - binarySearch + array shift
add(E)
方法違反了List
定義(追加),但與Collection
定義一致。
以下方法應引發UnsupportedOperationException
:
add(int index, E element)
addAll(int index, Collection<? extends E> c)
set(int index, E element)
如果不允許重復值(這可能是一個邏輯限制),請考慮同時實現NavigableSet
,它是SortedSet
。
構建由ArrayList和TreeSet支持的自定義集合。 委派對ArrayList的隨機訪問和對TreeSet的搜索。 當然,這意味着每次寫操作都將非常昂貴,因為每次都必須對ArrayList進行排序。 但是讀取應該非常有效。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.