My implementation of merging two sorted lists in linear time - what could be improved?

后端 未结 9 546
忘掉有多难
忘掉有多难 2021-01-01 04:47

Fromg Google\'s Python Class:

E. Given two lists sorted in increasing order, create and return a merged
list of all the elements in sorted order. You may mod         


        
相关标签:
9条回答
  • 2021-01-01 04:53

    Here's my implementation from a previous question:

    def merge(*args):
        import copy
        def merge_lists(left, right):
            result = []
            while (len(left) and len(right)):
                which_list = (left if left[0] <= right[0] else right)
                result.append(which_list.pop(0))
            return result + left + right
        lists = [arg for arg in args]
        while len(lists) > 1:
            left, right = copy.copy(lists.pop(0)), copy.copy(lists.pop(0))
            result = merge_lists(left, right)
            lists.append(result)
        return lists.pop(0)
    
    0 讨论(0)
  • 2021-01-01 04:54

    I agree with other answers that extending and sorting is the most straightforward way, but if you must merge, this will be a little faster because it does not make two calls to len every iteration nor does it do a bounds check. The Python pattern, if you could call it that, is to avoid testing for a rare case and catch the exception instead.

    def linear_merge(list1, list2):
        merged_list = []
        i = 0
        j = 0
    
        try:
            while True:
                if list1[i] <= list2[j]:
                    merged_list.append(list1[i])
                    i += 1
                else:
                    merged_list.append(list2[j])
                    j += 1
        except IndexError:
            if i == len(list1):
                merged_list.extend(list2[j:])
            if j == len(list2):
                merged_list.extend(list1[i:])
        return merged_list
    

    edit Optimized per John Machin's comment. Moved try outside of while True and extended merged_list upon exception.

    0 讨论(0)
  • 2021-01-01 04:56

    Here's a generator approach. You've probably noticed that a whole lot of these "generate lists" can be done well as generator functions. They're very useful: they don't require you to generate the whole list before using data from it, to keep the whole list in memory, and you can use them to directly generate many data types, not just lists.

    This works if passed any iterator, not just lists.

    This approach also passes one of the more useful tests: it behaves well when passed an infinite or near-infinite iterator, eg. linear_merge(xrange(10**9), xrange(10**9)).

    The redundancy in the two cases could probably be reduced, which would be useful if you wanted to support merging more than two lists, but for clarity I didn't do that here.

    def linear_merge(list1, list2):
        """
        >>> a = [1, 3, 5, 7]
        >>> b = [2, 4, 6, 8]
        >>> [i for i in linear_merge(a, b)]
        [1, 2, 3, 4, 5, 6, 7, 8]
        >>> [i for i in linear_merge(b, a)]
        [1, 2, 3, 4, 5, 6, 7, 8]
        >>> a = [1, 2, 2, 3]
        >>> b = [2, 2, 4, 4]
        >>> [i for i in linear_merge(a, b)]
        [1, 2, 2, 2, 2, 3, 4, 4]
        """
        list1 = iter(list1)
        list2 = iter(list2)
    
        value1 = next(list1)
        value2 = next(list2)
    
        # We'll normally exit this loop from a next() call raising StopIteration, which is
        # how a generator function exits anyway.
        while True:
            if value1 <= value2:
                # Yield the lower value.
                yield value1
                try:
                    # Grab the next value from list1.
                    value1 = next(list1)
                except StopIteration:
                    # list1 is empty.  Yield the last value we received from list2, then
                    # yield the rest of list2.
                    yield value2
                    while True:
                        yield next(list2)
            else:
                yield value2
                try:
                    value2 = next(list2)
    
                except StopIteration:
                    # list2 is empty.
                    yield value1
                    while True:
                        yield next(list1)
    
    0 讨论(0)
  • 2021-01-01 04:57

    Another generator:

    def merge(xs, ys):
        xs = iter(xs)
        ys = iter(ys)
        try:
            y = next(ys)
        except StopIteration:
            for x in xs:
                yield x
            raise StopIteration
        while True:
            for x in xs:
                if x > y:
                    yield y
                    break
                yield x
            else:
                yield y
                for y in ys:
                    yield y
                break
            xs, ys, y = ys, xs, x
    
    0 讨论(0)
  • 2021-01-01 05:02

    hi i just did this exercise and i was wondering why not use,

    def linear_merge(list1, list2):
      return sorted(list1 + list2)
    

    pythons sorted function is linear isn't it?

    0 讨论(0)
  • 2021-01-01 05:07

    This question covers this in more detail than you probably need. ;) The chosen answer matches your requirement. If I needed to do this myself, I would do it in the way that dbr described in his or her answer (add the lists together, sort the new list) as it is very simple.

    EDIT:

    I'm adding an implementation below. I actually saw this in another answer here which seems to have been deleted. I'm just hoping it wasn't deleted because it had an error which I'm not catching. ;)

    def mergeSortedLists(a, b):
        l = []
        while a and b:
            if a[0] < b[0]:
                l.append(a.pop(0))
            else:
                l.append(b.pop(0))
        return l + a + b
    
    0 讨论(0)
提交回复
热议问题