Quicksort does not work with large arrays - c++

I'm trying to sort large arrays with Quicksort and Mergesort to evaluate performances.
I've a problem: if I impose a large number of elements in an array, the program does not start to generate values randomly. In the code below, if N=500000, it works very well. If N > 500000, for example 1000000, it does not work. With MergeSort the limit is 200000. I tried on multiple devices, C++ on Eclipse IDE.
Someone knows how to solve the problem?
#define N 800000
#include <iostream>
#include <cstdlib>
#include <time.h>
#include <chrono>
using namespace std;
void Exchange(int *a, int *b) {
int temp;
temp = *a;
*a = *b;
*b = temp;
}
int Partition(int A[], int p, int r) {
int x = A[r];
int i = p - 1;
for (int j = p; j <= r; j++) {
if (A[j] < x) {
i++;
Exchange(&A[i], &A[j]);
}
}
Exchange(&A[i + 1], &A[r]);
return i + 1;
}
int RPartition(int A[], int p, int r) {
srand(time(NULL));
int i = p + rand() % (p - r);
Exchange(&A[i], &A[r]);
return Partition(A, p, r);
}
void QuickSort(int A[], int p, int r) {
if (p < r) {
int q = RPartition(A, p, r);
QuickSort(A, p, q - 1);
QuickSort(A, q + 1, r);
}
}
void Stampa(int A[], int n) {
for (int i = 0; i < n; i++) {
cout << A[i] << "\n";
}
}
int main() {
srand(50000);
int A[N];
for (int i = 0; i < N; i++) {
A[i] = rand();
}
cout << "Array non ordinato\n";
Stampa(A, N);
auto start = std::chrono::system_clock::now();
QuickSort(A, 0, N - 1);
auto end = std::chrono::system_clock::now();
cout << "\nArray ordinato\n";
Stampa(A, N);
std::chrono::duration<double> elapsed = end - start;
cout << "Elapsed time: " << elapsed.count() << "s";
}

The explanation is very simple: you allocate the array as a local variable with automatic storage (aka on the stack), hence if the size is too large, you get a stack overflow.
You should either allocate the array from the heap or define it as static data.
Here is a modified version:
int main() {
srand(time(NULL));
int *A = new int[N];
for (int i = 0; i < N; i++) {
A[i] = rand();
}
cout << "Array non ordinato\n";
Stampa(A, N);
auto start = std::chrono::system_clock::now();
QuickSort(A, 0, N - 1);
auto end = std::chrono::system_clock::now();
cout << "\nArray ordinato\n";
Stampa(A, N);
std::chrono::duration<double> elapsed = end - start;
cout << "Elapsed time: " << elapsed.count() << "s";
delete[] A;
}

Related

Merge Sort C++ Incorrectly Sorting

