在python中查找更改集的最小值和最大值的有效方法

时间:2014-01-10 15:54:24

标签: python set max min

我需要在变化的大集合中找到最小/最大值,在C ++中,它可能是

#include<set>
using namespace std;
int minVal(set<int> & mySet){
    return *mySet.begin();
}
int maxVal(set<int> & mySet){
    return *mySet.rbegin();
}
int main(){
    set <int> mySet;
    for(..;..;..){
       // add or delete element in mySet
       ...
       // print the min and max value in the set
       printf("%d %d\n", minVal(mySet), maxVal(mySet)); 
    }
}

在C ++中,每个查询操作都是O(1),但是在python中,我尝试使用内置方法min和max但是它太慢了。每个最小/最大操作需要O(n)时间(n是我的Set的长度)。有没有优雅有效的方法来做到这一点?或者任何数据类型都支持这些操作?

mySet=set()
for i in range(..):
  # add or delete element in mySet
  ...
  # print the min and max value in the set
  print(min(mySet),max(mySet))

4 个答案:

答案 0 :(得分:4)

在复杂性方面的有效实现是包装python set(使用哈希表)并在对象中保留一对maxElementminElement属性,并更新这些属性因此在添加或删除元素时。这使得每个查询都存在,最小和最大O(1)。删除操作虽然是最简单实现的O(n)最坏情况(因为如果碰巧删除了最小元素,你必须找到next-to-minimum元素,并且最大值也是如此)。

这就是说,C ++实现使用平衡搜索树,它具有O(log n)存在检查,删除和插入操作。您可以在bintrees包中找到此类数据结构的实现。

我不会像评论中建议的那样仅使用heapq,因为堆是O(n)来检查元素的存在(我猜想,我认为你需要一组数据结构的主要点)。

答案 1 :(得分:0)

numpy min max是原生方法的两倍

import time as t
import numpy as np

def initialize():
    storage.reset()

def tick():

    array = data.btc_usd.period(250, 'close')

    t1 = t.time()

    a = min(array)
    b = max(array)

    t2 = t.time()

    c = np.min(array)
    d = np.max(array)

    t3 = t.time()

    storage.t1 = storage.get('t1', 0)
    storage.t2 = storage.get('t2', 0)
    storage.t1 += t2-t1
    storage.t2 += t3-t2


def stop():

    log('python: %.5f' % storage.t1)
    log('numpy: %.5f' % storage.t2)
    log('ticks: %s' % info.tick)

yeilds:

[2015-11-06 10:00:00] python: 0.45959
[2015-11-06 10:00:00] numpy: 0.26148
[2015-11-06 10:00:00] ticks: 7426

但我认为你正在寻找更像这样的东西:

import time as t
import numpy as np

def initialize():
    storage.reset()

def tick():

    storage.closes = storage.get('closes', [])
    if info.tick == 0:
        storage.closes = [float(x) for x in data.btc_usd.period(250, 'close')]
    else:
        z = storage.closes.pop(0) #pop left
        price = float(data.btc_usd.close)
        storage.closes.append(price) #append right
    array = np.array(storage.closes)[-250:]

    # now we know 'z' just left the list and 'price' just entered
    # otherwise the array is the same as the previous example

    t1 = t.time()
    # PYTHON METHOD
    a = min(array)
    b = max(array)

    t2 = t.time()
    # NUMPY METHOD
    c = np.min(array)
    d = np.max(array)

    t3 = t.time()
    # STORAGE METHOD
    storage.e = storage.get('e', 0)
    storage.f = storage.get('f', 0)
    if info.tick == 0:
        storage.e = np.min(array)
        storage.f = np.max(array)
    else:
        if z == storage.e:
            storage.e = np.min(array)
        if z == storage.f:
            storage.f = np.max(array)
        if price < storage.e:
            storage.e = price
        if price > storage.f:
            storage.f = price

    t4 = t.time()

    storage.t1 = storage.get('t1', 0)
    storage.t2 = storage.get('t2', 0)
    storage.t3 = storage.get('t3', 0)    
    storage.t1 += t2-t1
    storage.t2 += t3-t2
    storage.t3 += t4-t3


def stop():

    log('python: %.5f'  % storage.t1)
    log('numpy: %.5f'   % storage.t2)
    log('storage: %.5f' % storage.t3)
    log('ticks: %s'     % info.tick)

yeilds:

[2015-11-06 10:00:00] python: 0.45694
[2015-11-06 10:00:00] numpy: 0.23580
[2015-11-06 10:00:00] storage: 0.16870
[2015-11-06 10:00:00] ticks: 7426

它将我们降低到本机方法的大约1/3,对250个列表进行7500次迭代

答案 2 :(得分:0)

您可以使用两个优先级队列分别维护集合中的最小值和最大值。不幸的是,stdlib的heapq不支持在O(log n)时间内立即从队列中删除条目。建议的workaround只是将条目标记为已删除,然后在您从队列中弹出条目时将其丢弃(尽管在许多情况下这可能是可以的)。下面是实现该方法的Python类:

from heapq import heappop, heappush

class MinMaxSet:
    def __init__(self):
        self.min_queue = []
        self.max_queue = []
        self.entries = {}  # mapping of values to entries in the queue

    def __len__(self):
        return len(self.entries)

    def add(self, val):
        if val not in self.entries:
            entry_min = [val, False]
            entry_max = [-val, False]

            heappush(self.min_queue, entry_min)
            heappush(self.max_queue, entry_max)

            self.entries[val] = entry_min, entry_max

    def delete(self, val):
        if val in self.entries:
            entry_min, entry_max = self.entries.pop(val)
            entry_min[-1] = entry_max[-1] = True  # deleted

    def get_min(self):
        while self.min_queue[0][-1]:
            heappop(self.min_queue)
        return self.min_queue[0][0]

    def get_max(self):
        while self.max_queue[0][-1]:
            heappop(self.max_queue)
        return -self.max_queue[0][0]

演示:

>>> s = MinMaxSet()
>>> for x in [1, 5, 10, 14, 11, 14, 15, 2]:
...     s.add(x)
... 
>>> len(s)
7
>>> print(s.get_min(), s.get_max())
1 15
>>> s.delete(1)
>>> s.delete(15)
>>> print(s.get_min(), s.get_max())
2 14

答案 3 :(得分:0)

自2020年以来,软件包二叉树已被废弃,应替换为sortedcontainers

用法示例:

import sortedcontainers

s = sortedcontainers.SortedList()
s.add(10)
s.add(3)
s.add(25)
s.add(8)
min = s[0]      # read min value
min = s.pop(0)  # read and remove min value
max = s[-1]     # read max value
max = s.pop()   # read and remove max value

除了SortedList外,您还具有SortedDict和SortedSet。这是API documentation