quick sort c++ code error segmentation fault 11? - c++

Code:
#include <iostream>
#include <stdlib.h>
#include <time.h>
using namespace std;
void partition(int *A, int start, int end){ //end is the position of the last number
cout<<"start is "<<start<<" end is "<<end<<endl;
if(end - start+1 > 1){
int i = start + 1, j = start + 1, pivot = A[start];
while(j <= end){
if(A[j] <= pivot){
swap(A[j], A[i]);
i++;
}
j++;
}
swap(A[start], A[i-1]);
partition(A, start, i-1);
partition(A, i, end);
}
}
void QuickSort(int *A, int n){
partition(A, 0, n-1);
}
int main() {
int n, method;
string sortMethod[ ] = {
"Insertion sort", "Selection sort", "Bubble sort", "Merge sort", "Quick sort"
};
int m = sizeof(sortMethod)/sizeof(string);
srand(time(0));
while (true){
cout << "Number of test marks: ";
cin >> n;
if ( n==0 ) break;
int *A = new int[n];
for (int i=0; i < n; i++) cin>>A[i];
//A[i] = rand()%101;
for (int i=0; i < n; i++)cout << A[i] << " ";
cout<<endl<<endl;
cout << "Sorting method: \n";
for (int i=0; i < m; i++) cout << i+1 << ": " << sortMethod[i] << endl;
// cin >> method;
method = 5;
cout<<endl;
int t = time(0);
QuickSort(A,n);
if (method > m) continue;
cout << sortMethod[method-1] << endl;
if (n <= 100) {
for (int i=0; i < n; i++) {
if (i> 0 && i%10==0) cout << endl;
cout << A[i] << " ";
}
cout << endl;
}
else {
cout << "Sorting completed in " << time(0) - t << " sec.\n";
}
cout << endl;
}
cout << "Program ends here."<<endl;
return 0;
}
When some of my input numbers have the same value, I get a "Segmentation fault: 11".
For example, an input of "4 7 7 3 1" would produce infinite lines of the following output: "start is 1 end is 3".
May I ask how should I improve my code? I know that Segfault 11 happens when you try to access an invalid memory, and i think that's likely what I did here, although i cant seem to identify the error. Thanks!

So this is what's happening here. Imagine that in a certain partition the first element (the pivot) is also the largest.
This means that in every iteration of the while loop the value of A[j]<=pivot will be true and i will be increased.
Since both i and j are increased by 1 in every iteration there value is the same, so at the end of the loop they are both equal to end+1.
Then you are invoking partition(A, start, i-1) which is really the same as partition(A, start, end) - meaning you have an infinite recursion which continues until you reach... well, stack overflow and the program crush with segfault.
The minimal fix will be to make sure that the sub partitions are strictly smaller than the original one by excluding the pivot from them. So something like this:
partition(A, start, i-2); // i-1 is the pivot, so we don't need to include it
partition(A, i, end);

Related

Why does my mergesort code always fail when sorting the right half in C++?

