@@ -67,11 +67,16 @@ function estimateSortingTime() { |
| 67 | 67 | case 'heap': |
| 68 | 68 | return baseTime * Math.log2(array.length) * 2; |
| 69 | 69 | case 'shell': |
| 70 | + case 'comb': |
| 70 | 71 | return baseTime * array.length * 0.3; |
| 71 | 72 | case 'radix': |
| 72 | 73 | return baseTime * 3; |
| 73 | 74 | case 'gnome': |
| 74 | 75 | return baseTime * array.length * 0.7; |
| 76 | + case 'pancake': |
| 77 | + return baseTime * array.length * 0.8; |
| 78 | + case 'bitonic': |
| 79 | + return baseTime * Math.log2(array.length) * Math.log2(array.length); |
| 75 | 80 | case 'bogo': |
| 76 | 81 | return baseTime * 10; // Who knows! |
| 77 | 82 | default: |
@@ -339,6 +344,15 @@ async function startSort() { |
| 339 | 344 | case 'bogo': |
| 340 | 345 | await bogoSort(); |
| 341 | 346 | break; |
| 347 | + case 'comb': |
| 348 | + await combSort(); |
| 349 | + break; |
| 350 | + case 'pancake': |
| 351 | + await pancakeSort(); |
| 352 | + break; |
| 353 | + case 'bitonic': |
| 354 | + await bitonicSort(); |
| 355 | + break; |
| 342 | 356 | } |
| 343 | 357 | |
| 344 | 358 | // Stop slide whistle and play zoot |
@@ -763,6 +777,138 @@ function markAllSorted() { |
| 763 | 777 | }); |
| 764 | 778 | } |
| 765 | 779 | |
| 780 | +// Comb Sort (improved Bubble Sort with gap) |
| 781 | +async function combSort() { |
| 782 | + let gap = array.length; |
| 783 | + let shrink = 1.3; |
| 784 | + let sorted = false; |
| 785 | + |
| 786 | + while (gap > 1 || !sorted) { |
| 787 | + // Update gap |
| 788 | + gap = Math.floor(gap / shrink); |
| 789 | + if (gap < 1) gap = 1; |
| 790 | + |
| 791 | + sorted = true; |
| 792 | + |
| 793 | + // Single pass with current gap |
| 794 | + for (let i = 0; i + gap < array.length; i++) { |
| 795 | + await compare(i, i + gap); |
| 796 | + if (array[i] > array[i + gap]) { |
| 797 | + await swap(i, i + gap); |
| 798 | + sorted = false; |
| 799 | + } |
| 800 | + } |
| 801 | + |
| 802 | + // Mark sorted elements when gap is 1 (final pass) |
| 803 | + if (gap === 1 && sorted) { |
| 804 | + for (let i = 0; i < array.length; i++) { |
| 805 | + document.querySelectorAll('.bar-row')[i].classList.add('sorted'); |
| 806 | + await sleep(getDelay() / 4); |
| 807 | + } |
| 808 | + } |
| 809 | + } |
| 810 | +} |
| 811 | + |
| 812 | +// Pancake Sort (flip sort) |
| 813 | +async function pancakeSort() { |
| 814 | + for (let curr_size = array.length; curr_size > 1; curr_size--) { |
| 815 | + // Find index of maximum element in unsorted portion |
| 816 | + let maxIdx = 0; |
| 817 | + for (let i = 1; i < curr_size; i++) { |
| 818 | + await compare(i, maxIdx); |
| 819 | + if (array[i] > array[maxIdx]) { |
| 820 | + maxIdx = i; |
| 821 | + } |
| 822 | + } |
| 823 | + |
| 824 | + // Move maximum element to end if it's not already there |
| 825 | + if (maxIdx !== curr_size - 1) { |
| 826 | + // Flip to move max to beginning |
| 827 | + if (maxIdx !== 0) { |
| 828 | + await flip(maxIdx + 1); |
| 829 | + } |
| 830 | + |
| 831 | + // Flip to move max to correct position |
| 832 | + await flip(curr_size); |
| 833 | + } |
| 834 | + |
| 835 | + document.querySelectorAll('.bar-row')[curr_size - 1].classList.add('sorted'); |
| 836 | + } |
| 837 | + document.querySelectorAll('.bar-row')[0].classList.add('sorted'); |
| 838 | +} |
| 839 | + |
| 840 | +// Helper function for pancake sort - flips array from 0 to n-1 |
| 841 | +async function flip(n) { |
| 842 | + let start = 0; |
| 843 | + let end = n - 1; |
| 844 | + |
| 845 | + while (start < end) { |
| 846 | + await swap(start, end); |
| 847 | + start++; |
| 848 | + end--; |
| 849 | + } |
| 850 | +} |
| 851 | + |
| 852 | +// Bitonic Sort (requires power of 2 array size) |
| 853 | +async function bitonicSort() { |
| 854 | + // Adjust array size to nearest power of 2 if needed |
| 855 | + const originalLength = array.length; |
| 856 | + const nextPowerOf2 = Math.pow(2, Math.ceil(Math.log2(array.length))); |
| 857 | + |
| 858 | + // Pad with large values if necessary |
| 859 | + while (array.length < nextPowerOf2) { |
| 860 | + array.push(999); |
| 861 | + } |
| 862 | + renderArray(); |
| 863 | + |
| 864 | + // Start the bitonic sort |
| 865 | + await bitonicSortRecursive(0, array.length, true); |
| 866 | + |
| 867 | + // Remove padding if we added any |
| 868 | + if (array.length > originalLength) { |
| 869 | + array.length = originalLength; |
| 870 | + renderArray(); |
| 871 | + } |
| 872 | + |
| 873 | + // Mark all as sorted |
| 874 | + for (let i = 0; i < originalLength; i++) { |
| 875 | + document.querySelectorAll('.bar-row')[i].classList.add('sorted'); |
| 876 | + } |
| 877 | +} |
| 878 | + |
| 879 | +async function bitonicSortRecursive(lo, cnt, dir) { |
| 880 | + if (cnt > 1) { |
| 881 | + let k = Math.floor(cnt / 2); |
| 882 | + |
| 883 | + // Sort in ascending order |
| 884 | + await bitonicSortRecursive(lo, k, true); |
| 885 | + |
| 886 | + // Sort in descending order |
| 887 | + await bitonicSortRecursive(lo + k, k, false); |
| 888 | + |
| 889 | + // Merge the whole sequence |
| 890 | + await bitonicMerge(lo, cnt, dir); |
| 891 | + } |
| 892 | +} |
| 893 | + |
| 894 | +async function bitonicMerge(lo, cnt, dir) { |
| 895 | + if (cnt > 1) { |
| 896 | + let k = Math.floor(cnt / 2); |
| 897 | + |
| 898 | + for (let i = lo; i < lo + k; i++) { |
| 899 | + await compare(i, i + k); |
| 900 | + |
| 901 | + // Swap if needed based on direction |
| 902 | + if ((array[i] > array[i + k]) === dir) { |
| 903 | + await swap(i, i + k); |
| 904 | + } |
| 905 | + } |
| 906 | + |
| 907 | + await bitonicMerge(lo, k, dir); |
| 908 | + await bitonicMerge(lo + k, k, dir); |
| 909 | + } |
| 910 | +} |
| 911 | + |
| 766 | 912 | // Initialize |
| 767 | 913 | generateArray(); |
| 768 | 914 | document.querySelector('.algorithm-btn').click(); |