Merge sort algorithm advice - c++

I have made a program that sorts a list using a merge sort algorithm.
The problem is that I think it should work but it is not working, the merge function returns a array that was sent as parameter. Can you please see the code I wrote and tell me what is wrong, and how it can be improved.
Thanks
void merge_sort(int *niz, int low, int medium, int high) {
int *niz2 = new int[high-low];
int bottom = low;
int top = medium + 1;
for (int f1=low; f1<high-low; f1++) {
if (low > medium) {
niz2[f1] = niz[top++];
}
else if (top > high) {
niz2[f1] = niz[bottom++];
}
else if (niz[bottom] < niz[top]) {
niz2[f1] = niz[bottom++];
}
else {
niz2[f1] = niz[top++];
}
}
niz = niz2;
}
void merge(int *niz, int low, int high) {
if (low < high) {
int medium = (high+low)/2;
merge(niz, low, medium);
merge(niz, medium+1, high);
merge_sort(niz, low, medium, high);
}
}
The output of program:
3 5 2 3 4 9 5 2 7 10
3 5 2 3 4 9 5 2 7 10

You are passing the pointer by value, so the value you assign to niz inside function is not visible in caller function.
Your signatures should be
void merge(int niz[], int low, int medium, int high) and
void merge_sort(int niz[], int low, int high).
In merge which you have named merge_sort, at the bottom, then you should copy back the contents from niz2 to niz, instead of niz = niz2.
*EDIT - *
Also you have got the merge function wrong (which you have named merge_sort). If say you call the function with low = 100, medium = 120, high = 140.
Then for (int f1=low; f1<high-low; f1++) would never loop.
It should be for (int f1=0; f1<high-low; f1++). One another consequence of above mistake is SIGSGV, because you would be accessing, niz2 out of bounds (for the given example).

I think there are lots of errors in this code but the biggest one is
niz = niz2;
Here you are trying to copy the niz2 array back to niz, but it doesn't do that, it just copies the pointer.

I see that you are trying to assign the contents of niz2 to niz via niz = niz2;
. This is incorrect since niz is a pass-by-value pointer, and niz2 is a local pointer that points to an array.
If you want to copy niz2 to niz you either need a loop like for (int i = low; i < high; i++) niz[i] = niz2[i], use an api function like memcpy to overwrite the input array, or if you're trying to redirect the int* niz pointer to use the newly created niz2 array, then you need to pass the input as a pointer-to-pointer then modify it directly, eg merge_sort(int** niz, int low...) and call it via merge_sort(&niz, 0, 20);. Not that if you do modify the input pointer to point to a new array, you should delete the old one first, eg delete [] *niz; *niz = niz2;
The statement niz = niz2; copies the address pointed to by niz2 over the temporary niz pointer in the parameter list. When you pass a pointer to a function that recieves an int* (such as foo(int* nPtr);), the pointer you send is copied into the temporary variable/pointer nPtr. Using foo(int** nPtr); tells it that it's working with the 'address of a pointer to and int', not just the 'address of an int'. In this case you can redirect nPtr via a statement like *nPtr = &tmpInt or *nPtr = tmpPtr. To get the the actual int or data at the source, you'd use tmpInt = **nPtr.

Related

Why local arrays in functions seem to prevent TCO?