When I try to do the merge in C++, strange errors appear.
When I input an array of length 10 and values
[9, 8, 57, 2, 34, 21, 0, 4, 8, 6]
to sort, the first step should be to sort
[9, 8]
Then
[9, 8, 57]
, then it should be
[2, 34]
As shown in the figure below, the merge method can complete the sorting of 8, 9, and 57 on the left half (as shown in the green box).
But when it comes to sorting on the right half, the program can not even display this position correctly (The original value, as shown in the red box, arr[3] and arr[4] should have been 2 and 34, but here are 6 and 4255921 that have not been entered)
enter image description here
And another weird thing is that the final program also can't finish outputting the sorted array.
enter image description here
here is my code:
#include <iostream>
using namespace std;
int times = 0;//the times to call merge function
void merge(int* arr, int left, int mid, int right)
{
times++;
cout << "the " << times <<" times to call merge function" << endl;
//use a temp array to store the sorted array
int length =right-left+1;
int tmparr[length] = {0};
int i = left, j = mid+1;
int k;
for(k = 0; i <= mid && j <= right; k++)
{
if(arr[i] <= arr[j])
tmparr[k] = arr[i++];
else
tmparr[k] = arr[j++];
}
while(i <= mid)//if left half is not compeleted
tmparr[k++] = arr[i++];
while(j <= right)//else right half is not compelted
tmparr[k++] = arr[j++];
//cout to show the sorted array fragment
cout << "The array values between "<< left << " and " << right << "are currently:" << endl;
for(k = 0, i = left; k < length; k++)
{
arr[i++] = tmparr[k];
cout << arr[i - 1] << " ";
}
cout << endl;
}
void sort(int* a, int l, int r)
{
//when there is more than one element
if(l < r)
{
int mid = (l + r)/2;
sort(&a[l], l, mid); //sort the left half
sort(&a[mid+1], mid+1, r);//sort the right half
merge(&a[l], l, mid, r);
cout << "Complete the sorting between " << l <<" and " << r << endl << endl;
}
}
int main()
{
//enter array
int n;
cout << "enter the length of array:" << endl;
cin >> n;
cout << "enter the values of elements:" << endl;
int a[n];
for(int i = 0; i < n ; i++)
cin >> a[i];
//check the original array
cout << "the original array :" << endl;
for(int i = 0; i < n ; i++)
cout << a[i] << ' ';
cout << endl;
//mergesort
sort(a, 0, n-1);
//show the result
cout << "the results after mergersort:" << endl;
for(int i = 0; i < n ; i++)
{
cout << a[i] <<" ";
}
return 0;
}
Can someone tell me how to solve this weird but amazing problem o_o? thanks a lot :)
The array argument passed from the sort() function is wrong.
Writing like this:
sort(&a[l], l, mid);
You are firstly moving l elements ahead in &a[l], then moving l elements ahead again via the 2nd argument l.
Instead of this:
sort(&a[l], l, mid); //sort the left half
sort(&a[mid+1], mid+1, r);//sort the right half
merge(&a[l], l, mid, r);
You should write like this:
sort(a, l, mid); //sort the left half
sort(a, mid+1, r);//sort the right half
merge(a, l, mid, r);

C++: Quicksort words instead of numbers

I am trying to write a code that uses quicksort to sort words by alphabetical order, but when I run my code it gets stuck on inputting the user's words. What's the reason behind this? It works fine when I leave the array as an integer array. Thanks in advance!
#include <iostream>
#include <cstdlib>
#include <cstring>
using namespace std;
void quicksort(char a[], int size, int left, int right)
{
int i = left;
int j = right;
int pivot = a[(left+right)/2];
char temp;
while (i <= j)
{
while (a[i] < pivot) i++;
while (a[j] > pivot) j--;
if (i <= j)
{
temp = a[i];
a[i] = a[j];
a[j] = temp;
i++;
j--;
}
}
if (i < right)
quicksort(a, size, i, right);
if (j > left)
quicksort(a, size, left, j);
}
int main()
{
char a[10], n;
system("clear");
cout << "Enter the number of elements to be sorted: " << endl;
cin >> n;
cout << "Enter the elements to be sorted (press ENTER after each word): " << endl;
for (int i = 0; i < n; i++)
cin >> a[i];
quicksort(a, n, 0, n-1);
cout << endl;
cout << "The sorted elements are: " << endl;
for (int i = 0; i < n; i++)
cout << a[i] << " ";
cout << endl;
return 0;
}
You code may work but you're trying to read words in an array of char. You need to use a string (store a whole word) or an array of string (store multiple strings).
Your code may look like this:
int main()
{
string a[10], n;
system("clear");
cout << "Enter the number of elements to be sorted: " << endl;
cin >> n;
cout << "Enter the elements to be sorted (press ENTER after each word): " << endl;
for (int i = 0; i < n; i++)
{
cin >> a[i];
quicksort(a, n, 0, a[i].length -1);
}
cout << "The sorted elements are: " << endl;
for (int i = 0; i < n; i++)
cout << a[i] << " " << endl;
return 0;
}
Please have in mind the that the code structure in c++ it's different than python. Have a look to this coding and naming conventions
http://www.dofactory.com/reference/csharp-coding-standards
Thank you all for helping! This is the final solution:
#include <iostream>
#include <cstdlib>
#include <cstring>
using namespace std;
void quicksort(std::string a[], int size, int left, int right)
{
int i = left;
int j = right;
std::string pivot = a[(left+right)/2];
std::string temp;
while (i <= j)
{
while (a[i] < pivot) i++;
while (a[j] > pivot) j--;
if (i <= j)
{
temp = a[i];
a[i] = a[j];
a[j] = temp;
i++;
j--;
}
}
if (i < right)
quicksort(a, size, i, right);
if (j > left)
quicksort(a, size, left, j);
}
int main()
{
std::string a[100];
int n;
system("clear");
cout << "Enter the number of elements to be sorted: " << endl;
cin >> n;
cout << "Enter the elements to be sorted (press ENTER after each word): " << endl;
for (int i = 0; i < n; i++)
{
cin >> a[i];
}
quicksort(a, n, 0, n-1);
cout << endl;
cout << "The sorted elements are: " << endl;
for (int i = 0; i < n; i++)
cout << a[i] << " ";
cout << endl;
return 0;
}