I'm writing a program that will do 5 different sorting functions and compare times across them. I'm outputting the 1000th element of each array to see if it's sorted correctly, all of my other sorts except merge sort are producing the correct number. Merge sort is close but off, it is within an element or two of getting the correct answer (outputting 25011 rather than 25034 for the 1000th element.) Here is the code for my merge sort:
//Zach Heesaker. CS3. Project 4
#include <iostream>
#include <fstream>
#include <string>
#include <iomanip>
#include <stdio.h>
#include <ctime>
#include <cstdio>
#include <time.h>
#include <stdint.h>
#include<list>
#include<cmath>
using namespace std;
const int n = 10000;
int numswaps, numcompares;
void swap(int& a, int& b);
void print(int arr[], int n, ofstream& outf, double time);
void read(int arr[], int size);
void mergepass(int arr[], int y[], int& n, int& L);
void mergeSort(int arr[], int n);
void merge(int arr[], int y[], int L, int m, int n);
int main()
{
int numsorts = 5;
string whichsort;
ofstream outf("output.ot");
int arr[n + 1];
clock_t start, end;
double time;
outf << "Sort Name: " << setw(5) << " " << "1000th Element: " << setw(1) << " " << "Number of Moves: " << setw(1) << " " << "Time taken: " << endl;
read(arr, n);
numcompares = 0;
numswaps = 0;
start = clock();
mergeSort(arr, n);
end = clock();
time = double(end - start) / double(CLOCKS_PER_SEC);
}
void mergeSort(int arr[], int size)
{
int L = 1;
int y[n + 1];
while (L < n)
{
mergepass(arr, y, size, L);
L = 2 * L;
mergepass(y, arr, size, L);
L = 2 * L;
}
}
void merge(int arr[], int y[], int L, int m, int n)
{
int i, j, k, t;
i = L;
k = L;
j = m + 1;
while ((i <= m) && (j <= n))
{
numcompares++;
if (arr[i] <= arr[j])
{
numswaps++;
y[k++] = arr[i++];
}
else
{
numswaps++;
y[k++] = arr[j++];
}
}
if (i > m)
{
for (t = j; t <= n; t++)
{
numswaps++;
y[k + t - j] = arr[t];
}
}
else
{
for (t = i; t <= m; t++)
{
numswaps++;
y[k + t - i] = arr[t];
}
}
}
void mergepass(int arr[], int y[], int& n, int& L)
{
int i, t;
i = 1;
while (i <= n - 2 * L + 1)
{
merge(arr, y, i, i + L - 1, i + 2 * L - 1);
i = i + 2 * L;
}
if ((i + L - 1) < n)
{
merge(arr, y, i, i + L - 1, n);
}
else
{
for (t = i; t <= n; t++)
{
numswaps++;
y[t] = arr[t];
}
}
}
void swap(int& a, int& b)
{
int temp;
temp = a;
a = b;
b = temp;
numswaps += 3;
}
void print(int arr[], int n, ofstream& outf, double time)
{
outf << left << setw(6) << " " << left << arr[1000] << setw(12) << " " << left << numswaps << setw(10) << " " << left << "\t" << time << endl;
}
void read(int arr[], int size)
{
ifstream ifs("input.txt");
int i = 0;
while (!ifs.eof())
{
ifs >> arr[i];
i++;
}
}
int merge(int arr[], int left, int right)
{
int pivot = arr[right];
int k = (left - 1);
for (int j = left; j <= right - 1; j++)
{
numcompares++;
if (arr[j] < pivot)
{
k++;
swap(arr[k], arr[j]);
}
}
swap(arr[k + 1], arr[right]);
return (k + 1);
}
Any ideas as to what is going wrong in here? Thank you.

How do I resolve "Cannot Access Memory at Address c++" issue