Looks like having a local array in your function prevents tail-call optimization on it on all compilers I've checked it on:
int foo(int*);
int tco_test() {
// int arr[5]={1, 2, 3, 4, 5}; // <-- variant 1
// int* arr = new int[5]; // <-- variant 2
int x = foo(arr);
return x > 0 ? tco_test() : x;
}
When variant 1 is active, there is a true call to tco_test() in the end (gcc tries to do some unrolling before, but it still calls the function in the end). Variant 2 does TCO as expected.
Is there something in local arrays which make it impossible to optimize tail calls?
If the compiler sill performed TCO, then all of the external foo(arr) calls would receive the same pointer. That's a visible semantics change, and thus no longer a pure optimization.
The fact that the local variable in question is an array is probably a red herring here; it is its visibility to the outside via a pointer that is important.
Consider this program:
#include <stdio.h>
int *valptr[7], **curptr = valptr, **endptr = valptr + 7;
void reset(void)
{
curptr = valptr;
}
int record(int *ptr)
{
if (curptr >= endptr)
return 1;
*curptr++ = ptr;
return 0;
}
int tally(void)
{
int **pp;
int count = 0;
for (pp = valptr; pp < curptr; pp++)
count += **pp;
return count;
}
int tail_function(int x)
{
return record(&x) ? tally() : tail_function(x + 1);
}
int main(void)
{
printf("tail_function(0) = %d\n", tail_function(0));
return 0;
}
As the tail_function recurses, which it does via a tail call, the record function records the addresses of different instances of the local variable x. When it runs out of room, it returns 1, and that triggers tail_function to call tally and return. tally sweeps through the recorded memory locations and adds their values.
If tally were subject to TCO, then there would just be one instance of x. Effectively, it would be this:
int tail_function(int x)
{
tail:
if (record(&x))
return tally();
x = x + 1;
goto tail;
}
And so now, record is recording the same location over and over again, causing tally to calculate an incorrect value instead of the expected 21.
The logic of record and tally depends on x being actually instantiated on each activation of the scope, and that outer activations of the scope have a lifetime which endures until the inner ones terminate. That requirement precludes tail_function from recursing in constant space; it must allocate separate x instances.

Passing an array into a function c++

so I'm having an issue passing an entire array of histograms into a function in C++
the arrays are declared like this
TH1F *h_Energy[2];
h_Energy[0] = new TH1F("h1", "h1", 100, 0, 100);
h_Energy[1] = new TH1F("h2", "h2", 100, 0, 100);
And here is what I'm trying to do in the function:
void overlayhists(TH1 *hists, int numhists) {
int ymax = 0;
for (int i=0; i<numhists; i++) {
if (hist[i].GetMaximum() > ymax) {
ymax = (hist[i].GetMaximum())*1.05;
}
}
}
And I'm passing the function an array like this
overlayhists(*h_Energy, 2);
Where h_Energy is an 1D array with 2 elements. The code will run through the first histogram in the loop but as soon as it starts the second loop and tries to access hist[i].GetMaximum() on the second try it segfaults.
What gives?
This creates an array of pointers to type TH1F
TH1F *h_Energy[2]; //edited after OP changed
If you want to use this, and subsequently pass it as an argument
You must first initialize it, and then create your function prototype to accommodate:
void overlayhists(TH1F **hists, int numhists);
^^
From what you have shown above, you would call it like this: (after your initializations)
h_Energy[0] = new TH1F("h1", "h1", 100, 0, 100);
h_Energy[1] = new TH1F("h2", "h2", 100, 0, 100);
overlayhists(h_Energy, 2);
1. Passing any array to function in c++ to change the content:
Refer to this code snippet:
//calling:
int nArr[5] = {1,2,3,4,5};
Mul(nArr, 5);
Whenever you pass an array to function you actually pass the pointer to first element of the array. This is implicit to C++ and C. If you pass normal value(non array) it will be considered as pass by value though.
// Function Mul() declaration and definition
void MUl(int* nArr, size_t nArrSize){
size_t itr = 0;
for(;itr<nArrSize; itr++)
nArr[i] = 5*nArr;// here we've coded to multiply each element with 5
}
2. Passing any Ptr to function in c++ to change what pointer is pointing to:
Now let us suppose we want to copy nArr (from above code snippet) to another array, say nArrB
The best way for a beginner would be to use reference to the pointer.
You can pass reference to the pointer to your function
//so we had
int nArr[5] = {1,2,3,4,5};
int *nArrB;
Here we don't know the gonnabe size of nArrB.
to copy nArr to nArrB we have to pass nArr, address of pointer to nArrB(or reference to pointer of nArrB or pointer to pointer of nArrB) and size of array.
Here is the implementation.
//Calling
CopyNArr(nArr, &nArrB, 5);
//Function implementation
void CopyNArr(int* nArr, int* & nArrB, size_t nArrSize) {
// dymanically allocating memory size for array. Assuming 4 byte int size
nArrB = new int[nArrSize*4];
size_t itr = 0;
//Copying values
for(;itr<nArrSize; itr++)
nArrB[i] = nArr[i];
}
//After copy nArrB is pointing to first element of 5 element array.
I hope it helped. Write for any further clarification.
You have an array of size 2, but you've created only one element. And that one with a wrong index. Array indexing starts with 0.
The elements should be at h_histogram[0] and h_histogram[1].
I am sorry if this answer is completely irrelevant but
I am tempted to post it. These is an experiment I have
done after seeing your question.
#include<iostream>
using namespace std;
main()
{
int e[2]={0,1};
int *p[2];
int i;
/*
Printing the array e content using one pointer
from an array of pointers. Here I am not using p[2]
at all.
*/
p[1]=e;
cout<<"Elements of e are : \n";
for(i=0;i<2;i++)
{
cout<<*(p[1]+i)<<endl;
/*
In the above line both *((*p)+i) and *(p+i)
won't serve the purpose of printing the array values.
*/
}
/*Printing the array e content using pointer to array*/
cout<<"Elements of e are : \n";
for(i=0;i<2;i++)
{
cout<<*(e+i)<<endl;
}
/*Note that pointer to array is legal but array TO pointer
(don't confuse with array OF pointers) is not.*/
}
Hope this will refresh your understanding.

