Can anyone point out why this implementation of quick sort is not working, i have gone through it several times and can't seem to find the error
int quickPartition ( int data[], int p, int r)
{
int x=data[r];
int i=p-1;
for (int j=p; j<r; j++)
{
if(data[j]<x)
{
i++;
int temp=data[i];
data[i]=data[j];
data[j]=temp;
}
int temp=data[i+1];
data[i+1]=data[r];
data[r]=temp;
}
i++;
cout<<"i:"<<i<<endl;
return i;
}
void myQuickSort(int data[], int left, int right)
{
if(left<right)
{
int q=quickPartition(data,left,right);
myQuickSort(data,left,q-1);
myQuickSort(data,q+1,right);
}
}
the call to quicksort is simply
myQuickSort(anArray,0,size-1);
Methinks
int temp=data[i+1];
data[i+1]=data[r];
data[r]=temp;
should go outside the for loop.
Your implementation of partition looks entirely bogus. What you want is iterate from both ends and on each end find an object which belongs to the opposite part. If the iterators meet, you are done. Otherwise you swap the two objects and find the next pair.
Personally, I can't think properly in the abstractions you are using: I have a much easier time to think in terms of iterators pointing to the respective objects and finding the next object to swap should be functions as well. Also, I need to factor things into small, comprehensible bits. You swap objects at some point. This should be a separate function. With this partition() would look something like this:
int* partition(int* left, int* right, int value) {
while (left != right)
{
left = find_forward(left, right, value);
right = find_backward(left, right, value);
if (left != right)
{
swap(left, right);
}
}
return left;
}
I haven't tested this but something along those lines should work. Obviously, I would just use std::swap() to swap elements and std::find_if() to find suitable locations (for the backward case using std::reverse_iterator). Well, if this weren't a homework assignment you would just use std::sort() anyway: it doesn't use a vanilla quick-sort but a variation which detects that it is running into a bad case and uses std::heap_sort() in this case to guarantee that it stays O(n log n).
Related
I have a method, which i want to execute differently depending on if the passed variable is an element of a vector or not, like for example:
void method(int a){
if (/*a is an element of a vector*/) //do one thing
else //do another thing
}
and then in main:
vector<int> a;
a.pushback(1);
int b = 1;
method(a[0]); // does one thing
method(b); // does the other thing
What is the simplest way to do that?
Well, for all cases this is impossible, because it actually requires your function to look at how it is executed, and there is no such thing in C++. The hated eval() comes to mind.
But in a certain case, when your vector is a global entity, you could pass your variable by link instead of value. Then, you can check if it fits the space between the start and end of the desired vector. This is how it is done(not tested though, but should work)
vector<int> v;
//fill it somewhere somehow
void method(int& a)
{
int* beg = v.data();
int* end = beg + v.size();
int* val = &a;
if ((val >= beg) && (val < end))
{
//it is a part of vector
}
else
{
//it is not a part of vector
{
}
Problem is that you really shouldn't do it this way... As people in the comments said, it DOES look like an XY problem.
An int is an int. An int does not wear a label around its neck, telling everyone where it came from. When an int is passed to a function, there is nothing that specifies where the int originates.
You should take this as an opportunity to learn about iterators, and implement an overloaded method that takes either an
void method(int);
for a parameter, or a
void method(std::vector<int>::iterator iter);
for a parameter (or, perhaps, a const_iterator), and invoke the alternative method() by passing it an iterator to the int in your vector.
I'm trying to sort first half of a deque deque<data> sortDValues of pairs
struct data {
int dValue;
int index;
};
by the dValue using c++ function with lambda expression
sort(sortDValues.begin(), sortDValues.begin() + partASize - i,
[](data const &a, data const &b) { return a.dValue > b.dValue; });
This approach works well most of time, but in some special cases the final program falls. I've located, that the problem of this is in the sort function, however, I couldn't figure out, why.
I'm not sure, if it can have anything in common with filling this dequeue
deque<data> sortDValues;
for(number n : indices)
{
if(perm[n] >= partASize)
sortDValues.push_back(dValues[n]);
else
sortDValues.push_front(dValues[n]);
}
I can give a specific case of this problem: first number is the index, the second the dValue:
Thank you in advance for answers, I wasn't able to find out, where the problem is.
I've been trying to write a templated function in C++ that can accept an array of any type and sort it. The sort used has to be a quick sort or a merge sort, but I'm having a lot of trouble with implementing either of these, as a quick sort header usually comes with a top and bottom parameter, and a merge sort comes with a first and last parameter. My function header looks like this: void mySort(T *array, int n)
So far I have this:
template <typename T>
void sort(T *a, int n)
{
int i = 0;
int j = n-1;
int tmp;
int pivot = a[(n-1)/2];
while (i <= j){
while (a[i] < pivot)
i++;
while (a[j] > pivot)
j--;
if (i<=j){
tmp = a[i];
a[i] = a[j];
a[j] = a[i];
i++;
j--;
}
}
if(0<j)
sort(a, j);
/*
if(i<right)
sort(
*/
}
I was trying to use a recursive call to sort, but I couldn't figure out how to call recursive for the right partition created, without a different parameter list.
Before answering the actual question: your code would benefit from factoring the partition code out of the body of the function! That way, you'd essentially call partition to determine the mid-point between the two arrays to be called, i.e., you'd have something like this:
template <typename T>
void sort(T* a, int n) {
T* mid = partition(a, n);
// ...
}
The idea is that [a, mid) contains all elements sorting smaller than the pivot and [mid, a + n) contains all elements sorting equal or greater than the pivot. All what remains is
Call sort() recursively with the two array, i.e.,
sort(a, mid - a);
sort(mid, (a + n) - mid);
Make sure sort() terminates if the array obtained is small than 2.
Of course, if you want your Quick Sort to be quick you'll also need to pull half a dozen or so tricks. Like:
Use Introsort to guarantee the complexity is O(n lg n) (e.g. together with Merge Sort).
Use Insertion Sort on small ranges.
Use an implementation of partition and insertion sort taking advantage of suitable sentinels.
Sort really sort ranges directly.
One of the things which oddly is rather futile to play with is choice of a pivot. As far as I can tell, using the middle element works as well as any more advanced technique (assuming optimizations like those mentioned above are implemented).
Separate the called function from the recursive function:
// recursive function
template <typename T>
void quicksort(T *a, int lo, int hi)
{
// ...
}
// called function
template <typename T>
void sort(T *a, int n)
{
if(n < 2)return;
quicksort(a, 0, n-1);
}
I am writing a function to sort an array using heap sorting. So far I have:
template <typename Item, typename SizeType>
void heap_sort(Item data[], SizeType size) {
vector<int> v(data,data+size);
SizeType unsorted = size;
make_heap(v.begin(),v.end());
while(unsorted > 1) {
--unsorted;
swap(data[0], data[unsorted]);
reheapify_down(data,unsorted);
}
}
and:
template <typename Item, typename SizeType>
void reheapify_down(Item data[], SizeType size) {
SizeType current(0), big_child;
bool heap_ok = false;
while(!heap_ok && 2*current+1 < size) {
if(2*current+2 > size)
big_child = 2*current + 1;
else if(data[2*current+1] > data[2*current+2])
big_child = 2*current+1;
else
big_child = 2*current + 2;
if(data[current] < data[big_child]) {
swap(data[current],data[big_child]);
current = big_child;
}
else
heap_ok = true;
}
}
When I run the program, it outputs an incorrectly sorted array though. Is there something that I am just missing or some error that I overlooked?
Just a few suggestions.
First, I'd write a small proxy class that does nothing but let you use 1-based indexing on your collection. All the index math used in heaps assumes 1-based indexing, and it's a lot easier to compensate for 0-based indexing in one place than throughout all the code. As it stands right now, I have a hard enough time following the indexing to be sure your reheapify_down is correct. It's certainly the right general idea, but it would take a lot of work to be certain all the math is right.
Second, I'd write a check_heap (or whatever) that you can use to verify both your make_heap and your reheapify_down (as an aside, I'd decide on either "make_heap" or "heapify", so the names would be either "make_heap" and "remake_heap", or else "heapify" and "reheapify").
Beyond that, however, it's hard to be certain of the problem, especially since you haven't included the code for your make_heap in the question. If it isn't working correctly, the rest has no hope.
I am currently trying to write a program that alphabetizes strings. I have one error. It's that minLocation does not take 2 arguments. I am fairly new to programming could anyone give me a hint as to why this part of my code is wrong?
int minLocation(string list[], int first, int last)
{
int mIndex=first;
int loc = 0;
for (loc = first+1; loc <= last; loc++)
if (list[loc] < list [mIndex])
mIndex = loc;
return mIndex;
void Sort(string slist[],int length)
{
int mIndex;
for (int loc = 0; loc < length-1; loc++)
{
mIndex = minLocation (loc,length-1);
swap (loc, minIndex);
}
}
Without seeing the definition of minLocation, we can't tell. But it's a safe bet that it doesn't take two arguments - compilers don't lie to you just for the fun of it, you can usually assume that what they're saying is true :-)
You need to find the definition, something like:
int minLocation (int loc) { ...
and figure out how you're actually meant to call it. Given that it looks like it's trying to find which of two indexes has the lower value, it may be that it needs more than two arguments.
And, on top of that, you need to decide whether you want that variable called mIndex or minIndex. Most compilers aren't quite smart enough to figure that out for you.
Based on your edits that muinFunction is defined as:
int minLocation (string list[], int first, int last) { ...
it seems evident that it also needs the string array as well as the two indexes. You will need to change the call to:
mIndex = minLocation (slist, loc, length-1);
And keep an eye on the swap call as well. It may have a similar requirement, based on the coding style.