I am getting the following debug error from Eclipse IDE
Failed to execute MI command:
-data-evaluate-expression *((array500000)+30000)#10000
Error message from debugger back end:
Cannot access memory at address 0x42f250
but I am not sure how to resolve the issue. Would anyone give me any advice please? I am new to coding.
Tried different IDE. My code works on online IDE but not other IDEs.
using namespace std;
using namespace std::chrono;
void Swap(int *x,int *y) {
int temp=*x;
*x=*y;
*y=temp;
}
void Insertion(int A[],int n) {
int i,j,x;
for(i=1;i<n;i++) {
j=i-1;
x=A[i];
while(j>-1 && A[j]>x){
A[j+1]=A[j];
j--;
}
A[j+1]=x;
}
}
void Merge(int A[],int l,int mid,int h) {
int i=l,j=mid+1,k=l;
int B [500000];
while(i<=mid && j<=h) {
if(A[i]<A[j])
B[k++]=A[i++];
else
B[k++]=A[j++];
}
for(;i<=mid;i++) {
B[k++]=A[i];
}
for(;j<=h;j++) {
B[k++]=A[j];
}
for(i=l;i<=h;i++) {
A[i]=B[i];
}
}
void MergeSort(int A[],int l,int h) {
if(l<h) {
int mid=(l+h)/2;
MergeSort(A,l,mid);
MergeSort(A,mid+1,h);
Merge(A,l,mid,h);
}
}
void ArrayAscend (int A[], int n) {
for (int a = 0; a < n ; a++) {
A [a] = a + 1;
}
}
void ArrayRandom (int A[], int n) {
ArrayAscend (A,n);
srand (time(NULL));
for (int i= n-1 ; i > 0; i--) {
int j = rand () % (i+1);
Swap (&A[i], &A[j]);
}
}
void ArrayDescend (int A[], int n) {
for (int a = 0; a < n ; a++) {
A [a] = n - a;
}
}
int main() {
int arraySize500000 = 500000;
int array500000[arraySize500000] = {};
cout << "*********************Insertion Sort*********************" <<endl;
cout << "---------- Arrays with 500000 Integers ----------" <<endl;
ArrayAscend (array500000,arraySize500000);
auto t1 = system_clock::now();
Insertion(array500000,arraySize500000);
auto t2 = system_clock::now();
auto duration1 = duration_cast<microseconds>(t2-t1);
cout << "Array in ascending order took " << duration1.count()<<" microseconds"<<endl;
ArrayDescend (array500000,arraySize500000);
auto t3 = system_clock::now();
Insertion(array500000,arraySize500000);
auto t4 = system_clock::now();
auto duration2 = duration_cast<microseconds>(t4-t3);
cout << "Array in descending order took " << duration2.count()<<" microseconds"<<endl;
ArrayRandom (array500000,arraySize500000);
auto t5 = system_clock::now();
Insertion(array500000,arraySize500000);
auto t6 = system_clock::now();
auto duration3 = duration_cast<microseconds>(t6-t5);
cout << "Array in random order took " << duration3.count()<<" microseconds"<<endl;
return 0;
}
I expect the output of the duration of each insertion sorts.
int B [500000];
int arraySize500000 = 500000;
int array500000[arraySize500000] = {};
Even if this is converted to a constexpr, as pointed out by John, these will create 2MB arrays on the stack. Visual Studio for example only has 1MB of stack allocated.
You should use std::vector<int> array500000(500000) instead.

Obtaining Large Signed Value in my QuickSort/InsertionSort Algorithm

so my code is essentially working; however, I need clarification as to why when I implement insertion sort when I get to less than 20 elements in a subarray it adds a large signed value at the end when I print them out.
#include <iostream>
#include <cstdlib>
#include <ctime>
using namespace std;
void swap(int* a, int* b)
{
int t = *a;
*a = *b;
*b = t;
}
int partitionMiddle (int arr[], int low, int high) {
int pivot = arr[high];
int i = (low - 1);
for (int j = low; j <= high- 1; j++)
{
if (arr[j] <= pivot)
{
i++; // increment index of smaller element
swap(&arr[i], &arr[j]);
}
}
swap(&arr[i + 1], &arr[high]);
return (i + 1);
}
void chooseMiddle....
void chooseMedian{code here...}
void insertionSort(int arr[], int low, int high){
int j;
for(int i = low+1; i <= high; i++){
j = i;
while(j>low && arr[j-1]> arr[j]){
swap(arr[j], arr[j-1]);
j= j-1;
}
}
}
void quickSortMiddle(int arr[], int low, int high)
{
int pi = partitionMiddle(arr, low, high);
if (high-low > 20)
{
quickSortMiddle(arr, low, pi - 1);
quickSortMiddle(arr, pi + 1, high);
}
else {
insertionSort(arr, low, pi);
insertionSort(arr, pi+1, high);
}
}
void printArray(int arr[], int size)
{
int i;
for (i=0; i < size; i++)
printf("%d ", arr[i]);
}
int main()
{
clock_t x, k;
x = clock();
int arr[10000];
srand((unsigned)time(0));
for(int i =0; i<10000; i++) {
arr[i] = (rand()%100)+1;
}
int n = sizeof(arr)/sizeof(arr[0]);
cout << "Original array: " ;
printArray(arr, n);
cout << endl;
cout << "With Insertion Sort & Middle Element";
chooseMiddle(arr, 0, n-1);
quickSortMiddle(arr, 0, n-1);
cout << endl;
k = clock();
// can comment this one vvvv or the previous one out to try them both
cout << "With Insertion Sort & Median Element";
chooseMedian(arr, 0, arr[((n-1)/2)], n-1);
quickSortMiddle(arr, 0, n-1);
cout << endl;
k = clock();
printf("Sorted array: ");
printArray(arr, n);
cout << endl;
cout << "CPU Time : ";
cout << k-x;
cout << endl << endl;
return 0;
}
My expected results were to not just have -272632368 at the very end of my sorted array when I print it out. I think I went out of bounds in my insertion sort algorithm but I'm not sure as to where. Maybe someone with a better eye can catch it.
**** EDIT...So I went to debug the code on my own and it the number was appearing there somehow having to do with the n-1 parameter when I was calling the chooseMedian/chooseMiddle or quickSortMiddle functions. I changed it to simply being 'n'. I don't get why, but it's working now. If someone can explain why, that'd be helpful, but if not, that's okay too.
****EDIT2...So now that I have your attention, can you please explain to me why using pointers in the swap function is better than not? I found this example of a swap function online and don't know why they used pointers.

