我需要在变化的大集合中找到最小/最大值,在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))
答案 0 :(得分:4)
在复杂性方面的有效实现是包装python set
(使用哈希表)并在对象中保留一对maxElement
和minElement
属性,并更新这些属性因此在添加或删除元素时。这使得每个查询都存在,最小和最大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。