C++ Binary Search Not Working Correctly - Finds Element Not in Array

I am running the binary search algorithm in C++ but it gives me spurious results. For example, searching for the value 21 gives me a
"Value is Found"
message but my array consists only of numbers from 0 to 20.
Any help is greatly appreciated.
#include <iostream>
#include <iomanip>
using namespace std;
int binarySearch(const int [], int, int, int, int ); // function prototype
int main()
{
const int arraySize = 10;
int arr[ arraySize ];
int key;
for( int i = 0; i <= arraySize; i++) // generate data for array
arr[i] = 2*i;
cout << "The array being searched is: " << endl;
for (int j = 0; j<=arraySize; j++) // print subscript index of the array
{
cout << setw(5) << j << " ";
}
cout << endl;
for (int z = 0; z<=arraySize; z++) // print elements of the array below index
{
cout << setw(5) << arr[z] << " ";
}
cout << "\n" <<"Enter value you want to search in array " << endl;
cin >> key;
int result = binarySearch(arr, key, 0, arraySize, arraySize); // function call
if (result == 1) // print result of search
cout << "Key is found " << endl;
else
cout << "Key not found " << endl;
return 0;
} // end main function
int binarySearch(const int a[], int searchKey, int low, int high, int length)
{
int middle;
while (low <= high){
middle = (low + high) / 2;
if (searchKey == a[middle]) // search value found in the array, we have a match
{
return 1;
break;
}
else
{
if( searchKey < a[middle] ) // if search value less than middle element
high = middle - 1; // set a new high element
else
low = middle + 1; // otherwise search high end of the array
}
}
return -1;
}
You are invoking undefined behavior because your for loop conditions are <=arraySize. Change it to <arraySize. On making this change, the code works perfectly for sample inputs.
By writing int arr[ arraySize ]; you are creating an array of 10 elements (i.e., from 0 to 9), while in the for loops, you start from 0 and move until 10.
Live Demo

Insertion sort implementation in C++ results in multiple errors