Calling function from one class in another in C++

So, I am writing a program in C++ that has a function in the Sort class that I wish to call in the Main class. The function has several data members used that are present in that class, that are not present in the Main class and I keep getting a C2660 error, that "Function does not take 0 arguments". Is there a way (short of writing a bunch of getters and setters) to resolve this?
#include "Sort.h"
#include "Timer.h"
using namespace std;
int main
{
Sort *sort = new Sort();
Timer ti;
sort->SetRandomSeed(12345);
sort->InitArray();
cout << "starting InsertionSort" << endl;
ti.Start();
sort->InsertionSort();
ti.End();
cout << "Insertion sort duration: " << ti.DurationInMilliSeconds() << "ms" << endl;
//sort->InitList();
//cout << "starting InsertionSortList()" << endl;
//ti.Start();
//sort->InsertionSortList();
//ti.End();
//cout << "Insertion sort list duration: " << ti.DurationInMilliSeconds() << "ms" << endl;
sort->InitArray();
cout << "starting SelectionSort" << endl;
ti.Start();
sort->SelectionSort();
ti.End();
cout << "SelectionSort duration: " << ti.DurationInMilliSeconds() << "ms" << endl;
sort->InitArray();
cout << "starting MergeSort" << endl;
ti.Start();
sort->MergeSort();
ti.End();
cout << "MergeSort duration: " << ti.DurationInMilliSeconds() << "ms" << endl;
sort->InitArray();
cout << "starting QuickSort" << endl;
ti.Start();
sort->QuickSort();
ti.End();
cout << "QuickSort duration: " << ti.DurationInMilliSeconds() << "ms" << endl;
sort->InitVector();
cout << "starting std::sort() of Vector<int>" << endl;
ti.Start();
sort->VectorSort();
ti.End();
cout << "std::sort() duration: " << ti.DurationInNanoSeconds() << "ns" << endl;
delete sort;
cout << endl <<"Press [Enter] key to exit";
getchar();
}
Sort.cpp
//const int for array
int num = 10000000;
int val = 10000;
//array
int *tmpArray, *qArr, *insArr, *selArr, *mergArr = NULL;
int low, high;
//duration for timer
int duration = 0;
Sort::Sort()
{
}
Sort::~Sort()
{
}
void Sort::InitArray()
{
//int for index
int i = 0;
tmpArray = new int[num];
qArr = new int[num];
insArr = new int[num];
selArr = new int[num];
mergArr = new int[num];
//fill temp array with sequential numbers
for (int i = 0; i < num; i++)
{
tmpArray[i] = 1 + rand() % val;
}
for (i = 0; i < num; i++)
{
qArr[i] = tmpArray[i];
insArr[i] = tmpArray[i];
selArr[i] = tmpArray[i];
mergArr[i] = tmpArray[i];
}
low = qArr[0];
high = qArr[num - 1];
int n = sizeof(tmpArray) / sizeof(tmpArray[0]);
}
void Sort::InitVector()
{
vector<int> v(num);
std::generate(v.begin(), v.end(), std::rand);
}
void Sort::InitList()
{
// A set to store values
std::list<int> l;
// Loop until we get 50 unique random values
while (l.size() < num)
{
l.push_back(1 + rand() % val);
}
for (int n : l) {
std::cout << n << '\n';
}
}
//setting seed
void Sort::SetRandomSeed(unsigned int seed)
{
seed = rand();
}
void Sort::InsertionSort()
{
int i, key, j;
for (i = 1; i < n; i++)
{
key = insArr[i];
j = i - 1;
/* Move elements of arr[0..i-1], that are
greater than key, to one position ahead
of their current position */
while (j >= 0 && insArr[j] > key)
{
insArr[j + 1] = insArr[j];
j = j - 1;
}
insArr[j + 1] = key;
}
delete[] insArr;
insArr = NULL;
}
int Sort::partition(int qArr[], int low, int high)
{
int pivot = qArr[high]; // pivot
int i = (low - 1); // Index of smaller element
for (int j = low; j <= high - 1; j++)
{
// If current element is smaller than or
// equal to pivot
if (qArr[j] <= pivot)
{
i++; // increment index of smaller element
swap(&qArr[i], &qArr[j]);
}
}
swap(&qArr[i + 1], &qArr[high]);
return (i + 1);
}
void Sort::QuickSort(int qArr[], int low, int high)
{
if (low < high)
{
/* pi is partitioning index, arr[p] is now
at right place */
int pi = partition(qArr, low, high);
// Separately sort elements before
// partition and after partition
QuickSort(qArr, low, pi - 1);
QuickSort(qArr, pi + 1, high);
}
delete[] qArr;
qArr = NULL;
}
void Sort::SelectionSort()
{
int i, j, min_idx;
// One by one move boundary of unsorted subarray
for (i = 0; i < n - 1; i++)
{
// Find the minimum element in unsorted array
min_idx = i;
for (j = i + 1; j < n; j++)
if (selArr[j] < selArr[min_idx])
min_idx = j;
// Swap the found minimum element with the first element
swap(&selArr[min_idx], &selArr[i]);
}
delete[] selArr;
selArr = NULL;
}
void Sort::swap(int *xp, int *yp)
{
int temp = *xp;
*xp = *yp;
*yp = temp;
}
void Sort::VectorSort()
{
std::sort(v.begin(), v.end());
}
/* l is for left index and r is right index of the
sub-array of arr to be sorted */
void Sort::merge(int mergArr[], int l, int m, int r)
{
int i, j, k;
int n1 = m - l + 1;
int n2 = r - m;
int* L;
int* R;
/* create temp arrays */
L = new int[n1];
R = new int[n2];
/* Copy data to temp arrays L[] and R[] */
for (i = 0; i < n1; i++)
L[i] = mergArr[l + i];
for (j = 0; j < n2; j++)
R[j] = mergArr[m + 1 + j];
/* Merge the temp arrays back into arr[l..r]*/
i = 0; // Initial index of first subarray
j = 0; // Initial index of second subarray
k = l; // Initial index of merged subarray
while (i < n1 && j < n2)
{
if (L[i] <= R[j])
{
mergArr[k] = L[i];
i++;
}
else
{
mergArr[k] = R[j];
j++;
}
k++;
}
/* Copy the remaining elements of L[], if there
are any */
while (i < n1)
{
mergArr[k] = L[i];
i++;
k++;
}
/* Copy the remaining elements of R[], if there
are any */
while (j < n2)
{
mergArr[k] = R[j];
j++;
k++;
}
}
void Sort::MergeSort(int mergArr[], int l, int r)
{
if (l < r)
{
// Same as (l+r)/2, but avoids overflow for
// large l and h
int m = l + (r - l) / 2;
// Sort first and second halves
MergeSort(mergArr, l, m);
MergeSort(mergArr, m + 1, r);
merge(mergArr, l, m, r);
}
delete[] mergArr;
mergArr = NULL;
}
Sort.h
#include <iomanip>
#include <fstream>
#include <string>
#include <queue>
#include <stack>
#include <vector>
#include<iostream>
#include<cstdio>
#include<sstream>
#include<algorithm>
#include<list>
using namespace std;
#pragma once
class Sort
{
public:
Sort();
~Sort();
void InitArray();
void InitVector();
void InitList();
void SetRandomSeed(unsigned int seed);
int n, right, left, l, r, m;
vector<int> v;
void InsertionSort();
int partition(int qArr[], int low, int high);
void QuickSort(int qArr[], int low, int high);
void swap(int * xp, int * yp);
void VectorSort();
void MergeSort(int arr[], int l, int r);
void merge(int arr[], int l, int m, int r);
void SelectionSort();
};
Ignoring the Timer class (those are all good) here is the rest of the code. The C2660 errors are shown for the sort->MergeSort() and sort->QuickSort() calls in main.
I resolved the issues myself. I created helper functions in the Sort class that have no arguments and call the functions themselves to use in the main. Helper Functions shown below.
Sort.cpp
//method for Main to run to prevent C2660 errors
void Sort::mergeHelper()
{
MergeSort(mergArr, l, r);//call merge sort method
}
//method for Main to run to prevent C2660 errors
void Sort::quickHelper()
{
QuickSort(qArr, low, high);//call quick sort method
}
int Main
{
sort->quickHelper();
sort->mergeHelper();
}

