#!/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 return merge 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 return merge def prepare3(): def merge(a,b): a, b = iter(a), iter(b) try: 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 b except: yield from a return merge merge1 = prepare1() merge2 = prepare2() merge3 = prepare3() lst1 = list(range(1, 100000, 2)) lst2 = list(range(2, 100001, 2)) lst11 = list(range(1, 100000, 2)) lst22 = list(range(2, 100001, 2)) lst111 = list(range(1, 100000, 2)) lst222 = list(range(2, 100001, 2)) def f1(): merge1([], []) merge1([1, 3, 5], [2, 4, 6]) merge1(lst1, lst2) def f2(): list(merge2([], [])) list(merge2([1, 3, 5], [2, 4, 6])) list(merge2(lst11, lst22)) def f3(): list(merge3([], [])) list(merge3([1, 3, 5], [2, 4, 6])) list(merge3(lst111, lst222)) def main(): t1 = timeit.Timer('f1()', 'from __main__ import f1') t2 = timeit.Timer('f2()', 'from __main__ import f2') t3 = timeit.Timer('f3()', 'from __main__ import f3') for t in t1, t2, t3: print(t.repeat(3, 100)) if __name__ == '__main__': main()
[guest@localhost py]$ ./mergecmp1.py
[0.6375549949998458, 0.0005647759999192203, 0.0005668369994964451]
[4.651441780999448, 4.622966723999525, 4.6205978140005755]
[3.620450236000579, 3.6205695090002337, 3.611680899000021]
[guest@localhost py]$
IsemВ динамической памяти там обычно хранится всё. (Это чтобы была возможность что-то удалять и освобождать память из под этого.)
где хранится прицепленный к структуре массив?
IsemЭти операции синтаксически одинаковые и означают “прочитать часть объекта”. То, что они по разному выполняются, - это обычный полиморфизм, до которого нам дела нет. Ты сказал, что операции со списком и кортежем не отличаются по скорости, если это операции чтения. Вот тебе операция взятия среза, под операцию записи она не подпадает, потому что список не меняется.
В действительности (это неявно), взятие среза у списка - это одна операция, которая создает новый список, а взятие среза у тьюпла - это другая операция, которая создает новый тьюпл.
IsemНу, не знаешь ты C, не примазывайся. Если изучал C++, то C ты не знаешь. А если думаешь, что знаешь, то ты заблуждаешься. Потому что они разные и всё там работает по-разному.
Ключевое слово в этой фразе: теоретизировал. Считаем, что ты говоришь за себя о себе, а не о других.
IsemВ общем, с чего ты взял, что в десятки раз? Как замерял?
Итератолры пошли великолепно (особенно по сравнению с вызовом pop первого элемента в цикле), потому что скорость работы merge увеличилась в десятки раз.
Я думаю, ты их не тождественно замерил. Вверху показано, что в 6-8 раз.
IsemА кому нужна merge() без mergesort() ? Ты ещё скажи взять какую-нибудь часть из merge() и потестировать её. В том-то и дело, что никому эта функция не нужна, она вспомогательная. И как показали результаты, никакого существенного преимущества итераторный вариант не даёт, только код делает нечитаемым.
Мы же (то есть ты), стал тестировать mergesort (не inplace), на основе такой же merge (то есть не inplace).
IsemЭто ты его читал или тоже где-то в теории читал, что у Кнута много сортировок? ;)
У Кнута, кстати, подробно рассмотрены десятки алгоритмов сортировки, рекомендую.
IsemФантазии, фантазии… Комарик сел - комарика прихлопнули.
Вот эот pop и делает алгоритм merge ужасно неэффективным.
IsemДа, давай, взялся за гуж, не говори, что не дюж :)
С итерабельным вариант готов, осталось все то же самое сделать inplace и довести их до совершенства. Кто начнет? Готов?
IsemДа можно и оставить, мне просто жалко тебя, я как представлю, какой это получится быдлокодище (ты, кстати, исключение в merge() отловил, как новичок), то я просто вижу, как ты смотришь на этого монстра и думаешь “нафиг я всё это писал”. Так оно ещё потом и получится медленным - двойной удар.
А бессмысленную полемику предлагаю отставить.
IsemЭто ещё зачем? И как ты представишь, если программа на питоне переносится на разные архитектуры?
Чтобы написать оптимальный код, надо представлять что происходит на уровне команд процессора (CPU то есть).