def max_heapify(self, index): """ Algorithm: We move downwards(bottom) in the heap in each step until heap is in it's correct form. Max-Heapify (A, i): left = 2*i // = means "assignment" right = 2*i + 1 largest = i if left < len(A) and A[left] > A[largest] then: largest = left if right < len(A) and A[right] > A[largest] then: largest = right if largest != i then: swap A[i] and A[largest] Max-Heapify(A, largest) :param index: :return: """ l_idx = MaxHeap.left(index) r_idx = MaxHeap.right(index) largest = index if l_idx < self.capacity and self.get(l_idx) is not None and self.get(l_idx) > self.get(largest): largest = l_idx if r_idx < self.capacity and self.get(r_idx) is not None and self.get(r_idx) > self.get(largest): largest = r_idx if largest != index: swap(self.harr, largest, index) self.max_heapify(largest)
def dutch_national_flag(arr): """ Algorithm - Dutch national flag or three way partitioning Lo := 1; Mid := 1; Hi := N; while Mid <= Hi do Invariant: a[1..Lo-1]=0 and a[Lo..Mid-1]=1 and a[Hi+1..N]=2; a[Mid..Hi] are unknown. case a[Mid] in 0: swap a[Lo] and a[Mid]; Lo++; Mid++ 1: Mid++ 2: swap a[Mid] and a[Hi]; Hi-- :param arr: """ from Array import swap mid = low = 0 high = len(arr) - 1 while mid <= high: curr = arr[mid] if curr == 0: swap(arr, low, mid) low += 1 mid += 1 elif curr == 1: mid += 1 else: swap(arr, mid, high) high -= 1
def min_heapify(self, index): """ Algorithm: We move downwards(bottom) in the heap in each step until heap is in it's correct form. Min-Heapify (A, i): left = 2*i # `=` means `assignment` right = 2*i + 1 smallest = i if left < len(A) and A[left] < A[smallest] then: smallest = left if right < len(A) and A[right] < A[smallest] then: smallest = right if smallest != i then: swap A[i] and A[smallest] Min-Heapify(A, smallest) :param index: :return: """ l_idx = MinHeap.left(index) r_idx = MinHeap.right(index) smallest = index if l_idx < self.capacity and self.get(l_idx) is not None and self.get(l_idx) < self.get(smallest): smallest = l_idx if r_idx < self.capacity and self.get(r_idx) is not None and self.get(r_idx) < self.get(smallest): smallest = r_idx if smallest != index: swap(self.harr, smallest, index) self.min_heapify(smallest)
def max_heapify(self, index): """ Algorithm: We move downwards(bottom) in the heap in each step until heap is in it's correct form. Max-Heapify (A, i): left = 2*i // = means "assignment" right = 2*i + 1 largest = i if left < len(A) and A[left] > A[largest] then: largest = left if right < len(A) and A[right] > A[largest] then: largest = right if largest != i then: swap A[i] and A[largest] Max-Heapify(A, largest) :param index: :return: """ l_idx = MaxHeap.left(index) r_idx = MaxHeap.right(index) largest = index if l_idx < self.capacity and self.get( l_idx) is not None and self.get(l_idx) > self.get(largest): largest = l_idx if r_idx < self.capacity and self.get( r_idx) is not None and self.get(r_idx) > self.get(largest): largest = r_idx if largest != index: swap(self.harr, largest, index) self.max_heapify(largest)
def separate_v2(arr): # Similar to quick-sort partition. ip = -1; pivot = 0 for i in range(0, len(arr)): if arr[i] < pivot: # if we use `arr[i] <= pivot`, then `0` will be placed somewhere between the -ve numbers. ip += 1 swap(arr, i, ip)
def min_heapify(self, index): """ Algorithm: We move downwards(bottom) in the heap in each step until heap is in it's correct form. Min-Heapify (A, i): left = 2*i # `=` means `assignment` right = 2*i + 1 smallest = i if left < len(A) and A[left] < A[smallest] then: smallest = left if right < len(A) and A[right] < A[smallest] then: smallest = right if smallest != i then: swap A[i] and A[smallest] Min-Heapify(A, smallest) :param index: :return: """ l_idx = MinHeap.left(index) r_idx = MinHeap.right(index) smallest = index if l_idx < self.capacity and self.get( l_idx) is not None and self.get(l_idx) < self.get(smallest): smallest = l_idx if r_idx < self.capacity and self.get( r_idx) is not None and self.get(r_idx) < self.get(smallest): smallest = r_idx if smallest != index: swap(self.harr, smallest, index) self.min_heapify(smallest)
def replace_weight(self, data: T, new_weight: K) -> True: heap_node_idx: int = self._data_position_mapping_.get(data) if heap_node_idx is None: print("No such element -", data) return False heap_node: HeapNode[T, K] = self._harr_[heap_node_idx] curr_weight = heap_node.weight heap_node.weight = new_weight curr_idx = heap_node_idx parent_idx = MinBinaryHeap.parent(curr_idx) if new_weight < curr_weight: while self._harr_[curr_idx] < self._harr_[parent_idx]: self._data_position_mapping_[data] = parent_idx # Update curr node data index to point to it's parent self._data_position_mapping_[self._harr_[parent_idx].data] = curr_idx # Update parent index to point to curr_idx. swap(self._harr_, parent_idx, curr_idx) curr_idx = parent_idx parent_idx = MinBinaryHeap.parent(curr_idx) # curr_idx, parent_idx = parent_idx, MinBinaryHeap.parent(curr_idx) elif new_weight > curr_weight: self.min_heapify(curr_idx) else: print("Old weight({}) and new weight({}) are same".format(curr_weight, new_weight)) return False return True
def left_rotate_v3(arr, d): from Array import swap n = len(arr) for di in xrange(0, d): first = arr[0] for i in xrange(1, n): swap(arr, i, i - 1) arr[n - 1] = first
def left_rotate_v3(arr, d): from Array import swap n = len(arr) for di in xrange(0, d): first = arr[0] for i in xrange(1, n): swap(arr, i, i-1) arr[n-1] = first
def separate_v2(arr): # Similar to quick-sort partition. ip = -1 pivot = 0 for i in range(0, len(arr)): if arr[i] < pivot: # if we use `arr[i] <= pivot`, then `0` will be placed somewhere between the -ve numbers. ip += 1 swap(arr, i, ip)
def reverse_arr(arr, start=0, end=-1): from Array import swap alen = len(arr) end = (alen - 1) if end < 0 else end while start < end: swap(arr, start, end) start += 1 end -= 1
def segregate_v2(arr): start = 0 end = len(arr) - 1 mid = (start + end) / 2 while start < end: if arr[mid] == 0: swap(arr, mid, start) start += 1 elif arr[mid] == 1: swap(arr, mid, end) end -= 1
def segregate_v1(arr): """ Similar to quick sort partition by considering 0 as pivot. :param arr: :return: """ pivot = 0 ip = -1 for i in range(0, len(arr)): if arr[i] <= pivot: ip += 1 swap(arr, i, ip) return ip
def extract_min(self) -> HeapNode[T, K]: if len(self._harr_) == 0: return None min_idx = 0 last_idx = -1 min_heap_node = self._harr_[min_idx] last_heap_node = self._harr_[last_idx] self._data_position_mapping_.pop(min_heap_node.data) # Remove first node self._data_position_mapping_[last_heap_node.data] = min_idx # Update last_node index to min_idx swap(self._harr_, min_idx, last_idx) # Move last node to the first index(min_idx) self._harr_.pop(last_idx) # Remove last node self.min_heapify(min_idx) return min_heap_node
def push(self, data: T, weight: K, *args, **kwargs) -> HeapNode[T, K]: heap_node = HeapNode(data, weight, *args, **kwargs) self._harr_.append(heap_node) curr_idx = len(self._harr_) - 1 parent_idx = MinBinaryHeap.parent(curr_idx) self._data_position_mapping_[data] = curr_idx while self._harr_[curr_idx] < self._harr_[parent_idx]: self._data_position_mapping_[data] = parent_idx # Update curr node data index to point to it's parent self._data_position_mapping_[self._harr_[parent_idx].data] = curr_idx # Update parent index to point to curr_idx. swap(self._harr_, parent_idx, curr_idx) curr_idx = parent_idx parent_idx = MinBinaryHeap.parent(curr_idx) return heap_node
def insert(self, elt): if self.is_full(): print("Heap is full, can't insert key") return False # First insert the new key at the end. self.harr.append(elt) self.heap_size += 1 elt_idx = self.heap_size - 1 # Fix the min heap property if it is violated # Algorithm: We move upwards(top) step-by-step until heap is in it's correct form. # while parent(elt) >=0 and harr[parent(elt)] > elt: # swap(parent, elt) # index(elt) = parent(elt) while Heap.parent(elt_idx) >= 0 and self.get(Heap.parent(elt_idx)) > elt: swap(self.harr, Heap.parent(elt_idx), elt_idx) elt_idx = Heap.parent(elt_idx) return True
def insert(self, elt): if self.is_full(): print("Heap is full, can't insert key") return False # First insert the new key at the end. self.harr.append(elt) self.heap_size += 1 elt_idx = self.heap_size - 1 # Fix the max heap property if it is violated. # Algorithm: We move upwards(top) step-by-step until heap is in it's correct form. # while parent(elt) >=0 and harr[parent(elt)] < elt: # swap(parent, elt) # index(elt) = parent(elt) while Heap.parent(elt_idx) >= 0 and self.get( Heap.parent(elt_idx)) < elt: swap(self.harr, Heap.parent(elt_idx), elt_idx) elt_idx = Heap.parent(elt_idx) return True
def min_heapify(self, curr_index: int): left_idx = MinBinaryHeap.left_child(curr_index) right_idx = MinBinaryHeap.right_child(curr_index) left_elt = None right_elt = None if len(self._harr_) >= (left_idx + 1): left_elt = self._harr_[left_idx] if len(self._harr_) >= (right_idx + 1): right_elt = self._harr_[right_idx] smallest_elt_idx = curr_index if left_elt and left_elt < self._harr_[smallest_elt_idx]: smallest_elt_idx = left_idx if right_elt and right_elt < self._harr_[smallest_elt_idx]: smallest_elt_idx = right_idx if smallest_elt_idx != curr_index: self._data_position_mapping_[self._harr_[smallest_elt_idx].data] = curr_index self._data_position_mapping_[self._harr_[curr_index].data] = smallest_elt_idx swap(self._harr_, smallest_elt_idx, curr_index)
def rearrange_v1(arr): from Array import swap # Partitioning array same as quick sort partition by taking 0 as pivot so that all the -ve numbers # will be at left and +ve numbers will be at right. pindex = -1 pivot = 0 for i in range(0, len(arr)): if arr[i] < pivot: pindex += 1 swap(arr, i, pindex) print(pindex) print(arr) # Since -ve and +ve numbers are separated, we start from the first -ve number and first +ve number, # and swap every alternate negative number with next positive number i_pos = pindex + 1 for i in range(0, len(arr), 2): if i_pos >= len(arr) or arr[i] > 0: break swap(arr, i, i_pos) i_pos += 1