1 /* In-place merging of integer sequences */
3 #define MIN(x,y) ((x)<(y) ? (x) : (y))
4 #define SWAP(x,y) do { int _=(x); (x)=(y); (y)=_; } while(0)
5 #define BLEN(x) ((x) == p1pos ? p1len : (x) == p2pos ? p2len : B)
7 static void reverse(int *A, int n) // reverse a sequence
17 static void rotate(int *A, int p, int q) // rotate a sequence
24 static void merge(int *A, int M, int N)
26 int T = M+N; // total length of the buffer
27 int B = 1; // block size = ceil(sqrt(N))
31 int Z = MIN(B+T%B,T); // aux buffer size
32 int Mz=0, Nz=0; // find Z largest items
34 if (Mz == M || A[M-Mz-1] > A[T-Nz-1])
39 M -= Mz; // fix up lengths
41 rotate(A, M, Mz); // and move the items to the beginning
44 // select-sort all blocks & track the mixed block
45 int mixed_block = M%B ? Z+M-M%B : -1;
46 for (int i=Z; i<T; i+=B) {
48 for (int j=i; j<T; j+=B)
49 if (A[j+B-1] < A[best+B-1])
51 for (int j=0; j<B; j++)
52 SWAP(A[i+j], A[best+j]);
55 else if (mixed_block == best)
59 // convert the mixed block to two partial ones
60 int p1pos=-1, p1len=-1, p2pos=-1, p2len=-1;
61 if (mixed_block >= 0) {
65 while (p1pos<T && A[p1pos+B-1] <= A[mixed_block+p1len-1])
67 if (p1pos <= mixed_block) {
68 rotate(A+p1pos, mixed_block-p1pos, p1len);
69 p2pos = mixed_block+p1len;
71 rotate(A+mixed_block, p1len, p1pos-mixed_block-p1len);
82 while (es1 < T && (s1 == es1 || A[es1-1] <= A[es1]))
87 int es2 = s2 + BLEN(s2);
101 rotate(A+dest, Z, T-s1);
104 for (int i=T-Z; i<T; i++) {
106 for (int j=i+1; j<T; j++)
120 int A[] = { 2, 4, 8, 9, 10, 11, 13, 14, 16, 1, 5, 6, 11, 12, 15, 17, 18 };
123 for (i=0; i<sizeof(A)/sizeof(A[0]); i++) printf("%d ", A[i]);
127 int M = 1+random()%1000;
128 int N = 1+random()%1000;
130 for (int i=0; i<M; i++) A[i] = (i?A[i-1]:0) + random()%100;
131 for (int i=0; i<N; i++) A[M+i] = (i?A[M+i-1]:0) + random()%100;
133 for (int i=1; i<M+N; i++)
134 if (A[i] < A[i-1]) { puts("BUG"); return 1; }