Why my Hwang-Lin implementation is so slow? - c++

I wrote an implementation of Hwang-Lin merge algorithm (A simple algorithm for merging two disjoint linearly ordered sets). Though it works, it turns out to be very slow. Here is my implementation:
template<typename Iter>
void hwang_lin_buf(Iter first1, Iter first2, Iter last, Iter buf_start) {
ptrdiff_t m = first2 - first1, n = last - first2, buff_size = m;
swap_blocks(first1, buf_start, m);
block_rotate(first1, first2, last);// B first1 - first1 + n, A buf_start - buf_start + m
Iter a = buf_start, b = first1, buffer = first1 + n, buffer_end = buffer + buff_size;
while (m > 0 && n > 0) {
if (n > m) {
size_t alpha = (size_t) floor(log2((double) n / m)), x = n - pow(2, alpha) + 1;
if (*(a + m - 1) < *(b + x - 1)) {
block_rotate(b + x - 1, buffer, buffer_end); //pull out the set of all elements in B >= bx
buffer = b + x - 1; //new buffer position
buffer_end = buffer + buff_size;
n = x - 1;
} else {
Iter place = binary_search(b + x - 1, b + n - 1, a + m - 1);
if (place != b + n) {
block_rotate(place, buffer, buffer_end); //pull out the set of all elements in B >= am
buffer = place;
buffer_end = buffer + buff_size;
}
std::swap(*(a + m - 1), *(buffer_end - 1)); //insert am
--buff_size;
buffer_end = buffer + buff_size;
--m;
n = place - b;
}
} else {
size_t alpha = (size_t) floor(log2((double) m / n)), x = m - std::pow(2, alpha) + 1;
if (*(b + n - 1) < *(a + x - 1)) {
swap_blocks(a + x - 1, buffer_end - m + x - 1,
m - (x - 1)); //pull out the set of all elements in A >= ax
buff_size -= m - (x - 1);
buffer_end = buffer + buff_size;
m = x - 1;
} else {
Iter place = binary_search(a + x - 1, a + m - 1, b + n - 1);
ptrdiff_t c_size = a + m - place;
swap_blocks(place, buffer_end - c_size, c_size); //pull out the set of all elements in A >= bn
buff_size -= c_size;
buffer_end = buffer + buff_size;
block_rotate(b + n - 1, buffer, buffer_end); //insert bn
--buffer;
buffer_end = buffer + buff_size;
--n;
m -= c_size;
}
}
}
if (m > 0)
swap_blocks(a, buffer, m);
}
Here are functions used in it:
template<typename Iter>
inline void swap_blocks(Iter pos1, Iter pos2, size_t len) {
for (size_t i = 0; i < len; ++i)
std::swap(*(pos1 + i), *(pos2 + i));
}
template<typename Iter>
inline Iter binary_search(Iter be, Iter en, Iter key) {//returns first iter bigger than key if nothing found
while (be < en) {
Iter mid = be + (en - be) / 2;
if (*mid < *key)
be = mid + 1;
else
en = mid;
}
if (((en == be) && (*be == *key)) || (*be > *key))
return be;
else
return be + 1;
}
template<typename Iter>
inline void floating_hole(Iter pos1, Iter pos2, size_t len) {
auto t = *(pos1 - 1);
for (size_t i = 0; i < len; ++i) {
*(pos1 + i - 1) = *(pos2 + i);
*(pos2 + i) = *(pos1 + i);
}
*(pos1 + len - 1) = t;
}
template<typename Iter>
inline void block_rotate(Iter first1, Iter first2, Iter last) {
ptrdiff_t i = first2 - first1, j = last - first2;
if (i == 0 || j == 0)
return;
Iter p = first1 + i;
while (i != j) {
if (i > j) {
swap_blocks(p - i, p, j);
i -= j;
} else {
swap_blocks(p - i, p + j - i, i);
j -= i;
}
}
swap_blocks(p - i, p, i);
}
I run tests to compare my implementation with std::inplace_merge. I expected my code to be somewhat slower, but I got following results for merging vector of 100000(two parts of 50000) int64_t with -O3 optimization:
Hwang-Lin: 5.72054 s
std::inplace_merge: 0.0010003 s
std::inplace_merge was 5000 times faster! Am I missing something?

