Quicksort; Segmentation Fault, but can't find where? - c++

I made a quicksort algorithm as normal functions within main, then attempted to transfer it to a class (per what my instructor wanted). However, I am now getting a segmentation fault error, but I cannot figure out where it is occurring. Source code below; thanks.
main.cpp
#include "MergeSort.h"
#include "QuickSort.h"
#include <iostream>
using namespace std;
const int SIZE = 10;
int main() {
cout << "This is compiling.\n";
int testArray[SIZE] = {5,3,9,2,1,3,8,1,7,9};
for (int i = 0; i < SIZE; i++) {
cout << testArray[i];
}
QuickSort test(testArray, SIZE);
int * result = test.getArray();
cout << endl;
for (int i = 0; i < SIZE; i++) {
cout << result[i];
}
return 0;
}
QuickSort.cpp
#include "QuickSort.h"
//constructor
QuickSort::QuickSort(const int anArray[], int aSize) {
array_p = new int[aSize];
size = aSize;
for (int i = 0; i < size; i++)
array_p[i] = anArray[i];
quickSort(0, aSize - 1);
return;
}
//destructor
QuickSort::~QuickSort() {
delete [] array_p;
return;
}
//accessor function for array
int * QuickSort::getArray() {
return array_p;
}
//PRIV MEM FUNCTIONS
void QuickSort::quickSort(int start, int end)
{
if (start == end)
return;
int pivot;
pivot = partition(array_p, start, end);
//quickSort everything before where pivot is now
quickSort(start, pivot - 1);
//quickSort everything after where pivot is now
quickSort(pivot, end);
return;
}
int QuickSort::partition(int a[], int start, int end)
{
int first, last, pivot;
pivot = end;
first = start;
last = end - 1; //minus one is because pivot is at last
while (first < last) {
if (a[first] > a[pivot] && a[last] < a[pivot]) {
swap(a, first, last);
first++;
last--;
}
else {
if (a[first] <= a[pivot])
first++;
if (a[last] >= a[pivot])
last--;
}
}
if (a[pivot] > a[first]) {
swap(a, pivot, first + 1);
return first + 1;
}
else {
swap(a, pivot, first);
return first;
}
}
void QuickSort::swap(int a[], int indexOne, int indexTwo)
{
int temp = a[indexOne];
a[indexOne] = a[indexTwo];
a[indexTwo] = temp;
return;
}
I think it might be
quickSort(start, pivot - 1);
because once I comment it out, I do not get the error; however, I cannot figure out why.

Change quickSort(pivot, end);
to
quickSort(pivot+1, end);
and
if (start == end)
to if (start >= end).
Your code will run just fine now.

Related

What is wrong with my merge sort implementation refer to CLRS?

