简体   繁体   English

Java的侵入式列表实现?

[英]Intrusive list implementation for Java?

Is there any (well implemented) intrusive double linked list class(es) available for Java? 是否有任何(良好实现的)侵入式双链表类可用于Java? Or should I do my own? 或者我应该自己做? Boost has it for C++: http://beta.boost.org/doc/libs/1_40_0/doc/html/boost/intrusive/list.html . Boost为C ++提供了它: http//beta.boost.org/doc/libs/1_40_0/doc/html/boost/intrusive/list.html

Intrusive list is a container having (in this case) next and prev pointers within element, so typical list operations like replace and remove can be directly targeted into elementary class instead of container class. 侵入列表是一个容器(在这种情况下)是元素中的next和prev指针,因此像replace和remove这样的典型列表操作可以直接定位到基本类而不是容器类。 There are some certain situations, where intrusive list are the best solution. 在某些情况下,侵入列表是最佳解决方案。

I try to give an appropriate example. 我试着给出一个恰当的例子。 Let's assume I have linked lists L list1 and L list2 owned by different type of classes X1 and Y2. 假设我有不同类型的X1和Y2所拥有的链表L list1和L list2。

class Q (which has nothing to do or doesn't easily get access the interfaces of x1 and Y2 otherwise) needs to do i) replace, ii) remove operation for element e, which exists always in somewhere, in list1 xor list2 depending on run-time state, but that information is not stored directly anywhere. Q类(没有任何关系或者不容易访问x1和Y2的接口,否则)需要做i)替换,ii)删除元素e的操作,它总是存在于某个地方,在list1 xor list2中取决于运行时状态,但该信息不会直接存储在任何地方。

With intrussive list Q can just store reference to an element to member element e and it always points the right place. 使用intrussive列表Q可以将元素的引用存储到成员元素e,并且它总是指向正确的位置。

Otherwise you have to choose from several clearly more complex workarounds one or the other. 否则,您必须从几个明显更复杂的解决方法中选择一个或另一个。 - Wrapper class for element e and and additional methods for completing operations i and ii. - 元素e的包装类和完成操作i和ii的其他方法。 No. 没有。

Basically, the question is still not about the performance but architectural complexity. 基本上,问题仍然不是性能而是架构复杂性。 This can also be understood as one kind of shared object situation where solution IL avoids the update need for every client Lx and Q. 这也可以理解为一种共享对象情况,其中解决方案IL避免了对每个客户端Lx和Q的更新需求。

Please notice I do NOT necessary need compatibility to other standard containers. 请注意,我没有必要与其他标准容器兼容。 Just an generic intrusive lsit implementation with an iterating, add, remove and find operations used with unknown element class. 只是一个通用的侵入式lsit实现,具有与未知元素类一起使用的迭代,添加,删除和查找操作。

Thanks. 谢谢。

I'm not aware of any existing implementations (and no, I don't consider the normal Java collections to be intrusive). 我不知道任何现有的实现(不,我不认为普通的Java集合是侵入性的)。