This is a console application on CodeBlocks 13.12.
I am getting a variety of errors when I run this Insertion Sort.
Sometimes it prints outrageously large values that weren't in the original array. Or sometimes it runs and sorts the array perfectly fine.
Can anybody please point out what could possibly be wrong? Sorry I'm a noob.
#include <iostream>
#include <ctime>
#include <cstdlib>
using namespace std;
void insertionSort(int arr[], int size);
int main()
{
int size;
srand(time(NULL));
cout << "Specify the size of your array: ";
cin >> size;
int theArray[size]; // creates an array of a size the user chooses
cout << endl << "Your current array: {";
for (int i = 0; i < size; i++) //prints out the original array
{
theArray[i] = rand() % 10000;
cout << theArray[i];
if (i != size - 1) // to beautify output
{
cout << ", ";
}
if (i % 10 == 0 && i != 0)
{
cout << endl;
}
}
cout << "}" << endl << endl;
insertionSort(theArray, size);
}
void insertionSort(int arr[], int size)
{
int begin = clock(); // are for timing the sort
for (int i = 0; i < size; i++) //does the sorting
{
int j = i + 1;
int temp = arr[j];
while (arr[i] > arr[j])
{
arr[j] = arr[i];
arr[i] = temp;
j--;
i--;
}
}
int end = clock(); // are for timing the sort
cout << endl << "Your sorted array is: {";
for (int i = 0; i < size; i++) // prints out sorted array
{
cout << arr[i];
if (i != size - 1)
{
cout << ", ";
}
if (i % 10 == 0 && i != 0)
{
cout << endl;
}
}
cout << "}" << endl << endl << "Your sort took: " << end - begin << " milliseconds" << endl << endl;
}
Additionally to #marom's answer, in your while loop, you don't put limitations neither on i or j, hence you try to access arr[-1], arr[-2] and so on. Also, you go back to the beginning of the sorted array, since you decrement i. Have a look at this code, compiled with g++ 4.8.1 gives no errors. Also, try to use std::swap defined in header <utility> since c++11 or in header <algorithm> until c++11.
#include <iostream>
#include <ctime>
#include <cstdlib>
#include <utility>
using namespace std;
void insertionSort(int arr[], int size);
int main()
{
int size;
srand(time(NULL));
cout << "Specify the size of your array: ";
cin >> size;
int theArray[size]; // creates an array of a size the user chooses
cout << endl << "Your current array: {";
for (int i = 0; i < size; i++) //prints out the original array
{
theArray[i] = rand() % 10000;
cout << theArray[i];
if (i != size - 1) // to beautify output
{
cout << ", ";
}
if (i % 10 == 0 && i != 0)
{
cout << endl;
}
}
cout << "}" << endl << endl;
insertionSort(theArray, size);
}
void insertionSort(int arr[], int size)
{
int begin = clock(); // are for timing the sort
for (int i = 0; i < size - 1; i++) //does the sorting
{
int j = i + 1;
int temp = arr[j];
while (j > 0 && arr[j] < arr[j - 1])
{
// ^^ this ensures that we don't try to access arr[-1]
swap(arr[j], arr[j-1]); //prefer std functions if they do the job you want
j--;//we don't go back
}
}
int end = clock(); // are for timing the sort
cout << endl << "Your sorted array is: {";
for (int i = 0; i < size; i++) // prints out sorted array
{
cout << arr[i];
if (i != size - 1)
{
cout << ", ";
}
if (i % 10 == 0 && i != 0)
{
cout << endl;
}
}
cout << "}" << endl << endl << "Your sort took: " << end - begin << " milliseconds" << endl << endl;
}
At least this is wrong:
void insertionSort(int arr[], int size)
{
int begin = clock(); // are for timing the sort
for (int i = 0; i < size; i++) //does the sorting
{
int j = i + 1;
When i is size-1 then j equals size and you get over the bounds of the array (valid values are from 0 to size-1 included). You need to limit your for loop to i < size-1
First advice : don't do all your printing or clock measure in your sort function. Keep that for your main program. Your sort function must remain clear and concise with no side effect.
Now, i find it better to split the code into 2 simple functions :
First, if arr is assumed already sorted up the index n-1
you want to insert the adequate element of the table at pos offset so that
arr will be sorted up to index n:
void insert(int arr[], int n){
int i=n, temp=arr[n];
while ( (arr[i-1]>temp) && (i>0) )
{
arr[i]=arr[i-1];
i--;
}
arr[i]=temp;
}
Now we just have to call our insertion for all offsets in arr except first one:
void insertionSort(int arr[], int size)
{
for(int n=1; n<size; n++) insert(arr,n);
}
As already mentioned by marom in his answer, when i = size - 1 you set j = size and access memory out of bounds, similarly, consider the case where j is set to the smallest element in the array, in that case you reach the left most position of the array by swapping the elements and decrementing, and eventually, i will become negative (since you do not put a bound to check if i becomes less than 0) and so will j and you will be accessing memory out of your bounds again.
Moreover, you are decrementing the value of i as well, which does not make sense, since by decrementing the value of i you are making extra runs for the external for loop.
So, your function shall look something like this ::
for (int i = 0; i < size - 1; i++) //changed the limit of for loop
{
int j = i + 1;
int temp = arr[j];
while ((j > 0) && (arr[j - 1] > arr[j])) //instead of working with the values of i, now we are doing everything with j
{
arr[j] = arr[j - 1];
arr[j - 1] = temp;
j--;
}
}
Hope this helps!

i know what causes the segfault, but why?

Ok, so I have a simple c++ program that's supposed to run a couple sorting algorithms on an array composed of ints and track the time each one takes.. pretty basic, however I've run into a problem.
When the program first starts, it asks how many items you would like in the array. My assignment involves setting the array at specific lengths from 100 items all the way to 750000. It'll handle many values, including up to around 600000. When I try 750000 however it immediately segfaults. A couple couts here and there led me to discover that the error happens when the fourth array (all of the same length) is initialized. The weird thing is that it only happens on my OS; at my school it works no problem. (i'm on the latest ubuntu while my school uses redhat. not sure if that's useful)
I'll include the complete code just for reference but the segfault occurs at line 27:
int array1[num], array2[num], array3[num], array4[num]; // initialize arrays
I know this because I initialized each array on separate lines and put couts in between. array1, 2, and 3 were initialized, then it segfaults. Again this ONLY happens when the arrays are longer than about 600000 or so. Anything less works fine.
Full code:
#include <iostream>
#include <cstdlib>
#include <ctime>
using namespace std;
void insertionSort(int array[], int size);
void bubbleSort(int array[], int size);
void mergeSort(int array[], int first, int last, int size);
void quickSort(int array[], int size);
int main()
{
cout << endl << endl << "\t\t**** Extra Credit Assignment- Sorting ****" << endl << endl << endl;
cout << "Enter the number of items to sort: ";
int num;
cin >> num;
while(cin.fail()) // while cin does not recieve an integer
{
cin.clear();
cin.ignore(1000, '\n');
cout << "Invalid entry. Try again: "; // try again
cin >> num;
}
int array1[num], array2[num], array3[num], array4[num]; // initialize arrays
int randNum, sizeOfArray = sizeof(array1)/sizeof(array1[0]); // random number, size of the arrays
srand(time(NULL)); // random seed (used with rand())
for(int i = 0; i < sizeOfArray; i++) // traverse through the array
{
randNum = rand() % 2147483647+1; // establish random number (from 1 to 2147483647)
array1[i] = array2[i] = array3[i] = array3[i] = randNum; // set randNum to all arrays at current index
}
time_t beginTime, endTime;
double elapsedTime;
cout << endl << "Elapsed time:" << endl << "\tInsertion Sort-\t";
time(&beginTime);
insertionSort(array1, sizeOfArray);
time(&endTime);
elapsedTime = difftime(endTime, beginTime);
cout << elapsedTime << " seconds" << endl << "\tBubble Sort-\t";
time(&beginTime);
bubbleSort(array2, sizeOfArray);
time(&endTime);
elapsedTime = difftime(endTime, beginTime);
cout << elapsedTime << " seconds" << endl << "\tMerge Sort-\t";
time(&beginTime);
mergeSort(array3, 0, sizeOfArray-1, sizeOfArray);
time(&endTime);
elapsedTime = difftime(endTime, beginTime);
cout << elapsedTime << " seconds"<< endl;
/* ********************* TESTING *************************
// *******************************************************
cout << "Insertion->Unsorted:\t";
for(int i = 0; i < sizeOfArray; i++)
{
cout << array1[i] << " ";
}
cout << endl;
insertionSort(array1, sizeOfArray);
cout << "Insertion->Sorted:\t";
for(int i = 0; i < sizeOfArray; i++)
{
cout << array1[i] << " ";
}
cout << endl;
cout << "Bubble->Unsorted:\t";
for(int i = 0; i < sizeOfArray; i++)
{
cout << array2[i] << " ";
}
cout << endl;
bubbleSort(array2, sizeOfArray);
cout << "Bubble->Sorted:\t\t";
for(int i = 0; i < sizeOfArray; i++)
{
cout << array2[i] << " ";
}
cout << endl;
cout << "Merge->Unsorted:\t";
for(int i = 0; i < sizeOfArray; i++)
{
cout << array3[i] << " ";
}
cout << endl;
mergeSort(array3, 0, sizeOfArray-1, sizeOfArray);
cout << "Merge->Sorted:\t\t";
for(int i = 0; i < sizeOfArray; i++)
{
cout << array3[i] << " ";
}
cout << endl; */
return 0;
}
void insertionSort(int array[], int size)
{
for(int i = 1; i < size; i++)
{
int item = array[i], index = i;
while(index > 0 && array[index-1] > item)
{
array[index] = array[index-1];
index--;
}
array[index] = item;
}
}
void bubbleSort(int array[], int size)
{
bool sorted = false;
for(int i = 1; i < size && !sorted; i++)
{
sorted = true;
for(int i2 = 0; i2 < size-i; i2++)
{
int nextI = i2+1;
if(array[i2] > array[nextI])
{
swap(array[i2], array[nextI]);
sorted = false;
}
}
}
}
void merge(int array[], int first, int mid, int last, int size)
{
int tempArray[size];
int first1 = first, first2 = mid+1;
int last1 = mid, last2 = last;
int index = first1;
while(first1 <= last1 && first2 <= last2)
{
if(array[first1] < array[first2])
{
tempArray[index] = array[first1];
first1++;
}
else
{
tempArray[index] = array[first2];
first2++;
}
index++;
}
while(first1 <= last1)
{
tempArray[index] = array[first1];
first1++;
index++;
}
while(first2 <= last2)
{
tempArray[index] = array[first2];
first2++;
index++;
}
for(index = first; index <= last; index++)
{
array[index] = tempArray[index];
}
}
void mergeSort(int array[], int first, int last, int size)
{
if(first < last)
{
int mid = (first+last)/2;
mergeSort(array, first, mid, size);
mergeSort(array, mid+1, last, size);
merge(array, first, mid, last, size);
}
}
Any help is greatly appreciated. It might be a memory limitation on my system? I really don't know lol just a thought.
You can't allocate such big arrays on the stack which has a fixed limited size, try:
int* array1 = new int[num];
As others have noted, the SEGV you're getting is due to overflowing the stack. The reason it happens on your ubuntu machine and not your school's redhat machine is likely due to differences in the default stack size.
You may be able to change your default stack size with ulimit -s which, with no additional arguments, will print your current stack size in kilobytes. For example, on my machine, that prints 8192 or 8 megabytes. I can raise it to 16MB with ulimit -s 16384
An array of 750000 ints will require about 3MB of stack space (4 bytes per int), so 4 such arrays (like you have) will require 12MB...
You've allocated very large arrays on the stack and you're overflowing the stack. If you new them or make them static, they'll be allocated on the heap and you won't fail.
It's because the stack is not an infinite resource. When you do int x[big_honkin_number], it tries to allocate enough space on the stack for that array.
You can usually compile/link your code to give you more stack but a better solution is to use dynamic memory allocation (i.e., new).