В данном фрагменте Python кода функция сортирует список чисел но работает медленно и иногда возвращает неверный результат: def weird_sort(a): for i in range(len(a)): for j in range(i+1,len(a)): if a[i] > a[j]: a[i], a[j] = a[j], a[i] return a; найдите логическую ошибку, оцените сложность алгоритма, предложите исправление и модификации для работы с большими объёмами данных

12 Окт в 08:19
5 +5
0
Ответы
1

Коротко — логическая ошибка в отступах: функция возвращает список внутри внешнего цикла, поэтому сортировка прерывается после первой итерации и список может остаться частично отсортированным.

Разбор и исправление

Исходный код спроблемой—returnвнутрициклас проблемой — return внутри цикласпроблемойreturnвнутрицикла:
def weird_sortaaa:
for i in rangelen(a)len(a)len(a):
for j in rangei+1,len(a)i+1,len(a)i+1,len(a):
if aiii > ajjj:
aiii, ajjj = ajjj, aiii return a # <- возвращаем слишком рано!

Правильный вариант — return должен быть после завершения обоих циклов:
def weird_sortaaa:
for i in rangelen(a)len(a)len(a):
for j in rangei+1,len(a)i+1, len(a)i+1,len(a):
if aiii > ajjj:
aiii, ajjj = ajjj, aiii return a

Альтернативы и улучшения

1) Использовать встроенную сортировку Python рекомендуетсядляобщегослучая—быстрая,надежнаярекомендуется для общего случая — быстрая, надежнаярекомендуетсядляобщегослучаябыстрая,надежная:
def weird_sortaaa:
a.sort # in-place, Onlognn log nnlogn return a

или возвращающая новый список: return sortedaaa

2) Немного оптимизировать ваш On2n^2n2-алгоритм уменьшитьчислообменовуменьшить число обменовуменьшитьчислообменов — классический selection sort:
def selection_sortaaa:
n = lenaaa for i in rangennn:
min_idx = i
for j in rangei+1,ni+1, ni+1,n:
if ajjj < aminidxmin_idxmini dx:
min_idx = j
if min_idx != i:
aiii, aminidxmin_idxmini dx = aminidxmin_idxmini dx, aiii return a

Сложность

Исходный двоичный цикл: время On2n^2n2 точно n(n−1)/2сравненийточно ~ n(n-1)/2 сравненийточно n(n1)/2сравнений. Количество обменов в худшем случае тоже On2n^2n2 висходнойверсиивыменяетеприкаждомобнаружениименьшегоэлементав исходной версии вы меняете при каждом обнаружении меньшего элементависходнойверсиивыменяетеприкаждомобнаружениименьшегоэлемента.Selection sort: On2n^2n2 сравнений, но только Onnn обменов.Встроенный sorted/list.sort: Onlognn log nnlogn в среднем и в худшем TimsortTimsortTimsort, память Onnn в худшем для некоторых сценариев, обычно работает очень быстро на реальных данных.

Работа с большими объёмами данных

Если данные в памяти помещаются: используйте list.sort или sorted. Для чисел можно рассмотреть numpy.sort эффективнодлябольшихмассивовчиселэффективно для больших массивов чиселэффективнодлябольшихмассивовчисел.

Если данные не помещаются в ОЗУ внешняясортировкавнешняя сортировкавнешняясортировка:

Разбиваете файл/поток на чанки, сортируете каждый чанк в памяти и сохраняете отсортированные чанки на диск.Затем выполняете k-way merge например,heapq.mergeвPythonнапример, heapq.merge в Pythonнапример,heapq.mergeвPython по отсортированным файлам, записывая результат в выходной файл.
Пример концепта упрощённоупрощённоупрощённо:
import heapq, tempfile
def external_sortinfile,outfile,chunksize=1000000infile, outfile, chunk_size=10_000_00infile,outfile,chunks ize=100 000 0:
chunks = with openinfileinfileinfile as f:
while True:
chunk = listislice(f,chunksize)islice(f, chunk_size)islice(f,chunks ize) if not chunk:
break
chunk = int(x)forxinchunkint(x) for x in chunkint(x)forxinchunk chunk.sort tmp = tempfile.TemporaryFilemode=′w+t′mode='w+t'mode=w+t tmp.writelines(f"{x}\n" for x in chunk)
tmp.seek000 chunks.appendtmptmptmp with openoutfile,′w′outfile, 'w'outfile,w as out:
for val in heapq.merge∗[map(int,c)forcinchunks]*[map(int, c) for c in chunks][map(int,c)forcinchunks]:
out.write(f"{val}\n")

Для параллельной обработки: разбить данные на части, отсортировать параллельно multiprocessing/MapReducemultiprocessing/MapReducemultiprocessing/MapReduce, затем выполнить k-way merge.

Если данные лежат в БД — сортировать средствами СУБД индексы,ORDERBYсexternalsortиндексы, ORDER BY с external sortиндексы,ORDERBYсexternalsort.

Для очень больших потоков и простых числовых ключей можно использовать radix sort / counting sort линейноевремялинейное времялинейноевремя при ограниченном диапазоне ключей.

Коротко по практическим рекомендациям

Для большинства задач — заменить ваш код на a.sort или sortedaaa.Если нужен in-place и вы не хотите побочных эффектов — a.sort; return a.Если память ограничена — использовать внешнюю сортировку chunk+mergechunk+mergechunk+merge или системные инструменты sortвUnixsort в UnixsortвUnix.Для почти отсортированных данных insertion sort илиоставитьTimsortили оставить TimsortилиоставитьTimsort будет быстрым.

Если нужно, могу:

Подправить ваш конкретный фрагмент кода в проекте.Показать рабочую реализацию внешней сортировки с учётом чтения/записи файлов.Рассчитать примерно время и место при конкретных объёмах данных.
12 Окт в 09:23
Не можешь разобраться в этой теме?
Обратись за помощью к экспертам
Гарантированные бесплатные доработки в течение 1 года
Быстрое выполнение от 2 часов
Проверка работы на плагиат
Поможем написать учебную работу
Прямой эфир