|
| 1 | +package templates; |
| 2 | + |
| 3 | +import sorts.InsertionSort; |
| 4 | +import utils.Delays; |
| 5 | +import utils.Highlights; |
| 6 | +import utils.Reads; |
| 7 | +import utils.Writes; |
| 8 | + |
| 9 | +/* translated from Richard Cookman's original MIT licensed C++ implementation |
| 10 | + * https://github.com/ceorron/stable-inplace-sorting-algorithms#zip_sort |
| 11 | + */ |
| 12 | + |
| 13 | +public abstract class ZipSorting extends Sort { |
| 14 | + private InsertionSort insertSorter; |
| 15 | + |
| 16 | + protected ZipSorting(Delays delayOps, Highlights markOps, Reads readOps, Writes writeOps) { |
| 17 | + super(delayOps, markOps, readOps, writeOps); |
| 18 | + } |
| 19 | + |
| 20 | + protected void zipRotate(int[] arr, int first, int middle, int last, double sleep, boolean mark, boolean temp) { |
| 21 | + if(middle == last) |
| 22 | + return; |
| 23 | + int next = middle; |
| 24 | + while(first != next) { |
| 25 | + Writes.swap(arr, first++, next++, sleep, mark, temp); |
| 26 | + if(next == last) next = middle; |
| 27 | + else if(first == middle) middle = next; |
| 28 | + } |
| 29 | + } |
| 30 | + |
| 31 | + protected void zipMerge(int[] arr, int left, int right, int end, double sleep, boolean mark, boolean temp) { |
| 32 | + //the swap buffer, 2048 bytes / sizeof(int), as per documentation |
| 33 | + short buffer_count = 512; |
| 34 | + int[] swapbufr = new int[buffer_count]; |
| 35 | + |
| 36 | + //all of the middle sections |
| 37 | + int mdlstart = right; |
| 38 | + int mdltop = right; |
| 39 | + |
| 40 | + while((left != right) & (right != end)) { |
| 41 | + if(mdltop != right) { |
| 42 | + //if we have a middle section test the middle against the right - long run optimisation |
| 43 | + if(Reads.compare(arr[right], arr[mdltop]) == -1) { |
| 44 | + if(mdltop != mdlstart) { |
| 45 | + //move in a buffers worth at a time |
| 46 | + short count = 0; |
| 47 | + do { |
| 48 | + //construct(swapbufr[count++], std::move(*left)); |
| 49 | + if(mark) Highlights.markArray(1, left); |
| 50 | + Writes.write(swapbufr, count++, arr[left], sleep, false, true); |
| 51 | + //construct(*left, std::move(*right)); |
| 52 | + if(mark) Highlights.markArray(2, right); |
| 53 | + Writes.write(arr, left, arr[right], sleep, mark, temp); |
| 54 | + ++right; |
| 55 | + ++left; |
| 56 | + } while(((count < buffer_count) & (left != mdlstart) & (right != end)) && Reads.compare(arr[right], arr[mdltop]) == -1); |
| 57 | + |
| 58 | + //move the new smallest into the correct place in the middle section |
| 59 | + //move the middle section right |
| 60 | + int mdlend = right; |
| 61 | + int mdl = mdlend - count; |
| 62 | + do { |
| 63 | + --mdlend; |
| 64 | + --mdl; |
| 65 | + //construct(*mdlend, std::move(*mdl)); |
| 66 | + if(mark) Highlights.markArray(2, mdl); |
| 67 | + Writes.write(arr, mdlend, arr[mdl], sleep, mark, temp); |
| 68 | + } while(mdl != mdltop); |
| 69 | + |
| 70 | + //move in the new data |
| 71 | + for(short i = 0; i < count; ++i, ++mdltop) |
| 72 | + //construct(*mdltop, std::move(swapbufr[i])); |
| 73 | + Writes.write(arr, mdltop, swapbufr[i], sleep, mark, temp); |
| 74 | + |
| 75 | + if((count >= buffer_count) | (left == mdlstart) | (right == end)) |
| 76 | + //if we exit because we reach the end of the input we can move across |
| 77 | + --left; |
| 78 | + else { |
| 79 | + //swap the middle with the left |
| 80 | + Writes.swap(arr, left, mdltop, sleep, mark, temp); |
| 81 | + ++mdltop; |
| 82 | + if(mdltop == right) |
| 83 | + mdltop = mdlstart; |
| 84 | + } |
| 85 | + } else { |
| 86 | + Writes.swap(arr, left, right, sleep, mark, temp); |
| 87 | + ++right; |
| 88 | + } |
| 89 | + } else { |
| 90 | + Writes.swap(arr, left, mdltop, sleep, mark, temp); |
| 91 | + ++mdltop; |
| 92 | + if(mdltop == right) |
| 93 | + mdltop = mdlstart; |
| 94 | + } |
| 95 | + } else { |
| 96 | + //test the right against the left |
| 97 | + if(Reads.compare(arr[right], arr[left]) == -1) { |
| 98 | + Writes.swap(arr, left, right, sleep, mark, temp); |
| 99 | + ++right; |
| 100 | + } |
| 101 | + } |
| 102 | + |
| 103 | + ++left; |
| 104 | + if(left == mdlstart) { |
| 105 | + //if the left reaches the middle, re-order the middle section so smallest first |
| 106 | + zipRotate(arr, mdlstart, mdltop, right, sleep, mark, temp); |
| 107 | + mdlstart = right; |
| 108 | + mdltop = right; |
| 109 | + } |
| 110 | + } |
| 111 | + |
| 112 | + if(left != right) { |
| 113 | + //if the right has reached the end before the left |
| 114 | + zipRotate(arr, mdlstart, mdltop, right, sleep, mark, temp); |
| 115 | + zipRotate(arr, left, mdlstart, right, sleep, mark, temp); |
| 116 | + } |
| 117 | + } |
| 118 | + |
| 119 | + protected void zipSort(int[] arr, int beg, int end, boolean hybrid, double sleep, boolean mark, boolean temp) { |
| 120 | + insertSorter = new InsertionSort(this.Delays, this.Highlights, this.Reads, this.Writes); |
| 121 | + int sze = end - beg; |
| 122 | + if(sze <= 1) |
| 123 | + return; |
| 124 | + |
| 125 | + int len = 1; |
| 126 | + |
| 127 | + if(hybrid){ |
| 128 | + //sort small runs with insertion sort before doing merge |
| 129 | + int insert_count = 16; |
| 130 | + { |
| 131 | + int len = insert_count; |
| 132 | + int count = 0; |
| 133 | + for(int bg = beg; bg != end; count+=len) { |
| 134 | + int ed = (count + len > sze ? end : bg + len); |
| 135 | + insertSorter.customInsertSort(arr, bg, ed, sleep, temp); |
| 136 | + bg = ed; |
| 137 | + } |
| 138 | + } |
| 139 | + if(sze <= insert_count) |
| 140 | + return; |
| 141 | + |
| 142 | + len = insert_count; |
| 143 | + } |
| 144 | + |
| 145 | + //go through all of the lengths starting at 1 doubling |
| 146 | + while(len < sze) { |
| 147 | + int pos = 0; |
| 148 | + //go through all of the sorted sublists, zip them together |
| 149 | + while(pos + len < sze) { |
| 150 | + //make the two halves |
| 151 | + int cleft = beg + pos; |
| 152 | + int cright = cleft + len; |
| 153 | + int cend = (pos + (len * 2) > sze ? end : cright + len); |
| 154 | + |
| 155 | + //do zip merge |
| 156 | + zipMerge(arr, cleft, cright, cend, sleep, mark, temp); |
| 157 | + pos += (len * 2); |
| 158 | + } |
| 159 | + len *= 2; |
| 160 | + } |
| 161 | + } |
| 162 | +} |
0 commit comments