import java.util.ArrayList; import java.util.Collections; import java.util.Random; public class FibonacciHeapExperiments { // Class to hold experiment results public static class ExperimentResult { long runningTime; int finalHeapSize; int totalLinks; int totalCuts; int finalTrees; public ExperimentResult(long time, int size, int links, int cuts, int trees) { this.runningTime = time; this.finalHeapSize = size; this.totalLinks = links; this.totalCuts = cuts; this.finalTrees = trees; } } // Generate array of integers 1 to n in random order private static ArrayList getRandomArray(int n) { ArrayList arr = new ArrayList<>(); for (int i = 1; i <= n; i++) { arr.add(i); } Collections.shuffle(arr, new Random()); // Fixed seed for reproducibility return arr; } // First experiment: Insert n items randomly and delete minimum public static ExperimentResult experiment1(int n) { FibonacciHeap heap = new FibonacciHeap(); ArrayList randomArray = getRandomArray(n); long startTime = System.nanoTime(); // Insert all numbers for (int num : randomArray) { heap.insert(num, String.valueOf(num)); } // Delete minimum once heap.deleteMin(); long endTime = System.nanoTime(); return new ExperimentResult( (endTime - startTime) / 1_000_000, heap.size(), heap.totalLinks(), heap.totalCuts(), heap.numTrees() ); } // Second experiment: Insert n items randomly and delete minimum n/2 times public static ExperimentResult experiment2(int n) { FibonacciHeap heap = new FibonacciHeap(); ArrayList randomArray = getRandomArray(n); long startTime = System.nanoTime(); // Insert all numbers for (int num : randomArray) { heap.insert(num, String.valueOf(num)); } // Delete minimum n/2 times for (int i = 0; i < n/2; i++) { heap.deleteMin(); } long endTime = System.nanoTime(); return new ExperimentResult( (endTime - startTime) / 1_000_000, heap.size(), heap.totalLinks(), heap.totalCuts(), heap.numTrees() ); } // Third experiment: Insert n items randomly, delete min, then delete by index until 31 items remain public static ExperimentResult experiment3(int n) { FibonacciHeap heap = new FibonacciHeap(); ArrayList randomArray = getRandomArray(n); // Create sorted array of nodes, indexed by their values FibonacciHeap.HeapNode[] sortedNodes = new FibonacciHeap.HeapNode[n + 1]; long startTime = System.nanoTime(); // Insert all numbers randomly but keep track in sorted order for (int num : randomArray) { FibonacciHeap.HeapNode node = heap.insert(num, String.valueOf(num)); sortedNodes[num] = node; } // Delete minimum once heap.deleteMin(); // Delete elements until 31 remain, using index-based deletion int currentSize = heap.size(); while (currentSize > 31) { int indexToDelete = currentSize - 1; // Start from last index if (sortedNodes[indexToDelete] != null) { heap.delete(sortedNodes[indexToDelete]); sortedNodes[indexToDelete] = null; currentSize--; } } long endTime = System.nanoTime(); return new ExperimentResult( (endTime - startTime) / 1_000_000, heap.size(), heap.totalLinks(), heap.totalCuts(), heap.numTrees() ); } // Run multiple trials of an experiment and average the results public static ExperimentResult runTrials(int n, int numTrials, int experimentNum) { long totalTime = 0; int totalSize = 0; int totalLinks = 0; int totalCuts = 0; int totalTrees = 0; for (int i = 0; i < numTrials; i++) { ExperimentResult result; switch (experimentNum) { case 1: result = experiment1(n); break; case 2: result = experiment2(n); break; case 3: result = experiment3(n); break; default: throw new IllegalArgumentException("Invalid experiment number"); } totalTime += result.runningTime; totalSize += result.finalHeapSize; totalLinks += result.totalLinks; totalCuts += result.totalCuts; totalTrees += result.finalTrees; } return new ExperimentResult( totalTime / numTrials, totalSize / numTrials, totalLinks / numTrials, totalCuts / numTrials, totalTrees / numTrials ); } // Print results in table format private static void printTableResults(int experimentNumber, int m) { System.out.println("\nExperiment " + experimentNumber + ":"); System.out.println("┌────┬──────────┬────────────┬───────────┬────────────┬────────────┬───────────┐"); System.out.println("│ i │ n │ Time (ms) │Final Size │Total Links │Total Cuts │Final Trees│"); System.out.println("├────┼──────────┼────────────┼───────────┼────────────┼────────────┼───────────┤"); for (int i = 1; i <= m; i++) { int n = (int) Math.pow(3, i + 7) - 1; ExperimentResult result = runTrials(n, 20, experimentNumber); System.out.printf("│ %-2d │ %-8d │ %-10d │ %-9d │ %-10d │ %-10d │ %-9d │%n", i, n, result.runningTime, result.finalHeapSize, result.totalLinks, result.totalCuts, result.finalTrees ); } System.out.println("└────┴──────────┴────────────┴───────────┴────────────┴────────────┴───────────┘"); } // Main method to run all experiments public static void main(String[] args) { System.out.println("Running all experiments with 20 trials each..."); for (int exp = 1; exp <= 3; exp++) { printTableResults(exp, 5); // Run for i = 1 to 5 } } }