QuickSort not sorting array - c++

I've been trying to make a qsort algorithm, but so far I've failed miserably. Keep in mind I'm kind of a newbie when it comes to programming, so yeah. After I build and run, and input my array, it returns the same exact array, instead of sorting it. Here's the code in question:
#include <iostream>
using namespace std;
int v[11], i, n, st, dr;
void qsort (int v[11], int st, int dr)
{
int i=st, j=dr;
int aux;
int pivot = v[(st+dr)/2];
while(i<=j)
while(v[i]<pivot)
{
i++;
if(i<=j)
{
aux=v[i];
v[i]=v[j];
v[j]=aux;
i++;
j--;
}
}
if(st<j)
qsort(v,st,j);
if(i<dr)
qsort(v,i,dr);
}
int main()
{
cin>>n;
for(int i=1;i<=n;i++)
cin>>v[i];
st=v[1];
dr=v[n];
qsort(v, st, dr);
cout<<"vectorul sortat este"<<' ';
for(i=1;i<=n;i++)
cout<<v[i]<<' ';
return 0;
}
Thanks in advance!

st and dr should be the initial and final indices where you want to sort, not the values (also, keep in mind that in C++ a vector on n elements has indices from 0 to n-1, so fix also your for loops), so you have to change
st=v[1];
dr=v[n];
to
st=0
dr=n-1
or simply:
qsort(v, 0, n-1);

Related

Quick sort: Pivot is the first element that is greater than its neighbor

I am learning quick sort and I found an algorithm where pivot is the first element that is greater than its neighbor, here is pseudo code
void quicksort(int i,int j)
{
pivotindex=findpivot(i,j);
if(pivotindex!=-1)
{
pivot=a[pivotindex];
k=partition(i,j,pivot); // l
quicksort(i,k-1);
quicksort(k,j);
}
}
int findpivot(int i, int j)
{
for i=0 to j
{
if(a[i]>a[i+1])
return(i);
else if(a[i]<a[i+1])
return(i+1);
else
continue;
}
return(-1);
}
int partition(int i, int j, int pivot)
{
int l, r;
l=i, r=j;
do
{
swap(a[l],a[r]);
while(a[l]<pivot)
l=l+1;
while(a[r]>=pivot)
r=r-1;
} while(l<r);
return(l);
}
Will this pseudocode work fine?
I tried to write c++ code for this, here is my code
#include <iostream>
using namespace std;
void swap(int *i,int *j){
int temp = *i;
*i = *j;
*j = temp;
}
int partition(int l, int r, int idx, int arr[]){
do{
int index = arr[idx];
swap(&arr[l],&arr[r]);
//cout<<arr[l]<<" "<<arr[r]<<" pivot : "<<index<<endl;
while(arr[l]<index){
l=l+1;
}
while(arr[r]>=index){
r=r-1;
}
}while(l<r);
return l;
}
int findpivot(int l,int r,int arr[]){
for(int i = l; i<=r; i++){
if(arr[i]>arr[i+1]){
return i;
}
else if(arr[i+1]>arr[i]){
return i+1;
}
else{
continue;
}
}
return(-1);
}
void Quicksort(int l, int r,int arr[]){
int idx = findpivot(l,r,arr);
if(idx!=-1){
int pivot = arr[idx];
int k = partition(l,r,idx,arr);
Quicksort(l,k-1,arr);
Quicksort(k,r,arr);
}
}
int main()
{
int arr[10] = {19,23,11,43,24,68,98,47,99,89};
Quicksort(0,9,arr);
cout<<"final"<<endl;
for(int i =0;i<10;i++){
cout<<arr[i]<<" ";
}
return 0;
}
My code does fine till these steps and then it turns into an infinite loop, is something wrong with my code, or is the pseudocode wrong?
{89,23,11,43,24,68,98,47,99,19}
{19,23,11,43,24,68,98,47,99,89}
{19,11,23,43,24,68,98,47,99,89}
{11,19}
can someone help me with this.
In addition to what #stark says in a comment about the initial value in the pseudocode's iteration in findpivot, the termination condition is clearly incorrect. Your implementation fixes the initial value (which was probably a typo) but repeats the problem with the termination: for(int i = l; i<=r; i++).
But the termination condition must be i < r. If i is equal to r, the loop will access element a[r+1], which is outside the range (and possibly outside the array). In addition, the algorithm depends on findpivot detecting the end-of-recursion condition, which is when all the elements in the range are equal, not when all the elements in the range and the next element are equal. Hence the endless loop.

