Ejemplo n.º 1
0
class Max_Pri_Queue:
    def def_elem_key_handler(self, elem):
        return elem

    def __init__(self, **kwargs):
        """ Initialize the Queue """
        list = kwargs.get('list', [])
        cmprator = kwargs.get('cmprator', 
                              lib.utils.get_def_cmprator())
        self._debug = kwargs.get('debug', 0)
        self.elem_key_handler = kwargs.get('elem_key_handler', 
                                           self.def_elem_key_handler)
        self.id_to_idx_map = {}
        self.heap = Heap(
            list = list,
            cmprator = cmprator,
            debug = self._debug
        )
    
    @property
    def debug(self):
        return self._debug
    
    def maximum(self):
        """ Find elem whose key has max val in the queue """
        if not self.heap.heapsize > 0:
            raise ex.exceptions.HeapSizeZero("Heap empty")
        return self.heap.read(0)

    def update_id_idx_map(self, start_idx = 0):
        """ Update the internal id to heap index map """
        heapsize = self.heap.heapsize
        if not start_idx <= heapsize:
            raise ex.exceptions.BadIndexAccess(
                "Cannot go beyond heapsize idx " + str(heapsize)
            )
        curr_idx = start_idx
        while curr_idx < heapsize:
            curr_id = self.heap.read(curr_idx)
            self.id_to_idx_map[curr_id] = curr_idx 
            curr_idx += 1
        return True

    def swap_nodes(self, idx1, idx2):
        """ Swap heap nodes """
        tmp = self.heap.read(idx1)
        self.heap.write(idx1, self.heap.read(idx2))
        self.heap.write(idx2, tmp)
        id1 = self.heap.read(idx1)
        id2 = self.heap.read(idx2)
        self.id_to_idx_map[id1] = idx1
        self.id_to_idx_map[id2] = idx2
        return True

    def update_key(self, id, new_key, op = 'inc'): 
        """ Update key of element from k to new_k 
        provided k > new_k """

        # cannot increase key if heap empty
        idx = self.id_to_idx_map[id]
        heapsize = self.heap.heapsize
        if not heapsize > 0:
            raise ex.exceptions.HeapSizeZero("Heap empty")
        if not idx < heapsize:
            raise ex.exceptions.BadIndexAccess(
                "Accessing - [" + str(idx) + "] > " +\
                "heapsize idx " + str(heapsize - 1)
            )

        # check if heap property violated - if it is - fix it
        if op == 'inc':
            parent_idx = self.heap.get_parent_idx(idx)
            cmprator_out = self.heap.cmprator(
                               self.heap.read(idx), 
                               self.heap.read(parent_idx)
                           )

            while (cmprator_out > 0 and idx >= 0):
                self.swap_nodes(idx, parent_idx) 
                idx = parent_idx
                parent_idx = self.heap.get_parent_idx(idx)
                cmprator_out = self.heap.cmprator(
                                   self.heap.read(idx), 
                                   self.heap.read(parent_idx)
                               )
        else:
            self.heap.max_heapify(idx)
            self.update_id_idx_map(idx)
        return True
    
    def insert(self, id): 
        """ Insert a new element in the queue """
        if id in self.id_to_idx_map:
            raise ex.exceptions.DupElemInsertion(
                "Id " + str(id) + " already exists in queue"
            )
        self.heap.inc_heapsize(1)
        heap_new_idx = self.heap.heapsize - 1
        self.heap.write(heap_new_idx, id)
        self.update_id_idx_map(heap_new_idx)
        self.update_key(id, self.elem_key_handler(id))
        return True
    
    def extract_max(self):
        """ Remove and return elem whose key has max val in queue """
        try:
            max = self.maximum() 
        except ex.exceptions.HeapError as e:
            raise \
            ex.exceptions.HeapError("Cannot extract max - " +\
                                    e.message)

        self.swap_nodes(0, self.heap.heapsize - 1)
        self.heap.dec_heapsize(1)
        self.heap.max_heapify()
        self.update_id_idx_map()
        return max

    def get_iter(self):
        i = 0
        max = self.heap.heapsize
        while i < max:
            yield self.heap.read(i)
            i += 1

    def flush(self):
        count = 0
        while self.heap.heapsize > 0:
            self.extract_max()
            count += 1
        return count