有没有办法非常快速地跳到双向链表的中间元素,而不是这样做
for(int i = 0; i <= numOfElements/2; i++){
element = element.next;
}
这在我的代码中需要很多时间,如果我优化它,那将是非常酷:)
链接(或双链接)列表的要点是随机访问很慢(O(n)
)。
您需要使用不同类型的列表,例如跳过列表。
链表的全部意义在于这是不可能的。但是,存在其他数据结构(间接)允许此操作。一种这样的数据结构是跳过列表,其名称来自它可以做到这一点的事实:跳过项。
此数据结构不直接适用于您的情况,因为跳过列表实现字典,不允许直接访问索引项。但是,一般结构可以相应地进行调整。
我不确定这样做是否有意义,这取决于您需要双链表的原因。 理想情况下,您可以选择不使用它。但是,如果不可能,您可以使用其他类型的数据结构来支持它,例如以整数作为键的哈希映射。 然后你可以这样:
element.get(numOfElements/2);
当你说"跳到中间"时,你的意思是每次都确切的中间元素吗?或者只是"开头或结尾以外的某个地方,但确切的位置会有所不同"?
如果您指的是确切的中间,则可以维护指向列表中间的指针以及通常的开始和结束指针。每次在列表中添加或删除条目时,都有可能必须移动此指针。请注意,在每一侧都需要两个插入物才能将其移动到一个位置,下面一个插入和一个上方的插入物会抵消。所以你必须保留一个"半计数器"。当在下面插入一个项目时,从半计数器中减去一个。在上面插入项目时,添加一个。如果半计数器现在为 -2,请将中间指针向下移动一个插槽并将半计数器重置为 0。如果半计数器现在为 +2,请将中间指针向上移动一个插槽并重置半计数器。几年前我做过一次。我忘了为什么。
如果你不是说确切的中间,那么我认为答案是"这不可能做到"。我想,您可以维护许多指向列表中各个点的指针。就像有一个字典,上面有第一个 A、第一个 B 等的标签。
或者我想,如果你知道你经常需要"非常接近中间",你可以保持一个中间指针,如我上面描述的那样,然后从那里搜索。
这些是否有助于解决您真正想要解决的问题,如果没有更多信息,我不能说。
您可以保留一个中间指针,但每次更新列表时都需要调整,如果您只需要一个足够的近似
值或者保留 2 个单独的列表,每次访问中间时,您都会调整它们,直到它们的长度相等(将长度作为每个列表的单独 var)
public class DoubledLickedList{
private Node fhead,ftail,shead,stail;
private AtomicInteger fsize,sSize;
public Class Node{
private Node next;
private Node prev;
public Node getNext(){
if(next==null && next==ftail)return shead;
return next;
}
public Node getPrev(){
if(prev==null && prev==shead)return ftail;
return prev;
}
}
public Node getMiddle(){
adjustToMiddle();
return ftail;
}
private void adjustToMiddle(){
while(fsize.get()>sSize.get()+1){
//pop first and push it to the second
fsize.incrementAndGet();
sSize.decrementAndGet();
}
while(sSize.get()>fsize.get()+1){
//pop second and push it to the first
sSize.incrementAndGet();
fsize.decrementAndGet();
}
}
}
如果你真的不需要列表,你可以使用Array,TreeMap或HashMap。
所有这些都具有更快的随机访问。