Concatenate two java.util.LinkedList in constant time

前端 未结 3 1101
你的背包
你的背包 2021-01-17 16:14

I\'m working on some piece of code, which is quite hot, and I need to add elements of one LinkedList (l1) to another LinkedList (

3条回答
  •  刺人心
    刺人心 (楼主)
    2021-01-17 16:23

    According to the comments, the goal is to create something like a "view" on the concatenated list - meaning that the data should not be copied. Instead, the given lists should "appear" like a single list.

    One way of how this could be implemented is to extend AbstractList. The implementation of get(int) and size() are fairly trivial. The crucial point is to create an Iterator for the concatenated list. The following is a very simple sketch of how this could be accomplished (but see the notes below)

    import java.util.AbstractList;
    import java.util.Arrays;
    import java.util.Collections;
    import java.util.Iterator;
    import java.util.List;
    
    public class MergedListTest
    {
        public static void main(String[] args)
        {
            testBasic();
            testEmptyA();
            testEmptyB();
        }
    
        private static void testBasic()
        {
            List list0 = Arrays.asList(0,1,2);
            List list1 = Arrays.asList(3,4,5);
            List expected = Arrays.asList(0,1,2,3,4,5);
            List actual = new MergedList(list0, list1);
            System.out.println(actual.equals(expected));
        }
    
        private static void testEmptyA()
        {
            List list0 = Collections.emptyList();
            List list1 = Arrays.asList(3,4,5);
            List expected = Arrays.asList(3,4,5);
            List actual = new MergedList(list0, list1);
            System.out.println(actual.equals(expected));
        }
    
        private static void testEmptyB()
        {
            List list0 = Arrays.asList(0,1,2);
            List list1 = Collections.emptyList();
            List expected = Arrays.asList(0,1,2);
            List actual = new MergedList(list0, list1);
            System.out.println(actual.equals(expected));
        }
    
    }
    
    
    class MergedList extends AbstractList
    {
        private final List list0;
        private final List list1;
    
        MergedList(List list0, List list1)
        {
            this.list0 = list0;
            this.list1 = list1;
        }
    
        @Override
        public T get(int index)
        {
            if (index < list0.size())
            {
                return list0.get(index);
            }
            return list1.get(index - list0.size());
        }
    
        @Override
        public Iterator iterator()
        {
            return new Iterator() 
            {
                private Iterator current = list0.iterator();
                private boolean first = true;
    
                @Override
                public boolean hasNext() 
                {
                    return current != null && current.hasNext();
                }
    
                @Override
                public T next() 
                {
                    T result = current.next();
                    if (!current.hasNext())
                    {
                        if (first)
                        {
                            current = list1.iterator();
                        }
                        else
                        {
                            current = null;
                        }
                    }
                    return result;
                }
            };
        }
    
        @Override
        public int size()
        {
            return list0.size() + list1.size();
        }
    }
    

    Conceptually, it would make more sense to inherit from AbstractSequentialList: The AbstractList offers stub implementations, e.g. of iterator(), that eventually delegate to get(int), whereas AbstractSequentialList offers the "opposite" stub implementations, e.g. of get(int) that eventually delegate to iterator(). However, this requires a ListIterator implementation, which is a bit more fiddly than the trivial sketch above.

    Also note that I assumed that the resulting view should be unmodifiable - but this should be in line with the given description.

    And finally, note that there are (of course) already implementations for this and similar tasks, and these implementations may be far more sophisticated than the one sketched above. For example, Google Guava offers different Iterators#concat methods that allow you to concatenate multiple iterators. So if you are already using Guava, the implementation of the iterator() method above could boil down to

    @Override
    public Iterator iterator()
    {
        return Iterators.concat(list0.iterator(), list1.iterator());
    }
    

提交回复
热议问题