I tried to implement merge sort using C++, however, something went wrong. I have no idea what is wrong.
The following code is what I wrote based on CLRS. I think it is quite easy to understand the meaning.
#include <iostream>
#include <vector>
using namespace std;
void merge(vector<int>& nums, int p, int q, int r);
void mergeSort(vector<int>& nums, int p, int r){
if (p < r) {
int q = (p + r) / 2;
mergeSort(nums, p, q);
mergeSort(nums, q + 1, r);
merge(nums, p, q, r);
}
}
void merge(vector<int>& nums, int p, int q, int r) {
int s1 = p, s2 = q + 1;
vector<int> l1, l2;
for (int i = s1; i <= q; i++) {
l1.push_back(nums[i]);
}
for (int i = s2; i <= r; i++) {
l2.push_back(nums[i]);
}
int left = 0, right = 0;
int idx = 0;
while (left < l1.size() && right < l2.size()) {
if (l1[left] < l2[right]) {
nums[idx] = l1[left++];
}
else {
nums[idx] = l2[right++];
}
idx++;
}
while (left < l1.size()) {
nums[idx++] = l1[left++];
}
while (right < l2.size()) {
nums[idx++] = l2[right++];
}
}
int main() {
vector<int> vect;
vect.push_back(1);
vect.push_back(3);
vect.push_back(12);
vect.push_back(23);
vect.push_back(4);
vect.push_back(11);
vect.push_back(44);
vect.push_back(322);
mergeSort(vect, 0, vect.size() - 1);
for (int i = 0; i < vect.size(); i++) {
cout << vect[i] << endl;
}
return 0;
}
I want to use the program to sort some integers, however, it only shows many duplicate numbers. What's going on? I don't think there is a problem of the merge function.
The code needs a one line fix:
int idx = p; // not idx = 0
Optimized top down using arrays from Wiki article (note bottom up is slightly faster):
void TopDownMerge(int A[], int bgn, int mid, int end, int B[])
{
int i, j, k;
i = bgn, j = mid, k = bgn;
while(1){
if(A[i] <= A[j]){ // if left smaller
B[k++] = A[i++]; // copy left element
if(i < mid) // if not end of left run
continue; // continue
do // else copy rest of right run
B[k++] = A[j++];
while(j < end);
break; // and break
} else { // else right smaller
B[k++] = A[j++]; // copy right element
if(j < end) // if not end of right run
continue; // continue
do // else copy rest of left run
B[k++] = A[i++];
while(i < mid);
break; // and break
}
}
}
void TopDownSplitMerge(int B[], int bgn, int end, int A[])
{
if (end - bgn <= 1) // if run size == 1
return; // consider it sorted
int mid = (end + bgn) / 2;
TopDownSplitMerge(A, bgn, mid, B);
TopDownSplitMerge(A, mid, end, B);
TopDownMerge(B, bgn, mid, end, A);
}
void TopDownMergeSort(int A[], int n) // n = size (not size-1)
{
if(n < 2)
return;
int *B = new int [n]; // 1 time allocate and copy
for(size_t i = 0; i < n; i++)
B[i] = A[i];
TopDownSplitMerge(B, 0, n, A); // sort data from B[] into A[]
delete B;
}
Afterwards, I finally get to fix the bugs of my program. After modification, here is the code:
class Solution {
public:
vector<int> temp;
vector<int> sortArray(vector<int>& nums) {
temp.resize((int)nums.size(), 0);
mergeSort(nums, 0, nums.size() - 1);
return nums;
}
void mergeSort(vector<int>& nums, int start, int end) {
if (start >= end) return;
int middle = (start + end) / 2;
mergeSort(nums, start, middle);
mergeSort(nums, middle + 1, end);
merge(nums, start, middle, end);
}
void merge(vector<int>& nums, int leftStart, int middle, int rightEnd) {
int leftEnd = middle;
int rightStart = middle + 1;
int i = leftStart, j = rightStart;
int index = 0;
while (i <= leftEnd && j <= rightEnd) {
if (nums[i] < nums[j]) {
temp[index] = nums[i++];
}
else {
temp[index] = nums[j++];
}
index++;
}
while (i <= leftEnd) {
temp[index++] = nums[i++];
}
while (j <= rightEnd) {
temp[index++] = nums[j++];
}
for (int i = 0; i < rightEnd - leftStart + 1; i++) {
nums[i + leftStart] = temp[i];
}
}
};
Here is something should be careful next time:
In the merge part, it is difficult to merge in place. It'd be better to use another temp array to store the merged results and update to the target array (nums in this case).
Readable identifers is very recommended (Although the pseudocode of CLRS may not use that part).
Need to use debuggers to find the bug of program {However, it takes like forever to load local variables of VS Code debugers.

vector mergesort() nothing happens

I am not too sure what I did wrong in this Mergesort algorithm I made.
my output I am receiving is
4 3 5 5 4 3 8 8 8
I am speculating my int mid value could be causing this but then again I don't think it really matters as I am being consistent in merger func.
#include <iostream>
#include <vector>
using namespace std;
void merger(vector<int> &arr, int beg, int end) {
vector<int> temp;
int mid = (beg + end-1) / 2;
int right=mid+1;
int left = beg;
while (left <= mid && right <= end) {
if (arr[left] <= arr[right]) {
temp.push_back(arr[left++]);
}
else temp.push_back(arr[right++]);
}
if(left<mid){
while (left <= mid) {
temp.push_back(arr[left++]);
}
}
else{
while (right <= end) {
temp.push_back(arr[right++]);
}
}
int j = 0;
for (auto x : temp) {
arr[j++] = x;
}
// temp.clear();
}
void mergesort(vector<int> &arr, int beg, int end) {
//base case
if (beg >= end)return;
//make mid
int mid = (beg+end-1) / 2;
mergesort(arr, beg, mid);
mergesort(arr, mid+1, end);
merger(arr, beg, end);
}
int main() {
vector<int> arr1 = { 7,5,2,4,10,5,4,3,8 };
mergesort(arr1, 0, arr1.size()-1);
for (auto x : arr1) {
cout << x << " ";
}
cout << endl;
return 0;
}
```````````````````````````````````````
In merger, the index variable j needs to start at beg because the elements you copy into temp start with arr[beg]. Change the declaration to
int j = beg;
right before you loop to copy the sorted temp array back into arr.

Why is this Quick Sort implementation giving a weird output

My Quick Sort is giving a weird output.Some sections of the output are sorted while some some sections are just random.I am using pivot element to partition the array recursively using partition function into 2 halves with the left half elements less than the pivot element and right half elements greater than the pivot element.
#include <iostream>
using namespace std;
int partition(int *arr, int start, int end)
{
int pivot = start;
int temp;
int temp2;
while (start < end)
{
while (arr[start] <= arr[pivot])
start++;
while (arr[end] > arr[pivot])
end--;
if (start < end)
{
temp = arr[start];
arr[start] = arr[end];
arr[end] = temp;
}
}
temp2 = arr[pivot];
arr[pivot] = arr[end];
arr[end] = temp2;
return end;
}
void quickSort(int input[], int size)
{
int lb = 0;
int ub = size - 1;
int loc;
if (lb < ub)
{
loc = partition(input, lb, ub);
quickSort(input, loc - 1);
quickSort(input + loc + 1, ub - loc);
}
else
return;
}
int main()
{
int n;
cin >> n;
int *input = new int[n];
for (int i = 0; i < n; i++)
{
cin >> input[i];
}
quickSort(input, n);
for (int i = 0; i < n; i++)
{
cout << input[i] << " ";
}
delete[] input;
}
in this part when you try to sort the array from the location start to pivot you have
quickSort(input, loc - 1);
quickSort(input + loc + 1, ub - loc);
which means input[loc] is never treated since you go from 0 to loc -1 and loc +1 to end
which is corrected here
if (lb < ub)
{
loc = partition(input, lb, ub);
quickSort(input, loc );
quickSort(input + loc + 1, ub - loc);
}

Segmentation Fault, Merge Sort algortihm

This is a merge- sort algorithm I wrote. Although, it works well for smaller arrays, it gives a segmentation fault for arrays containing more than 7/8 elements. It also fails in some cases where a number is repeated. For example - {5,5,1,2,1}. I have been trying to identify the error but to no avail
I know that the code is not completely efficient but I am concentrating on making it work right now. Suggestions regarding the improvements in the code will be helpful. Thank you in advance.
#include <iostream>
using namespace std;
void printarray(int a[], int size);
void splitsort(int b[], int start, int end); //Split array into half
void merge(int b[], int start, int end); // merge the sorted arrays
int main()
{
cout << "This is merge sort" << endl;
int array[] = { 9,8,7,6,5,4,3,2,1 };
int length = sizeof(array) / sizeof(array[0]);
printarray(array, length);
splitsort(array, 0, length - 1);
cout << "sorted array" << endl;
printarray(array, length);
return 0;
}
void printarray(int a[], int size) {
for(int i = 0; i<size; i++) {
cout << a[i] << ",";
}
cout << endl;
return;
}
void splitsort(int b[], int start, int end) {
//base case
if(end == start) { return; }
//
splitsort(b, start, (start + end) / 2);
splitsort(b, (start + end) / 2 + 1, end);
merge(b, start, end);
return;
}
void merge(int b[], int start, int end) {
int tempb[(end - start) + 1];
//base case
if(end == start) { return; } // if single element being merged
int i = start;
int j = (start + end) / 2 + 1;
for(int k = start; k <= end; k++) {
if(i == (start + end) / 2 + 1) { tempb[k] = b[j]; j++; }// finished first array
else if(j == end + 1) { tempb[k] = b[i]; i++; }// finished second array
else if(b[i] >= b[j]) {
tempb[k] = b[j];
j++;
}
else if(b[j] >= b[i]) {
tempb[k] = b[i];
i++;
}
}
for(int k = start; k <= end; k++) {
b[k] = tempb[k];
}
return;
}
int tempb[(end - start) + 1];
tempb can have as few as 2 elements, while the main array has 10 elements. You end up accessing tempb[9], causing segmentation fault.
To fix the problem, change the size to int tempb[max_size]; where max_size is the size of array as calculated earlier int length = sizeof(array) / sizeof(array[0]);
Changing tempb to std::vector<int> tempb(max_size) will help in debugging as well as being compliant with C++ standard.

Merge Sort: Heap Corruption on delete[]

Working on a class project in which i need to implement a Merge Sort to sort 500,000 items.
After many attempts I tried looking for source code online and found some here: http://www.sanfoundry.com/cpp-program-implement-merge-sort/
I had to alter the code to use a dynamic array (for size). When the program runs the merge function, I create a new, dynamic array using the number of elements (or high) that are being merged. Once the function is finished sorting them and merge them into the original array, i use delete[] on the new dynamic array. This is where I get my "Heap Corruption Detected" error.
Here is the code (wall of text):
//Heap Sort
#include <iostream>
#include <fstream>
#include <sstream>
#include <ctime>
#include <stdlib.h>
#include <stdio.h>
using namespace std;
//Function Prototypes
void mergesort(int *a, int low, int high);
void merge(int *a, int low, int high, int mid);
int main()
{
//Start with element 1 of the array
int line_no = 0;
int num;
int array_size = 500000;
int* num_array = new int[array_size];
//Open file for input
fstream in_file("CSCI3380_final_project_dataset.txt", ios::in);
//Test for file opening
if (!in_file)
{
cout << "Cannot open words1.txt for reading" << endl;
exit(-1);
}
//Read file
while(true)
{
//Read one line at a time
in_file >> num;
//Test for eof
if (in_file.eof())
break;
num_array[line_no] = num;
//Increment array position
line_no++;
}
//Close the file
in_file.close();
//Start Time
clock_t time_a = clock();
//Run Sorting Algorithim
mergesort(num_array, 0, array_size-1);
//End Time
clock_t time_b = clock();
//Elapsed Time
if (time_a == ((clock_t)-1) || time_b == ((clock_t)-1))
{
cout << "Unable to calculate elapsed time" << endl;
}
else
{
int total_time_ticks = time_b - time_a;
cout << "Elapsed time: " << total_time_ticks << endl;
}
delete[] num_array;
return 0;
}
void mergesort(int *a, int low, int high)
{
int mid;
if (low < high)
{
mid=(low+high)/2;
mergesort(a,low,mid);
mergesort(a,mid+1,high);
merge(a,low,high,mid);
}
return;
}
void merge(int *a, int low, int high, int mid)
{
//--------------------------Create new array-------------------------------
int* sort_array = new int[high];
//--------------------------New Array Created-----------------------------
int i, j, k;
i = low;
k = low;
j = mid + 1;
while (i <= mid && j <= high)
{
if (a[i] < a[j])
{
sort_array[k] = a[i];
k++;
i++;
}
else
{
sort_array[k] = a[j];
k++;
j++;
}
}
while (i <= mid)
{
sort_array[k] = a[i];
k++;
i++;
}
while (j <= high)
{
sort_array[k] = a[j];
k++;
j++;
}
for (i = low; i < k; i++)
{
a[i] = sort_array[i];
}
//---------------------------Delete the New Array--------------------
delete[] sort_array;
//--------------------------Oh No! Heap Corruption!------------------
}
I'll spare you the "you should be using vectors", "you should be using smart pointers", etc. You should be, and I'll leave it at that. Regarding your actual problem....
You're writing one-past the allocated space of your array. The allocated size is high:
int* sort_array = new int[high];
meaning you can only dereference from 0..(high-1). Yet this:
while (j <= high)
{
sort_array[k] = a[j];
k++;
j++;
}
is one location that is guaranteed to write to sort_array[high], and therefore invoke undefined behavior.
A Different Approach
Mergesort is about div-2 partitioning. You know this. What you may not have considered is that C and C++ both perform pointer-arithmetic beautifully and as such you only need two parameters for mergesort(): a base address and a length. the rest can be taken care of for you with pointer math:
Consider this:
void mergesort(int *a, int len)
{
if (len < 2)
return;
int mid = len/2;
mergesort(a, mid);
mergesort(a + mid, len-mid);
merge(a, mid, len);
}
And a merge implementation that looks like this:
void merge(int *a, int mid, int len)
{
int *sort_array = new int[ len ];
int i=0, j=mid, k=0;
while (i < mid && j < len)
{
if (a[i] < a[j])
sort_array[k++] = a[i++];
else
sort_array[k++] = a[j++];
}
while (i < mid)
sort_array[k++] = a[i++];
while (j < len)
sort_array[k++] = a[j++];
for (i=0;i<len;++i)
a[i] = sort_array[i];
delete[] sort_array;
}
Invoked from main() like the following. Note: I've removed the file i/o in place of a random generation just to make it easier to test:
#include <iostream>
#include <ctime>
#include <cstdlib>
#include <cstdio>
using namespace std;
//Function Prototypes
void mergesort(int *a, int len);
void merge(int *a, int mid, int len);
int main()
{
std::srand((unsigned int)std::time(nullptr));
// Start with element 1 of the array
int array_size = 500000;
int* num_array = new int[array_size];
std::generate_n(num_array, array_size, std::rand);
// Start Time
clock_t time_a = clock();
// Run Sorting Algorithim
mergesort(num_array, array_size);
// End Time
clock_t time_b = clock();
//Elapsed Time
if (time_a == ((clock_t)-1) || time_b == ((clock_t)-1))
{
cout << "Unable to calculate elapsed time" << endl;
}
else
{
int total_time_ticks = time_b - time_a;
cout << "Elapsed time: " << total_time_ticks << endl;
}
delete[] num_array;
return 0;
}
This resulted is an elapsed time of:
Elapsed time: 247287
More Efficient
By now you've seen that you will need at most N-space in addition to you sequence. The top-most merge should e evidence enough of that. What you may not consider is that in-reality that is exactly the space you need, and you can allocate it up-front and use it throughout the algorithm if you desire. You can keep the current entrapping for mergesort(), but we'll be wrapping it up with a front-loader that allocates all the space we'll ever need once:
// merges the two sequences a[0...mid-1] and a[mid...len-1]
// using tmp[] as the temporary storage space
static void merge_s(int *a, int *tmp, int mid, int len)
{
int i=0, j=mid, k=0;
while (i < mid && j < len)
{
if (a[i] < a[j])
tmp[k++] = a[i++];
else
tmp[k++] = a[j++];
}
while (i < mid)
tmp[k++] = a[i++];
while (j < len)
tmp[k++] = a[j++];
for (i=0;i<len;++i)
a[i] = tmp[i];
}
static void mergesort_s(int *a, int *tmp, int len)
{
if (len < 2)
return;
int mid = len/2;
mergesort_s(a, tmp, mid);
mergesort_s(a + mid, tmp+mid, len-mid);
merge_s(a, tmp, mid, len);
}
void mergesort(int *a, int len)
{
if (len < 2)
return;
int *tmp = new int[len];
mergesort_s(a,tmp,len);
delete [] tmp;
}
This resulted in an elapsed time of:
Elapsed time: 164704
Considerably better than we had before. Best of luck.
The copy step shown in WhozCraig's code example can be avoided using a pair of functions to control the direction of the merge (note - a bottom up merge would still be faster).
Note - I wouldn't recommend using either WhozCraig's or my code example, since these methods were probably not covered in your class, and it's supposed to be code written based on what you were taught in your class. I don't know if bottom up merge sort was covered in your class, so I didn't post an example of it.
mergesort_s(int *a, int *tmp, int len)
{
// ...
mergesort_atoa(a, tmp, 0, len);
// ...
}
mergesort_atoa(int *a, int *tmp, int low, int end)
{
if((end - low) < 2){
return;
}
int mid = (low + end) / 2;
mergesort_atot(a, tmp, low, mid);
mergesort_atot(a, tmp, mid, end);
merge_s(tmp, a, low, mid, end);
}
mergesort_atot(int *a, int *tmp, int low, int end)
{
if((end - low) < 2){
tmp[0] = a[0];
return;
}
int mid = (low + end) / 2;
mergesort_atoa(a, tmp, low, mid);
mergesort_atoa(a, tmp, mid, end);
merge_s(a, tmp, low, mid, end);
}
void merge_s(int *src, int *dst, int low, int mid, int end)
{
int i = low; // src[] left index
int j = mid; // src[] right index
int k = low; // dst[] index
while(1){ // merge data
if(src[i] <= src[j]){ // if src[i] <= src[j]
dst[k++] = src[i++]; // copy src[i]
if(i < mid) // if not end of left run
continue; // continue (back to while)
while(j < end) // else copy rest of right run
dst[k++] = src[j++];
return; // and return
} else { // else src[i] > src[j]
dst[k++] = src[j++]; // copy src[j]
if(j < end) // if not end of right run
continue; // continue (back to while)
while(i < mid) // else copy rest of left run
dst[k++] = src[i++];
return; // and return
}
}
}