I am having a problem with merge sorting. I'm using the code below, and I'm getting a heap corruption detected. It happens when I try to deallocate memory, so I would imagine I'm writing an out of bound index.
More specifically I think it's at the last for loop. When I print out the array, the first index is some garbage number, and the last index is actually the one before the last that I want. I've tried everything and I can't get around to solving this, can somebody tell me what exactly I'm doing wrong? 'Cause I can't seem to understand what the problem is.
Here's the code I'm using:
template <class T>
int Mergesort(T arr[], int n) {
MergeSortRec(arr, 0, n, n);
return 0;
}
template <class T>
void MergeSortRec(T arr[], int left, int right, int size) {
if(right > left) {
int mid = ((left + right) /2);
MergeSortRec(arr, left, mid, size);
MergeSortRec(arr, mid+1, right, size);
Merge(arr, left, mid, right, size);
}
return;
}
template <class T>
void Merge(T arr[], int left, int mid, int right, int size) {
int i = 0;
int j = left;
int k = mid + 1;
T* temp = new T[right - left];
while(j <= mid && k <= right) {
if(arr[j] < arr[k]) {
temp[i++] = arr[j++];
} else {
temp[i++] = arr[k++];
}
}
while(j <= mid) {
temp[i++] = arr[j++];
}
while(k <= right) {
temp[i++] = arr[k++];
}
for(int a = left; a <= right; a++) {
arr[a] = temp [a-left];
}
Cheers.
The problem is here:
T* temp = new T[right - left];
//...
for(int a = left; a <= right; a++) {
arr[a] = temp [a-left];
}
You allocate right-left elements, but the for loop steps through right-left+1 entries, so you run off the end of the array and trample on some memory you shouldn't. If you added delete [] temp; after that for loop (without it you are leaking memory!) you would probably see your error much earlier.
In fact, all your loops go one too far; it's just most obvious in this simple loop.
Related
I don't understand why they give me different output when I compile them. For example ... when I compile only one algorithm the answer is good, the same is for the other one, but when I compile them both at the same time they give me some weird output.
My code:
#include <iostream>
using namespace std;
int parent(int i){
return i/2;
}
int leftChild(int i){
return 2*i+1;
}
int rightChild(int i){
return 2*i+2;
}
void maxHeapify(int a[], int i, int n){
int largest;
int temp;
int l = leftChild(i);
int r = rightChild(i);
// p.countOperation("CMPbottomUp",n);
if (l <= n && (a[l] > a[i]))
largest = l;
else
largest = i;
// p.countOperation("CMPbottomUp",n);
if (r <= n && (a[r] > a[largest]))
largest = r;
if (largest != i){
// p.countOperation("ATTbottomUp",n);
temp = a[i];
// p.countOperation("ATTbottomUp",n);
a[i] = a[largest];
//p.countOperation("ATTbottomUp",n);
a[largest] = temp;
maxHeapify(a, largest, n);
}
}
void buildMaxHeap(int a[], int n){
for (int i=n/2; i>=0; i--){
maxHeapify(a, i, n);
}
}
void heapSort(int a[],int n){
buildMaxHeap(a,n);
int n1=n;
int temp;
for(int i=n1;i>0;i--){
temp = a[0];
a[0] = a[i];
a[i] = temp;
n1--;
maxHeapify(a,0,n1);
}
}
int partitionArray(int arr[], int left, int right){
int i = left, j = right;
int tmp;
int pivot = arr[(left + right) / 2];
while (i <= j) {
while (arr[i] < pivot)
i++;
while (arr[j] > pivot)
j--;
if (i <= j) {
tmp = arr[i];
arr[i] = arr[j];
arr[j] = tmp;
i++;
j--;
}
}
return i;
}
void quickSort(int arr[], int left, int right) {
int index;
index = partitionArray(arr, left, right);
if (left < index - 1)
quickSort(arr, left, index - 1);
if (index < right)
quickSort(arr, index, right);
}
int main(){
int x[8]= {5,87,21,4,12,7,44,3};
int a[8];
for(int i=0;i<8;i++){
a[i] = x[i];
}
heapSort(x,8);
quickSort(a,0,8);
for(int i=0;i<8;i++){
cout<<a[i]<<' ';
}
cout<<endl;
for(int j=0;j<8;j++){
cout<<x[j]<<' ';
}
return 0;
}
Example output:
1) When I compile only one algorithm the output is : 3,4,5,7,12,21,44,87 (which is good)
2) When I compile both of them in the code the output is: 87,4,5,7,12,21,44,87 (quickSort) and 3,3,4,5,7,12,21,44 (heapSort)
I think that should work:
heapSort(x,7);
quickSort(a,0,7);
Arrays a and x are right next to each others in stack. Seeing how you have duplicate value 87 in output, it seems your sort functions access memory outside the array you give to them. This is buffer overrun, a type of Undefined Behaviour. With that, your code could do anything because you have corrupted variable values (or worse, corrupted addresses/pointers).
Double check how you access arrays. Remember that C array indexes for your arrays of length 8 are 0..7!
I can't figure out why this code isn't quite correct. It sorts most of the array, but some numbers are out of place. Any help would be much appreciated.
int partition(int* an_array, int from, int to)
{
int pivot = an_array[(from + to) / 2];
int left = from;
int right = to;
while(left < right)
{
while(an_array[left] < pivot)
{
left = left + 1;
}//end while loop
while(an_array[right] > pivot)
{
right = right - 1;
}//end while
if(left < right)
{
swap_numbers(an_array[left], an_array[right]);
left = left + 1;
right = right - 1;
}//end if
}//end while loop
return right;
}//end partition function
void quick_sort(int* an_array, int from, int to)
{
if(from >= to) return;
int p = partition(an_array, from, to);
quick_sort(an_array, from, p);
quick_sort(an_array, p + 1, to);
}//end quick_sort
You forget to add:
swap_numbers(an_array[from], an_array[right]);
just before
return right;
I am doing my homework, and completed quicksort recursive, however it doesn't sort in a correct way. Seems to be it doesn't swap correctly.
Here is my code
#include<iostream>
#include<ctime>
#include<string>
using namespace std;
int quick_sort_help(string &text,int left, int right, int pivot){
char val = text[pivot];
char temp;
//swap
// temp =text[pivot];
//text[pivot]= text[right];
//text[right]=temp;
//swap(&text[left],&text[right]);
int l = left;
int r = right;
int i=left;
while (i<=r)
{
while (text[i]<val)
i++;
while (text[right]>val)
r--;
if (i<=r)
{
temp=text[i];
text[i]=text[r];
text[r]=temp;
i++;
r--;
}
}
return l;
}
void quicksort(string &text,int left, int right){
if (left < right){
int pivot=(left+right)/2;
int pivottwo = quick_sort_help(text, left, right, pivot);
quicksort(text, left, pivottwo - 1);
quicksort(text, pivottwo + 1, right);
}
}
void quick_sort(string &text,int size){
quicksort(text,0,size);}
int main()
{
string text="this is a test string text,.,!";
int size = text.length();
float t1, t2;
t1 = clock();
quick_sort(text,size);
t2=clock();
cout<<"quicksort Sort: "<<(t2-t1)/CLK_TCK*1000<<" msec\n";
cout<<text<<endl;
system("pause");
return 0;
}
the output I am getting:
hi a e e,g.nii,r!tssssxttttt
You have to:
1) Don't use size but size-1 value
void quick_sort(string &text,int size){
quicksort(text,0,size-1);}
2) Pivot is not (left+right)/2 but it's the value returned by quick_sort_help, and pivottwo is not necessary:
void quicksort(string &text,int left, int right)
{
if (left < right)
{
int pivot = quick_sort_help(text, left, right);
quicksort(text, left, pivot - 1);
quicksort(text, pivot + 1, right);
}
}
3) Test my j value (your r) in the second while and make the exchange before returning the pivot (the i value):
int quick_sort_help(string &text,int left, int right)
{
char val = text[right];
char temp;
int j = right;
int i = left - 1;
while (true)
{
while (text[++i] < val);
while (text[--j] > val) {
if(j == left)
break;
}
if(i >= j)
break;
temp=text[i];
text[i]=text[j];
text[j]=temp;
}
temp=text[i];
text[i]=text[right];
text[right]=temp;
return i;
}
Take a look at this : Quicksort implementation
while (text[right]>val)
r--;
That doesn't seem likely. You're decrementing r, but the condition you test never changes (should depend on r, probably...)
Also
return l;
looks suspicious, since the calling function seem to expect it to be the new position of the pivot, whereas it is the old left.
Another one, you use closed intervals (see why you shouldn't), which means you're accessing the string out-of bounds (which is UB).
SO Posts
When to use merge sort and when to use quick sort?
Quick Sort Vs Merge Sort
Wikipedia
http://en.wikipedia.org/wiki/Merge_sort
http://en.wikipedia.org/wiki/Quicksort
quick_sort is suppose to have worst case O(n^2) but merge_sort is suppose to not have a worst case and always be O (n*log N). I thought that it was dependent upon the ordering of the data set - reverse order, forward order, or random, but when I a run test...quick_sort is always faster. The code I used is below:
/*
Needs a reszie function added
*/
#include "c_arclib.cpp"
template <class T> class dynamic_array
{
private:
T* array;
T* scratch;
public:
int size;
dynamic_array(int sizein)
{
size=sizein;
array = new T[size]();
}
void print_array()
{
for (int i = 0; i < size; i++) cout << array[i] << endl;
}
void merge_recurse(int left, int right)
{
if(right == left + 1)
{
return;
}
else
{
int i = 0;
int length = right - left;
int midpoint_distance = length/2;
int l = left, r = left + midpoint_distance;
merge_recurse(left, left + midpoint_distance);
merge_recurse(left + midpoint_distance, right);
for(i = 0; i < length; i++)
{
if((l < (left + midpoint_distance)) && (r == right || array[l] > array[r]))
{
scratch[i] = array[l];
l++;
}
else
{
scratch[i] = array[r];
r++;
}
}
for(i = left; i < right; i++)
{
array[i] = scratch[i - left];
}
}
}
int merge_sort()
{
scratch = new T[size]();
if(scratch != NULL)
{
merge_recurse(0, size);
return 1;
}
else
{
return 0;
}
}
void quick_recurse(int left, int right)
{
int l = left, r = right, tmp;
int pivot = array[(left + right) / 2];
while (l <= r)
{
while (array[l] < pivot)l++;
while (array[r] > pivot)r--;
if (l <= r)
{
tmp = array[l];
array[l] = array[r];
array[r] = tmp;
l++;
r--;
}
}
if (left < r)quick_recurse(left, r);
if (l < right)quick_recurse(l, right);
}
void quick_sort()
{
quick_recurse(0,size);
}
void rand_to_array()
{
srand(time(NULL));
int* k;
for (k = array; k != array + size; ++k)
{
*k=rand();
}
}
void order_to_array()
{
int* k;
int i = 0;
for (k = array; k != array + size; ++k)
{
*k=i;
++i;
}
}
void rorder_to_array()
{
int* k;
int i = size;
for (k = array; k != array + size; ++k)
{
*k=i;
--i;
}
}
};
int main()
{
dynamic_array<int> d1(1000000);
d1.order_to_array();
clock_t time_start=clock();
d1.merge_sort();
clock_t time_end=clock();
double result = (double)(time_end - time_start) / CLOCKS_PER_SEC;
cout << result;
}
Worst case for quick sort is when the pivot element is the largest or smallest element in the array on every recursion. In that case you will have to do n-1 recursions (one of the arrays you split always only has one element) which gives you an O(n2) overall.
You can reproduce the worst case for quick sort if you use an already sorted array and pick the first or last element as pivot element.
Merge sort works very well for data that won't fit into memory, because each pass is linear and can be read/written to disk. Quick sort isn't even an option in that case, although the two may be combined - quick sort blocks that fit into memory, and merge sort those blocks until done.
Consider the container type as well - mergesort will work much better with a linked list, because you can split the list into equal parts by just traversing it and assigning nodes to alternate sublists; rearranging things around a pivot for quicksort is considerably more involved.
I'm not looking to copy a qsort algorithm. I'm practicing writing qsort and this is what I've come up with and I'm interested in what part of my code is wrong. Please don't tell me that this is homework cause I could just use the code in the link below.
Reference: http://xoax.net/comp/sci/algorithms/Lesson4.php
When this runs I get this in the console:
Program loaded.
run
[Switching to process 10738]
Running…
Current language: auto; currently c++
Program received signal: “EXC_ARITHMETIC”.
void myQSort(int min, int max, int* myArray)
{
// Initially find a random pivot
int pivotIndex = rand() % max;
int pivot = myArray[pivotIndex];
int i = 0 , j = max-1;
// Pointer to begining of array and one to the end
int* begin = myArray;
int* end = &myArray[max-1];
// While begin < end
while( begin < end )
{
// Find the lowest bound number to swap
while( *begin < pivot )
{
begin++;
}
while( *end > pivot )
{
// Find the highest bound number to swap
end--;
}
// Do the swap
swap(begin,end);
}
// Partition left
myQSort(0, pivotIndex-1, myArray);
// Partiion right
myQSort(pivotIndex+1,max, myArray);
}
EDIT--
Code for Swap:
void swap(int* num, int* num2)
{
int temp = *num;
*num = *num2;
*num2 = temp;
}
// sort interval [begin, end)
void myQSort(int* begin, int* end)
{
if(end - begin < 2)
return;
int* l = begin;
int* r = end - 1;
// Initially find a random pivot
int* pivot = l + rand() % (r - l + 1);
while(l != r)
{
// Find the lowest bound number to swap
while(*l < *pivot) ++l;
while(*r >= *pivot && l < r) --r;
// Do the swap
if(pivot == l) { pivot = r; }
std::swap(*l, *r);
}
// Here l == r and numbers in the interval [begin, r) are lower and in the interval [l, end) are greater or equal than the pivot
// Move pivot to the position
std::swap(*pivot, *l);
// Sort left
myQSort(begin, l);
// Sort right
myQSort(l + 1, end);
}
You're not using the min parameter in your code, anywhere. You need to set begin and your pivot value using that.
I tried working out the codes above. But, they don't compile.
#Mihran: Your solution is correct algorithmically but the following line generates an error:
myQSort(min, begin - myArray, myArray);
This is because begin is of type int* and myArray is of type long, following which the compiler shows this error message:
implicit conversion loses integer precision
Here's a working solution in C++:
#include <iostream>
using namespace std;
void mySwap(int& num1, int& num2){
int temp = num1;
num1 = num2;
num2 = temp;
}
void myQsort(int myArray[], int min, int max){
int pivot = myArray[(min + max) / 2];
int left = min, right = max;
while (left < right) {
while (myArray[left] < pivot) {
left++;
}
while (myArray[right] > pivot) {
right--;
}
if (left <= right) {
mySwap(myArray[left], myArray[right]);
left++;
right--;
}
}
if (min < right) {
myQsort(myArray, min, right);
}
if (left < max) {
myQsort(myArray, left, max);
}
}
int main()
{
int myArray[] = {1, 12, -5, 260, 7, 14, 3, 7, 2};
int min = 0;
int max = sizeof(myArray) / sizeof(int);
myQsort(myArray, min, max-1);
for (int i = 0; i < max; i++) {
cout<<myArray[i]<<" ";
}
return 0;
}
Here's a clear C++ implementation, for reference:
#include <iostream>
#include <vector>
using namespace std;
int partition(std::vector<int>& arr, int low, int high) {
// set wall index
int wall_index = low;
int curr_index = low;
int pivot_elem = arr[high]; // taking last element as pivot_element
// loop through the entire received arr
for (int i = curr_index; i < high; ++i) {
// if element is less than or equal to pivot_elem
// swap the element with element on the right of the wall
// i.e swap arr[i] with arr[wall_index]
if (arr[i] <= pivot_elem) {
// swap
int temp = arr[wall_index];
arr[wall_index] = arr[i];
arr[i] = temp;
// move the wall one index to the right
wall_index++;
curr_index++;
} else {
// if the element is greater than the pivot_element
// then keep the wall at the same point and do nothing
curr_index++;
}
}
// need to swap the pivot_elem i.e arr[high] with the element right of the wall
int temp = arr[wall_index];
arr[wall_index] = arr[high];
arr[high] = temp;
return wall_index;
}
void quick_sort(std::vector<int>& arr, int low, int high) {
if (low < high) { // element with single arr always have low >= high
int split = partition(arr, low, high);
quick_sort(arr, low, split-1);
quick_sort(arr, split, high);
}
}
int main() {
std::vector<int> data = {6,13,8,4,2,7,16,3,8};
int N = data.size();
quick_sort(data, 0, N-1);
for (int i : data) {
cout << i << " ";
}
return 0;
}
I don't see a clean implementation of Quicksort on SO, so here is my easy to understand implementation
PLEASE DONT USE IN PRODUCTION CODE
This is only for your understanding
// Swap position a with b in an array of integer numbers
void swap(int *numbers, int a, int b){
int temp = numbers[a];
numbers[a] = numbers[b];
numbers[b] = temp;
}
static int partition(int *data, int low, int high) {
int left = low, right = high, pivot = data[low];
while (left < right) {
// Everthing on the left of pivot is lower than the pivot
while ((left <= right) && data[left] <= pivot) // <= is because left is the pivot initially
left++;
// Everything on the right of the pivot is greater than the pivot
while((left <= right) && data[right] > pivot)
right--;
if (left < right)
swap(data, left, right);
}
// Put the pivot in the 'rigthful' place
swap(data, low, right);
return right;
}
// Quicksort
static void quick_sort(int *numbers, int low, int high)
{
if (high > low) {
int p_index = partition(numbers, low, high);
quick_sort(numbers, low , p_index - 1);
quick_sort(numbers, p_index + 1, high);
}
}