Related

double free or corruption (!prev) occured using the vector in C++

When I was writing the Iteration Merge Sort Code using the vector in C++,I met the error double free or corruption (!prev) when the vector size n is between 17 and 30;When n is smaller than 17 or larger than 30,there is no error.And the code Implemented sorting function.But I didn't use free or delete,why this error will occur?
#include <iostream>
#include <vector>
#include <cstdlib>
#include <random>
using namespace std;
// v1[left...middle] and v1[middle+1...right] are Ordered,merge them to v2;
void Merge(vector<int> &v1, vector<int> &v2, int left, int middle, int right)
{
int i = left, j = left, k = middle + 1;
while (i <= middle && k <= right)
{
if (v1[i] <= v1[k])
v2[j] = v1[i++];
else
v2[j] = v1[k++];
++j;
}
while (i <= middle)
{
v2[j++] = v1[i++];
}
while (k <= right)
{
v2[j++] = v1[k++];
}
}
// Merge adjacent subsequences of length interval in v1 into v2
void MergePass(vector<int> &v1, vector<int> &v2, int interval)
{
int i = 0, k = v1.size() - 2 * interval + 1;
while (i < k)
{
Merge(v1, v2, i, i + interval - 1, i + 2 * interval - 1);
i += 2 * interval;
}
/*for (i = 0; i < v1.size() - 2 * interval + 1; i += 2 * interval)
{
Merge(v1, v2, i, i + interval - 1, i + 2 * interval - 1);
}*/
if (i < v1.size() - interval)
Merge(v1, v2, i, i + interval - 1, v1.size() - 1);
else
{
for (; i < v1.size(); i++)
{
v2[i] = v1[i];
}
}
}
void MergeSort(vector<int> &v)
{
int k= v.size();
vector<int> v1(k);
int i = 1;
while (i < v.size())
{
MergePass(v, v1, i);
i *= 2;
MergePass(v1, v, i);
i *= 2;
}
}
int main()
{
vector<int> v;
int n;
cout << "input the size:";
cin >> n;
for (int j = 0; j < n; j++)
{
v.push_back(rand() % 1000 + 1);
}
MergeSort(v);
I have solved this problem.
In MergePass function
if (i < v1.size() - interval)
Merge(v1, v2, i, i + interval - 1, v1.size() - 1);
the size() returns std::size_t,when v1.size()<interval,v1.size()<interval will get a very large positive integer,Merge(v1, v2, i, i + interval - 1, v1.size() - 1) will still be run.So there is out-of-bounds.I change it to
if (i < (int)v1.size() - interval)
Merge(v1, v2, i, i + interval - 1, v1.size() - 1);
Thanks to #PaulMcKenzie and everyone helped me.

Input 300 000 sets of numbers with cin or scanf

Hi,
I am participating in programming contest. My algorithm is fine with number of sets to 5000.
Sets of values are consist of three integers.
But I enter 300 000 sets of numbers, it takes too long.
Limit of running program: 14s.
Fetching data: 576s. (Way too long)
My formatted input is:
300000
a b c
300000 - number of sets
a, b, c - elements of the set
My algorithm (dont judge about the code):
#include <iostream>
using namespace std;
int min_replacements(int n, int *ds, int *ps, int *rs);
int max(int a, int b, int c);
bool ot(int a, int b, int c);
bool ooo(int a, int b, int c);
bool to(int a, int b, int c);
int main()
{
int n = 0;
cin >> n;
int *ds, *ps, *rs;
ds = new int[n];
ps = new int[n];
rs = new int[n];
int d{}, p{}, r{};
for (int i = 0; i < n; i++)
{
scanf("%d %d %d", &ds[i], &ps[i], &rs[i]);
printf("%d", i);
}
int t = min_replacements(n, ds, ps, rs);
printf("%d\n", t);
delete[] ds;
delete[] ps;
delete[] rs;
}
bool ot(int a, int b, int c)
{
return (a != 0 && b == 0 && c == 0);
}
bool ooo(int a, int b, int c)
{
return (a == 0 && b != 0 && c == 0);
}
bool to(int a, int b, int c)
{
return (a == 0 && b == 0 && c != 0);
}
int max(int a, int b, int c)
{
int m = 0;
if (a == b && c < a)
{
m = a;
}
if (b == c && a < b)
{
m = b;
}
if (a == c && b < c)
{
m = c;
}
if (b < a && c < a)
{
m = a;
}
if (a < b && c < b)
{
m = b;
}
if (a < c && b < c)
{
m = c;
}
if (a == b && b == c)
{
m = a;
}
return m;
}
int min_replacements(int n, int *ds, int *ps, int *rs)
{
int t = 0;
if (ds[0] == ps[0] && ps[0] == rs[0] && ds[0] == rs[0])
{
return (n + ps[0]) * rs[0];
}
bool loop = true;
while (loop)
{
for (int i = 0; i < n - 1; ++i)
{
if (ot(*(ds + i), *(ps + i), *(rs + i)) || ooo(*(ds + i), *(ps + i), *(rs + i)) || to(*(ds + i), *(ps + i), *(rs + i)))
{
continue;
}
int m = max(*(ds + i), *(ps + i), *(rs + i));
if (m == *(ds + i))
{
*(ps + i + 1) += *(ps + i);
*(rs + i + 1) += *(rs + i);
*(ps + i) = *(rs + i) = 0;
t += 2;
}
if (m == *(ps + i))
{
*(ds + i + 1) += *(ds + i);
*(rs + i + 1) += *(rs + i);
*(ds + i) = *(rs + i) = 0;
t += 2;
}
if (m == *(rs + i))
{
*(ds + i + 1) += *(ds + i);
*(ps + i + 1) += *(ps + i);
*(ps + i) = *(ds + i) = 0;
t += 2;
}
}
for (int i = 0; i < n; ++i)
{
if (ot(*(ds + i), *(ps + i), *(rs + i)) || ooo(*(ds + i), *(ps + i), *(rs + i)) || to(*(ds + i), *(ps + i), *(rs + i)))
{
loop = false;
}
else
{
loop = true;
}
}
if (loop)
{
*ds += *(ds + n - 1);
*ps += *(ps + n - 1);
*rs += *(rs + n - 1);
*(ds + n - 1) = *(ps + n - 1) = *(rs + n - 1) = 0;
t -= 2;
}
}
if (t == 0)
return 0;
return t + 1;
}
I used a cin in this algorithm
Can you help me? Thank you so much.
How do you know the std::cin part is the problem? Did you profile your code? If not, I suggest doing that, it's often surprising which part of the code is taking up most time. See e.g. How can I profile C++ code running on Linux?.
You're doing a lot of unnecessary work in various parts of the code. For example, your max function does at least 7 comparissons, and looks extremely error prone to write. You could simply replace the whole function by:
std::max({ a, b, c })
I would also take a look at your min_replacements function and see if it can be simplified. Unfortunately, you're using variable names which are super vague, so it's pretty much impossible to understand what the code should be doing. I suggest using much more descriptive variable names. That way the code will become much easier to reason about. The way it's currently written, there's a very good change even you yourself won't be able to make sense of it in a month's time.
Just glacing over the min_replacements function though, there's definitely a lot more work going on than necessary. E.g. the last for-loop:
for (int i = 0; i < n; ++i)
{
if (ot(*(ds + i), *(ps + i), *(rs + i)) || ooo(*(ds + i), *(ps + i), *(rs + i)) || to(*(ds + i), *(ps + i), *(rs + i)))
{
loop = false;
}
else
{
loop = true;
}
}
Each loop iterator sets the loop variable. Assuming this code is correct, you don't need the loop at all, just do the check only once for i = n - 1. That's already O(n) changed to O(1).

Detect a 2d collision in C++

I need to create a function that returns a bool that is false if there is no collision between two sprites and true if there is, I was thinking for a long time and I can not find an exact solution, the objective is to detect if there is a collision per pixel, that is if two pixels with the alpha value (from rgba) different than 0 (it is visible) coincide in the same place in the space, the function has the following signature :
bool checkPixelCollision(
const Vector2& pixelPos1,
const Vector2& pixelSize1,
const vector<uint8_t> pixel1,
const Vector2& pixelPos2,
const Vector2& pixelSize2,
const vector<uint8_t> pixel2);
Vector2 is a struct with the next form:
struct Vector2
{
float x;
float y;
};
pixelPos1 is the position of the upper left corner of the rectangle that contains sprite 1, pixelSize1 is the size (x = width; y = height) of the rectangle that contains sprite 1, pixel1 is a vector that has the rgba values ​​of each pixel of the sprite, they are stored from 4 to 4 so that i contains the amount of r of the pixel i; i + 1 the amount of g of the pixel i; i + 2 the amount of b of the pixel i; i + 3 the amount of alpha of the pixel i, so that if i + 3 is different from 0 is a visible pixel, the size of pixel1 is given by pixelSize1.x * pixelSize1.y * 4.
The other three parameters of the header are those corresponding to sprite 2. The objective would therefore be to check when there is a collision (either on the side or corner that is) and from there establish a collision rectangle between both rectangles (the coincident area), and set two indexes that travel pixel1 and pixel2 (since each one will have to start from a different position in its corresponding vector).
The problem is that I can not find an optimal and / or easy way to do it and that it works. If anyone knows any way to do it, I would appreciate it very much.
EDIT
Here is my code (it doesn't work)
#include <algorithm>
#include <stdint.h>
#include <vector>
struct Vector2
{
float x;
float y;
};
float clamp(float val, float min, float max) {
return std::max(min, std::min(max, val));
}
bool checkPixelCollision(const Vector2& pixelPos1, const Vector2& pixelSize1, const vector<uint8_t> pixel1, const Vector2& pixelPos2, const Vector2& pixelSize2, const vector<uint8_t> pixel2) {
return check(pixelPos1,pixelSize1,pixel1,pixelPos2,pixelSize2,pixel2)||check(pixelPos2,pixelSize2,pixel2,pixelPos1,pixelSize1,pixel1);
}
bool check(const Vector2& pixelsPos1, const Vector2& pixelsSize1, const vector<uint8_t> pixels1, const Vector2& pixelsPos2, const Vector2& pixelsSize2, const vector<uint8_t> pixels2){
bool res = false;
if (pixelsPos1.x <= pixelsPos2.x + pixelsSize2.x && pixelsPos1.y <= pixelsPos2.y + pixelsSize2.y && pixelsPos1.x >= pixelsPos2.x && pixelsPos1.y >= pixelsPos2.y) {
float i = pixelsSize2.x - (pixelsSize1.y*((pixelsPos1.x - pixelsPos2.x + pixelsSize2.x) / pixelsSize1.x));
float j = pixelsSize2.y - (pixelsSize1.y*((pixelsPos1.y - pixelsPos2.y + pixelsSize2.y) / pixelsSize1.y));
float ifin = fmin(pixelsSize1.x - pixelsSize2.x, pixelsSize1.x);
float jfin = fmin(pixelsSize1.y - pixelsSize2.y, pixelsSize1.y);
float i2 = 0;
float j2 = 0;
while (j<jfin-1) {
int k = floor((pixelsSize2.x*j) + i) * 4 - 1;
int k2 = floor((pixelsSize1.x*j2) + i2) * 4 - 1;
if (pixels1[k2 + 3] != 0 && pixels2[k + 3] != 0) {
res = true;
}
if (i < ifin) {
i = i + 1;
i2 = i2 + 1;
}
else {
i2 = 0;
i = pixelsSize2.x - (pixelsSize1.x*((pixelsPos1.x - pixelsPos2.x + pixelsSize2.x) / pixelsSize1.x));
j = j + 1;
j2 = j2 + 1;
}
}
}
else if (pixelsPos1.x <= pixelsPos2.x + pixelsSize2.x && pixelsPos1.y + pixelsSize1.y >= pixelsPos2.y && pixelsPos1.x >= pixelsPos2.x && pixelsPos1.y + pixelsSize1.y <= pixelsPos2.y + pixelsSize2.y) {
float i = clamp(pixelsSize2.x - (pixelsSize1.x*((pixelsPos1.x - pixelsPos2.x + pixelsSize2.x) / pixelsSize1.x)), 0.0f, pixelsSize2.x);
float jfin = clamp(pixelsSize1.y*((pixelsPos2.y - pixelsPos1.y+pixelsSize1.y) / pixelsSize1.y), 0.0f, pixelsSize1.y);
float ifin = fmin(pixelsSize1.x - pixelsSize2.x, pixelsSize1.x);
float j = 0;
float i2 = 0;
float j2 = clamp(pixelsSize1.y - pixelsSize1.y*((pixelsPos2.y - pixelsPos1.y + pixelsSize1.y) / pixelsSize1.y),0.0f, pixelsSize1.y);
while (j<jfin-1) {
int k = floor((pixelsSize2.x*j) + i) * 4 - 1;
int k2 = floor((pixelsSize1.x*j2) + i2) * 4 - 1;
if (pixels1[k2 + 3] != 0 && pixels2[k + 3] != 0) {
res = true;
}
if (i < ifin) {
i = i + 1;
i2 = i2 + 1;
}
else {
i2 = 0;
i = clamp(pixelsSize2.x - (pixelsSize1.x*((pixelsPos1.x - pixelsPos2.x + pixelsSize2.x) / pixelsSize1.x)),0.0f, pixelsSize2.x);
j = j + 1;
j2 = j2 + 1;
}
}
}
else if (pixelsPos1.x + pixelsSize1.x >= pixelsPos2.x && pixelsPos1.y<= pixelsPos2.y + pixelsSize2.y && pixelsPos1.x + pixelsSize1.x <= pixelsPos2.x + pixelsSize2.x && pixelsPos1.y >= pixelsPos2.y) {
float ifin = clamp(pixelsSize1.x*((pixelsPos2.x - pixelsPos1.x + pixelsSize1.x) / pixelsSize1.x), 0.0f, pixelsSize1.x);
float j = clamp(pixelsSize2.y - (pixelsSize1.y*((pixelsPos1.y - pixelsPos2.y + pixelsSize2.y) / pixelsSize1.y)),0.0f, pixelsSize2.y);
float jfin = fmin(pixelsSize1.y - pixelsSize2.y, pixelsSize1.y);
float i = 0;
float i2 = clamp(pixelsSize1.x - pixelsSize1.x*((pixelsPos2.x - pixelsPos1.x + pixelsSize1.x) / pixelsSize1.x), 0.0f, pixelsSize1.x);
float j2 = 0;
while (j<jfin-1) {
int k = floor((pixelsSize2.x*j) + i) * 4 - 1;
int k2 = floor((pixelsSize1.x*j2) + i2) * 4 - 1;
if (pixels1[k2 + 3] != 0 && pixels2[k + 3] != 0) {
res = true;
}
if (i < ifin) {
i = i + 1;
i2 = i2 + 1;
}
else {
i2 = clamp(pixelsSize1.x - pixelsSize1.x*((pixelsPos2.x - pixelsPos1.x + pixelsSize1.x) / pixelsSize1.x), 0.0f, pixelsSize1.x);
i = 0;
j = j + 1;
j2 = j2 + 1;
}
}
}
else if (pixelsPos1.x + pixelsSize1.x >= pixelsPos2.x && pixelsPos1.y + pixelsSize1.y >= pixelsPos2.y && pixelsPos1.x + pixelsSize1.x <= pixelsPos2.x + pixelsSize2.x && pixelsPos1.y + pixelsSize1.y <= pixelsPos2.y + pixelsSize2.y) {
float jfin = clamp(pixelsSize1.y*((pixelsPos2.y - pixelsPos1.y + pixelsSize1.y) / pixelsSize1.y), 0.0f, pixelsSize1.y);
float j = 0;
float ifin = clamp(pixelsSize1.x*((pixelsPos2.x - pixelsPos1.x + pixelsSize1.x) / pixelsSize1.x), 0.0f, pixelsSize1.x);
float i = 0;
float i2 = clamp(pixelsSize1.x - pixelsSize1.x*((pixelsPos2.x - pixelsPos1.x + pixelsSize1.x) / pixelsSize1.x), 0.0f, pixelsSize1.x);
float j2 = clamp(pixelsSize1.y - pixelsSize1.y*((pixelsPos2.y - pixelsPos1.y + pixelsSize1.y) / pixelsSize1.y), 0.0f, pixelsSize1.y);
while (j<jfin-1) {
int k = floor((pixelsSize2.x*j) + i) * 4 - 1;
int k2 = floor((pixelsSize1.x*j2) + i2) * 4 - 1;
if (pixels1[k2 + 3] != 0 && pixels2[k + 3] != 0) {
res = true;
}
if (i < ifin) {
i = i + 1;
i2 = i2 + 1;
}
else {
i2 = clamp(pixelsSize1.x - pixelsSize1.x*((pixelsPos2.x - pixelsPos1.x + pixelsSize1.x) / pixelsSize1.x), 0.0f, pixelsSize1.x);
i = 0;
j = j + 1;
j2 = j2 + 1;
}
}
}
return res;
}
Start by checking if the bounding rectangles of the two sprites overlap. If they don't, great; no collision is possible. If they do overlap, calculate the overlapping rectangle for each sprite and compare pixel by pixel - if pixel a or pixel b is transparent then there is no collision caused by that pixel, if both pixels are non-transparent there is a collision and you are done. If you finish checking all pixels in the overlapping area and there are no collisions you are also done.

Struggling to understand a program that calculates the sum of numbers in hex, oct, bin and dec

I've been struggling to understand how the function long long number here works. The bit that I can't fully grasp is the for cycles in the if's. Why when we have a number in dec do we have to raise it to that power? Shouldn't we just sum it up and leave it? Also why do we raise the other numbers to that power?
Here is the code:
int counter(long long n, int k) {
int counter = 0;
while (n != 0) {
counter++;
n /= k;
}
return counter;
}
int number2(long long n, int number) {
return (n / (long long) pow(10, number)) % 10;
}
int toDecimal(long long n, int k) {
long long decimal = 0;
for (int i = 0; i < counter(n, 10); i++) {
decimal += number2(n, i)*(int)pow(k, i);
}
return decimal;
}
long long number(char *arr, int start) {
int end = start;
long long number2 = 0;
while (*(arr + end) != ' ' && *(arr + end) != '\0') {
end++;
}
int numberSize = end - start;
if (*(arr + start) != '0') {
for (int i = 0; i < numberSize; i++) {
number2 += (*(arr + start + i) - '0')*pow(10, numberSize - i - 1);
}
return number2;
}
if (*(arr + start) == '0' && (*(arr + start + 1) != 'b' && *(arr + start + 1) != 'x')) {
for (int i = 1; i < numberSize; i++) {
number2 += (*(arr + start + i) - '0')*pow(10, numberSize - i - 1);
}
return toDecimal(number2, 8);
}
if (*(arr + start) == '0' && *(arr + start + 1) == 'b') {
for (int i = 2; i < numberSize; i++) {
number2 += (*(arr + start + i) - '0')*pow(10, numberSize - i - 1);
}
return toDecimal(number2, 2);
}
if (*(arr + start) == '0' && *(arr + start + 1) == 'x') {
int *hex = new int[numberSize - 2];
for (int i = 2; i < numberSize; i++) {
if (*(arr + start + i) >= '0'&&
*(arr + start + i) <= '9')
arr[i - 2] = (*(arr + start + i) - '0');
if (*(arr + start + i) >= 'A'&&
*(arr + start + i) <= 'F')
arr[i - 2] = (int)(*(arr + start + i) - '7');
number2 += arr[i - 2] * pow(16, numberSize - i - 1);
}
delete[] hex;
return number2;
}
}
int main() {
char first[1000];
cin.getline(first, 1000);
int size = strlen(first);
long numberr = number(&first[0], 0);
for (int counter = 0; counter < size; counter++) {
if (first[counter] == ' '&&first[counter + 1] == '+') {
numberr += number(&first[0], counter + 3);
}
}
cout << numberr << "\n";
return 0;
}
The number is a string and is a sequence of single characters representing digits. You have to convert the characters to numbers ("1" --> 1) and then multiply it by the right number of tens to move it to the right place. For example: "123" --> (1 * 10^2) + (2 * 10^1) + (3 * 10^0)

QuickSort algorithm fails due to stack overflow error in best case - C++

I have a problem with the Quick Sort algorithm that I'm trying to implement.
I take a course of Fundamental Algorithms and we're provided for the laboratory assignments with pseudocode for various argorithms to implement. These algorithms are taken from Cormen and assimilated to C++ language and we're supposed to verify efficiency and generate charts for the number of assignments and comparisons within.
Now the question:
The following code is supposed to make a Quick Sort on an array of 10000 numbers and work with it in the Best Case scenario (taking the pivot of the array always at the middle):
int partition(int *a, int p, int r) {
int x = a[r];
countOpQS++;
int index = p - 1;
for (int count = p; count <= (r - 1); count++) {
if (a[count] <= x) {
index += 1;
swap(a[index], a[count]);
countOpQS += 3;
}
countOpQS++;
}
swap(a[index + 1], a[r]);
countOpQS += 3;
return (index + 1);
}
int select(int *a, int p, int r, int index) {
if (p == r) {
return a[p];
}
int q;
q = partition(a, p, r);
//countOpQS++;
int k = q - p + 1;
if (index <= k) {
return select(a, p, q - 1, index);
} else {
return select(a, q + 1, r, index - k);
}
}
void bestQuickSort(int *a, int p, int r) {
if (p < r) {
select(a, p, r, (r - p + 1) / 2);
bestQuickSort(a, p, (r - p + 1) / 2);
bestQuickSort(a, ((r - p + 1) / 2) + 1, r);
}
}
The call in the main function is done by:
for (index = 100; index <= 10000; index += 100) {
countOpQS = 0;
for (int k = 0; k < index; k++) {
a[k] = rand();
}
bestQuickSort(a, 1, index);
out3 << index << ", " << countOpQS << "\n";
}
It should be doable with these methods, but it jumps into stack overflow pretty quickly while running. I even raised the reserved stack in Visual Studio, due to it being a necessity while going into the worst case possible (already ordered array, random pivot).
Do you guys have any idea of why it doesn't work?
Firstly, you should know that your function select() rearranges the elements in the range [p, r], in such a way that the element at the index-th(note that index is one-based!) position is the element that would be in that position in a sorted sequence, just as std::nth_element does.
So when you chose the median element of the subarray by select(a, p, r, (r - p + 1) / 2);, the index of median is based on p.
For example: when p = 3, r = 5, so (r - p + 1) / 2 is 1, the median would be placed in a[4], it means you should call the function like this: select(a, 3, 5, 2). And after that, you just call the bestQuickSort() like this:
bestQuickSort(a, p, (r - p + 1) / 2); // (r - p + 1) / 2 is 1 now!
bestQuickSort(a, ((r - p + 1) / 2) + 1, r);
of course it doesn't work! The whole code for this is:
int select(int *a, int p, int r, int index) {
if (p == r) {
return a[p];
}
int q;
q = partition(a, p, r);
//countOpQS++;
int k = q - p + 1;
if(k== index)
return a[q];
else if (index <= k) {
return select(a, p, q - 1, index);
} else {
return select(a, q + 1, r, index - k);
}
}
void bestQuickSort(int *a, int p, int r) {
if (p < r) {
select(a, p, r, (r - p + 1) / 2 + 1); // the index passed to select is one-based!
int midpoint = p + (r - p + 1) / 2;
bestQuickSort(a, p, midpoint - 1);
bestQuickSort(a, midpoint + 1, r);
}
}
BTW, your version of quicksort didn't always run in best case, though every time you choose the exact median of the (sub)array, but the time complexity of select is not always O(n) since you simply choose the a[r] as the pivot, the worst-case performance of select is quadratic: O(n*n).