I am getting garbage values in my Merge Sort code

I am trying to implement merge sort algorithm in C++. This is my code.Logic seems to be fine.
But the output I'm getting is garbage values.I'm not able to get where the problem is in the code.
I think my logic is correct but I'm not sure.
#include <iostream>
using namespace std;
void Merge(int A[],int L[],int nL,int R[],int nR);
void MergeSort(int A[]);
//Function to Merge Arrays L and R into A.
//nL = number of elements in L
//nR = number of elements in R.
void Merge(int A[],int L[],int nL,int R[],int nR)
{
// i - to mark the index of left subarray (L)
// j - to mark the index of right sub-raay (R)
// k - to mark the index of merged subarray (A)
int i=0;
int j=0;
int k=0;
while(i<nL && j<nR)
{
if(L[i]<=R[i])
{ A[k]=L[i];
i=i+1;
}
else
{ A[k]=R[j];
j=j+1;
}
k=k+1;
}
while(i<nL)
{ A[k]=L[i];
i=i+1;
k=k+1;
}
while(j<nR)
{ A[k]=R[j];
j=j+1;
k=k+1;
}
}
// Recursive function to sort an array of integers.
void MergeSort(int A[],int n)
{
if (n<2) return;//base condition.If the array has less than two
//elements, do nothing
int mid=n/2;
// create left and right subarrays
// mid elements (from index 0 till mid-1) should be part of left sub-
//array
// and (n-mid) elements (from mid to n-1) will be part of right sub-
//array
int left[mid];
int right[n-mid];
for(int i=0;i<mid-1;i++) left[i]=A[i];// create left subarray
for(int i=mid;i<n-1;i++) right[i-mid]=A[i];// create right subarray
MergeSort(left,mid);
MergeSort(right,n-mid);
Merge(A,left,mid,right,n-mid);
}
int main()
{ int A[]={2,4,7,1,5,3};
int n=sizeof(A)/sizeof(A[0]);
MergeSort(A,n);
for(int i=0;i<n;i++) cout<<A[i]<<" ";
return 0;
}
Expected output is 1 2 3 4 5 7
But actual is 0 -785903160 1 0(every time it's different)
This has been answered at, how-to-implement-classic-sorting-algorithms-in-modern-c. But I thought I'd post an answer that beginners my find valuable as I've seen this asked many times in the past. It must be a popular homework question.
In my opinion, if this is a modern C++ assignment, there should be a lot less of using indexing.
So in this implementation, I have not used std::merge and wrote the merge so some method could be seen.
Avoid the idiom: using namespace std; Why it is taught is beyond me. Typedef your types, it is much clearer.
using data_vect = std::vector<int>;
Hopefully this is clear enough and completely done with iterators. It is not as efficient as possible, the push_back in Merge could be avoided among other things. I DuckDucked this sort and the first few hits were not that great.
#include <iostream>
#include <vector>
using data_vect = std::vector<int>;
using dv_iter = data_vect::iterator;
data_vect Merge(data_vect& first, data_vect& second)
{
data_vect result;
dv_iter fval = first.begin();
dv_iter sval = second.begin();
for (;fval != first.end() || sval != second.end();)
{
if (fval == first.end())
result.push_back(*sval++);
else if (sval == second.end())
result.push_back(*fval++);
else if (*fval < *sval)
result.push_back(*fval++);
else
result.push_back(*sval++);
}
return result;
}
void MergeSort(data_vect& input)
{
int half = input.size() / 2;
if (! half)
return;
data_vect left(input.begin(), input.begin() + half );
data_vect right(input.begin() + half, input.end());
MergeSort(left);
MergeSort(right);
input = Merge(left, right);
}
int main()
{
data_vect A = { 6,2,7,4,1,5,3 };
MergeSort(A);
for ( auto& val : A )
std::cout << val << " ";
return 0;
}
Although understandable,
it is not possibile in C++ to declare an array with a variable size, e.g. int[mSize].
All arrays must have a constant size, e.g. int[10] or
const int mSize = 10;
int[mSize] mArray...
You want a storage container which has a variable size. as #PaulMcKenzie suggested,
you might want to use a Vector object. Your code would look something like this:
#include <iostream>
#include <vector>
using namespace std;
void Merge(vector<int>& A, vector<int>& L, vector<int>& R);
void MergeSort(vector<int>& A);
//Function to Merge Arrays L and R into A.
void Merge(vector<int>& A, vector<int>& L, vector<int>& R)
{
// i - to mark the index of left subarray (L)
// j - to mark the index of right sub-raay (R)
// k - to mark the index of merged subarray (A)
unsigned int i=0;
unsigned int j=0;
unsigned int k=0;
while(i<L.size() && j<R.size())
{
if(L[i]<=R[i])
{ A[k]=L[i];
i=i+1;
}
else
{ A[k]=R[j];
j=j+1;
}
k=k+1;
}
while(i<L.size())
{ A[k]=L[i];
i=i+1;
k=k+1;
}
while(j<R.size())
{ A[k]=R[j];
j=j+1;
k=k+1;
}
}
// Recursive function to sort an array of integers.
void MergeSort(vector<int>& A)
{
int n = A.size();
if (n<2) return;//base condition.If the array has less than two
//elements, do nothing
int mid=n/2;
// create left and right subarrays
// mid elements (from index 0 till mid-1) should be part of left sub-
//array
// and (n-mid) elements (from mid to n-1) will be part of right sub-
//array
vector<int> left(mid);
vector<int> right(n-mid);
for(int i=0;i<mid;i++) left[i]=A[i];// create left subarray
for(int i=mid;i<n;i++) right[i-mid]=A[i];// create right subarray
MergeSort(left);
MergeSort(right);
Merge(A,left,right);
}
int main()
{ vector<int> A={2,4,7,1,5,3};
MergeSort(A);
for(unsigned int i=0;i<A.size();i++) cout<<A[i]<<" ";
return 0;
}
[Edit]
I noticed I accidentally used comma's instead of dots in vector.size() calls. Also, I noticed 2 arrays stopping one item too early in copying left and right vectors.
Your code did not work. Above code compiles fine, but produces 1 3 5 2 4 7 as output. Also, have you thought of a vector of uneven length, such as 5 4 3 2 1?
At this point, the code will not split properly

Need to devise a recursive algorithm for the following problem in c++

A recursive algorithm that gets an integer n and integer array A as input and check if the given array
A contains two integers, such that n= A[i]+A[j] where A[i] & A[j] can be at any position in array.
This is what I have come up with
#include <iostream>
using namespace std;
void func(int arr[],int size,int n)
{
if (size==1)
return;
else
{
for (int i=0;i<n;i++)
for (int j=i+1;j<n;j++)
if (arr[i]+arr[j]==n)
{
cout<<"yes";
return;
}
func(arr,size-1,n);
}
}
int main()
{
int A[] = {1,2,3,4,5};
int n = 8;
func(A,5,n);
return 0;
}
I know it's using recursion but I want a recursive function that avoids all unnecessary iterations. Any help will be greatly appreciated!!
#include <iostream>
using namespace std;
void func(int arr[],int index,int size,int n)
{
if(index==size-1)
return;
int flag=0;
for (int j=index+1;j<size;j++)
if (arr[index]+arr[j]==n)
{
flag=1;
cout<<"yes";
}
if(flag==0)
func(arr,index+1,size,n);
}
int main()
{
int A[] = {1,2,3,4,5};
int n = 6;
func(A,0,5,n);
return 0;
}
If you really want a recursive code, this may be one kind of implementation. All i have done is start from 0th index and sum it with every other element and compare it with with 'n'. If it matches fine otherwise make a recursive call with next index(prev index + 1).

bad_alloc exception while implementing the merge sort for larger arrays

I'm implementing the merge sort algorithm using C++. An exception(bad_alloc) is raised, while sorting larger arrays. Since i'm new to C++ i have no idea about how to get rid of this error. The answer i'm willing is not handling the exception, but the reason.
Here's my main method where i initially calls merge_sort function.
int *arr;
int main(){
int limits[2]={10,10000000}; //numbers of elements that should be in an array at each iteration
for(int l=0;l<sizeof(limits)/sizeof(*limits);l++){
cout<<"\n"<<endl;
arr=new int[limits[l]];
for(int cnt=0;cnt<limits[l];cnt++){ //creating the random array using random numbers
int temp=rand()%2147483647;
arr[cnt]=temp;
}
clock_t t;
t=clock();
cout<<"\nNumber of elements : "<<limits[l]<<endl;
merge_sort(0,limits[l]-1); //calling the merge sort function
cout<<endl;
t=clock()-t;
cout<<"The time taken : "<<t<<endl;
delete[] arr;
}
cin.get();
return 0;
}
Up to 1000000 elements this works fine. I'm having the trouble when sorting the array of size 10000000.
Here's the full code for test purposes.
#include<iostream>
#include<string.h>
#include<limits>
#include<time.h>
#include<stdlib.h>
using namespace std;
void merge_sort(int i,int j);
void merge(int i,int temp,int j);
int *arr;
//main method
int main(){
int limits[2]={10,10000000}; //numbers of elements that should be in an array at each iteration
for(int l=0;l<sizeof(limits)/sizeof(*limits);l++){
cout<<"\n"<<endl;
arr=new int[limits[l]];
for(int cnt=0;cnt<limits[l];cnt++){ //creating the random array using random numbers
int temp=rand()%2147483647;
arr[cnt]=temp;
}
clock_t t;
t=clock();
cout<<"\nNumber of elements : "<<limits[l]<<endl;
merge_sort(0,limits[l]-1); //calling the merge sort function
t=clock()-t;
cout<<"The time taken : "<<t<<endl;
delete[] arr;
}
cin.get();
return 0;
}
//method implementing the merge sort algorithm
void merge_sort(int i,int j){
if(i<j){
int temp=(i+j)/2;
merge_sort(i,temp);
merge_sort(temp+1,j);
merge(i,temp,j);
}
return;
}
//method implementing the merge algorithm
void merge(int i,int temp,int j){
int n1=temp-i+2; //calculating the sub array lengthes
int n2=j-temp+1;
int *L=NULL;
int *R=NULL;
L=new int[n1]; //dynamically initializing the sub left and right hand side arrays
R=new int[n2];
for(int x=0;x<n1-1;x++){
L[x]=arr[i+x];
}
for(int y=0;y<n2-1;y++){
R[y]=arr[temp+y+1];
}
L[n1-1]=numeric_limits<int>::max(); //adding the largest possible integer to the end of each array
R[n2-1]=numeric_limits<int>::max();
int a=0;
int b=0;
for(int k=i;k<=j;k++){ //merging the two sub arrays
if(L[b]>R[a] ){
arr[k]=R[a];
a++;
}
else{
arr[k]=L[b];
b++;
}
}
}
It's better if someone can give me the reason behind this rather than a fix. Thanks!
Your merge function has a memory leak, and a very big one:
L = new int[n1];
R = new int[n2];
The memory is never deallocated. If you're coming from a language such as Java or C#, you see that C++ works differently. There is no automatic garbage collection, and using new[] in C++ requires you use delete[] at some point, else you get a memory leak.
But a better solution would be to replace those lines with this:
#include <vector>
//...
// Remove the int *L and int *R declarations.
//
std::vector<int> L(n1);
std::vector<int> R(n2);
You should always think vector first over using new[]/delete[] to avoid these types of memory errors.
Once you make those changes, the program will complete, but takes a while (at least it did with Visual Studio 2013 in debug mode).
In release mode, the time took for 10000000 was 3,300 ms.
Edit: For an experiment, I used the following code to see what would happen if the vector was moved out of the function, and just reused:
std::vector<int> L;
std::vector<int> R;
void merge(int i, int temp, int j){
int n1 = temp - i + 2;
int n2 = j - temp + 1;
L.resize(n1);
R.resize(n2);
//...
}
So I made the vectors global. The amount of time it took was closer to 2,000 ms, so approximately 1,000 ms faster. The advantage is the usage of resize to resize the vectors as opposed to redeclaring them, or using new[]/delete[] multiple times.

Quicksort incorrect results

I have this quicksort code which I want to troubleshoot. There is this code that I have changed in the partition. Have tried selected the pivot element as the median of the array. But still it does not give me the correct output. Here I have different four types of arrays that I have created dynamically and trying to sort them. There are quicksort applied four times.
int counter=0, comparison=0;
void QUICKSORT(int *,int,int);
int PARTITION(int * ,int,int);
int values(float l);
int main(){
int i,n,q;
cout<<"Enter number of elements:";
cin>>n;
int* a = new int[ n ];
for(int p=1;p<=n;p++)
{
q = rand() % (n*100) ;
a[p]=q;
}
cout<<"\nThe elements od the original array are:\n\n";
for(i=1;i<=n;i++)
cout<<a[i]<<" ";
clock_t tStart = clock();
QUICKSORT(a,1,n);
cout<<"\nThe elements of the sorted array are:\n\n";
for(i=1;i<=n;i++)
cout<<a[i]<<" ";
}
// function for the generation of random poisson values. This function is called as many times
// as the array size decided by the user
int values(float l)
{
for (int i=0;i<1000;i++)
{
float L=exp(-l);
float k=0;
float p=1;
//begin while
do{
k=k+1;
double u = rand() / (double)RAND_MAX;
p=p*u;
} while (p>L);
return k-1;
}
}
//}
void QUICKSORT(int *a,int p,int r){
int q;
if(p<r){
q=PARTITION(a,p,r);
QUICKSORT(a,p,q-1);
QUICKSORT(a,q+1,r);
}
}
int PARTITION(int *a,int p,int r){
counter++;
// cout<<" first a " <<a[p]<<endl;
// cout<<" second a : "<<a[r-1]<<endl;
int x=(a[r]+a[p])/2;
//int x=a[r];
int i = p-1,temp,j;
for(j=p;j<=r-1;j++){
if(a[j]<=x){
i=i+1;
temp=a[i];
a[i]=a[j];
a[j]=temp;
}
}
temp=a[i+1];
a[i+1]=a[r];
a[r]=temp;
return(i+1);
}
At a glance..
QUICKSORT(a,p,q-1);
QUICKSORT(a,q+1,r);
That looks like it should be either:
QUICKSORT(a,p,q);
QUICKSORT(a,q+1,r);
or:
QUICKSORT(a,p,q-1);
QUICKSORT(a,q,r);
But also that partition method looks very questionable. Even if it successfully finds the median I doubt it's worth the effort. The point of quicksort is to sort with as few comparisons as possible, so looping through each entire subarray to find the median kind of defeats that purpose, and is overkill. I would suggest picking three items: first, middle, last, and just using the median of those.