quicksort, helper class problems, timesort, vector, c++

my biggest problem is getting the quickSortHelper class to work. i know what i want the parameters to be, and the stuff inside i need to call on is what i can't figure out. i've tried a mixture of using the partition and quicksort but i can't figure it out. the code is written like this because i will be using a timesort class in the future to solve and time 6+ sorting algorithms. i got it to work by just throwing the code inside main. but all i want inside main is what i have here.
#include <iostream>
#include <algorithm>
#include <vector>
#include <chrono>
#include <functional>
#include <random>
//i know not all the above libraries are being used, once quickSort is
//working i plan on adding it to 5 other sorting algorithms, where these
//are neccessary.
using namespace std;
void quickSort(vector<int>&, int, int);
int partition(vector<int>&, int, int);
double timeSort(vector<int> &v, function<void(vector<int>&)>f);
int main()
{
vector<int>intVec(1000);
generate(intVec.begin(), intVec.end(), rand);
int p = 0;
int q = 1000;
quickSort(intVec, p, q);
auto time = timeSort(intVec, quickSort);
for (auto i = 0u; i != intVec.size(); ++i)
cout << intVec[i] << " ";
cout << "\nQuick sort took " << time << " nanoseconds\n";
char chubby;
cin >> chubby;
return 0;
}
double timeSort(vector<int> &v, function<void(vector<int>&)>f)
{
auto start = chrono::high_resolution_clock::now();
f(v);
auto end = chrono::high_resolution_clock::now();
return static_cast<double>(((end - start).count()));
}
int partition(vector<int>&intVec, int p, int q)
{
int x = intVec[p];
int i = p;
int j;
for (j = p + 1; j < q; j++)
{
if (intVec[j] <= x)
{
i = i + 1;
swap(intVec[i], intVec[j]);
}
}
swap(intVec[i], intVec[p]);
return i;
}
void quickSort(vector<int>&intVec, int p, int q)
{
int r;
if (p < q)
{
r = partition(intVec, p, q);
quickSort(intVec, p, r);
quickSort(intVec, r + 1, q);
}
}
void quickSortHelper(vector<int>&intVec)
{
//i want to make a call to the timeSort function with
//quickSortHelper, i can't use quickSort directly because timeSort
//only has 2 parameters, the vector to be solved, and the method of
//solving it. i know
}
I suggest simplifying your program:
int main(void)
{
vector<int>intVec(1000);
unsigned int duration = 0;
for (unsigned int iteration = 0;
iteration < 1000000;
++iteration)
{
generate(intVec.begin(), intVec.end(), rand);
int p = 0;
int q = 1000;
auto start = chrono::high_resolution_clock::now();
quickSort(intVec, p, q);
auto end = chrono::high_resolution_clock::now();
duration += (end - start);
}
cout << "Average time for quicksort: " << (duration / 1000000) << "\n";
cout.flush();
return 0;
}
I made the following changes:
1) Running the sort for many iterations to get an average duration.
2) Removed the timing function; it only complicates things.
Umm... If I understand correctly, this should do it:
void quickSortHelper(vector<int>&intVec)
{
quickSort(intVec, 0, intVec.size());
}