exercises(つまり#6)の1つは、キュー実装のパフォーマンスを比較するように要求しています。それはいくつかの違いがあるように聞こえるので、私はそれを把握しようとしました。ここに私のコードはPythonでのキュー実装の違い
import timeit
class QueueStart(object):
'''Queue implementation with head in the beginning of a list'''
def __init__(self):
self.items = []
def enqueue(self, i):
self.items.append(i)
def dequeue(self):
return self.items.pop(0)
def isEmpty(self):
return len(self.items) == 0
def size(self):
return len(self.items)
class QueueEnd(object):
'''Queue implementation with head at the end of a list'''
def __init__(self):
self.items = []
def enqueue(self, item):
self.items.insert(0, item)
def dequeue(self):
return self.items.pop()
def isEmpty(self):
return len(self.items) == 0
def size(self):
return len(self.items)
# store results for further plotting
start_add_list = [] # QueueStart.enqueue(item) runtimes for inputs of different sizes
start_pop_list = [] # the same for QueueStart.dequeue(item)
end_add_list = [] # the same for QueueEnd.enqueue(item)
end_pop_list = [] # the same for QueueEnd.dequeue(item)
for i in range(100000, 500000, 10000):
qs = QueueStart()
qs.items = list(range(i))
qe = QueueEnd()
qe.items = list(range(i))
start_add = timeit.Timer('qs.enqueue(1)', 'from __main__ import qs')
start_pop = timeit.Timer('qs.dequeue()', 'from __main__ import qs')
end_add = timeit.Timer('qe.enqueue(1)', 'from __main__ import qe')
end_pop = timeit.Timer('qe.dequeue()', 'from __main__ import qe')
start_add_list.append(start_add.timeit(number=1000))
start_pop_list.append(start_pop.timeit(number=1000))
end_add_list.append(end_add.timeit(number=1000))
end_pop_list.append(end_pop.timeit(number=1000))
を反映プロットは、insert
とpop(index)
はO(n)があることが知られています。興味深いことに、グラフからわかるように、insert(0, item)
はpop(0)
の2倍の時間がかかります。その観察は私にはなぜ、これが当てはまるのか不思議に思った。表面上、2つの方法は非常によく似ていますが、明らかにボンネットの下には何か面白いことがあります。それで、問題は、あなたが私にそれを理解させる助けになるか?
これはおそらく実装に依存します。これは、基になる配列を追加したり削除したりするときに、操作がメモリをどのように管理するかに基づいています。例えば、 'pop(0)'は未使用メモリを犠牲にしてどの配列要素を '[0]'に変更することができるのに対し、 'insert(0、...)アレイの前面にあります。 – chepner
@chepner:エクササイズの本はこう書いています: "リストの最後にpopが呼び出されると、O(1)が必要ですが、リストの最初の要素か中間のどこかでpopが呼び出されると、Oその理由は、Pythonがリストを実装する方法にあります**アイテムがリストの先頭から取り出されるとき、Pythonの実装では、リスト内の他のすべての要素が、最初の位置に近い位置にシフトされます**。 "私が理解しているように、 'insert(0、...)'と 'pop(0)'の両方が最悪の場合にシフトを起こす可能性があります。 –