问题
I want to be able to access a certain node in my Doubly Linked List in O(1) time. I know that if i traverse the list to find a certain node it would take O(n) time so I want to map the nodes to an array list where I can access the nodes in O(1) time.
I'm really unsure how I would do this mapping. I would like to see an example of how this can be done.
Edit: I would like to be able to access any node in the linked list so I can move the nodes around in O(1) time.
Example: Move node with ID 5 to end of list in O(1) time.
Edit 2: I uploaded a picture example of what I'm trying to accomplish
回答1:
You can't do this with the built-in data structures ArrayList and LinkedList.
In general, it is not possible at all to have both of
- O(1) indexing (by position in the list)
- O(1) removing/adding/moving anywhere in the list.
The possibilities:
- You can get to O(log(N)) for both these if you use a tree-based structure.
- You can get to O(1) for indexing with a array-based structure, but then removing/adding in the middle takes O(n).
- You can use a Hash-Map like-structure with adding/removing in O(1), but it only allows O(1) access by key, not access by index (other than iterating, i.e. O(n)). (This means, if you add/remove something in the middle, the indexes after it won't change.)
Even if you try to combine a linked list with an array, you'll have O(n) for removing/adding (since you still have to update the array).
Okay, with your added image to show what you want, it is doable. You are in fact reimplementing something like LinkedHashMap, but only with consecutive integer keys and with ability to manipulate the "Linked" part.
If your linked list consists of Node
objects, you would have an ArrayList<Node>
.
You would only add elements to the ArrayList when adding new nodes to the linked list, else use the ArrayList only for lookup.
Here is an example:
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);
}
}
You might want to add more operations here, but these are enough for the example in the question:
FastIndexedLinkedList<String> ll = new FastIndexedLinkedList<String>();
ll.add("0");
ll.add("1");
ll.add("2");
ll.add("3");
ll.moveNodeToEnd(2);
回答2:
I'm not entirely sure of your purpose, do you simply wish to retrieve the object's index in O(1)?
This is how it would look:
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 );
}
Now, if you want to find an object in your list, what you do is get its index from the mapper object with
mapper.get( o );
================================
Re: your edit
You can't (or there's none that I am aware of). You are essentially demanding the best of both worlds (linked lists and arrays).
回答3:
LinkedHashMap: provides O(1) time and keys are doubly-linked list ordered.
回答4:
Use the toArray()
method to convert your LinkedList to an array for constant-time retrieval:
LinkedList.toArray(arr)
来源:https://stackoverflow.com/questions/5752087/arraylist-mapping-to-linkedlist-nodes