Copying arrays via pointers in C++

I've never programmed in C++ before and I'm trying to figure out how to recursively pass segments of an array in a C++ method. I am trying to convert the following pseudo code into C++.
SlowSort(A[1...n])
if n = 2
if A[1] > A[2]
Swap(A[1], A[2])
else if n > 2
SlowSort(A[1...(2n/3)])
SlowSort(A[(n/3+1)... n])
SlowSort(A[1...(2n/3)])
The recursive calls are the bits I'm having a problem with. I was thinking about creating two new arrays that point to the wanted locations but don't know how to go about that, specifically doing that and defining the length of the array. I've tried googling it and searching this site, but there doesn't seem to be anything, that I understand, on it. Also, in case I fudged up somewhere in my code, here's what I have for the first bit.
int SlowSort(int A[])
{
int length = (sizeof(A)/sizeof(*A));
if(length ==2)
{
if(A[0] > A[1])
{
int temp = A[0];
A[0] = A[1];
A[1] = temp;
}
}
In short, how do In covert the else if statement into C++? Explanation would be nice too.
Thanks
You will want to pass indices into the array instead, and use those.
void SlowSort(int A[], int left, int right)
{
if (right - left == 2)
if (A[left] > A[right])
Swap(A[left], A[right]);
else
{
int n = right - left + 1;
SlowSort(A, left, 2 * n / 3);
SlowSort(A, left + n / 3 + 1, right);
SlowSort(A, left, left + 2* n / 3);
}
The above code might not be correct regarding what the algorithm is supposed to do, but you get the idea I'm trying to describe. The thing is: you don't make a copy of the array. Instead, pass the same array always and the range (i.e. the indices) you are sorting.
You simply pass required pointer using the pointer arithmetic. For example the following pseudo code
SlowSort(A[(n/3+1)... n])
could be written as
SlowSort( A + n/3+1, n - n/3 - 1 );
So the function could be declared as
void SlowSort( int A[], size_t n );
As for this code snippet
int SlowSort(int A[])
{
int length = (sizeof(A)/sizeof(*A));
then it is invalid because array is implicitly converted to a ponter to its first element when it is passed as an argument to a function seclared such a way. So the value of length will not be equal to the number of elements.
This is pretty simple. Since arrays are just consecutive pointers. If you have a method:
Your code would look like this:
void slowSort(int[] array, int length)
{
if(length == 2)
{
if(array[0] > array[1])
{
int temp = array[0];
array[0] = array[1];
array[1] = temp;
}
}
else
{
slowSort(&array[0], (2 * length) / 3 - 1);
slowSort(&array[length / 3], length - (length / 3 - 1));
slowSort(&array[0], (2 * length) / 3 - 1);
}
}
The trick I use here is that I pass the pointer of the element I want to start with and the pass the end point.
This works because when you pass an array in C++ you just pass the pointer of the first element. Here I pass a custom pointer of the array.
The modern C++ way to do this would be to pass iterators to the beginning and one-past-the-end of the range. In this case, the iterators are pointers.
void SlowSort(int* begin, int* end)
{
unsigned length = end-begin;
if(length == 2)
{
if(begin[0] > begin[1])
{
std::swap( begin[0], begin[1] );
}
} else if(length>2) {
SlowSort(begin, begin+2*length/3);
SlowSort(begin+length/3, end);
SlowSort(begin, begin+2*length/3);
}
}
then, for the case of working with an entire array:
template<unsigned N>
void SlowSort( int(&Arr)[N] ) {
return SlowSort( Arr, Arr+N );
}
we dispatch it to the iterator version, relying on decaying of array-to-pointer. This has to be a template function, as we want it to work with multiple different array sizes.
Note that an int Arr[] is not an array. It is a different way to say int* Arr, left over as a legacy from C. In fact, as a parameter to a function, saying void foo( int A[27] ) results in void foo( int* A ): function parameters cannot be arrays.
They can, however, be references-to-arrays, which is what the above template function uses.

C++ int array pointers recursively to find prime factors

I am trying to make a function that can return the prime factors of a given number in an array (or multi-set, but I'm trying to use an array).
For example, if I put in 12, I want to get 2, 2, and 3, not 2, and 3 like with a set. This is so that I can use these to see if it is a Smith number or not, so I need the numbers seperately.
Also, I am taking a recursive approach.
I have tried (to no avail) to return the array many ways, including passing an initial pointer into the code which points to a space to store the array.
I've tried just initializing the array in the function and then returning it.
From what I can tell, I can get the array back from the base case iteration and then when trying to construct a new array with size oldArray+1 to copy values to, things get messy. This is where I get lost.
From what I've read, although this isn't the most efficient implementation, I should be able to make it work.
I have a function, nextPrime(int n), which given n will give back the next prime up from that number.
See source below:
int* find(int n, int p) {
int root = (int) floor(sqrt(n));
if (p > root) {
// Base case, array gets initialized and returned
// depending on value of n and p.
if (n > 1) {
factors = new int[1];
factors[0] = n;
return factors;
}
else {
factors = new int[0];
return factors;
}
}
else
if (n%p == 0){
// Inductive step if p is a factor
int newFloor = (int) floor(n/p);
factors = find(newFloor, p);
// Initialize new array.
int* newFactors;
newFactors = new int[(sizeof(factors) / sizeof(int)) + 1];
// Add p to first slot, fill rest with contents of factors.
factors[0] = p;
for (int i = 0; i < (sizeof(factors) / sizeof(int)); i++) {
newFactors[i+1] = factors[i];
}
return newFactors;
}
else {
// Inductive step p isn't a factor of n
factors = find(n, factors, nextPrime(p));
return factors;
}
}
As I say, the error is with returning the array and using its value, but why does it seem to return OK from the first iteration?
Something like this could work. Not terribly efficient !!
void FindFactors( int number , std::vector<int>& factors )
{
for ( int i = 2; i <= number; ++i )
{
if ( number % i == 0 )
{
factors.push_back( i );
FindFactors( number / i , factors);
break;
}
}
}
int main()
{
std::vector<int> factors;
FindFactors( 121 , factors );
return 0;
}
After you call the function factors will contain only the prime factors.
You should be using std::vector for this. The main problem you have is that a pointer to an array has no way of knowing the number of items the array contains. Concretely, the part where you say sizeof(factors) is wrong. As I understand, you're expecting that to give you the number of items in the array pointed to by factors, but it really gives you the number of bytes needed to store a pointer to int.
You should be either returning a vector<int> or passing it in as a reference and updating it each time you find a factor.

c++ type error message from compiler, what does it mean?

I'm using g++ on fedora linux 13.
I'm just practicing some exercises from my c++ textbook
and can't get this one program to compile. Here is the code:
double *MovieData::calcMed() {
double medianValue;
double *medValPtr = &medianValue;
*medValPtr = (sortArray[numStudents-1] / 2);
return medValPtr;
}
Here is the class declaration:
class MovieData
{
private:
int *students; // students points to int, will be dynamically allocated an array of integers.
int **sortArray; // A pointer that is pointing to an array of pointers.
double average; // Average movies seen by students.
double *median; // Median value of movies seen by students.
int *mode; // Mode value, or most frequent number of movies seen by students.
int numStudents; // Number of students in sample.
int totalMovies; // Total number of movies seen by all students in the sample.
double calcAvg(); // Method which calculates the average number of movies seen.
double *calcMed(); // Method that calculates the mean value of data.
int *calcMode(); // Method that calculates the mode of the data.
int calcTotalMovies(); // Method that calculates the total amount of movies seen.
void selectSort(); // Sort the Data using selection sort algorithm.
public:
MovieData(int num, int movies[]); // constructor
~MovieData(); // destructor
double getAvg() { return average; } // returns the average
double *getMed() { return median; } // returns the mean
int *getMode() { return mode; } // returns the mode
int getNumStudents() { return numStudents; } // returns the number of students in sample
};
Here is my constructor and destructor and selectSort():
MovieData::MovieData(int num, int movies[]) {
numStudents = num;
// Now I will allocate memory for student and sortArray:
if(num > 0) {
students = new int[num];
sortArray = new int*[num];
// The arrays will now be initialized:
for(int index = 0;index < numStudents;index++) {
students[index] = movies[index];
sortArray[index] = &students[index];
}
selectSort(); // sort the elements of sortArray[] that point to the elements of students.
totalMovies = calcTotalMovies();
average = calcAvg();
median = calcMed();
mode = calcMode();
}
}
// Destructor:
// Delete the memory allocated in the constructor.
MovieData::~MovieData() {
if(numStudents > 0) {
delete [] students;
students = 0;
delete [] sortArray;
sortArray = 0;
}
}
// selectSort()
// performs selection sort algorithm on sortArray[],
// an array of pointers. Sorted on the values its
// elements point to.
void MovieData::selectSort() {
int scan, minIndex;
int *minElement;
for(scan = 0;scan < (numStudents - 1);scan++) {
minIndex = scan;
minElement = sortArray[scan];
for(int index = 0;index < numStudents;index++) {
if(*(sortArray[index]) < *minElement) {
minElement = sortArray[index];
minIndex = index;
}
}
sortArray[minIndex] = sortArray[scan];
sortArray[scan] = minElement;
}
}
The compiler is giving this error:
moviedata.cpp: In memberfunction
'double * MovieData::calcMed()':
moviedata.cpp:82: error: invalid
operands of types 'int*' and 'double'
to binary 'operator/'
I'm not sure what to make of this error, i've tried static casting the types with no luck, what does this error message mean?
you are trying to divide a pointer by a double, which the compiler is saying it does not know how todo.
sortArray is probably defined by
int ** sortArray;
its also worth noting you are returning a pointer to a stack variable, who's value will be undefined as soon as you return out of the function.
sortArray[numStudents - 1] is a pointer to int, which can't be on the left side of a division (when you remember pointers are addresses, this makes sense). If you post more of your code, we can help you correct it.
Perhaps you want something like:
int *MovieData::calcMed() {
return sortArray[(numStudents - 1) / 2];
}
This returns the middle element in your array, which should be a pointer to the middle student. I'm not clear why you're sorting lists of pointers (not the actual values), or why you're returning a pointer here. The return value + 1 will be a pointer to the next value in students, which is not the next greater value numerically. So you might as well return the actual student (int from students). If you do this, you can also average the two middle elements when the count is even (this rule is part of the typical median algorithm).
Note that I changed the return type to int *, the type of sortArray's elements. Also, your comment is incorrect. This is the median, not the mean.
Also, your selection sort is wrong. The inner loop should start at scan + 1.
Your code shows a lack of understanding of pointers. You need to do more reading and practice on simpler examples.
More specifically:
double medianValue; creates a double variable. What for? You're apparently going to return a double * and returning a pointer to a local variable is always wrong, because local variables are "recycled" when their function ends.
double *medValPtr = &medianValue; creates a pointer called medValPtr and sets it to the location of medianValue. Well.
Due to the current contents of medValPtr, *medValPtr = (sortArray[numStudents-1] / 2); has the same effect as typing medianValue = (sortArray[numStudents-1] / 2); (supposing it were to compile at all).
Which it doesn't because sortArray[numStudents-1] is, at a guess, the last item in the array sortArray but happens to be a pointer to something else. You can't divide a pointer (numerically you can, but C++ disallows it's always wrong).
Finally you return medValPtr; which is wrong because medValPtr is pointing to a local variable.
You probably want something like:
int *MovieData::calcMed() {
return sortArray[numStudents/2];
}