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);
}
Related
Here is my problem:
I have a struct:
struct point
{
int x;
int y;
};
and then I have an array:
for (int i = 0;i < n;i++)
{
arr[i].x=rand() % n + 1;
}
I defined the quicksort function as follows:
void quicksort(int *a, int left, int right);
and I want to sort the point by X coordinate, so I call the quicksort:
quicksort(arr.x, 0, n-1);
And this is the error message:
error: request for member 'x' in 'arr', which is of non-class type 'point [(((unsigned int)(((int)n) + -0x000000001)) + 1)]'
Sorry if the question is too stupid or badly formulated, the truth is I'm a newbie and I'm really willing to learn as much as possible and I'd be very thankful for your help!
If you always want to sort by x, then you can hard-code it into the sort function, and just pass a pointer to the array to sort:
void quicksort(point * arr, int left, int right) {
// test points with
// if (arr[i].x < arr[j].x) {/* i sorts before j */}
}
quicksort(arr, 0, n-1);
To specify a class member to sort by, you need a pointer-to-member, not a pointer; something like:
void quicksort(point * arr, int point::*member, int left, int right){
// test points with
// if (arr[i].*member < arr[j].*member) {/* i sorts before j */}
}
quicksort(arr, &point::x, 0, n-1);
More generically, you could follow the example of std::sort and accept any comparison functor:
template <typename RandIter, typename Compare>
void quicksort(RandIter begin, RandIter end, Compare compare) {
// test points with
// if (compare(*it1, *it2)) {/* *it1 sorts before *it2 */}
}
quicksort(arr, arr+n,
[](point const &lhs, point const &rhs) {return lhs.x < rhs.x;});
And of course, unless you're learning how to implement a sorting algorithm, just use std::sort.
quicksort(arr,0,n-1);
then within quicksort, try to compare the arr[i].x
There are a few problems with your code.
1. quicksort accepts int* but you try to pass int value x
2. You try to pass int but you actually call an undefined variable arr.x
What you need to do is either call in the form of &arr[i].x, but to accomplish what you want, you probably want to pass the entire struct as a pointer.
You need to pass arr as the parameter, as that is the array to be sorted. arr.x is meaningless. You are not passing the string "arr.x" as a parameter which can somehow be interpreted as meaning sort on the x field - when the compiler sees this, it is looking for an x element of arr, which doesn't exist, as the error message suggests - only the elements of arr (e.g. arr[0]) have x elements (accessed as arr[0].x).
Assuming this is for academic purposes (why else would you declare your own sorting algorithm instead of using one of the ones already implemented with a custom comparator?), you can do this a few ways:
Array
std::array<point, 10> myArray; // declares an array of size 10 for points
template<size_t N>
void quicksort(std::array<point, N>& arr, ...)
{
// implement sort operating on arr
}
Vector
std::vector<point> myVector; // declares a dynamic array/vector of points
void quicksort(std::vector<point>& arr, ...)
{
// implement sort operating on arr
}
If for some god-awful reason, you want to keep it in C:
Legacy
const size_t SIZE = 10;
point arr[SIZE]; // declare an array of 10 points
void quicksort(point* p, const size_t n, ...)
{
// implement sort operating on elements in p passing in SIZE for n
}
I'd rather defined the function as:
void quicksort(void *a,int left,int right, size_t size, int (*fp)(void*,void*));
size is the size of one element of array and fp is a compare function which returns true if the two arguments are equal. Now you can pass the call the function as:
quicksort(arr,0,n-1,sizeof(arr)/sizeof(arr[0]), compare);
where function compare is something like:
int compare(void* a, void* b) { return *((int*)a) >= *((int*)b); }
Rest of the implementation of function is trivial I think.
(almost) never try to fool the system by passing a pointer to a member when you really want to pass a pointer to an object. Do as Grijesh suggested. Passing a member can lead to horrible side effects. For example, quicksort is going to sort all the integers together, regardless of which of them are X's and which are Y's. In milder cases you may get wrong compare criteria, and often hard to debug effects such as incorrect pointer optimization. Just be honest with the compiler and pass the object pointer if you need to pass an object pointer. There are very very very few exceptions, mostly to do with low-level system programming where the "other side' of the function call won't be able to handle the object.
I am a beginner programmer in my first year of university. My tutor has asked us to do some research on a recursive algorithm and make it none recursive. No natter how much I try it seems impossible.
The question reads
A is a character string (e.g. A = "hello") and interchange, which is
an abstraction, exchanges the k-th with the i-th character of A,
e.g. CALL interchange("hello", 2, 3) would change "hello" to
"hlelo").
The idea is to print out all the possible permutations
The version in c++ reads
void perm(char*a, const int k, const int n)
{
if(k==n)
{
cout << a;
}
else
{
for (i=k;i<=n;i++)
{
interchange(a, k, i);
perm(a, k+1, n)
}
}
}
My tutor much prefers to use a language called ADL that seems only to appear in the Horowitz book "algorithms and data structures". He has posed the question in ADL so I will add that code in too, its very easy to understand.
proc perm(IN a, IN k, IN n)
if k=n then
print(a)
else
{
for i <- k to n do
call interchange(a,k,i)
call perm( a, k+1, n)
end
}
end
thanks for anyone who can help.
Martyn
A recursive algorithm is simply an algorithm that uses a stack.
The recursion allows you to use the call stack as your data stack.
Any recursive function taking this form:
void perm(char*a, const int k, const int n)
{
// check if your code should return
// make a recursive call with new data
}
Can be changed to this:
void perm(char*a, const int k, const int n)
{
// Create a stack, push (a,k,n)
while ( /* stack isn't empty */ )
{
// check if stack should be *popped* (instead of returning)
// Put new data on the stack (instead of recursing)
}
}
Here's a hint, without doing your homework for you. As you walk down the string, looking at the ith character, you're in one of three possible states:
i == k
i == n
else
What do you print in each of those three cases?
I'd like to write a template binary search algorithm, which can search a template type element in a template type QList using an arbitary comparator, like this:
template<typename T,typename compare_less>
static int binary_search(QList<T>* list, T target) {
int low = 0;
int high = list->count()-1;
while (low <= high) {
int middle = low + (high - low)/2;
if (compare_less(*target, *list[middle]))
high = middle - 1;
else if (compare_less(*list[middle],*target))
low = middle + 1;
else
return middle;
}
return low;
}
Now how can I implement this correctly in order to make it work with QDateTime* template parameters? I'd like to call the function like this:
int index = binary_search<QDateTime*, ???>(dateTimeList,date);
Where dateTimeList is of type QList, date is of type QDateTime* and I really don't have any clue what to write in the place of question marks.
Can someone help me implement the algorithm correctly and show me how to call the algorithm with these arguments?
You shouldn't have to implement anything, if the Qt documentation is valid. Just use std::binary_search with your list's .begin() and .end(), and if you need to implement a comparator, do so and pass it to the STL algorithm.
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.
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).