Форум сайта python.su
здравствуйте,
пишу merge sort algorithm по статье из википедии сортировка слиянием. ту часть, где в статье внизу написано на псевдокоде.
мой код:
m = [4, 3, 5, 1, 6, 9 , 7 , 8] def mergesort (m): left = [] right = [] result = [] if len(m) <= 1: return m else: middle = len(m) / 2 for i in range(0, middle): left.append(m[i]) for i in range(middle, len(m)): right.append(m[i]) left = mergesort(left) right = mergesort(right) result = merge(left, right) return result def merge(left, right): result = [] while len(left) > 0 and len(right) > 0: if left[0] <= right[0]: result.append(left[0]) left.pop(0) else: result.append(right[0]) right.pop(0) if len(left) > 0: result.append(left) if len(right) > 0: result.append(right) return result b = mergesort(m) print b
[1, 3, 6, 7, [4], [8], [[5]], [[[9]]]]
Офлайн
Как-то писал mergesort():
"""Merge sort.""" def merge(left, right): """Merge two lists in ascending order.""" lst = [] while left and right: if left[0] < right[0]: lst.append(left.pop(0)) else: lst.append(right.pop(0)) if left: lst.extend(left) if right: lst.extend(right) return lst def mergesort(lst): """Sort the list by merging O(n * log n).""" length = len(lst) if length >= 2: mid = int(length / 2) lst = merge(mergesort(lst[:mid]), mergesort(lst[mid:])) return lst
Офлайн
!!! все исправилось, когда я заменил в merge, в последних условиях, append на extend. спасибо
Отредактировано iawrow (Авг. 27, 2015 12:16:55)
Офлайн
Сложно придумать более неэффективную операцию, чем удаление первого элемента списка в цикле:
py.user.next
for … :
list.pop(0)
def merge(a,b): a, b = iter(a), iter(b) def gen(a, b): vb = next(b) while 1: va = next(a) if va > vb: va, vb, a, b = vb, va, b, a yield va yield from gen(a, b) yield from a yield from b
Офлайн
IsemТы бы хоть проверил сначала.
Такой merge для списков из 100 000 элементов работает примерно в 30 и более раз быстрее, к тому же не разрушает исходные списки:
>>> def merge(a,b): ... a, b = iter(a), iter(b) ... def gen(a, b): ... vb = next(b) ... while 1: ... va = next(a) ... if va > vb: va, vb, a, b = vb, va, b, a ... yield va ... yield from gen(a, b) ... yield from a ... yield from b ... >>> def mergesort(lst): ... """Sort the list by merging O(n * log n).""" ... length = len(lst) ... if length >= 2: ... mid = int(length / 2) ... lst = merge(mergesort(lst[:mid]), mergesort(lst[mid:])) ... return lst ... >>> mergesort([]) [] >>> list(mergesort([3, 2, 1])) [1] >>> list(mergesort([4, 3, 2, 1])) [1] >>>
Офлайн
py.user.nextВ этом все и дело, что возвращается генератор, а не список (а почему, кстати, именно список, а не тьюпл, например?).
Там не только генератор возвращается на выходе (хотя нужен список)
def merge(a,b): a, b = iter(a), iter(b) def gen(a, b): vb = next(b) try: while 1: va = next(a) if va > vb: va, vb, a, b = vb, va, b, a yield va except: yield vb yield from gen(a, b) yield from a yield from b
def mergesort(lst): mid = len(lst) // 2 return merge(mergesort(lst[:mid]), mergesort(lst[mid:])) if mid else lst
>>> print(*mergesort([3, 2, 1])) 1 2 3 >>> tuple(mergesort([3, 2, 1, 9, -3])) (-3, 1, 2, 3, 9) >>>
Офлайн
#!/usr/bin/env python3 import timeit def prepare1(): def merge(left, right): """Merge two lists in ascending order.""" lst = [] while left and right: if left[0] < right[0]: lst.append(left.pop(0)) else: lst.append(right.pop(0)) if left: lst.extend(left) if right: lst.extend(right) return lst def mergesort(lst): """Sort the list by merging O(n * log n).""" length = len(lst) if length >= 2: mid = int(length / 2) lst = merge(mergesort(lst[:mid]), mergesort(lst[mid:])) return lst return mergesort def prepare2(): def merge(a,b): a, b = iter(a), iter(b) def gen(a, b): vb = next(b) try: while 1: va = next(a) if va > vb: va, vb, a, b = vb, va, b, a yield va except: yield vb yield from gen(a, b) yield from a yield from b def mergesort(lst): mid = len(lst) // 2 return merge(mergesort(lst[:mid]), mergesort(lst[mid:])) if mid else lst return mergesort mergesort1 = prepare1() mergesort2 = prepare2() def f1(): mergesort1([]) mergesort1([3, 2, 1]) mergesort1([4, 3, 2, 1]) mergesort1([4, 3, 2, 1, 4, 3, 2, 1]) def f2(): list(mergesort2([])) list(mergesort2([3, 2, 1])) list(mergesort2([4, 3, 2, 1])) list(mergesort2([4, 3, 2, 1, 4, 3, 2, 1])) def main(): t1 = timeit.Timer('f1()', 'from __main__ import f1') t2 = timeit.Timer('f2()', 'from __main__ import f2') for t in t1, t2: print(t.repeat(3, 10000)) if __name__ == '__main__': main()
[guest@localhost py]$ ./mergecmp.py
[0.48058103199946345, 0.47939332600071793, 0.47897031599859474]
[0.6807953729985456, 0.6841518840010394, 0.6824002640023537]
[guest@localhost py]$
Отредактировано py.user.next (Авг. 28, 2015 07:00:23)
Офлайн
Возьмем побольше элементов для сортировки, чтобы понять асимптотическую сложность алгоритмов:
import timeit import random def prepare1(): def merge(left, right): """Merge two lists in ascending order.""" lst = [] while left and right: if left[0] < right[0]: lst.append(left.pop(0)) else: lst.append(right.pop(0)) if left: lst.extend(left) if right: lst.extend(right) return lst def mergesort(lst): """Sort the list by merging O(n * log n).""" length = len(lst) if length >= 2: mid = int(length / 2) lst = merge(mergesort(lst[:mid]), mergesort(lst[mid:])) return lst return mergesort def prepare2(): def merge(a,b): a, b = iter(a), iter(b) def gen(a, b): vb = next(b) try: while 1: va = next(a) if va > vb: va, vb, a, b = vb, va, b, a yield va except: yield vb yield from gen(a, b) yield from a yield from b def mergesort(lst): mid = len(lst) // 2 return merge(mergesort(lst[:mid]), mergesort(lst[mid:])) if mid else lst return mergesort mergesort1 = prepare1() mergesort2 = prepare2() lst = list(range(400000)) random.shuffle(lst) def f1(): mergesort1(lst) def f2(): list(mergesort2(lst)) def main(): t1 = timeit.Timer('f1()', 'from __main__ import f1') t2 = timeit.Timer('f2()', 'from __main__ import f2') for t in t1, t2: print(t.repeat(1, 1)) if __name__ == '__main__': main()
def mergesort(lst): mid = len(lst) // 2 return tuple(merge(mergesort(lst[:mid]), mergesort(lst[mid:]))) if mid else lst
Отредактировано Isem (Авг. 28, 2015 07:51:41)
Офлайн
#!/usr/bin/env python3 import timeit def prepare1(): def merge(left, right): """Merge two lists in ascending order.""" lst = [] while left and right: if left[0] < right[0]: lst.append(left.pop(0)) else: lst.append(right.pop(0)) if left: lst.extend(left) if right: lst.extend(right) return lst def mergesort(lst): """Sort the list by merging O(n * log n).""" length = len(lst) if length >= 2: mid = int(length / 2) lst = merge(mergesort(lst[:mid]), mergesort(lst[mid:])) return lst return mergesort def prepare2(): def merge(a,b): a, b = iter(a), iter(b) def gen(a, b): vb = next(b) try: while 1: va = next(a) if va > vb: va, vb, a, b = vb, va, b, a yield va except: yield vb yield from gen(a, b) yield from a yield from b def mergesort(lst): mid = len(lst) // 2 return merge(mergesort(lst[:mid]), mergesort(lst[mid:])) if mid else lst return mergesort mergesort1 = prepare1() mergesort2 = prepare2() lst = list(range(100000))[::-1] def f1(): mergesort1([]) mergesort1([3, 2, 1]) mergesort1([4, 3, 2, 1]) mergesort1([4, 3, 2, 1, 4, 3, 2, 1]) mergesort1(lst) def f2(): list(mergesort2([])) list(mergesort2([3, 2, 1])) list(mergesort2([4, 3, 2, 1])) list(mergesort2([4, 3, 2, 1, 4, 3, 2, 1])) list(mergesort2(lst)) def main(): t1 = timeit.Timer('f1()', 'from __main__ import f1') t2 = timeit.Timer('f2()', 'from __main__ import f2') for t in t1, t2: print(t.repeat(3, 10)) if __name__ == '__main__': main()
[guest@localhost py]$ ./mergecmp.py
[12.73703371800002, 12.702942302999986, 12.771910132000016]
[9.36449182199999, 9.416434981000009, 9.488683936999962]
[guest@localhost py]$
Отредактировано py.user.next (Авг. 28, 2015 10:21:39)
Офлайн
py.user.nextЕсли вызвать mergesort2, то у меня получается
list(mergesort2())
list(mergesort1(lst))
Офлайн