Merge sort code debugging - c++
I am trying to write a code for merge sort. I am not getting the correct output. I am following this pseudocode link Following is my code. I pass my unsorted array into merge_sort function and call merge function recursively to sort and combine the sub arrays.I know there are more simpler and efficient ways to write code for merge sort but I want to try on my own otherwise I won't learn. Thanks in advance.
int* merge_sort(int* a,int size)
{
//cout<<size;
//cout<<"hi";
if(size == 1)
{
//cout<<"less";
//cout<<a[0];
return a;
}
int* left;
int* right;
int middle = ceil(size/2);
left = new int(middle);
right = new int(middle);
for(int i=0;i<middle;i++)
{
left[i]=a[i];
//cout<<left[i];
}
cout<<"\t";
for(int j=middle;j<size;j++)
{
right[j]=a[j];
//cout<<right[j];
}
cout<<"\t";
left = merge_sort(left,middle);
//if(size==2)
//cout<<left[0];
right = merge_sort(right,middle);
//if(size==2)
//cout<<right[0];
return merge(left,right,middle);
}
int* merge(int* l,int* r,int m)
{
int* result;
result = new int(2*m); //to store the output
int lsize=m; // to keep track of left sub list
int rsize=m; // to keep track of right sub list
int counter = 0; // will use to index result
//cout<<m;
while(lsize>0 || rsize>0)
{
if(lsize>0 && rsize>0)
{
if(l[0]<=r[0])
{
result[counter]=l[0];
counter++; //to store next value in result
lsize--;
l=&l[1]; //decrementing the size of left array
}
else
{
result[counter]=r[0];
counter++;
rsize--;
r=&r[1]; //dec. size of right array
}
}
else if(lsize>0)
{
result[counter]=l[0];
counter++;
lsize--;
l=&l[1];
}
else if(rsize>0)
{
result[counter]=l[0];
counter++;
lsize--;
l=&l[1];
}
}
return result;
}
Your code:
int *left = new int(middle);
allocates a single integer initialized to middle. You need:
int *left = new int [middle];
which allocates an array of middle integers. Rinse and repeat for int *right. Actually, you need to use:
int *right = new int [size - middle];
This gets the correct size for the right array. You then have to modify the recursive call to merge_sort() for the right sub-array:
merge_sort(right, size - middle);
Finally, you have to rewrite merge() to take the size of the left array and the size of the right array independently, because they may be of different sizes. For example, if you sort 10 elements,
you then end up with a call to merge two arrays of 5 (which is fine), but at the next level you need to merge an array of 2 and an array of 3 elements (and you're hosed).
The allocation of result also has the () vs [] allocation problem. And there are some other as yet unresolved problems. But these are important steps in the right direction.
As mentioned in a comment to the question, you have a monumental memory leakage problem, too. What's more, it is not trivial to fix because merge_sort() does an early exit without allocating new memory, so it isn't as simple as 'delete the memory returned by merge_sort()'.
Copy and paste is wonderful until you forget to edit the pasted copy correctly:
else if (lsize > 0)
{
result[counter] = l[0];
counter++;
lsize--;
l = &l[1];
}
else if (rsize > 0)
{
result[counter] = l[0];
counter++;
lsize--;
l = &l[1];
}
Methinks you should be using r and rsize in the second of these blocks.
This still isn't the whole story...
And the residual problem (apart from memory management, which is still 100% leaky and problematic) is:
for(int j=middle;j<size;j++)
{
right[j]=a[j];
//cout<<right[j];
}
You're copying into parts of right that you've not allocated. You need something more like:
for(int j = 0; j < size - middle; j++)
{
right[j] = a[j + middle];
//cout<<right[j];
}
This code works as long as you always sort at least two items at the top level (you crash freeing unallocated space if you sort 1 item — that's part of the memory management problem).
#include <iostream>
using namespace std;
namespace {
int *merge(int *l, int m, int *r, int n);
void dump_array(int *a, int size)
{
int i;
cout << size << ": ";
for (i = 0; i < size; i++)
{
cout << ' ' << a[i];
if (i % 10 == 9)
cout << '\n';
}
if (i % 10 != 0)
cout << '\n';
}
};
int *merge_sort(int *a, int size)
{
cout << "-->> merge_sort:\n";
dump_array(a, size);
if (size <= 1)
{
cout << "<<-- merge_sort: early return\n";
return a;
}
int middle = size/2;
int *left = new int[middle];
int *right = new int[size - middle];
cout << middle << ": ";
for (int i = 0; i < middle; i++)
{
left[i] = a[i];
cout << ' ' << left[i];
}
cout << "\n";
cout << (size - middle) << ": ";
for (int j = 0; j < size - middle; j++)
{
right[j] = a[j + middle];
cout << ' ' << right[j];
}
cout << "\n";
cout << "MSL:\n";
int *nleft = merge_sort(left, middle);
cout << "NL: ";
dump_array(nleft, middle);
cout << "OL: ";
dump_array(left, middle);
cout << "OR: ";
dump_array(right, size - middle);
cout << "MSR:\n";
int *nright = merge_sort(right, size - middle);
cout << "NR: ";
dump_array(nright, size - middle);
cout << "NL: ";
dump_array(nleft, middle);
cout << "OL: ";
dump_array(left, middle);
cout << "OR: ";
dump_array(right, size - middle);
int *result = merge(nleft, middle, nright, size - middle);
cout << "<<-- merge_sort:\n";
dump_array(result, size);
return result;
}
namespace {
int *merge(int *l, int m, int *r, int n)
{
int *result = new int[m + n];
int lsize = m;
int rsize = n;
int counter = 0;
cout << "-->> merge: (" << m << "," << n << ")\n";
dump_array(l, m);
dump_array(r, n);
while (lsize > 0 || rsize > 0)
{
if (lsize > 0 && rsize > 0)
{
if (l[0] <= r[0])
{
result[counter] = l[0];
cout << "C: " << counter << "; L = " << l[0] << "; LS = " << lsize << '\n';
counter++;
lsize--;
l++;
}
else
{
result[counter] = r[0];
cout << "C: " << counter << "; R = " << r[0] << "; RS = " << rsize << '\n';
counter++;
rsize--;
r++;
}
}
else if (lsize > 0)
{
result[counter] = l[0];
cout << "C: " << counter << "; L = " << l[0] << "; LS = " << lsize << '\n';
counter++;
lsize--;
l++;
}
else if (rsize > 0)
{
result[counter] = r[0];
cout << "C: " << counter << "; R = " << r[0] << "; RS = " << rsize << '\n';
counter++;
rsize--;
r++;
}
}
cout << "<<-- merge:\n";
dump_array(result, m+n);
return result;
}
};
int main()
{
for (int i = 2; i <= 10; i++)
{
int array1[] = { 9, 3, 5, 7, 1, 8, 0, 6, 2, 4 };
cout << "\nMerge array of size " << i << "\n\n";
int *result = merge_sort(array1, i);
delete[] result;
}
return 0;
}
This is the debug-laden code. It's the level to which I went to get the result. I could perhaps have used a debugger. Were I on a machine where valgrind works, it might have helped too (but it does not work on Mac OS X 10.8.x, sadly).
There are still many, many ways to improve the code — including the memory management. You'd probably find it easiest to pass the input array to merge() for use as the result array (avoiding the memory allocation in that code). This would reduce the memory management burden.
When you remove the debug code, you'll need to call the dump_array() function in the main() program to get the before and after sorting array images.
Code converted to template functions and leak-free
I've simplified the code a fair bit, especially in the merge() function. Also, more as a matter of curiosity than anything else, converted it to a set of template functions, and then used them with 4 different array types (int, double, std::string, char). The amount of debugging has been dramatically reduced, and the main debugging is conditional on being compiled with -DTRACE_ENABLED now.
The code is now leak-free; valgrind on a Linux box (virtual machine) gives it a clean bill of health when there are no exceptions. It is not guaranteed exception-safe, though. In fact, given the naked uses of new and delete, it is pretty much guaranteed not to be exception-safe. I've left the namespace control in place, but I'm far from convinced it is really correct — indeed, I'd lay odds on it not being good. (I'm also curious if anyone has any views on how to layout code within a namespace { … }; block; it seems odd not indenting everything inside a set of braces, but …)
#include <iostream>
using namespace std;
namespace {
#if !defined(TRACE_ENABLED)
#define TRACE_ENABLED 0
#endif
enum { ENABLE_TRACE = TRACE_ENABLED };
template <typename T>
void merge(T *l, int m, T *r, int n, T *result);
template <typename T>
void dump_array(const char *tag, T *a, int size)
{
int i;
cout << tag << ": (" << size << ") ";
for (i = 0; i < size; i++)
{
cout << " " << a[i];
if (i % 10 == 9)
cout << '\n';
}
if (i % 10 != 0)
cout << '\n';
}
};
template <typename T>
void merge_sort(T *a, int size)
{
if (size <= 1)
return;
if (ENABLE_TRACE)
dump_array("-->> merge_sort", a, size);
int middle = size/2;
T *left = new T[middle];
T *right = new T[size - middle];
for (int i = 0; i < middle; i++)
left[i] = a[i];
for (int j = 0; j < size - middle; j++)
right[j] = a[j + middle];
merge_sort(left, middle);
merge_sort(right, size - middle);
merge(left, middle, right, size - middle, a);
delete [] left;
delete [] right;
if (ENABLE_TRACE)
dump_array("<<-- merge_sort", a, size);
}
namespace {
template <typename T>
void merge(T *l, int m, T *r, int n, T *result)
{
T *l_end = l + m;
T *r_end = r + n;
T *out = result;
if (ENABLE_TRACE)
{
cout << "-->> merge: (" << m << "," << n << ")\n";
dump_array("L", l, m);
dump_array("R", r, n);
}
while (l < l_end && r < r_end)
{
if (*l <= *r)
*out++ = *l++;
else
*out++ = *r++;
}
while (l < l_end)
*out++ = *l++;
while (r < r_end)
*out++ = *r++;
if (ENABLE_TRACE)
dump_array("<<-- merge", result, m+n);
}
};
#include <string>
int main()
{
for (size_t i = 1; i <= 10; i++)
{
int array1[] = { 9, 3, 5, 7, 1, 8, 0, 6, 2, 4 };
if (i <= sizeof(array1)/sizeof(array1[0]))
{
cout << "\nMerge array of type int of size " << i << "\n\n";
dump_array("Original", array1, i);
merge_sort(array1, i);
dump_array("PostSort", array1, i);
}
}
for (size_t i = 1; i <= 10; i++)
{
double array2[] = { 9.9, 3.1, 5.2, 7.3, 1.4, 8.5, 0.6, 6.7, 2.8, 4.9 };
if (i <= sizeof(array2)/sizeof(array2[0]))
{
cout << "\nMerge array of type double of size " << i << "\n\n";
dump_array("Original", array2, i);
merge_sort(array2, i);
dump_array("PostSort", array2, i);
}
}
for (size_t i = 1; i <= 10; i++)
{
std::string array3[] = { "nine", "three", "five", "seven", "one", "eight", "zero", "six", "two", "four" };
if (i <= sizeof(array3)/sizeof(array3[0]))
{
cout << "\nMerge array type std::string of size " << i << "\n\n";
dump_array("Original", array3, i);
merge_sort(array3, i);
dump_array("PostSort", array3, i);
}
}
for (size_t i = 1; i <= 10; i++)
{
char array4[] = "jdfhbiagce";
if (i <= sizeof(array4)/sizeof(array4[0]))
{
cout << "\nMerge array type char of size " << i << "\n\n";
dump_array("Original", array4, i);
merge_sort(array4, i);
dump_array("PostSort", array4, i);
}
}
return 0;
}
Related
Selection sort not sorting properly
The array doesn't sort properly and bubble sort and quick sort work fine. I have checked many times to find any mistakes but couldn't find one. (feel free to edit the question if it doesn't seem right).................................... ............................................................................................................................................................................................... #include <iostream> #include <ctime> using namespace std; const int MaxElements = 500; int compCount = 0; // keeps track of comparisons of elements in array int moveCount = 0; // keeps track of movement of elements in array int main() { // Declarations clock_t before; //time before sorting clock_t after; //time after sorting double result; //Total time int n; //size of set int sample[MaxElements]; //array // Prompt the user for size of set cout << "Enter size of set: "; cin >> n; cout << "---------------Selection Sort-----------------\n"; // Generate random values into the array generateSample(sample, n); cout << "Unsorted array: "; printElements(sample, n); before = clock(); selectionSort(sample, n); after = clock(); result = static_cast<double>(after - before) / CLOCKS_PER_SEC; cout << "\nSorted: "; printElements(sample, n); cout << endl << before << " " << after << "\n"; cout << result << "\n"; cout << "Movement: " << moveCount << endl; cout << "Comparison: " << compCount << endl; } // Swap algorithm void swap(int* x, int* y) { int temp = *x; *x = *y; *y = temp; } void selectionSort(int arr[], int n) { int i, j, current; for (i = 0; i < n - 1; i++) { current = i; for (j = i + 1; j < n; j++) { compCount++; if (arr[j] < arr[current]) { current = j; } if (current != i) { swap(arr[current], arr[i]); moveCount += 3; } } } }
This if statement if (current != i) { swap(arr[current], arr[i]); moveCount += 3; } must be placed outside the inner loop that is after it.
Program is meant to count how many duplicates are in an array. However, it returns the wrong frequency values
Normally I would use other methods to fix this program but I am not allowed to use advanced techniques for this project, and so what I have is more or less as far as I'm allowed to go. So my program is meant to take in an array with 10 numbers and then output how many of each value is in the array. For example, {1, 1, 1, 1, 1, 2, 2, 2, 2, 2} is meant to return 5 1 5 2 However, it returns 6 1 4 2 I've made sure that the finalData and Data arrays are holding the proper values. cout << count(data, data + MAX_VALUE, finalData[i+1]) << " " << data[i] << "\n"; seems to be outputting the wrong value. for some reason. I believe the error is in my last function, getResults, more specifically the last for loop. Here is that function. void getResults(int finalData[], int data[]) { int temp[MAX_VALUE]; int j = 0; for (int i = 0; i < MAX_VALUE - 1; i++) if (finalData[i] != finalData[i + 1]) temp[j++] = finalData[i]; temp[j++] = finalData[MAX_VALUE - 1]; for (int i = 0; i < j; i++) { finalData[i] = temp[i]; } for (int i = 0; i < j; i++) { cout << count(data, data + MAX_VALUE, finalData[i+1]) << " " << data[i] << "\n"; } } This is my complete code. #include<iostream> #include<iomanip> #include<string> #include<cmath> #include <algorithm> using namespace std; void printHeader(); int getData(string); void getResults(int finalData[], int data[]); const int MAX_VALUE = 10; int main(void) { int countValue = 0; int freq = 0; printHeader(); int data[MAX_VALUE] = {}; int frequency[MAX_VALUE] = {}; for (int i = 0; i < MAX_VALUE; i++) { cout << "Please enter data position " << i + 1 << "\n"; data[i] = getData("\nPlease enter a valid integer.\n"); } sort(data, data + MAX_VALUE); int values[MAX_VALUE] = {}; int secondData[MAX_VALUE] = {}; for (int i = 0; i < MAX_VALUE; i++) { secondData[i] = data[i]; } getResults(data, secondData); return 0; } void printHeader() { } int getData(string error) { int userInput = 0; do { cin >> userInput; if (cin.fail()) { cout << error; } } while (cin.fail()); return userInput; } void getResults(int finalData[], int data[]) { int temp[MAX_VALUE]; int j = 0; for (int i = 0; i < MAX_VALUE - 1; i++) if (finalData[i] != finalData[i + 1]) temp[j++] = finalData[i]; temp[j++] = finalData[MAX_VALUE - 1]; for (int i = 0; i < j; i++) { finalData[i] = temp[i]; } for (int i = 0; i < j; i++) { cout << count(data, data + MAX_VALUE, finalData[i+1]) << " " << data[i] << "\n"; } } Got the right answer. Made the changes I listed at the top as well as the following change to the count function. cout << count(data, data + MAX_VALUE, finalData[i]) << " " << finalData[i] << "\n";
You have done a simple error. When you call getResults you pass the same array(pointer) to 2 different parameters. Now when you update finalData the unwanted side effect update also data(they are the same pointer(with different name). So when you call count will not return the expected result. To solve this problem you can do a copy of the input array and give it as second parameter of getResults(...) function.
C++ program wont compile with expected expression and function not allowed here
#include <iostream> using namespace std; const int lab8 = 10; int labArray[lab8]; void promptUser(int [], int); void sortArray(int [], int); void showArray(const int[], int); int searchArray(const int [], int, int value); int x = 0; int results = 0; int main() { promptUser(labArray, lab8); sortArray(labArray, lab8); showArray(labArray, lab8); cout << "Choose an integer you want to search from the array: " << endl; cin >> x; results = searchArray(labArray, lab8, x); if (results == -1) { cout << "That number does not exist in the array. \n"; else { cout << "The integer you searched for was for at element " << results; cout << " in the array. \n"; } } void promptUser(int numbers[], int size) { int index; for (index = 0; index <= size - 1;index++ ) { cout << "Please enter ten numbers to fill the array " << endl << (index + 1) << ": "; cin >> numbers[index]; } } void sortArray(int array[], int size) { bool swap; int temp; do { swap = false; for (int count = 0; count < (size -1); count++) { if (array[count] > array[count + 1]) { temp = array[count]; array[count] = array[count + 1]; array[count + 1] = temp; swap = true; } } } while (swap); } void showArray(const int array[], int size) { for (int count = 0; count < size; count++) { cout << "The array you entered when sorted was: "; cout << array[count] << " "; cout << endl; } } int searchArray(const int array[], int size, int value) { int first = 0, last = size - 1, middle, position = - 1; bool found = false; while (!found && first <= last) { middle = (first + last) / 2; if (array[middle] == value) { found = true; position = middle; } else if (array[middle] > value) last = middle - 1; else first = middle + 1; } return position; } I am new to c++ and just working on an assignment for my class. I thought the program I wrote would have worked but for the life of me I can not figure out why it will not compile. I am sure I am missing something or not understanding how it should work completely. The errors I keep receiving are expected expression on line 26 by the 'else' statement and when I put the 'if' and 'else' statements in I started receiving function not allowed here errors. Any help would be greatly appreciated.
In the if statement, you open the bracket { but you never close it. Not sure if this is the problem but it should raise some issues. if (results == -1) { cout << "That number does not exist in the array. \n"; **}** else { cout << "The integer you searched for was for at element " << results; cout << " in the array. \n"; } This is how it should look. Try it
How to move elements in an array, putting odds to the beginning of the array (smallest to largest), and evens to the back ( largest to smallest )
I have to write a functioncalled moveAndSortInt() that will receive an array of integers as an argument, and move all the even values down to the second half of the array and sort them from largest to smallest, while all the odd values will be sorted from smallest to largest. How can I improve my code? #include <iostream> using namespace std; void moveAndSortInt(int[], int); void displayName(); int main() { int ary1[] = { -19, 270, 76, -61, 54 }; int size = 5; int i; int ary2[] = {9, 8, -103, -73, 74, 53}; int size2 = 6; int j; displayName(); cout << endl; cout << "Original ary1[]" << endl; for (i = 0; i < size; i++) { cout << " " << ary1[i] << " "; } cout << endl; cout << "\nCallingMoveAndSortInt() --\n " << endl; moveAndSortInt(ary1, size); cout << "Updated ary1[]" << endl; for (i = 0; i < size; i++) { cout << " " << ary1[i] << " "; } cout << endl; cout << "\nOriginal ary2[]" << endl; for (j = 0; j < size2; j++) { cout << " " << ary2[j] << " "; } cout << endl; cout << "\nCallingMoveAndSortInt() --\n" << endl; moveAndSortInt(ary2, size2); cout << "Updated ary2[]" << endl; for (j = 0; j < size2; j++) { cout << " " << ary2[j] << " "; } } void moveAndSortInt(int ary[], int size) { int i, j; int temp; for (i = 0; i < 1 + size / 2; i++) { if (ary[i] % 2 == 0) { for (j = size - 1; j > size / 2; j--) { if (ary[j] % 2 != 0) { temp = ary[i]; ary[i] = ary[j]; ary[j] = temp; j = 0; } } } } return;
I would suggest using std::sort, the standard algorithm for sorting, which is often implemented with a Quicksort. It is very fast, and also supports custom comparison. Here's some code to get you started: #include <vector> #include <algorithm> int main() { std::vector<int> data = { 2, 213, 2, 2, 3 ,123, 4, 213, 2132, 123 }; std::sort(data.begin(), data.end(), [](int lhs, int rhs) { if (lhs % 2) // if lhs is odd if (rhs % 2) // and rhs is odd then just use comparision return lhs < rhs; else // and if rhs is even then rhs is "bigger" return false; else // if lhs is even if (rhs % 2) return true; // and rhs is odd then lhs is "bigger" else // and if they are both even just use comparision. return lhs < rhs; }); } I'm sorry if that code is a little hard to read, but it does the trick. This of course would work with C-style arrays too, just replace data.begin() with data and data.end() with data + size.
Alright, so I looked at it a bit. Let's start with conventions. int i; for (i = 1; i < 10; i++) Can be shortened to: for (int i = 1; i < 10; i++) Which looks better and is more readable. It would also be nice to have a few more comments, but that's something everyone needs to get better at, no matter how good they are. So it seems that your code does correctly sort the array into even and odd halves. That's all you need to do yourself as long as you know where they end because sorting them largest to smallest is something that std::sort can do for you. Edit: It was pointed out to me that my previous example is not exactly the same, as with the second one i can only be used in the loop. For your purposes, they work the same.
You can just reorder it #include <algorithm> #include <climits> #include <iostream> #include <vector> int main() { auto const shuffle = [] (int input) { if ( input % 2 ) { unsigned const dist_from_min = (unsigned)input - INT_MIN; return dist_from_min >> 1; } else { unsigned const dist_from_max = INT_MAX - (unsigned)input; return INT_MIN + (dist_from_max >> 1); } }; auto const ordering = [shuffle] (int left, int right) { return shuffle (left) < shuffle (right); }; std::vector <int> data = { 5, 2, 3, 0, -1, -3, 1, 100 , INT_MIN, INT_MIN + 1, INT_MAX, INT_MAX - 1 , -567, -765, 765, 567, -234, -432, 234, 432 }; std::sort ( data.begin ( ), data.end ( ), ordering ); for ( auto item : data ) std::cout << item << "\n"; }
Debugging a merge sort
void CensusData::mergeSort(int type) { if(type == 0) MERGE_SORT(type, 0, data.size()); } void CensusData::MERGE_SORT(int type, int p, int r){ //int q; //cout << "data size " << data.size() << endl; std::cout << "MERGE_SORT START ///("<< p << ", " << r << ")" <<std::endl; if(p < r) { int q = (p + r)/2; MERGE_SORT(type, p, q); MERGE_SORT(type, q + 1, r); MERGE(type, p, q ,r); } } void CensusData::MERGE(int type, int p, int q, int r){ if(type == 0) { std::cout << "MERGING" << std::endl; //int n1; //int n2; int n1 = q - p + 1; int n2 = r - q; int L[n1 + 1]; int R[n2 + 1]; for(int i = 1; i < n1; i++) { cout << "filling Left Array" << endl; L[i] = data[p + i - 1]->population; } for(int j = 1; j < n2; j++) { cout << "filling Right Array" << endl; R[j] = data[q + j]->population; } int i = 1; int j = 1; for(int k = p; p < r; p++) { cout << "for loop: " << endl; if(L[i] <= R[j]) { cout << "TRUE" << endl; data[k]->population = L[j]; i = i + 1; } /*else if(data[k]->population == R[j]) { cout << "FALSE" << endl; j = j + 1; }*/ else { data[k]->population = R[j]; j = j + 1; } } } } do not worry about type, it wont effect this program at all. basically i am trying to make a merge sort that will take a vector containing an integer, the vector looks like this: class Record { // declaration of a Record public: std::string* city; std::string* state; int population; Record(std::string&, std::string&, int); ~Record(); }; std::vector<Record*> data; basically i have been trying to get it to actually sort, but it doesn't seem to work at all, i have even seen garbage in the program. example input: 237 812826 68642 output: 4484540 812826 68642 Note: all of the rest of the program works fine (tested it with an insertion sort) only this part is not working.
Take a look at lecture 15 of the excellent Stanford Universities course Programming Abstractions. It covers all kinds of sorts including merge: http://see.stanford.edu/see/lecturelist.aspx?coll=11f4f422-5670-4b4c-889c-008262e09e4e You can even get the source code from SourceForge: http://sourceforge.net/projects/progabstrlib/files/