That's probably because the only major advantage such a list would have in Java would be the fast remove() call when you already have the Element to be removed at hand (and don't have an Iterator at that position). 这可能是因为当你已经有一个要移除的元素(并且在该位置没有Iterator时,这样的列表在Java中唯一的主要优点是快速remove()调用。 The not-copying-the-element is not a valid argument in Java, since Java List implementations handle only references anyway (and never copy the whole object). not-copy-the-element不是Java中的有效参数,因为Java List实现无论如何只处理引用(并且永远不会复制整个对象)。

But you can easily write a general-purpose List implementation that is intrusive by creating the necessary interface: 但是,通过创建必要的接口,您可以轻松编写一个通用的List实现:

public interface IntrusiveListElement<E extends<IntrusiveListElement<E>> {
  public void setNext(E next);
  public E getNext();
  public void setPrev(E prev);
  public E getPrev();
}

public class IntrusiveList<E extends IntrusiveListElement<E>> implements List<E> {
  // implement your run-of-the-mill double-linked list here
}

Your element class could look like this: 您的元素类可能如下所示:

public class MyBusinessElement implements IntrusiveListElement<MyBusinessElement> {
  private MyBusinessElement prev;
  private MyBusinessElement next;

  public void setNext(MyBusinessElement next) {
    this.next = next;
  }

      public MyBusinessElement getNext() {
    return next;
  }

  public void setPrev(MyBusinessElement prev) {
    this.prev = prev;
  }

  public MyBusinessElement getPrev() {
    return prev;
  }
}

Is there any (well implemented) intrusive double linked list class(es) available for Java? 是否有任何(良好实现的)侵入式双链表类可用于Java?

I don't believe you'll find one. 我不相信你会找到一个。

My understanding of "intrusive" is that the application object to be stored in the data structure needs to directly include ("intrude") the next/prev pointers within the application object . 我对“侵入式”的理解是, 要存储在数据结构的应用程序对象需要直接包含(“入侵”)应用程序对象中的next / prev指针

This is in contrast the "pointer wrapper" approach where the data structure node contains a pointer to the application object, thus requiring no modification to application object. 这与“指针包装器”方法形成对比,其中数据结构节点包含指向应用程序对象的指针,因此不需要修改应用程序对象。 The intrusive approach has a number of benefits including avoiding the double-dereferencing (once for the node and once for the node's pointer to the application object) common to the "pointer wrapper" approach. 侵入式方法有许多好处,包括避免对“指针包装器”方法通用的双重解除引用(一次用于节点,一次用于节点指向应用程序对象的指针)。

I don't believe you'll find an intrusive data structure library for Java. 我不相信你会找到一个针对Java的侵入式数据结构库。 Java lacks C++-like templates nor multiple inheritance, and it does not easily support copy-by-value of an entire object. Java缺乏类似C ++的模板,也没有多重继承,并且它不容易支持整个对象的按值复制。 Because of this, I don't think there's a way to generically add the next/prev instance fields to a Java object. 因此,我认为没有办法将下一个/ prev实例字段一般性地添加到Java对象中。

For example, given the application object: 例如,给定应用程序对象:

class Foo {
    int bar;
}

somehow you need to be able to add next/prev fields and list management methods to it or a derivative of it: 不知何故,你需要能够为它或它的衍生物添加next / prev字段和列表管理方法:

class Foo2 {
    int bar;
    Foo2 prev;
    Foo2 next;
}

One way to add these fields by providing a base class with these fields for these application classes to extend - this is Boost's approach. 添加这些字段的一种方法是通过为这些应用程序类提供这些字段的基类来扩展 - 这是Boost的方法。 However, this approach is very limiting in a single-inheritance language like Java. 但是,这种方法在像Java这样的单继承语言中非常有限。

Java interfaces are often Java's answer to multiple inheritance, eg an interface to require getNext() and getPrev() methods of application classes. Java接口通常是Java对多重继承的回答,例如需要应用程序类的getNext()和getPrev()方法的接口。 However, if you need intrusive data structures for performance reasons, accessing next/prev fields through a method may adversely affect those goals. 但是,如果出于性能原因需要侵入式数据结构,则通过方法访问next / prev字段可能会对这些目标产生负面影响。

Java generics also don't extend classes in needed way. Java泛型也不以所需方式扩展类。

Or should I do my own? 或者我应该自己做?

If its one time for a specific case for a carefully evaluated need, sure - roll your own. 如果有一次针对特定情况进行仔细评估需求,请确保自己动手。 If you're trying to roll a generic one for general purpose use, I'm not sure its worth it. 如果你试图将通用的一个用于通用目的,我不确定它是否值得。

One really gross approach would be to custom extend the application class to add the needed fields: 一个非常重要的方法是自定义扩展应用程序类以添加所需的字段:

class Foo3 extends Foo {
    Foo3 prev;
    Foo3 next;
}

and use cut-n-paste reuse to add the list management methods. 并使用cut-n-paste重用来添加列表管理方法。 I would however strongly recommend not using this approach. 但我强烈建议不要使用这种方法。

Soapbox 肥皂盒

You don't state why you need an intrusive data structure. 您没有说明为什么需要侵入式数据结构。 Perhaps you have valid reasons for needing one, but its hard to imagine them. 也许你有正当理由需要一个,但很难想象它们。 Java is heavily reliant on using object pointers and trying to avoid them like this would be difficult. Java非常依赖于使用对象指针并试图避免它们,因为这很难。

I respectfully suggest you consider: 我恭敬地建议你考虑一下:

  • are you trying to prematurely optimize, 你想过早地优化,
  • are you adding unnecessary complexity for little benefit 你是否添加了不必要的复杂功
  • if speed and memory management are paramount, are you using the right language? 如果速度和内存管理是最重要的,你使用正确的语言吗?

if you look to SDK code you will see that LinkedList is, in fact, a list of a private class Entry which contains next and previous elements. 如果您查看SDK代码,您会看到LinkedList实际上是包含next和previous元素的私有类Entry的列表。 So, if you include MyClass in this list, an element of the list will be an Entry with your object and the links for the next and previous elements of the list. 因此,如果在此列表中包含MyClass,则列表中的元素将是包含对象的条目以及列表的下一个和上一个元素的链接。

So, i think it is intrusive... 所以,我认为它是侵入性的......

private static class Entry<E> {
    E element;
    Entry<E> next;
    Entry<E> previous;

    Entry(E element, Entry<E> next, Entry<E> previous) {
        this.element = element;
        this.next = next;
        this.previous = previous;
    }
}

What do you hope to gain by using an intrusive list? 您希望通过使用侵入式列表获得什么? I'm hard pressed to think what the advantages would be. 我很难想到它的优点是什么。 Okay, there's a trivial efficiency that you have just one object instead of two for each node. 好的,有一个微不足道的效率,你只有一个对象而不是每个节点两个。 But the price of this is a big loss in flexibility and reliability. 但这样做的代价是灵活性和可靠性的巨大损失。 For example, now you can't have the same object in two lists at the same time. 例如,现在您不能同时在两个列表中拥有相同的对象。 What happens if a caller retrieves an instance of a list member and tries to change one of the pointers itself? 如果调用者检索列表成员的实例并尝试更改其中一个指针本身会发生什么? What it a caller clones a node and fails to update the pointers? 调用者克隆节点并且无法更新指针的内容是什么? Etc. 等等。

Dave Ray makes the point that with an intrusive list you can delete a node in constant time because you already have the pointers and don't need to re-find the item. Dave Ray指出,通过一个侵入式列表,您可以在恒定时间内删除一个节点,因为您已经拥有指针并且不需要重新找到该项目。 True, but that assumes that you've saved a handle to the node somewhere and are now coming back to it. 没错,但是假设你已经在某个地方保存了一个句柄,现在又回到了它。 With the Java LinkedList class pretty much the only way to access elements is to traverse the list with an Iterator, or to search for a particular object. 使用Java LinkedList类,访问元素的唯一方法是使用Iterator遍历列表,或搜索特定对象。 If you traverse with an Iterator, the Iterator.remove will remove in constant time. 如果使用迭代器遍历,Iterator.remove将在恒定时间内移除。 So it's only if you search, find, and then decide to remove that you pay this penalty. 因此,只有当您搜索,查找,然后决定删除您支付此罚款时。 I think it would be an improvement on the LinkedList implementation if they cached a pointer to the last object found to improve the performance on precisely this point. 我认为如果它们缓存了指向最后一个对象的指针,那将是对LinkedList实现的一种改进,这个对象在这一点上提高了性能。 My guess is that they didn't because it would make the remove non-deterministic: You could have the same object in the list multiple times -- either literally the same instance or two objects that compare equal -- and the contract on remove presently says that it always removes the first occurrence. 我的猜测是他们没有,因为它会使删除不确定:你可以多次在列表中有相同的对象 - 字面上相同的实例或两个比较相等的对象 - 和目前删除的合同说它总是删除第一次出现。 If there was a cached pointer, it would be difficult to say whether this was the first, second, or 42nd. 如果存在缓存指针,则很难说这是第一个,第二个还是第42个。

Oh, to actually answer your question: No, I'm not aware of an open-source implementation out there. 哦,实际上回答你的问题:不,我不知道那里有一个开源实现。 But then if I needed my own flavor of a linked list, I think I'd just roll my own. 但是如果我需要自己的链接列表的味道,我想我只是自己动手。 Presumably if the standard Java one doesn't meet your needs, that must mean that you have some pretty specialized need. 据推测,如果标准Java不符合您的需求,那必定意味着您有一些非常专业的需求。 In which case searching for an off-the-shelf implementation that happens to meet your specialized need sounds like a lot of trouble, and you could surely implement it in, what, a day or two of work? 在这种情况下,搜索恰好满足您的专业需求的现成实现听起来很麻烦,您肯定可以在一天或两天的工作中实现它? You'd probably spend more time searching for a suitable product than it would take to just do it. 您可能花费更多时间寻找合适的产品,而不是仅仅这样做。 You've probably already spent more time reading the replies to this post than it would have taken you to write it. 你可能已经花了更多的时间来阅读这篇文章的回复,而不是写你的回复。

Have you taken a look at the Deque class ? 你看过Deque课了吗? Per the javadoc, "A linear collection that supports element insertion and removal at both ends. The name deque is short for "double ended queue" and is usually pronounced "deck"." 根据javadoc,“支持两端元素插入和删除的线性集合。名称deque是”双端队列“的缩写,通常发音为”deck“。” It is implemented by ArrayDeque , LinkedBlockingDeque and LinkedList . 它是由执行ArrayDequeLinkedBlockingDeque链表

Java's semantics are by design intrusive, they use references and don't copy. Java的语义是设计侵入性的,它们使用引用而不是复制。 You basically just want to find the best linked list implementation that java has, LinkedList or whatever, and it'll be intrusive. 你基本上只是想找到java拥有的最好的链表实现, LinkedList或其他什么,它将是侵入性的。

import java.util.LinkedList;

public class Foo {

  public static void main(String[] args) {
    String[] i = new String[1];
    i[0] = "FOO";
    String[] j = new String[1];
    j[0] = "BAZ";

    LinkedList<String[]> list = new LinkedList<String[]>();

    list.add(i);
    list.add(j);

    for (String[] x: list) {
      System.out.println(x[0]);
    }

    i[0] = "ZILCH";

    for (String[] x: list) {
      System.out.println(x[0]);
    }
  }
}

Here's the output, notice how changing i changed the value in the list. 这是输出,请注意我如何更改列表中的值。

FOO
BAZ
ZILCH
BAZ

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM