【问题标题】:Arraylist mapping to linkedlist nodesArraylist 映射到链表节点
【发布时间】:2011-08-10 18:14:12
【问题描述】:

我希望能够在 O(1) 时间内访问我的双向链表中的某个节点。我知道如果我遍历列表以找到某个节点将花费 O(n) 时间,所以我想将节点映射到一个数组列表,我可以在 O(1) 时间内访问这些节点。

我真的不确定如何进行此映射。我想看一个如何做到这一点的例子。

编辑: 我希望能够访问链表中的任何节点,这样我就可以在 O(1) 时间内移动节点。

示例:在 O(1) 时间内将 ID 为 5 的节点移动到列表末尾。

编辑 2:我上传了我正在尝试完成的图片示例

【问题讨论】:

    标签: java arraylist linked-list


    【解决方案1】:

    使用内置数据结构 ArrayList 和 LinkedList 无法做到这一点。

    一般来说,根本不可能两者兼得

    • O(1) 索引(按列表中的位置)
    • O(1) 删除/添加/移动列表中的任意位置。

    可能性:

    • 如果您使用基于树的结构,则这两项都可以达到 O(log(N))。
    • 您可以使用基于数组的结构进行索引 O(1),但在中间删除/添加需要 O(n)。
    • 您可以在 O(1) 中使用具有添加/删除功能的 Hash-Map 类似结构,但它只允许 O(1) 通过键访问,而不是通过索引访问(迭代除外,即 O(n)) . (这意味着,如果你在中间添加/删除某些东西,它后面的索引不会改变。)

    即使您尝试将链表与数组组合,您也需要 O(n) 来删除/添加(因为您仍然需要更新数组)。


    好的,用你添加的图片来展示你想要的,这是可行的。您实际上是在重新实现 LinkedHashMap 之类的东西,但只能使用连续的整数键并且能够操作“链接”部分。

    如果您的链接列表由Node 对象组成,您将拥有ArrayList<Node>

    只有在向链表添加新节点时才向 ArrayList 添加元素,否则 ArrayList 仅用于查找。

    这是一个例子:

    class FastIndexLinkedIntList<X> {
       class Node {
          Node next;
          Node prev;
          int key;
          X value;
          Node(int key, X val) { this.key = key; this.value = val; }
       }
    
       ArrayList<Node> indexedNodes = new ArrayList<Node>();
       Node head;
       Node tail;
    
    
       public void add(X value) {
          int key = indexedNodes.size();
          Node node = new Node(key, value);
          insertAtEnd(node);
          indexedNodes.add(node);
       }
    
       private void insertAtEnd(Node n) {
          if(tail == null) {
             assert head == null;
             head = n;
             tail = n;
             return;
          }
          n.prev = tail;
          n.next = null;
          tail.next = n;
          tail = n;
       }
    
       private void removeNode(Node n) {
          if(n.next == null) {
             assert n == tail;  // last node
    
             tail = n.prev;
             tail.next = null;
          }
          else {
             n.next.prev = n.prev;
          }
    
          if(n.prev == null) {
             assert n == head; // first node
    
             head = n.next;
             head.prev = null;
          }
          else {
             n.prev.next = n.next;
          }
       }
    
       public void moveNodeToEnd(int key) {
          Node n = indexedNodes.get(key);
          removeNode(n);
          insertAtEnd(n);
       }
    
    }
    

    您可能想在此处添加更多操作,但对于问题中的示例来说这些就足够了:

    FastIndexedLinkedList<String> ll = new FastIndexedLinkedList<String>();
    ll.add("0");
    ll.add("1");
    ll.add("2");
    ll.add("3");
    ll.moveNodeToEnd(2);
    

    【讨论】:

    • 我只使用内置的 ArrayList,同时使用我自己的双向链表。此外,我不希望仅将链表保持有序。 LinkedList 中的节点将是 Integer 类型,并且将等于 arraylist 中的索引。所以一个 get 方法就足够了,而且是 O(1) 时间。我只是不完全理解如何在Java中进行arraylist和linkedlist之间的链接。
    • @DomX23:我认为这不是一个真正的问题。我在答案中添加了一个示例。
    【解决方案2】:

    我不完全确定你的目的,你只是想在 O(1) 中检索对象的索引吗?

    这就是它的样子:

    LinkedList<Object> aList; // your LinkedList
    Map<Object, Integer> mapper = new HashMap<Object, Integer>();
    Object[] arr = aList.toArray();
    for( int i = 0; i < arr.length; i++ ){
        mapper.put( arr[i], i );
    }
    

    现在,如果你想在列表中找到一个对象,你要做的就是从映射器对象中获取它的索引

    mapper.get( o );
    

    =================================

    回复:您的编辑

    你不能(或者我不知道)。您基本上要求两全其美(链表和数组)。

    【讨论】:

      【解决方案3】:

      LinkedHashMap:提供 O(1) 时间,并且键是双向链表排序的。

      【讨论】:

      • 我的目标不仅是获得 O(1) 时间,还要了解如何将 arraylist 中的索引链接到链表中的节点,并通过 arraylist 检索该节点。跨度>
      【解决方案4】:

      使用toArray() 方法将您的LinkedList 转换为数组以进行恒定时间检索:

      LinkedList.toArray(arr)

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-06-06
        • 2015-08-21
        • 2016-07-02
        • 1970-01-01
        • 2011-04-18
        • 1970-01-01
        相关资源
        最近更新 更多