简体   繁体   中英

Is there a way to find an element in a linked-list by its index from the end of it

I have a non-cyclic linked list data structure. Like this:

public class LinkLst<T>{
    private Node<T> first;

    public LinkLst(T t){
        first = new Node(t);
    }
}

public class Node<T>{
    private T t;
    private Node<T> next;

    public Node(T t){
        this.t = t;
    }

    public void setNext(Node<T> n){
         this.next = next;
    }
}

So we know by default the List contains no cycles. Is there a way to find a n-th element from the end of LinkLst<T> lst with only one iteration if n <= size(lst) and throw IndexOutOfBoundException if n > size(lst) .

public <T> T fromTheEnd(LinkLst<T> lst, int n){
   //...?
}

The only thing I could find is to reverse it and then find the desired element, but it requires 2 iterations. One for reverse and one to find the desired element. Also memory overhead.

public <T> T fromTheEnd(LinkList<T> ts, int idx) {
    Node<T> follower, leader;
    // We iterate until the leader hits the end of the list. follower follows leader
    // idx steps behind, so when leader.next = [], follower is the desired node.
    follower = leader = ts.first;
    for(int j = 0; j < idx; j++) {
        leader = leader.next;
    }
    // leader is now idx steps ahead
    while(leader.next != null) {
      leader = leader.next;
      follower = follower.next;
    }
    // leader has hit the end (next is null)
    // follower has your data
    return follower.t;
}

In essence, this is a single iteration with two "heads."

Example of indexing 2 into [1, 2, 3, 4, 5] , from the end.

Setup:
[1, 2, 3, 4, 5]
 ^ Leader
 ^ Follower

First loop:
[1, 2, 3, 4, 5]
 ^ F   ^ L

Second loop round 0:
[1, 2, 3, 4, 5]
    ^ F   ^ L

Second loop round 1:
[1, 2, 3, 4, 5]
       ^ F   ^ L

Loop ends: next(leader) = []
deref(follower) = 3

You'll probably want to factor out the method <T> LinkList<T> last(LinkList<T>, int) that returns the suffix of the list with the given length, which lets you express fromTheEnd as just last(ts, n).first.t .

If you don't want to iterate twice, you'd have to remember n values, which requires memory. Whether that's better than iterating twice is for you to decide.

Create an array of size n , and add values to array in a cyclic manner as you iterate the list.

When reaching end of list, and at least n elements have been iterated, the nth-from-last element is in the next position of the cyclic array.

This sacrifices memory for performance.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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