Bit-reversal algorithm by Rutkowska - algorithm

I found a very interesting paper about bit-reversal algorithm suitable for in-place FFT: "A simple algorithm for the bit-reversal permutation" by
Urszula Rutkowska from 1990 (doi.org/10.1016/0165-1684(91)90008-7).
However, her algorithm G1 does not appear to work as the very first iteration results in out-of-bounds error for that N1 = L << 1 and swap(a + 1, a + N1);. I assume L means the length of input vector.
Please, does anyone know if there was any errata for the paper or how to fix the algorithm?
The paper's pseudocode:
G1(L)
{int i,j,L1
N1,N2,a,b;
unsigned k;
j=0; L1=L-1;
N1=L<<1;N2=N1+1;
for(i=0;i<L1;i++)
{if(i<j)
{ a=i<<1;
b=j<<1;
swap(a,b);
swap(a+N2,b+N2);
swap(a+1,b+N1);
swap(b+1,a+N1);
}
else
if(i==j)
{ a=i<<1;
swap(a+1,a+N1);
}
k=L>>1;
while(k<=j){ j=j-k;
k=k>>1;
}
j+=k;
}
i<<=1;
swap(i+1,i+N1);
}
Screenshot of the paper:

It was pretty garbled, frankly. I had to read the paper for the idea (run Gold's algorithm (G) for L/4 and then derive the swaps for L) and then sort of massage the code into the right form. Here's my final result.
#include <assert.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
static bool is_power_of_two(int L) { return L > 0 && (L & (L - 1)) == 0; }
static void swap(int i, int j) { printf("swap %d,%d\n", i, j); }
static void G(int L) {
assert(is_power_of_two(L));
int j = 0;
for (int i = 0; i < L - 1; i++) {
if (i < j) {
swap(i, j);
}
int k = L >> 1;
while (j >= k) {
j -= k;
k >>= 1;
}
j += k;
}
}
static void G1(int L) {
assert(is_power_of_two(L));
if (L < 4) {
return;
}
int j = 0;
int N1 = L >> 1;
int N2 = N1 + 1;
int L2 = L >> 2;
for (int i = 0; i < L2 - 1; i++) {
if (i < j) {
int a = i << 1;
int b = j << 1;
swap(a, b);
swap(a + N2, b + N2);
swap(a + 1, b + N1);
swap(b + 1, a + N1);
} else if (i == j) {
int a = i << 1;
swap(a + 1, a + N1);
}
int k = L2 >> 1;
while (j >= k) {
j -= k;
k >>= 1;
}
j += k;
}
int a = (L2 - 1) << 1;
swap(a + 1, a + N1);
}
int main(int argc, char *argv[]) {
assert(1 < argc);
int L = atoi(argv[1]);
G(L);
putchar('\n');
G1(L);
}

Related

Can Bitonic Sort handle non-power-of-2 data in a non-recursive implementation ? (without using the method of padding to the power of 2)

Below is a pseudocode for a non-recursive implementation of Bitonic sort.
I can't think of a way to modify the pseudocode to handle data input of any size without using the method of padding the data to the power of 2.
void impBitonicSort() {
int i, j, k;
for (k = 2; k <= N; k = 2 * k) {
for (j = k >> 1; j > 0; j = j >> 1) {
for (i = 0; i < N; i++) {
int ij = i ^ j;
if ((ij) > i) {
if ((i & k) == 0 && a[i] > a[ij]) exchange(i, ij);
if ((i & k) != 0 && a[i] < a[ij]) exchange(i, ij);
}
}
}
}
}
The zero-one principle for sorting networks implies that we can just
skip the comparisons involving missing elements. The code in the
question uses backward comparators, so we have to switch to a bitonic
sort that uses only forward comparators. In tested C++:
#include <algorithm>
#include <cstdio>
#include <numeric>
#include <vector>
template <typename T>
void comparator(std::vector<T> &a, std::size_t i, std::size_t j) {
if (i < j && j < a.size() && a[j] < a[i])
std::swap(a[i], a[j]);
}
template <typename T> void impBitonicSort(std::vector<T> &a) {
// Iterate k as if the array size were rounded up to the nearest power of two.
for (std::size_t k = 2; (k >> 1) < a.size(); k <<= 1) {
for (std::size_t i = 0; i < a.size(); i++)
comparator(a, i, i ^ (k - 1));
for (std::size_t j = k >> 1; 0 < j; j >>= 1)
for (std::size_t i = 0; i < a.size(); i++)
comparator(a, i, i ^ j);
}
}
int main() {
for (int n = 2; n <= 8; n++) {
std::vector<int> unsorted(n);
std::iota(unsorted.begin(), unsorted.end(), 0);
do {
auto sorted = unsorted;
impBitonicSort(sorted);
if (!std::is_sorted(sorted.begin(), sorted.end())) {
for (int i : unsorted)
std::printf(" %d", i);
std::printf("\n");
return 1;
}
} while (std::next_permutation(unsorted.begin(), unsorted.end()));
}
}

Runtime error for large inputs for sorting ( quicksort)

This is a very simple program where the user inputs (x,y) coordinates and distance 'd' and the program has to find out the number of unrepeated coordinates from (x,y) to (x+d,y).
For eg: if input for one test case is: 4,9,2 then the unrepeated coordinates are (4,9),(5,9) and (6,9)(x=4,y=9,d=2). I have used a sorting algorithm as mentioned in the question (to keep track of multiple occurrences) however the program shows runtime error for test cases beyond 30. Is there any mistake in the code or is it an issue with my compiler?
For a detailed explanation of question: https://www.hackerearth.com/practice/algorithms/sorting/merge-sort/practice-problems/algorithm/missing-soldiers-december-easy-easy/
#include <stdio.h>
#include <stdlib.h>
int partition(int *arr, int p, int r) {
int x;
x = arr[r];
int tmp;
int i = p - 1;
for (int j = p; j <= r - 1; ++j) {
if (arr[j] <= x) {
i = i + 1;
tmp = arr[i];
arr[i] = arr[j];
arr[j] = tmp;
}
}
tmp = arr[i + 1];
arr[i + 1] = arr[r];
arr[r] = tmp;
return (i + 1);
}
void quicksort(int *arr, int p, int r) {
int q;
if (p < r) {
q = partition(arr, p, r);
quicksort(arr, p, q - 1);
quicksort(arr, q + 1, r);
}
}
int count(int A[],int ct) {
int cnt = 0;
for (int i = 0; i < ct; ++i) {
if (A[i] != A[i + 1]) {
cnt++;
}
}
return cnt;
}
int main() {
int t;
scanf("%d", &t);
long int tmp, y, d;
int ct = 0;
int i = 0;
int x[1000];
int j = 0;
for (int l = 0; l < t; ++l) {
scanf("%d%d%d", &tmp, &y, &d);
ct = ct + d + 1; //this counts the total no of coordinates for each (x,y,d)
for (int i = 0; i <= d; ++i) {
x[j] = tmp + i; //storing all possible the x and x+d coordinates
j++;
}
}
int cnt;
int p = ct - 1;
quicksort(x, 0, p); //quicksort sorting
for (int l = 0; l < ct; ++l) {
printf("%d ", x[l]); //prints sorted array not necessary to question
}
cnt = count(x, ct); //counts the number of non-repeated vertices
printf("%d\n", cnt);
}
The problem was the bounds of the array int x[1000] is not enough for the data given below.

Please spot the error in this merge sort code

I have provided the code for sorting an array using the merge sort algorithm, I'm unable to find the error, this code is not giving the correctly sorted array as it's output. The function mergesort is called recursively to divide the array till its size is reduced to 1. Then multiple arrays are merged using the merge function.
#include <bits/stdc++.h>
using namespace std;
void merge(int a[], int m, int l, int h) {
int n1 = m - l + 1, n2 = h - m;
int t1[n1], t2[n2];
for (int i = 0; i < n1; i++) {
t1[i] = a[i + l];
}
for (int i = 0; i < n2; i++) {
t2[i] = a[i + m + 1];
}
int k = 0, p = 0, r = 0;
while (k < n1 && p < n2) {
if (t1[k] <= t2[p]) {
a[r] = t1[k];
k++;
r++;
} else {
a[r] = t2[p];
p++;
r++;
}
}
while (k < n1) {
a[r] = t1[k];
k++;
r++;
}
while (p < n2) {
a[r] = t2[p];
p++;
r++;
}
}
void mergesort(int a[], int l, int h) {
if (l < h) {
int m = l + (h - l) / 2;
mergesort(a, l, m);
mergesort(a, m + 1, h);
merge(a, m, l, h);
}
}
int main() {
int a[5] = { 1, 2, 3, 4, 5 };
mergesort(a, 0, 4);
for (int i = 0; i < 5; i++) {
cout << a[i] << " ";
}
return 0;
}
The bug in the merge function is r should be initialized to l, not 0. You are not merging the slices into the original position.
Also note that the last loop while (p < n2) in this function is redundant: the remaining elements in the right slice are already in the proper place in the original array.
Here is a modified version:
void merge(int a[], int m, int l, int h) {
int n1 = m - l + 1, n2 = h - m;
int t1[n1], t2[n2];
for (int i = 0; i < n1; i++) {
t1[i] = a[i + l];
}
for (int i = 0; i < n2; i++) {
t2[i] = a[i + m + 1];
}
int k = 0, p = 0, r = l;
while (k < n1 && p < n2) {
if (t1[k] <= t2[p]) {
a[r] = t1[k];
k++;
r++;
} else {
a[r] = t2[p];
p++;
r++;
}
}
while (k < n1) {
a[r] = t1[k];
k++;
r++;
}
}
To further simplify the code, here are some more remarks:
it is less confusing to make use the convention that h be the first index beyond the end of the slice. This way the initial call uses the array length and mergesort can compute the slice length as h - l.
variable name l looks confusingly close to number 1.
the arguments to merge are usually in the order l, m, h, and m is the index of the start of the right slice.
the right slice does not need saving.
using variable length arrays with automatic storage t1[n2] may cause a stack overflow for large arrays.
Here is a modified version:
#include <bits/stdc++.h>
using namespace std;
void merge(int a[], int lo, int m, int hi) {
int i, j, k;
int n1 = m - lo;
int t1[n1];
for (i = 0; i < n1; i++) {
t1[i] = a[lo + i];
}
i = 0;
j = m;
k = lo;
while (i < n1 && j < hi) {
if (t1[i] <= a[j]) {
a[k++] = t1[i++];
} else {
a[k++] = a[j++];
}
}
while (i < n1) {
a[k++] = t1[i++];
}
}
void mergesort(int a[], int lo, int hi) {
if (hi - lo >= 2) {
int m = lo + (hi - lo) / 2;
mergesort(a, lo, m);
mergesort(a, m, hi);
merge(a, lo, m, hi);
}
}
int main() {
int a[5] = { 1, 5, 2, 4, 3 };
mergesort(a, 0, 5);
for (int i = 0; i < 5; i++) {
cout << a[i] << " ";
}
cout << "\n";
return 0;
}

Merge sort: time limit exceed

Why I am getting time limit exceeded error in sorting array using merge sort algorithm? What is wrong with my code? I have taken an input of 9 elements.
Input: 4 2 1 8 5 9 6 7 0
Output: Time limit exceeded
#include <bits/stdc++.h>
using namespace std;
int a[100];
void merge(int a[], int l, int r, int m) {
int t[r - l + 1];
int i = l, j = m + 1, k = 0;
while (i <= m && j <= r) {
if (a[i] < a[j])
t[k++] = a[i++];
else
t[k++] = a[j++];
}
while (i <= m)
t[k++] = a[i++];
while (j <= r)
t[k++] = a[j++];
for (int i = l; i <= r; i++)
a[i] = t[i - l];
}
void msort(int a[], int l, int r) {
if (l > r)
return;
int m = (r + l) / 2;
msort(a, l, m);
msort(a, m + 1, r);
merge(a, l, r, m);
}
int main() {
int n;
cin >> n;
for (int i = 0; i < n; i++)
cin >> a[i];
msort(a, 0, n - 1);
for (int i = 0; i < n; i++)
cout << a[i] << " ";
cout << endl;
return 0;
}
There are some problems in your code:
The test for termination in msort() is incorrect: you should stop when the slice has a single element or less. You currently loop forever on slices of 1 element.
if (l >= r) return;
You should test in main() if the number n of elements read from the user is no greater than 100, the size of the global array a into which you read the elements to be sorted. You should instead use a local array with the proper size or allocate the array from the heap. The temporary array t in merge() might also be too large for automatic allocation. It is more efficient to allocate temporary space once and pass it recursively.
Note also that it is idiomatic in C and C++ to specify array slices with the index of the first element and the index of the element after the last one. This simplifies the code and allows for empty arrays and avoid special cases for unsigned index types.
Here is a modified version with this approach:
#include <bits/stdc++.h>
using namespace std;
void merge(int a[], int l, int r, int m, int t[]) {
int i = l, j = m, k = 0;
while (i < m && j < r) {
if (a[i] < a[j])
t[k++] = a[i++];
else
t[k++] = a[j++];
}
while (i < m)
t[k++] = a[i++];
while (j < r)
t[k++] = a[j++];
for (int i = l; i < r; i++)
a[i] = t[i - l];
}
void msort(int a[], int l, int r, int t[]) {
if (r - l > 1) {
int m = l + (r - l) / 2;
msort(a, l, m, t);
msort(a, m, r, t);
merge(a, l, r, m, t);
}
}
void msort(int a[], int n) {
if (n > 1) {
int *t = new int[n];
msort(a, 0, n, t);
delete[] t;
}
}
int main() {
int n;
cin >> n;
if (n <= 0)
return 1;
int *a = new int[n];
for (int i = 0; i < n; i++)
cin >> a[i];
msort(a, n);
for (int i = 0; i < n; i++)
cout << a[i] << " ";
cout << endl;
delete[] a;
return 0;
}

how to generate Chase's sequence

In the draft section 7.2.1.3 of The art of computer programming, generating all combinations, Knuth introduced Algorithm C for generating Chase's sequence.
He also mentioned a similar algorithm (based on the following equation) working with index-list without source code (exercise 45 of the draft).
I finally worked out a c++ version which I think is quite ugly. To generate all C_n^m combination, the memory complexity is about 3 (m+1) and the time complexity is bounded by O(m n^m)
class chase_generator_t{
public:
using size_type = ptrdiff_t;
enum class GET : char{ VALUE, INDEX };
chase_generator_t(size_type _n) : n(_n){}
void choose(size_type _m){
m = _m;
++_m;
index.resize(_m);
threshold.resize(_m + 1);
tag.resize(_m);
for (size_type i = 0, j = n - m; i != _m; ++i){
index[i] = j + i;
tag[i] = tag_t::DECREASE;
using std::max;
threshold[i] = max(i - 1, (index[i] - 3) | 1);
}
threshold[_m] = n;
}
bool get(size_type &x, size_type &y, GET const which){
if (which == GET::VALUE) return __get<false>(x, y);
return __get<true>(x, y);
}
size_type get_n() const{
return n;
}
size_type get_m() const{
return m;
}
size_type operator[](size_t const i) const{
return index[i];
}
private:
enum class tag_t : char{ DECREASE, INCREASE };
size_type n, m;
std::vector<size_type> index, threshold;
std::vector<tag_t> tag;
template<bool GetIndex>
bool __get(size_type &x, size_type &y){
using std::max;
size_type p = 0, i, q;
find:
q = p + 1;
if (index[p] == threshold[q]){
if (q >= m) return false;
p = q;
goto find;
}
x = GetIndex ? p : index[p];
if (tag[p] == tag_t::INCREASE){
using std::min;
increase:
index[p] = min(index[p] + 2, threshold[q]);
threshold[p] = index[p] - 1;
}
else if (index[p] && (i = (index[p] - 1) & ~1) >= p){
index[p] = i;
threshold[p] = max(p - 1, (index[p] - 3) | 1);
}
else{
tag[p] = tag_t::INCREASE;
i = p | 1;
if (index[p] == i) goto increase;
index[p] = i;
threshold[p] = index[p] - 1;
}
y = index[p];
for (q = 0; q != p; ++q){
tag[q] = tag_t::DECREASE;
threshold[q] = max(q - 1, (index[q] - 3) | 1);
}
return true;
}
};
Does any one has a better implementation, i.e. run faster with the same memory or use less memory with the same speed?
I think that the C code below is closer to what Knuth had in mind. Undoubtedly there are ways to make it more elegant (in particular, I'm leaving some scaffolding in case it helps with experimentation), though I'm skeptical that the array w can be disposed of. If storage is really important for some reason, then steal the sign bit from the a array.
#include <stdbool.h>
#include <stdio.h>
enum {
N = 10,
T = 5
};
static void next(int a[], bool w[], int *r) {
bool found_r = false;
int j;
for (j = *r; !w[j]; j++) {
int b = a[j] + 1;
int n = a[j + 1];
if (b < (w[j + 1] ? n - (2 - (n & 1)) : n)) {
if ((b & 1) == 0 && b + 1 < n) b++;
a[j] = b;
if (!found_r) *r = j > 1 ? j - 1 : 0;
return;
}
w[j] = a[j] - 1 >= j;
if (w[j] && !found_r) {
*r = j;
found_r = true;
}
}
int b = a[j] - 1;
if ((b & 1) != 0 && b - 1 >= j) b--;
a[j] = b;
w[j] = b - 1 >= j;
if (!found_r) *r = j;
}
int main(void) {
typedef char t_less_than_n[T < N ? 1 : -1];
int a[T + 1];
bool w[T + 1];
for (int j = 0; j < T + 1; j++) {
a[j] = N - (T - j);
w[j] = true;
}
int r = 0;
do {
for (int j = T - 1; j > -1; j--) printf("%x", a[j]);
putchar('\n');
if (false) {
for (int j = T - 1; j > -1; j--) printf("%d", w[j]);
putchar('\n');
}
next(a, w, &r);
} while (a[T] == N);
}

Resources