bottom up mergesort - c++

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.

Related

I am trying to reverse an array using loop in cpp ? but don't know what the problem is?

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

C++ 2D vector SIGSEV error

I am getting segmentation error in the following code, can anyone bother to explain. I think it might have to do with initialization, but not sure. I am just trying to clone the existing stack and perform operation such as adding entry to the clone or removing entry from existing and cloning it to new stack.
#include <iostream>
#include <fstream>
#include <vector>
#include <queue>
#include <deque>
#include <string>
using namespace std;
#define in cin
#define out cout
int main()
{
//ifstream in("postfix.in");
//ofstream out("postfix.out");
int n;
in>>n;
long sum=0;
vector<int> tm(0);
vector<vector<int>> ar(0,tm);
//ar[0].push_back(0);
out<<ar[0][0];
for(int i=0;i<n;i++)
{
int ind,val;
in>>ind>>val;
if(val==0)
{
for(int j=0;j<ar[ind-1].size();j++)
ar[i].push_back(ar[ind-1][j]);
ar[i].pop_back();
}
else
{
for(int j=0;j<ar[ind-1].size();j++)
ar[i].push_back(ar[ind-1][j]);
ar[i].push_back(val);
}
}
for(int i=0;i<n;i++)
{
for(int j=0;j<ar[i].size();j++)
sum+=ar[i][j];
}
out<<sum<<endl;
return 0;
}
vector<int> tm(0);
vector<vector<int>> ar(0,tm);
Here you initialized ar as an empty vector of vector of int. Without enlarging its size through push_back(), resize(), insert(), etc., you cannot access ar[i].
You may instead initialize ar as
vector<vector<int>> ar(n);
But in the existing snippet you provided there is no clue about how large the second dimension should be.
Per your comment in this answer, your declaration of tm and ar should be
vector<int> tm(1, 0);
vector<vector<int>> ar(1, tm);
Or even shorter since tm is not really used later,
vector<vector<int>> ar(1, vector<int>(1, 0));
I think I see where you're getting tripped up.
vector<int> tm(0);
This does not create a vector containing a 0. This creates a vector with a size of 0. Because this list has a size of 0, you can't get the first element; since it's empty!
Same here:
vector<vector<int>> ar(0,tm);
This doesn't create a vector with 1 "row". It creates an empty vector, since you made the size 0 again.
You likely intended something like:
vector<int> tm(1, 0);
vector<vector<int>> ar(1,tm);
Which creates a row, tm, with a single 0, then creates a 2D vector, ar containing that 1 row.
Check the reference. You're attempting to use the "fill" constructor.
For starters it is a bad idea to use such definitions
#define in cin
#define out cout
It is better to use explicitly std::cin and std::cout because any programmer knows what these names mean.
These declarations
vector<int> tm(0);
vector<vector<int>> ar(0,tm);
do not make great sense. It would be much clear and simpler just to write
vector<int> tm;
vector<vector<int>> ar;
SO as the vectors are empty you may not use the subscript operator as you are doing for instance here
out<<ar[0][0];
^^^^^^^^^
for(int i=0;i<n;i++)
{
int ind,val;
in>>ind>>val;
if(val==0)
{
for(int j=0;j<ar[ind-1].size();j++)
^^^^^^^^^^^
ar[i].push_back(ar[ind-1][j]);
^^^^^
ar[i].pop_back();
^^^^^
}
and so on. You need at first ro append new elements to the vector before using the subscript operator.

Using a 2-d Array in a function

I am trying to solve a dynamic programming problem and I need to take the user input in the form of a 2-d array and use the values from the 2-d array inside the function.
The values of the 2-d array will not be changed when used inside the function.
In the function int dp i am getting the
error:
declaration of 'a' as multidimensional array must have bounds for all dimensions except the first
int max(int a,int b,int c)
{
if(a>=b && a>=c)return a;
if(b>=c && b>=a)return b;
else return c;
}
int max2(int a,int b)
{
if(a>b)return a;
else return b;
}
int dp(int i,int j,int a[][],int p,int q)
{
if((i-1)>=0 && (j-1)>=0 &&(i+1)<p &&(j+1)<q )
return max(a[i][j]+dp(i-1,j+1,a,p,q),a[i][j]+dp(i+1,j+1,p,q),
a[i][j]+dp(i,j+1,p,q));
if(i==0 && j!=0 && (j+1)<q)
return max2(a[i][j]+dp(i+1,j+1,p,q),a[i][j]+dp(i,j+1,p,q));
}
int main()
{
int p,q,r,s,T,a,b,i,j,k;
scanf("%d",&T);
for(a=0;a<T;a++)
{
scanf("%d %d",p,q);
int z[p][q];
int max=0;
for(i=0;i<q;i++)
{
for(j=0;j<p-1;j++)
scanf("%d ",&z[j][i]);
scanf("%d",&z[j+1][i]);
}
for(i=0;i<p;i++)
{
if(dp(i,0,z,p,q)>max)
max=dp(i,0,z,p,q);
}
}
}
It's all in the error message:
declaration of 'a' as multidimensional array must have bounds for all dimensions except the first
Your function signature does not have bounds for a's 2nd dimension:
int dp(int i,int j,int a[][],int p,int q)
// ^^^^^
You need to fill it in with a[][N] where N is whatever the correct bound is. The issue is that you are using VLAs here:
scanf("%d %d",p,q);
int z[p][q];
That is non-standard C++, and basically means you cannot write the signature of dp, since the second bound has to be known as a compile-time constant. You could either make it a single-dimensional array:
int* z = new int[p*q];
int dp(int i, int j, int* a, int p, int q)
// ^^^^^^
or dynamically allocate it in 2 dimensions and just pass it in that way:
int** z = new int*[p];
for (int i = 0; i < p; ++i) {
z[i] = new int[q];
}
int dp(int i, int j, int** a, int p, int q)
// ^^^^^^^
The function dp needs some information to perform meaningful index calculations, either done by the compiler or in the actual inplementation. Either a dimension must be specified in the type or the argument a could be of type int** while its dimensions are provided as separate arguments to dp. As this is C++, a type of std::vector< std::vector< int > > might be more suitable for the task.
You get that error because you cannot leave both the index(row,column) empty in int a[][] in your function declaration. You must have both specified or atleast the value of column index.
Use dynamic declaration
int **z = new int*[p];
for (int i = 0; i < p; i++)
z[i] = new int[q];
Change the parameter int a[][] to int **a
You can't dynamically declare an array on the stack as the size has to be known at compile time. The only way to do this would be by allocating memory for the array on the heap using the new keyword, then you could declare the size at run time.
Far easier, however, would be just to use a container class, or in your case, a container of containers like a vector of vector of ints;
#include <vector>
vector< vector<int> > arrArray(rows, vector<int>(columns));
The syntax might look a bit strange, but breaking it down;
vector<int> - a vector of type int
vector< vector<int> > - a vector of vectors of type int
arrArray(rows, vector<int>(columns)); - here in the first parameter, we are saying; create rows number of vector<int>'s in our array, and the second parameter initalises the array to some value. If it were just a 2D array of int, we might initalise it to 0, or omit the second parameter and rely on the default value of int. But, because our multidimensional vector also contains vectors, we set each row of our main vector to store a vector of int's which holds columns amount of integers.
Now you can access the array like you would any other;
arrArray[2][0] = 5;
You also get all the added benefits that container classes contain, including iterators and a lot of useful class methods for manipulating and checking your array. Once you understand the syntax of creating container classes, you'll find them much easier to work with than arrays. You also don't have to worry about having to manage your own memory, and have the ability to do bounds checking before accessing vector elements.

IOS C++ forbids comparison between pointer and integer (Not using strings)

I included the "not using strings" part in the title because when I was searching to find an answer on here I saw this problem a lot but it was with people using strings and getting chars mixed up. This is not my issue.
Trying to call an element of a 2D vector and see if it equals a certain number. I'm getting the comparison between pointer/integer error and I don't understand why. Here's my code, any help would be really appreciated.
bool UsedInRow(vector< vector<int> > vec(int n, vector<int> (int n)), int row, int num)
{
int n;
for (int col = 0; col < n; col++)
{
if (vec[row][col] == num)
{
return true;
}
}
return false;
}
Try this:
bool UsedInRow(const vector< vector<int> >& vec, int row, int num) { ... }
The expression you used vector< vector<int> > vec(int n, vector<int> (int n)) is actually a function pointer.
The compiler thinks that you are passing a function pointer.
Instead, pass the vector by reference:
bool UsedInRow(vector< vector<int> > &vec, int row, int num)
As the other answers point out, vec is a function pointer, not a vector.
You're being advised to change vec to a vector, but it's not clear that that's the right solution. There's no ambiguity in your declaration; vec is defined as a parameter of function pointer type.
If that's what you intended, you need to replace the reference to vec inside the function with a function call. For example, you might change
if (vec[row][col] == num)
to
if ((vec(42, something))[row][col] == num)
where something would itself have to be a function pointer, pointing to a function that takes an int argument and returns a vector<int> result.
The declaration of your UsedInRow function is quite complicated, and I can't tell how it's intended to be used.
If vec really should be just a vector, then you can make it one by deleting the (int n, vector<int> (int n)) part of the parameter declaration -- but then I'd have to wonder why you wrote it in the first place.
For a definitive answer, you'd need to explain to us what your UsedInRow function is supposed to do.

Mergesort for strings

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.