|
| 1 | +package com.thealgorithms.datastructures.heaps; |
| 2 | + |
| 3 | +import java.util.ArrayList; |
| 4 | +import java.util.Arrays; |
| 5 | +import java.util.Collections; |
| 6 | +import java.util.List; |
| 7 | + |
| 8 | +import com.thealgorithms.bitmanipulation.SingleBitOperations; |
| 9 | +import com.thealgorithms.maths.LeonardoNumber; |
| 10 | + |
| 11 | +public class LeonardoHeap<T extends Comparable<T>> { |
| 12 | + |
| 13 | + private int leonardoLevelTracker; |
| 14 | + private int leonardoHeapSize; |
| 15 | + private final List<T> leonardoHeap; |
| 16 | + |
| 17 | + public LeonardoHeap() { |
| 18 | + this.leonardoHeap = new ArrayList<T>(); |
| 19 | + this.leonardoLevelTracker = 0; |
| 20 | + this.leonardoHeapSize = 0; |
| 21 | + } |
| 22 | + |
| 23 | + public static Integer[] getLeonardoNumbers() { |
| 24 | + Integer[] leonardoNumbers = {1, 1, 3, 5, 9, 15, 25, 41, 67, 109, 177, 287, 465, 753, 1219, 1973, 3193, 5167, 8361, 13529, 21891, 35421, 57313, 92735, 150049, 242785, 392835, 635621, 1028457, 1664079, 2692537, 4356617, 7049155, 1405773, 18454929, 29860703, 48315633, 78176337, 126491971, |
| 25 | + 204668309, 331160281, 535828591}; |
| 26 | + |
| 27 | + return leonardoNumbers; |
| 28 | + } |
| 29 | + |
| 30 | + public int getHeapsize() { |
| 31 | + return this.leonardoHeapSize; |
| 32 | + } |
| 33 | + |
| 34 | + private void decreaseLeonardoLevelTracker() { |
| 35 | + int lastTreeLevel = getRightMostTree(); |
| 36 | + leonardoLevelTracker = SingleBitOperations.clearBit(leonardoLevelTracker, lastTreeLevel); |
| 37 | + if (lastTreeLevel != 0 && lastTreeLevel != 1) { |
| 38 | + leonardoLevelTracker = SingleBitOperations.setBit(leonardoLevelTracker, lastTreeLevel - 1); |
| 39 | + leonardoLevelTracker = SingleBitOperations.setBit(leonardoLevelTracker, lastTreeLevel - 2); |
| 40 | + } |
| 41 | + } |
| 42 | + |
| 43 | + private void increaseLeonardoLevelTracker() { |
| 44 | + Integer[] consecutiveTreeIndices = findConsecutiveLeonardoTreeIndices(leonardoLevelTracker); |
| 45 | + if (consecutiveTreeIndices[0] != -1) { |
| 46 | + // if 0th or 1st index is -1 that implies there are no concequtive trees |
| 47 | + leonardoLevelTracker = SingleBitOperations.clearBit(leonardoLevelTracker, consecutiveTreeIndices[0]); |
| 48 | + leonardoLevelTracker = SingleBitOperations.clearBit(leonardoLevelTracker, consecutiveTreeIndices[1]); |
| 49 | + leonardoLevelTracker = SingleBitOperations.setBit(leonardoLevelTracker, consecutiveTreeIndices[1] + 1); |
| 50 | + } else if ((leonardoLevelTracker & 2) == 0) { |
| 51 | + leonardoLevelTracker = SingleBitOperations.setBit(leonardoLevelTracker, 1); |
| 52 | + } else { |
| 53 | + leonardoLevelTracker = SingleBitOperations.setBit(leonardoLevelTracker, 0); |
| 54 | + } |
| 55 | + } |
| 56 | + |
| 57 | + private void decreaseHeapSize() { |
| 58 | + this.leonardoHeapSize--; |
| 59 | + } |
| 60 | + |
| 61 | + private void increaseHeapSize() { |
| 62 | + this.leonardoHeapSize++; |
| 63 | + } |
| 64 | + |
| 65 | + private void maxHeapifyLeonardoTree(int rootNodeIndex, int currentLeonardoLevel) { |
| 66 | + // A leonardo tree of level n is just 1 node(the root) plus the leonardo tree of n-1 level(left child) plus leonardo tree of n-2 level(right child) |
| 67 | + // To maxheapify a leonardo tree we need to compare the current root and roots of it's left and right subtree |
| 68 | + // We recursively hepify the left and right subtrees using the currentLeonardoLevel |
| 69 | + |
| 70 | + // BASE CASE |
| 71 | + if (currentLeonardoLevel == 0 || currentLeonardoLevel == 1) { |
| 72 | + return; // Trees with one node are in already max-heapified. |
| 73 | + } |
| 74 | + |
| 75 | + int currentRootNodeIndex = rootNodeIndex; |
| 76 | + int rightChildIndex = rootNodeIndex - 1; |
| 77 | + int leftChildIndex = rootNodeIndex - LeonardoNumber.leonardoNumber(currentLeonardoLevel - 2) - 1; |
| 78 | + int childIndexForSwap = -1; |
| 79 | + |
| 80 | + if (leonardoHeap.get(rightChildIndex).compareTo(leonardoHeap.get(leftChildIndex)) >= 0) { |
| 81 | + childIndexForSwap = rightChildIndex; |
| 82 | + } else { |
| 83 | + childIndexForSwap = leftChildIndex; |
| 84 | + } |
| 85 | + |
| 86 | + if (leonardoHeap.get(childIndexForSwap).compareTo(leonardoHeap.get(currentRootNodeIndex)) > 0) { |
| 87 | + swap(currentRootNodeIndex, childIndexForSwap); |
| 88 | + if (childIndexForSwap == rightChildIndex) { |
| 89 | + maxHeapifyLeonardoTree(rightChildIndex, currentLeonardoLevel - 2); |
| 90 | + } else { // swap happened with the left child |
| 91 | + maxHeapifyLeonardoTree(leftChildIndex, currentLeonardoLevel - 1); |
| 92 | + } |
| 93 | + } |
| 94 | + } |
| 95 | + |
| 96 | + private void shiftRootAndRestoreHeap() { |
| 97 | + |
| 98 | + if (getHeapsize() == 0) { |
| 99 | + return; |
| 100 | + } |
| 101 | + |
| 102 | + Integer[] currentLeonardoTreeLevels = findAllLeonardoTreeIndices(); |
| 103 | + int previousTreeSizeCumulative = 0; |
| 104 | + ArrayList<Integer> rootNodeIndices = new ArrayList<Integer>(); |
| 105 | + Collections.reverse(Arrays.asList(currentLeonardoTreeLevels)); // To get the Levels in decreasing order of levels |
| 106 | + |
| 107 | + // The number of roots are going to be same the the number of levels |
| 108 | + // iterate over the currentLeonardoTreeLevels and get roots |
| 109 | + |
| 110 | + for (int i = 0; i < currentLeonardoTreeLevels.length; i++) { |
| 111 | + rootNodeIndices.add(previousTreeSizeCumulative + LeonardoNumber.leonardoNumber(currentLeonardoTreeLevels[i]) - 1); |
| 112 | + previousTreeSizeCumulative = previousTreeSizeCumulative + LeonardoNumber.leonardoNumber(currentLeonardoTreeLevels[i]); |
| 113 | + } |
| 114 | + |
| 115 | + int rootNodeIndexForHeapify = rootNodeIndices.getLast(); |
| 116 | + int leonardoTreeLevelforHeapify = currentLeonardoTreeLevels[currentLeonardoTreeLevels.length - 1]; |
| 117 | + boolean swaped =false; |
| 118 | + |
| 119 | + for (int i = 1; i < rootNodeIndices.size(); i++) { |
| 120 | + |
| 121 | + int currentRootNodeIndex = rootNodeIndices.get(i); |
| 122 | + int prevRootNodeIndex = rootNodeIndices.get(i - 1); |
| 123 | + int j = i; |
| 124 | + while (leonardoHeap.get(prevRootNodeIndex).compareTo(leonardoHeap.get(currentRootNodeIndex)) > 0) { |
| 125 | + int currentLeonardoLevel = currentLeonardoTreeLevels[j]; |
| 126 | + if (currentLeonardoLevel > 1) { |
| 127 | + // compare child and swap |
| 128 | + |
| 129 | + int indexOfRightChild = rootNodeIndices.get(j) - 1; // right child is of level n-2 |
| 130 | + int indexOfLeftChild = rootNodeIndices.get(j) - 1 - LeonardoNumber.leonardoNumber(currentLeonardoLevel - 2); |
| 131 | + if (leonardoHeap.get(prevRootNodeIndex).compareTo(leonardoHeap.get(indexOfRightChild)) > 0 && leonardoHeap.get(prevRootNodeIndex).compareTo(leonardoHeap.get(indexOfLeftChild)) > 0) { |
| 132 | + swap(prevRootNodeIndex, currentRootNodeIndex); |
| 133 | + rootNodeIndexForHeapify = prevRootNodeIndex; |
| 134 | + leonardoTreeLevelforHeapify = currentLeonardoTreeLevels[j - 1]; |
| 135 | + swaped = true; |
| 136 | + } else { |
| 137 | + maxHeapifyLeonardoTree(currentRootNodeIndex, currentLeonardoLevel); |
| 138 | + swaped = false; |
| 139 | + } |
| 140 | + } else { |
| 141 | + swap(prevRootNodeIndex, currentRootNodeIndex); |
| 142 | + rootNodeIndexForHeapify = prevRootNodeIndex; |
| 143 | + leonardoTreeLevelforHeapify = currentLeonardoTreeLevels[j - 1]; |
| 144 | + swaped = true; |
| 145 | + } |
| 146 | + j = j - 1; |
| 147 | + if(j > 0) { |
| 148 | + currentRootNodeIndex = rootNodeIndices.get(j); |
| 149 | + prevRootNodeIndex = rootNodeIndices.get(j - 1); |
| 150 | + } |
| 151 | + else{ |
| 152 | + // j = 0 reached the left most tree |
| 153 | + break; |
| 154 | + } |
| 155 | + } |
| 156 | + |
| 157 | + if(swaped) { |
| 158 | + maxHeapifyLeonardoTree(rootNodeIndexForHeapify, leonardoTreeLevelforHeapify); |
| 159 | + swaped = false; |
| 160 | + } |
| 161 | + |
| 162 | + } |
| 163 | + |
| 164 | + maxHeapifyLeonardoTree(rootNodeIndexForHeapify, leonardoTreeLevelforHeapify); // In case of insert and no swap. |
| 165 | + |
| 166 | + } |
| 167 | + |
| 168 | + private int getRightMostTree() { |
| 169 | + // Isolate the rightmost set bit |
| 170 | + int isolatedBit = leonardoLevelTracker & -leonardoLevelTracker; |
| 171 | + int position = 0; |
| 172 | + |
| 173 | + while (isolatedBit > 1) { |
| 174 | + isolatedBit >>= 1; |
| 175 | + position++; |
| 176 | + } |
| 177 | + |
| 178 | + return position; |
| 179 | + } |
| 180 | + |
| 181 | + private static Integer[] findConsecutiveLeonardoTreeIndices(int num) { |
| 182 | + int prevOneIndex = -1; |
| 183 | + int currentLevel; |
| 184 | + |
| 185 | + Integer[] answer = new Integer[] {-1, -1}; |
| 186 | + for (int i = 0; num > 0; i++) { |
| 187 | + currentLevel = num & 1; |
| 188 | + if (currentLevel == 1) { |
| 189 | + if (prevOneIndex != -1) { |
| 190 | + answer[0] = prevOneIndex; |
| 191 | + answer[1] = i; |
| 192 | + } |
| 193 | + prevOneIndex = i; |
| 194 | + } else { |
| 195 | + prevOneIndex = -1; |
| 196 | + } |
| 197 | + num >>>= 1; |
| 198 | + } |
| 199 | + return answer; |
| 200 | + } |
| 201 | + |
| 202 | + private void swap(int i, int j) { |
| 203 | + T temp = leonardoHeap.get(i); |
| 204 | + leonardoHeap.set(i, leonardoHeap.get(j)); |
| 205 | + leonardoHeap.set(j, temp); |
| 206 | + } |
| 207 | + |
| 208 | + // TODO use lists |
| 209 | + private Integer[] findAllLeonardoTreeIndices() { |
| 210 | + int setBitCount = 0; |
| 211 | + for (int i = 0; i < Integer.SIZE; i++) { |
| 212 | + if ((leonardoLevelTracker & (1 << i)) != 0) { |
| 213 | + setBitCount++; |
| 214 | + } |
| 215 | + } |
| 216 | + |
| 217 | + Integer[] setBitIndexes = new Integer[setBitCount]; |
| 218 | + int index = 0; |
| 219 | + for (int i = 0; i < Integer.SIZE; i++) { |
| 220 | + if ((leonardoLevelTracker & (1 << i)) != 0) { |
| 221 | + setBitIndexes[index++] = i; |
| 222 | + } |
| 223 | + } |
| 224 | + return setBitIndexes; |
| 225 | + } |
| 226 | + |
| 227 | + |
| 228 | + public void insertElement(T element) { |
| 229 | + increaseLeonardoLevelTracker(); |
| 230 | + leonardoHeap.add(element); |
| 231 | + increaseHeapSize(); |
| 232 | + shiftRootAndRestoreHeap(); |
| 233 | + } |
| 234 | + |
| 235 | + public T deleteElement() { |
| 236 | + decreaseLeonardoLevelTracker(); |
| 237 | + decreaseHeapSize(); |
| 238 | + T element = leonardoHeap.removeLast(); |
| 239 | + shiftRootAndRestoreHeap(); |
| 240 | + |
| 241 | + return element; |
| 242 | + } |
| 243 | +} |
0 commit comments