~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/priodict.py

  • Committer: aaron.bentley at utoronto
  • Date: 2005-09-05 07:11:41 UTC
  • mto: (1185.3.4)
  • mto: This revision was merged to the branch mainline in revision 1390.
  • Revision ID: aaron.bentley@utoronto.ca-20050905071141-5f9ef30b0f6b3e21
Started work on djkstra longest-path algorithm

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
# Priority dictionary using binary heaps
 
2
# David Eppstein, UC Irvine, 8 Mar 2002
 
3
 
 
4
# Implements a data structure that acts almost like a dictionary, with two modifications:
 
5
# (1) D.smallest() returns the value x minimizing D[x].  For this to work correctly,
 
6
#        all values D[x] stored in the dictionary must be comparable.
 
7
# (2) iterating "for x in D" finds and removes the items from D in sorted order.
 
8
#        Each item is not removed until the next item is requested, so D[x] will still
 
9
#        return a useful value until the next iteration of the for-loop.
 
10
# Each operation takes logarithmic amortized time.
 
11
 
 
12
from __future__ import generators
 
13
 
 
14
class priorityDictionary(dict):
 
15
        def __init__(self):
 
16
                '''Initialize priorityDictionary by creating binary heap of pairs (value,key).
 
17
Note that changing or removing a dict entry will not remove the old pair from the heap
 
18
until it is found by smallest() or until the heap is rebuilt.'''
 
19
                self.__heap = []
 
20
                dict.__init__(self)
 
21
 
 
22
        def smallest(self):
 
23
                '''Find smallest item after removing deleted items from front of heap.'''
 
24
                if len(self) == 0:
 
25
                        raise IndexError, "smallest of empty priorityDictionary"
 
26
                heap = self.__heap
 
27
                while heap[0][1] not in self or self[heap[0][1]] != heap[0][0]:
 
28
                        lastItem = heap.pop()
 
29
                        insertionPoint = 0
 
30
                        while 1:
 
31
                                smallChild = 2*insertionPoint+1
 
32
                                if smallChild+1 < len(heap) and heap[smallChild] > heap[smallChild+1] :
 
33
                                        smallChild += 1
 
34
                                if smallChild >= len(heap) or lastItem <= heap[smallChild]:
 
35
                                        heap[insertionPoint] = lastItem
 
36
                                        break
 
37
                                heap[insertionPoint] = heap[smallChild]
 
38
                                insertionPoint = smallChild
 
39
                return heap[0][1]
 
40
        
 
41
        def __iter__(self):
 
42
                '''Create destructive sorted iterator of priorityDictionary.'''
 
43
                def iterfn():
 
44
                        while len(self) > 0:
 
45
                                x = self.smallest()
 
46
                                yield x
 
47
                                del self[x]
 
48
                return iterfn()
 
49
        
 
50
        def __setitem__(self,key,val):
 
51
                '''Change value stored in dictionary and add corresponding pair to heap.
 
52
Rebuilds the heap if the number of deleted items gets large, to avoid memory leakage.'''
 
53
                dict.__setitem__(self,key,val)
 
54
                heap = self.__heap
 
55
                if len(heap) > 2 * len(self):
 
56
                        self.__heap = [(v,k) for k,v in self.iteritems()]
 
57
                        self.__heap.sort()  # builtin sort probably faster than O(n)-time heapify
 
58
                else:
 
59
                        newPair = (val,key)
 
60
                        insertionPoint = len(heap)
 
61
                        heap.append(None)
 
62
                        while insertionPoint > 0 and newPair < heap[(insertionPoint-1)//2]:
 
63
                                heap[insertionPoint] = heap[(insertionPoint-1)//2]
 
64
                                insertionPoint = (insertionPoint-1)//2
 
65
                        heap[insertionPoint] = newPair
 
66
        
 
67
        def setdefault(self,key,val):
 
68
                '''Reimplement setdefault to pass through our customized __setitem__.'''
 
69
                if key not in self:
 
70
                        self[key] = val
 
71
                return self[key]