У python есть отсортированный список?

Под этим я подразумеваю структуру с:

  • O (log n) для операций x.push()
  • O (log n) сложность для поиска элемента
  • O (n) сложность вычисления list(x), которая будет сортироваться

У меня также был связанный вопрос о производительности list(...).insert(...), который теперь здесь.

Ответ 1

Стандартный список Python не сортируется в какой-либо форме. Стандартный модуль heapq может использоваться для добавления в O (log n) и удаления самого маленького в O (log n), но не является сортированным списком в вашем определении.

Существуют различные реализации сбалансированных деревьев для Python, которые отвечают вашим требованиям, например. rbtree, RBTree, или pyavl.

Ответ 2

Есть ли какая-то особая причина для ваших требований к большому O? Или вы просто хотите, чтобы это было быстро? Модуль sortedcontainers является чистым-Python и быстрым (как в реализациях fast-as-C, таких как blist и rbtree).

Сравнение производительности показывает, что эталонные тесты быстрее или совпадают с типом отсортированного списка. Также обратите внимание, что rbtree, RBTree и PyAVL предоставляют отсортированные типы dict и set, но не имеют отсортированного типа списка.

Если производительность является обязательным требованием, всегда помните о контроле. Модуль, который обосновывает требование быть быстрым с нотами Big-O, должен быть подозрительным, пока он не покажет сравнительные сравнения.

Отказ от ответственности: Я являюсь автором модуля сортированных контейнеров Python.


Установка:

pip install sortedcontainers

Использование:

>>> from sortedcontainers import SortedList
>>> l = SortedList()
>>> l.update([0, 4, 1, 3, 2])
>>> l.index(3)
3
>>> l.add(5)
>>> l[-1]
5

Ответ 3

Хотя я до сих пор не проверял "большие O" скорости основных операций с списком Python, стандартный модуль bisect, вероятно, также стоит упомянуть в этом контексте:

import bisect
L = [0, 100]

bisect.insort(L, 50)
bisect.insort(L, 20)
bisect.insort(L, 21)

print L
## [0, 20, 21, 50, 100]

i = bisect.bisect(L, 20)
print L[i-1], L[i]
## 20, 21

PS. Ах, извините, bisect упоминается в упомянутом вопросе. Тем не менее, я думаю, что это не будет большим вредом, если эта информация будет здесь)

ПФС. И Списки CPython на самом деле являются массивами (не скажем, skiplists и т.д.). Ну, я думаю, они должны быть чем-то простым, но что касается меня, это немного вводит в заблуждение.


Итак, если я не ошибаюсь, скорости bisect/list, вероятно, будут:

  • для push(): O (n) для наихудшего случая;
  • для поиска: если мы считаем, что скорость индексации массива равна O (1), поиск должен быть операцией O (log (n));
  • для создания списка: O (n) должна быть скоростью копирования списка, иначе O (1) для того же списка)

Обновление.. После обсуждения в комментариях позвольте мне связать здесь эти SO-вопросы: Как реализован список Python и Что такое сложность выполнения функций списка python во время выполнения

Ответ 4

Хотя он еще не предоставляет функцию пользовательского поиска, модуль heapq может удовлетворить ваши потребности. Он реализует очередь кучи, используя обычный список. Вам придется написать свой собственный эффективный тест на членство, который использует внутреннюю структуру очереди (что можно сделать в O (log n), я бы сказал...). Существует один недостаток: извлечение отсортированного списка имеет сложность O (n log n).

Ответ 5

import bisect

class sortedlist(list):
    '''just a list but with an insort (insert into sorted position)'''
    def insort(self, x):
        bisect.insort(self, x)

Ответ 6

Возможно, не сложно реализовать собственный список сортировок на Python. Ниже приведено доказательство концепции:

import bisect

class sortlist:
    def __init__(self, list):
        self.list = list
        self.sort()
    def sort(self):
        l = []
        for i in range(len(self.list)):
            bisect.insort(l, self.list[i])
        self.list = l
        self.len = i
    def insert(self, value):
        bisect.insort(self.list, value)
        self.len += 1
    def show(self):
        print self.list
    def search(self,value):
        left = bisect.bisect_left(self.list, value)
        if abs(self.list[min([left,self.len-1])] - value) >= abs(self.list[left-1] - value):
            return self.list[left-1]
        else:
            return self.list[left]

list = [101, 3, 10, 14, 23, 86, 44, 45, 45, 50, 66, 95, 17, 77, 79, 84, 85, 91, 73]
slist = sortlist(list)
slist.show()
slist.insert(99)
slist.show()
print slist.search(100000000)
print slist.search(0)
print slist.search(56.7)

========= Результаты ============

[3, 10, 14, 17, 23, 44, 45, 45, 50, 66, 73, 77, 79, 84, 85, 86, 91, 95, 101]

[3, 10, 14, 17, 23, 44, 45, 45, 50, 66, 73, 77, 79, 84, 85, 86, 91, 95, 99, 101]

101

3

50

Ответ 7

Я бы использовал модули biscect или sortedcontainers. Я не очень опытный, но я думаю, что модуль heapq работает. Он содержит Heap Queue