I am quite new for C++ programming, and recently wrote a mergesort method to sort some arrays. For my personal test, it works fine for integers and doubles. But when I try to sort strings, it gives me a "sematic issue" error which I am quite confused. The full code is:
#include <iostream>
#include <string>
using namespace std;
template<typename T>
class Sorting{
public:
static void merge(T* a, int left, int mid, int right){
int i=left; int j=mid+1; int k=0;
T t[right-left+1]; //****************ERROR LINE
for(;i<=mid && j<=right;k++){
if(*(a+i)<=*(a+j)){
t[k]=a[i];
i++;
}
else{
t[k]=a[j];
j++;
}
}
for(;i<=mid;i++,k++) t[k]=a[i];
for(;j<=right;j++,k++) t[k]=a[j];
for(i=0;i<k;i++) a[left+i]=t[i];
}
//Mergesort top-level function. Left is starting index, right is ending index
static void mergesort(T* a, int left, int right){
if(left>=right) return;
int mid=left+((right-left)>>1);
mergesort(a, left, mid);
mergesort(a, mid+1, right);
merge(a, left, mid, right);
}
};
int main(){
const int len=5;
string ss[len]={
"Yep",
"Nope",
"5",
"2.5",
"Stackoverflow"
};
double ar[len]={4.2, 3, 5.6, -15, 0};
Sorting<double>::mergesort(ar, 0, 4); for(int i=0; i<len;i++) cout<<ar[i]<<endl;
Sorting<string>::mergesort(ss, 0, 4); for(int i=0; i<len;i++) cout<<ss[i]<<endl;
return 0;
}
And I got a semantic error at that "//**ERROR LINE" like:
Variable length array of non-POD element type 'std::__1::basic_string<char>'
What is this error talking about? How should I modify my code?
In the error message, POD refers to plain old data type
You could use a std::vector of them, i.e.
std::vector<T> t;
t.resize (right-left+1);
You could also make t an array of pointers (i.e. T* t[right-left+1]; and update the code accordingly).
BTW, you are using variable length array, which is a GCC extension that some other compilers don't provide.
But sorting is available in C++ standard library. You'll need to #include<algorithm> and use std::sort on standard C++ containers.
You have a variable length array:
T t[right-left+1];
This is an extension supported by your particular compiler, and not part of the C++ Standard. It doesn't work for complex object types like std::string - hence the error message. You could replace it with a vector:
std::vector<T> t(right - left + 1);
Basile's idea to use pointers is better though - copying std::string objects around is pretty heavyweight (i.e. memory intensive, slow)... you just want to keep track of which a[] elements to move, rather than sorting copies of them then copying them back.
Related
#include <iostream>
using namespace std;
int* reverse(int arr[],int n){
int rev[100];
int j =0;
for(int i=n-1;i>=0;i--){
rev[j]=arr[i];
j++;
}
return rev;
}
int main() {
int n;
cin>>n;
int arr[100];
for(int i=0;i<n;i++){
cin>>arr[i];
}
cout<<reverse(arr,n);
}
I am trying reverse an array using loops but don't know what the error was it was returning some bin value.
Your rev temporary resides in automatic storage. It means that the object will be gone after the function returns. While C++ allows you to decay rev to an int* and then return said pointer, it does not mean that this returns the object itself. You merely get a pointer to an already destroyed object. Not very useful. In fact, doing anything with this pointer will cause undefined behaviour.
Usually what you want to do is reverse things in-place. That's also how std::reverse works.
So, there are two options. If you have a completely filled c-style array, you could write a reverse function like this:
template <std::size_t N>
void reverse(int (&a)[N]) {
// reverse a from 0 to N-1
}
reverse(a);
Or, if you have an only partially filled array, take a page out of the standard library and reverse a range, denoted by two iterators.
void reverse(int* begin, int* end) {
/* begin points to the first entry, end points one past the last */
}
reverse(a, a+n);
Of course, instead of using c-style arrays, you could use a dynamically growing array such as std::vector, which carries the actual size of the array around for you.
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.
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).
I'm trying to send a vector as an argument to a function and i can't figure out how to make it work. Tried a bunch of different ways but they all give different error messages.
I only include part of the code, since it's only this part that doesn't work.
(the vector "random" is filled with random, but sorted, values between 0 and 200)
Updated the code:
#include <iostream>
#include <ctime>
#include <algorithm>
#include <vector>
using namespace std;
int binarySearch(int first, int last, int search4, vector<int>& random);
int main()
{
vector<int> random(100);
int search4, found;
int first = 0;
int last = 99;
found = binarySearch(first, last, search4, random);
system("pause");
return(0);
}
int binarySearch(int first, int last, int search4, vector<int>& random)
{
do
{
int mid = (first + last) / 2;
if (search4 > random[mid])
first = mid + 1;
else if (search4 < random[mid])
last = mid - 1;
else
return mid;
} while (first <= last);
return -(first + 1);
}
It depends on if you want to pass the vector as a reference or as a pointer (I am disregarding the option of passing it by value as clearly undesirable).
As a reference:
int binarySearch(int first, int last, int search4, vector<int>& random);
vector<int> random(100);
// ...
found = binarySearch(first, last, search4, random);
As a pointer:
int binarySearch(int first, int last, int search4, vector<int>* random);
vector<int> random(100);
// ...
found = binarySearch(first, last, search4, &random);
Inside binarySearch, you will need to use . or -> to access the members of random correspondingly.
Issues with your current code
binarySearch expects a vector<int>*, but you pass in a vector<int> (missing a & before random)
You do not dereference the pointer inside binarySearch before using it (for example, random[mid] should be (*random)[mid]
You are missing using namespace std; after the <include>s
The values you assign to first and last are wrong (should be 0 and 99 instead of random[0] and random[99]
You'll have to pass the pointer to the vector, not the vector itself. Note the additional '&' here:
found = binarySearch(first, last, search4, &random);
You're passing in a pointer *random but you're using it like a reference &random
The pointer (what you have) says "This is the address in memory that contains the address of random"
The reference says "This is the address of random"
Anytime you're tempted to pass a collection (or pointer or reference to one) to a function, ask yourself whether you couldn't pass a couple of iterators instead. Chances are that by doing so, you'll make your function more versatile (e.g., make it trivial to work with data in another type of container when/if needed).
In this case, of course, there's not much point since the standard library already has perfectly good binary searching, but when/if you write something that's not already there, being able to use it on different types of containers is often quite handy.
found = binarySearch(first, last, search4, &random);
Notice the &.
You're using the argument as a reference but actually it's a pointer. Change vector<int>* to vector<int>&. And you should really set search4 to something before using it.
If you use random instead of * random your code not give any error
i have following code for bottom up mergesort it does it's operation on file m-by-m merges doubles m on each pass here is code
#include <iostream>
#include <vector>
using namespace std;
inline int Min(int a,int b)
{
return a<b?a:b;
}
void merge(int a[],int l,int m,int r)
{
vector<int>b;
int i, j;
for (i=m+1;i>=l;i--) b[i-1]=a[i-1];
for (j=m;j<r;j++) b[r+m-j]=a[j+1];
for (int k=l;k<=r;k++)
if ( b[j]<b[i])
a[k]=b[j--];
else
a[k]=b[i++];
}
void mergesort(int a[],int l,int r)
{
for (int m=1;m<=r-l;m=m+m)
for (int i=l;i<=r-m;i+=m+m)
merge(a,i,i+m-1,Min(i+m+m-1,r));
}
int main()
{
int a[]={12,4,7,3,9,8,10,11,6};
int n=sizeof(a)/sizeof(int);
mergesort(a,0,n-1);
for (int i=0;i<n;i++)
{
cout<<a[i]<< " ";
}
return 0;
}
but when i run this code there is exception which says that vector's out of range error was occured please help
You have not initialised your vector to have any data in it.
I guess this is an exercise which is why you are reinventing the wheel. I am not sure that is an excuse for using single-character identifiers which makes your code hard to understand.
If a is an array and l is its length you can initialise b with
vector<int> b( a, a+l );
Presumably you are creating a temporary clone of your array for the purpose of the sort.
Isn't mergesort recursive, by the way? I don't see yours being.
I have other issues with your code too, eg your indentation suggests that the for loops are nested but the semi-colons after the statements that are on the same line as the for statements suggest otherwise. I'd suggest you always use braces on your loops.
In function merge you have vector<int>b; b is of size 0 here. You should rezise() your vector, or initialize it with the array:
vector<int> v(arr, arr+size);
You create b as an empty vector, and then start addressing its elements. It has size 0, so that's invalid. You should give it a larger size.
Others have addressed your problem with trying to index elements in an empty vector. In addition, the following loop has a problem:
for (i=m+1;i>=l;i--) b[i-1]=a[i-1];
The last iteration through the loop has i=l and you address the [i-1] element of the vector/array. When l=0 this is the index -1 and will be out-of-range for both the vector and array.