STATUS_ACCESS_VIOLATION at 3-way quicksort (C++) - c++

I tried to implement the 3-way quicksort algorithm in C++, described here.
Unfortunality I get the exception STATUS_ACCESS_VIOLATION.
template<typename T, size_t SIZE>
void qsort(std::array<T, SIZE> &a, std::size_t lo, std::size_t hi) {
if (hi <= lo) {
return;
}
std::size_t lt = lo, gt = hi;
T v = a[lo];
std::size_t i = lo;
while (i <= gt) {
if (a[i] < v) {
std::swap(a[lt++], a[i++]);
} else if (a[i] > v) {
std::swap(a[i], a[gt--]);
} else {
i++;
}
}
qsort(a, lo, lt - 1);
qsort(a, gt + 1, hi);
}
template<typename T, size_t SIZE>
void quickSortThreeWay(std::array<T, SIZE> &a) {
std::size_t arraySize = sizeof(a) / sizeof(a[0]);
qsort(a, 0, arraySize - 1);
}
The array is a std::array I filled with random values. This works fine with other algorithms.
Can you help me find the problem? Thanks.
Thank you.

At this line of code:
qsort(a, lo, lt - 1);
When lo is 0, lt can be -1. Unfortunately, your signature doesn't allow negative numbers because you are using size_t, so in my test, when lo is 0, lt - 1 is 18446744073709551615. This test then fails to do what you want:
if (hi <= lo) { return }
Then it blindly goes on and crashes. You might think to allow negative numbers in your method signature instead of size_t, eg:
void qsort(std::array<T, SIZE> &a, int lo, int hi) {
std::cout << "qsort (a, " << lo << ", " << hi << ")" << std::endl;
When I run the above modified signature against an array of three strings:
std::array<std::string, 3> a;
a[0] = "hello";
a[1] = "abacus";
a[2] = "goodbye";
quickSortThreeWay (a);
I get -1 for that last parameter:
qsort (a, 0, 2)
qsort (a, 0, 1)
qsort (a, 0, -1)
qsort (a, 1, 1)
qsort (a, 3, 2)

Related

C++ iterate over subvectors of size N

I have an input vector which can be of any size. What I want is to divide this vector into vectors of size 64 each and do something. The input vector's size should not necessarily be of size multiple to 64.
So let's say I have a vector of size 200, then I should divide it into 3 vectors of size 64 and 1 vector of size 8.
What I thought of so far is the following:
vector<double> inputVector;
vector<vector<double>> resultVector;
UInt16 length = inputVector.size();
int div = (length % 64) == 0 ? length / 64 : (length / 64) + 1;
for (int i = 0, j = 0; i < div; i++) {
vector<double> current
for (int k = 0; k < 64; k++) {
current.push_back(inputVector[j]);
if (j++ >= length) break;
}
resultVector.push_back(current);
if (j >= length) break;
}
I am sure there would be a better way of doing so but I could't find any example
You can use iterators to create a subvector:
vector<double> inputVector;
vector<vector<double>> resultVector;
for (auto it = inputVector.cbegin(), e = inputVector.cend(); it != inputVector.cend(); it = e) {
e = it + std::min<std::size_t>(inputVector.cend() - it, 64);
resultVector.emplace_back(it, e);
}
The simplest is just for each element push_back to some vector, keep track of them, and if the chunk size is reached then "flush" them to the output vector:
template<typename T>
std::vector<std::vector<T>> devide(const std::vector<T>& v, size_t chunk) {
// iterative algorithm
std::vector<T> tmp;
std::vector<std::vector<T>> ret;
size_t cnt = 0;
for (auto&& i : v) {
tmp.push_back(i);
++cnt;
if (cnt == chunk) {
cnt = 0;
ret.push_back(tmp);
tmp.clear();
}
}
if (cnt != 0) {
ret.push_back(tmp);
}
return ret;
}
but that iterative approach is not optimal - we could copy chunks of memory. So iterate over vector and copy up to chunk count of elements each loop - and copy less on the last loop.
template<typename T>
std::vector<std::vector<T>> devide2(const std::vector<T>& v, size_t chunk) {
// chunk algorithm
std::vector<std::vector<T>> ret;
const auto max = v.size();
for (size_t i = 0; i < max; ) {
const size_t chunkend = std::min(i + chunk, max);
ret.emplace_back(v.begin() + i, v.begin() + chunkend);
i = chunkend;
}
return ret;
}
Tested on godbolt.
More in STL style:
void even_slice(In b, In e, size_t n, F f)
{
while(std::distance(b, e) >= n) {
f(b, b + n);
b = b + n;
}
if (b != e) {
f(b, e);
}
}
template<typename In, typename Out>
Out even_slice_to_vetors(In b, In e, size_t n, Out out)
{
using ValueType = typename std::iterator_traits<In>::value_type;
using ItemResult = std::vector<ValueType>;
even_slice(b, e, n, [&out](auto x, auto y) { *out++ = ItemResult{x, y}; });
return out;
}
https://godbolt.org/z/zn9Ex1
Note that you know exactly how many subvectors have the wanted maximum size:
template<typename It>
auto subdivide_in_chunks(It first, It last, size_t chunk_size) {
using value_type = typename std::iterator_traits<It>::value_type;
size_t size{ std::distance(first, last) / chunk_size };
std::vector<std::vector<value_type>> ret;
ret.reserve(size);
auto last_chunk = std::next(first, size * chunk_size);
while ( first != last_chunk ) {
auto next = std::next(first, chunk_size);
ret.emplace_back(first, next);
first = next;
}
ret.emplace_back(first, last); // This is the last, shorter one.
return ret;
}
With range-v3, you could simply write:
namespace rs = ranges;
namespace rv = ranges::views;
auto resultVector = inputVector
| rv::chunk(64)
| rs::to<std::vector<std::vector<double>>>;
Here's a demo.

Recursive Merge Sort Algorithm Implementation

I am a newbie to Algorithm. I try to implement recursive merge sorting using std::vector. But I am stuck. The code does not work.
I have looked at the algorithm from Introduction To Algorithms, Cormen/Leiserson/Rivest/Stein 3rd edition. The pseudocode which is I try to implement.
Here my merge function:
void merge(std::vector<int>& vec, size_t vec_init, size_t vec_mid, size_t vec_size) {
int leftLoop = 0;
int rightLoop = 0;
int vecLoop = 0;
size_t mid = vec_mid - vec_init + 1;
std::vector<int> Left_Vec(std::begin(vec), std::begin(vec) + mid);
std::vector<int> Right_Vec(std::begin(vec) + mid, std::end(vec));
for (size_t vecLoop = vec_init; vecLoop<vec_size; ++vecLoop) {
vec[vecLoop] = (Left_Vec[leftLoop] <= Right_Vec[rightLoop]) ? Left_Vec[leftLoop++] : Right_Vec[rightLoop++];
}
}
And here my Merge-Sort function
void merge_sort(std::vector<int>& vec, size_t vec_init, size_t vec_size) {
if (vec_init < vec_size) {
size_t vec_mid = (vec_init + vec_size) / 2;
merge_sort(vec, vec_init, vec_mid);
merge_sort(vec, vec_mid + 1, vec_size);
merge(vec, vec_init, vec_mid, vec_size);
}
}
When the input vec = {30,40,20,10}, the output vec = {10, 10, 0, 20}:
int main() {
auto data = std::vector{ 30, 40, 20, 10 };
merge_sort(data, 0, data.size());
for (auto e : data) std::cout << e << ", ";
std::cout << '\n';
// outputs 10, 10, 0, 20,
}
Where is my mistake about the algorithm or code?
There are a couple of problems. These changes will fix the code:
void merge(std::vector<int>& vec, size_t vec_start, size_t vec_mid, size_t vec_end) {
size_t leftLoop = 0;
size_t rightLoop = 0;
size_t vecLoop = 0;
// Not needed, much simpler if mid is relative to vec.begin()
//size_t mid = vec_mid - vec_init + 1;
// You didn't take vec_init and vec_size into account when calculating the ranges.
std::vector<int> Left_Vec(std::begin(vec) + vec_start, std::begin(vec) + vec_mid);
std::vector<int> Right_Vec(std::begin(vec) + vec_mid, std::begin(vec) + vec_end);
// Values are not uniformly distributed in the left and right vec. You have to check for
// running out of elements in any of them.
for (/*size_t*/ vecLoop = vec_start; leftLoop < Left_Vec.size() && rightLoop < Right_Vec.size(); ++vecLoop) {
// ^~~~~ shadowed outer vecLoop ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
vec[vecLoop] = Left_Vec[leftLoop] <= Right_Vec[rightLoop] ? Left_Vec[leftLoop++] : Right_Vec[rightLoop++];
}
// Copy the rest of the values into vec.
if (leftLoop == Left_Vec.size())
std::copy(Right_Vec.begin() + rightLoop, Right_Vec.end(), vec.begin() + vecLoop);
else
std::copy(Left_Vec.begin() + leftLoop, Left_Vec.end(), vec.begin() + vecLoop);
}
void merge_sort(std::vector<int>& vec, size_t vec_start, size_t vec_end) {
// Should only run the function if there are at least 2 elements, otherwise vec_mid
// would be always at least vec_start + 1 and the recursion would never stop.
if (vec_end - vec_start >= 2) {
size_t vec_mid = (vec_start + vec_end) / 2;
merge_sort(vec, vec_start, vec_mid);
merge_sort(vec, vec_mid /* + 1 */, vec_end);
// ^~~ + 1 here would skip an element
merge(vec, vec_start, vec_mid, vec_end);
}
}

Segmentation fault after main exit

I Have tried executing the following code in gdb, but with gdb I don`t see any segmentation fault but without gdb If I run the following code in standalone mode segmentation fault occurs. The code is related to range sum query implemented using segment tree.
#include <iostream>
#include <vector>
using namespace std;
class segmentTree
{
private:
vector<int> a;
void constructUtil(vector<int>& , int , int , int );
int queryUtil(int , int , int , int , int );
void updateUtil(int , int , int , int , int );
public:
segmentTree(vector<int> );
int query(int , int );
void update(int , int );
~segmentTree();
};
segmentTree::segmentTree(vector<int> v)
{
int n = v.size();
a.resize((2*n) - 1);
constructUtil(v, 0 , n - 1, 0);
}
segmentTree::~segmentTree()
{
a.clear();
}
void segmentTree::constructUtil(vector<int>& v, int start, int end, int i)
{
if(start == end)
{
a[i] = v[start];
}
else
{
int mid = start + ((end - start) >> 1);
constructUtil(v, start, mid, ((2*i) + 1));
constructUtil(v, mid + 1, end, ((2*i) + 2));
a[i] = a[(2*i) + 1] + a[(2*i) + 2];
}
}
int segmentTree::queryUtil(int ss, int se, int rs, int re, int i)
{
if(se < rs || re < ss)
{
return 0;
}
else if(rs <= ss && se <= re)
{
return a[i];
}
else
{
int sm = ss + ((se - ss) >> 1);
return queryUtil(ss, sm, rs, re, 2*i + 1) + queryUtil(sm + 1, se, rs, re, 2*i + 2);
}
}
int segmentTree::query(int l, int r)
{
int n = ((a.size() + 1) >> 1);
if(l < 0 || r > n-1)
{
return 0;
}
return queryUtil(0, n-1, l , r, 0);
}
void segmentTree::updateUtil(int ss, int se, int i, int si, int x)
{
if(ss > i || se < i)
{
return ;
}
else if(ss == se)
{
a[si] = x;
}
else
{
int sm = ss + ((se - ss) >> 1);
updateUtil(ss, sm, i, (2*si) + 1, x);
updateUtil(sm + 1, se, i, (2*si) + 2, x);
a[si] = a[(2*si) + 1] + a[(2*si) + 2];
}
}
void segmentTree::update(int i, int x)
{
int n = ((a.size() + 1) >> 1);
if(i < 0 || i > n-1)
{
return ;
}
else
{
updateUtil(0, n-1, i, 0, x);
}
}
int main()
{
int arr[] = {1, 3, 5, 7, 9, 11};
int n = sizeof(arr)/sizeof(arr[0]);
vector<int> v(arr, arr + n);
segmentTree st(v);
// Print sum of values in array from index 1 to 3
cout << "Sum of values in given range = " << st.query(1, 3) << endl;
// Update: set arr[1] = 10 and update corresponding
// segment tree nodes
st.update(1, 10);
// Find sum after the value is updated
cout << "Updated sum of values in given range = " << st.query(1, 3) << endl;
return 0;
}
Consider segmentTree::constructUtil with v.size() == 3. Then in the inital call to constructUtil you have start == 0 and end == 2.
Thus we get mid = 1.
In the second recursive call we are then passing start = 1, end = 2 and i = 2. start != end and so the else is executed.
However in the else block a[(2*i)+2] is accessed (by the way, no need for the parantheses there). This index will be 6.
But if you look at the size of a, it was given as 2*n-1. 2*3-1 = 5, so 6 is clearly out-of-bounds.
I don't know what your intentions with the code are, but that there is undefined behavior. You can easily catch it by either using something like valgrind, by replacing a[...] with a.at(...) for debug purposes, by stepping through the code with gdb and actually following all the variables (there does not need to be a segmentation fault for your program to have undefined behavior) or by entering debug std::cout statements with the variable content everywhere that could cause the issue.

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).

BinarySearch returning index of where it belongs

So i am looking to write a code to return the index that the key is or if it is not there, where it should be. what am i missing ?
min is 0, max is size - 1, buf is sorted
int binarySearch(string buf[], string key, int min, int max){
int mid;
while (max >= min){
mid = (min + max) / 2;
if (buf[mid] < key)
min = mid + 1;
else if (buf[mid] > key)
max = mid - 1;
else
return mid;
}
return min;
}
I had practically the same problem, so I wrote this generic code (maybe you may want to use a different namespace than std ;) ) The code below returns the an iterator to the largest element in the sequence which is smaller than or equal to val. It uses O(N log N) time for N = std::difference(first, last), assuming O(1) random access on [first ... last).
#include <iostream>
#include <vector>
#include <algorithm>
namespace std {
template<class RandomIt, class T>
RandomIt binary_locate(RandomIt first, RandomIt last, const T& val) {
if(val == *first) return first;
auto d = std::distance(first, last);
if(d==1) return first;
auto center = (first + (d/2));
if(val < *center) return binary_locate(first, center, val);
return binary_locate(center, last, val);
}
}
int main() {
std::vector<double> values = {0, 0.5, 1, 5, 7.5, 10, 12.5};
std::vector<double> tests = {0, 0.4, 0.5, 3, 7.5, 11.5, 12.5, 13};
for(double d : tests) {
auto it = std::binary_locate(values.begin(), values.end(), d);
std::cout << "found " << d << " right after index " << std::distance(values.begin(), it) << " which has value " << *it << std::endl;
}
return 0;
}
Source: http://ideone.com/X9RsFx
The code is quite generic, it accepts std::vectors, std::arrays and arrays, or any sequence that allows random access. The assumption (read precondition) is that val >= *first and that the values [first, last) are sorted, like needed for std::binary_search.
Feel free to mention bugs or malpractices that I have used.
int binary_srch_ret_index(ll inp[MAXSIZE], ll e, int low, int high) {
if (low > high) {
return -1;
}
int mid = (low + high) / 2;
if (e == inp[mid]) {
return mid;
}
if (e < inp[mid]) {
return binary_srch(inp, e, low, mid - 1);
} else {
return binary_srch(inp, e, mid + 1, high);
}
}
You searched for a character and you assumed that charaters in the buf are sorted.
If you want to search for a string use a string match pattern algorithm.
(http://en.wikipedia.org/wiki/String_searching_algorithm)
If you want to search a character or a number in an ordered array then see this:
http://www.programmingsimplified.com/c/source-code/c-program-binary-search
In binary search you can do value type search not reference type. If you want to search for string in string array you have to write a complex program or use has table
This seems to work:
#include <iostream>
#include <cassert>
int binarySearch(int buf[], int key, int min, int max);
int main()
{
int data[] = {1,2,4,6,7,9};
for(int i=0; i<6; i++)
{
int result = binarySearch(data, data[i], 0, 5);
assert(result == i);
}
assert(binarySearch(data, 3, 0, 5) == 1);
assert(binarySearch(data, 5, 0, 5) == 2);
assert(binarySearch(data, 8, 0, 5) == 4);
assert(binarySearch(data, 10, 0, 5) == 5);
return 0;
}
int binarySearch(int buf[], int key, int min, int max)
{
int mid;
while (max >= min){
mid = (min + max) / 2;
if (buf[mid] < key)
min = mid + 1;
else if (buf[mid] > key)
max = mid - 1;
else
return mid;
}
return std::min(min, max);
}