TrinadhreddySeelam_AOA_Assignment2
TrinadhreddySeelam_AOA_Assignment2
Homework2
Trinadhreddy Seelam,
02126243.
1. Implementation of HeapDelete:
Steps:
1. Set the key of the node to be deleted to infinity using 𝐻𝐸𝐴𝑃 − 𝐼𝑁𝐶𝑅𝐸𝐴𝑆𝐸 −
𝐾𝐸𝑌. This will move the node to the top of the heap.
2. Replace the value of the root (which is the node to be deleted) with the value of
the last element in the heap. This step is safe since infinity is larger than any other
key.
3. Decrease the size of the heap by 1, eIectively removing the last element (which
now contains the value of the deleted node) from consideration.
4. Finally, call 𝑀𝐴𝑋 − 𝐻𝐸𝐴𝑃𝐼𝐹𝑌 to restore the max-heap property. This operation
has a time complexity of 𝑂(𝑙𝑜𝑔 𝑛) and ensures that the heap remains a valid max-
heap.
Secondly, replacing the root with the last element of the heap and updating the
heap size takes constant time 𝑂(1).
Finally, the 𝑀𝐴𝑋 − 𝐻𝐸𝐴𝑃𝐼𝐹𝑌 operation is called, which also takes 𝑂(𝑙𝑜𝑔 𝑛) time.
The number of recursive calls is at most the height of the heap and is bounded by
𝑙𝑜𝑔 𝑛. Therefore, the overall time complexity of 𝐻𝐸𝐴𝑃 − 𝐷𝐸𝐿𝐸𝑇𝐸 is
𝑂(𝑙𝑜𝑔 𝑛), meeting the specified requirement.
2. Algorithm to merge k sorted lists into one sorted list:
Algorithm: MERGE-K-SORTED-LISTS(lists)
• 𝐼𝑛𝑖𝑡𝑖𝑎𝑙𝑖𝑧𝑒 𝑎𝑛 𝑒𝑚𝑝𝑡𝑦 𝑚𝑖𝑛 − ℎ𝑒𝑎𝑝 𝐻.
• 𝑓𝑜𝑟 𝑖 = 1 𝑡𝑜 𝑘 𝑑𝑜
o 𝐼𝑛𝑠𝑒𝑟𝑡 𝑡ℎ𝑒 𝑓𝑖𝑟𝑠𝑡 𝑒𝑙𝑒𝑚𝑒𝑛𝑡 𝑓𝑟𝑜𝑚 𝑙𝑖𝑠𝑡 𝑖 𝑖𝑛𝑡𝑜 𝐻, 𝑎𝑙𝑜𝑛𝑔 𝑤𝑖𝑡ℎ 𝑡ℎ𝑒 𝑖𝑛𝑑𝑒𝑥 𝑖.
• 𝐼𝑛𝑖𝑡𝑖𝑎𝑙𝑖𝑧𝑒 𝑎𝑛 𝑒𝑚𝑝𝑡𝑦 𝑟𝑒𝑠𝑢𝑙𝑡 𝑙𝑖𝑠𝑡.
• 𝑤ℎ𝑖𝑙𝑒 𝐻 𝑖𝑠 𝑛𝑜𝑡 𝑒𝑚𝑝𝑡𝑦 𝑑𝑜
o 𝐸𝑥𝑡𝑟𝑎𝑐𝑡 𝑡ℎ𝑒 𝑚𝑖𝑛𝑖𝑚𝑢𝑚 𝑒𝑙𝑒𝑚𝑒𝑛𝑡 (𝑣𝑎𝑙𝑢𝑒, 𝑙𝑖𝑠𝑡 𝑖𝑛𝑑𝑒𝑥) 𝑓𝑟𝑜𝑚 𝐻.
o 𝐴𝑑𝑑 𝑡ℎ𝑒 𝑣𝑎𝑙𝑢𝑒 𝑡𝑜 𝑡ℎ𝑒 𝑟𝑒𝑠𝑢𝑙𝑡 𝑙𝑖𝑠𝑡.
o 𝐼𝑓 𝑡ℎ𝑒𝑟𝑒 𝑖𝑠 𝑎𝑛𝑜𝑡ℎ𝑒𝑟 𝑒𝑙𝑒𝑚𝑒𝑛𝑡 𝑖𝑛 𝑡ℎ𝑒 𝑠𝑎𝑚𝑒 𝑙𝑖𝑠𝑡, 𝑖𝑛𝑠𝑒𝑟𝑡 𝑖𝑡 𝑖𝑛𝑡𝑜 𝐻 𝑤𝑖𝑡ℎ 𝑡ℎ𝑒 𝑙𝑖𝑠𝑡 𝑖𝑛𝑑𝑒𝑥.
• 𝑅𝑒𝑡𝑢𝑟𝑛 𝑡ℎ𝑒 𝑟𝑒𝑠𝑢𝑙𝑡 𝑙𝑖𝑠𝑡.
Each element in the min-heap is a tuple that contains the element value and the
index of the list that the element belongs to.
The main loop runs until the min-heap is empty, and in each iteration, it extracts the
minimum element and adds it to the result list.
The INSERT function maintains the min-heap property throughout the process.
To merge k sorted lists into one sorted list, we initialize the min-heap by inserting the
first element from each of the k lists into the heap. This takes 𝑂(𝑘 𝑙𝑜𝑔(𝑘)) time.
Each extraction and insertion operation that follows takes 𝑂(𝑙𝑜𝑔(𝑘)) time.
Since we process each of the n total elements across all lists once, the overall time
complexity is 𝑂(𝑛 𝑙𝑜𝑔(𝑘)).
Therefore, the algorithm runs in 𝑂(𝑛 𝑙𝑜𝑔(𝑘)) time to merge k sorted lists into one
sorted list.
3. Algorithm that produces the k smallest elements
To build a min-heap from an unsorted set of n elements, you can use a bottom-
up approach or any other linear-time heap construction algorithm.
This can be done in 𝑂(𝑛) time. Once you have the min-heap, you can extract the
minimum element (root) from it k times, which takes 𝑂(𝑙𝑜𝑔 𝑛) time per
extraction.
Proof of Correctness:
Therefore, the overall time complexity of this algorithm is 𝑂(𝑛 + 𝑘 𝑙𝑜𝑔 𝑛), which
satisfies the required time complexity.
This algorithm is eIicient when 𝑘 is much smaller than 𝑛, as the dominant term
in the time complexity is 𝑘 𝑙𝑜𝑔 𝑛.
The min-heap operation ensures that we can always eIiciently access the
smallest remaining element.
4.
a) All element values are equal:
If all the values in the array are the same, then the randomized quicksort
algorithm's running time will be the same as that of the regular quicksort
algorithm.
This is because the initial random choice of the pivot index and subsequent
swaps do not change anything when all elements are equal.
The partitioning step will always result in one partition being empty, which
causes the worst-case partitioning scenario to occur, and thus the runtime
becomes 𝛩(𝑛! ).
Algorithm: 𝑃𝐴𝑅𝑇𝐼𝑇𝐼𝑂𝑁′(𝐴, 𝑝, 𝑟)
• 𝑥 = 𝐴[𝑟]
• 𝑠𝑤𝑎𝑝 𝐴[𝑟] 𝑤𝑖𝑡ℎ 𝐴[𝑝]
• 𝑖 = 𝑝 − 1
• 𝑘 = 𝑝
• 𝑗 = 𝑝 + 1
• 𝑤ℎ𝑖𝑙𝑒 𝑗 <= 𝑟 − 1 𝑑𝑜
• 𝑖𝑓 𝐴[𝑗] < 𝑥 𝑡ℎ𝑒𝑛
• 𝑖 = 𝑖 + 1
• 𝑘 = 𝑖 + 2
• 𝑠𝑤𝑎𝑝 𝐴[𝑖] 𝑤𝑖𝑡ℎ 𝐴[𝑗]
• 𝑠𝑤𝑎𝑝 𝐴[𝑘] 𝑤𝑖𝑡ℎ 𝐴[𝑗]
• 𝑒𝑛𝑑 𝑖𝑓
• 𝑖𝑓 𝐴[𝑗] = 𝑥 𝑡ℎ𝑒𝑛
• 𝑘 = 𝑘 + 1
• 𝑠𝑤𝑎𝑝 𝐴[𝑘] 𝑤𝑖𝑡ℎ 𝐴[𝑗]
• 𝑒𝑛𝑑 𝑖𝑓
• 𝑗 = 𝑗 + 1
• 𝑒𝑛𝑑 𝑤ℎ𝑖𝑙𝑒
• 𝑠𝑤𝑎𝑝 𝐴[𝑖 + 1] 𝑤𝑖𝑡ℎ 𝐴[𝑟]
• 𝑟𝑒𝑡𝑢𝑟𝑛 (𝑖 + 1, 𝑘 + 1)
Steps:
- 𝐼𝑡𝑒𝑟𝑎𝑡𝑖𝑜𝑛 2 (𝑗 = 3):
- 𝐴𝑟𝑟𝑎𝑦: [5, 6, 5, 8, 5, 4, 1], 𝑘 = 3
- 𝐼𝑡𝑒𝑟𝑎𝑡𝑖𝑜𝑛 3 (𝑗 = 4):
- 𝐴𝑟𝑟𝑎𝑦: [5, 6, 5, 8, 5, 4, 1]
- 𝐼𝑡𝑒𝑟𝑎𝑡𝑖𝑜𝑛 4 (𝑗 = 5):
- 𝐴𝑟𝑟𝑎𝑦: [5, 6, 5, 8, 5, 4, 1], 𝑘 = 4
- 𝐼𝑡𝑒𝑟𝑎𝑡𝑖𝑜𝑛 5 (𝑗 = 6):
- 𝐴𝑟𝑟𝑎𝑦: [5, 4, 5, 8, 5, 6, 1], 𝑖 = 2, 𝑘 = 5
- 𝐼𝑡𝑒𝑟𝑎𝑡𝑖𝑜𝑛 6 (𝑗 = 7):
- 𝐴𝑟𝑟𝑎𝑦: [5, 4, 5, 8, 5, 6, 1], 𝑘 = 6
- 𝐸𝑛𝑑 𝑜𝑓 𝑤ℎ𝑖𝑙𝑒 𝑙𝑜𝑜𝑝.
Therefore, the partitioning is complete, and the final array is partitioned into
three segments: elements less than the pivot (1, 4), elements equal to the pivot
(5, 5, 5), and elements greater than the pivot (6, 8). The returned indices are (3,
7).
d) Loop Invariant:
At the beginning of each iteration of the loop, with 𝑗 pointing to the current
element A[𝑗], the following conditions are true:
This loop invariant is strong enough to prove the correctness of the algorithm
because it ensures that elements are correctly partitioned around the pivot.
5. a) Proof of Correctness:
Base Case: For an array 𝐴 with only one element (𝑛 = 1), 𝑝 𝑎𝑛𝑑 𝑟 𝑎𝑟𝑒 𝑒𝑞𝑢𝑎𝑙 (𝑝 =
𝑟), causing the loop to terminate. The single element remains sorted as it is.
Inductive case:
• As long as the loop condition remains 𝑝 < 𝑟, the stack depth continues to
increase. The worst-case scenario occurs when the partition process
consistently generates highly unequal subarrays.
• For instance, in the case of an already sorted array, PARTITION always places
only one element in the left subarray, while the rest are placed in the right
subarray.
• Each recursive call sorts a smaller subarray, which results in creating a new
stack frame. This leads to a stack depth of 𝑛 − 1, which has a time
complexity of 𝛩(𝑛), thereby exceeding the desired logarithmic bound.
𝑤ℎ𝑖𝑙𝑒 𝑝 < 𝑟 𝑑𝑜
𝑞 = 𝑃𝐴𝑅𝑇𝐼𝑇𝐼𝑂𝑁(𝐴, 𝑝, 𝑟)
𝑖𝑓 𝑞 − 𝑝 < 𝑟 − 𝑞 𝑡ℎ𝑒𝑛
𝑝 = 𝑞 + 1
𝑒𝑙𝑠𝑒
𝑟 = 𝑞 − 1
𝑒𝑛𝑑 𝑖𝑓
𝑒𝑛𝑑 𝑤ℎ𝑖𝑙𝑒
When distinct intervals are present, the algorithm functions similarly to regular
quicksort, thereby resulting in an expected runtime of 𝛩(𝑛 𝑙𝑜𝑔 𝑛) in general.
However, when all intervals overlap, the condition on line 12 is satisfied for every
iteration of the for loop. In such a scenario, the algorithm returns p and r,
indicating that only empty arrays remain to be sorted.
Since FUZZY-PARTITION is called only once and its runtime remains 𝛩(𝑛), the
total expected runtime becomes 𝛩(𝑛).