Skip to content

Commit a6bfebd

Browse files
committed
port of @ceorron's Zip Sort
1 parent f668896 commit a6bfebd

File tree

3 files changed

+226
-0
lines changed

3 files changed

+226
-0
lines changed

src/sorts/HybridZipSort.java

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
package sorts;
2+
3+
import templates.ZipSorting;
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+
final public class HybridZipSort extends ZipSorting {
14+
public HybridZipSort(Delays delayOps, Highlights markOps, Reads readOps, Writes writeOps) {
15+
super(delayOps, markOps, readOps, writeOps);
16+
this.setSortPromptID("Hybrid Zip");
17+
this.setRunAllID("Hybrid Zip Sort");
18+
this.setReportSortID("Hybrid Zip Sort");
19+
this.setCategory("Hybrid Sorts");
20+
this.isComparisonBased(true);
21+
this.isBucketSort(false);
22+
this.isRadixSort(false);
23+
this.isUnreasonablySlow(false);
24+
this.setUnreasonableLimit(0);
25+
this.isBogoSort(false);
26+
}
27+
28+
@Override
29+
public void runSort(int[] array, int length, int bucketCount) {
30+
this.zipSort(array, 0, length, true, 1, true, false);
31+
}
32+
}

src/sorts/ZipSort.java

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
package sorts;
2+
3+
import templates.ZipSorting;
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+
final public class ZipSort extends ZipSorting {
14+
public ZipSort(Delays delayOps, Highlights markOps, Reads readOps, Writes writeOps) {
15+
super(delayOps, markOps, readOps, writeOps);
16+
this.setSortPromptID("Zip");
17+
this.setRunAllID("Zip Sort");
18+
this.setReportSortID("Zip Sort");
19+
this.setCategory("Merge Sorts");
20+
this.isComparisonBased(true);
21+
this.isBucketSort(false);
22+
this.isRadixSort(false);
23+
this.isUnreasonablySlow(false);
24+
this.setUnreasonableLimit(0);
25+
this.isBogoSort(false);
26+
}
27+
28+
@Override
29+
public void runSort(int[] array, int length, int bucketCount) {
30+
this.zipSort(array, 0, length, false, 1, true, false);
31+
}
32+
}

src/templates/ZipSorting.java

Lines changed: 162 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,162 @@
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

Comments
 (0)