I'm trying to write quicksort and understand the algorithm. I understand the 3 basic principles of quick sort
The element a[i] is in its final place in the array for some i.
None of the elements in a[l], a[i1] is greater than a[i].
None of the elemtns in a[i+1],..., a[r] is less than a[i].
I think I'm missing something about this algorithm. Any guidance much appreciated.
My first question is l and r, those are the min and max of the array? or is it any place within the left and right side of the array.
#include <iostream>
using namespace std;
void quicksort(int a[], int l , int r);
int partition(int a[], int l, int r);
void exchange(int a[], int i, int j);
int main()
{
const int MAX_ARRAY = 9;
// Quicksort
// Array of integers
int numArray[MAX_ARRAY] = {25,10,25,34,38,7,6,43,56};
for ( int i = 0 ; i < MAX_ARRAY ; i++)
{
cout << numArray[i] << endl;
}
quicksort(numArray, 4, 7);
// Call quicksort
for ( int i = 0 ; i < MAX_ARRAY ; i++)
{
cout << numArray[i]<< endl;
}
system("pause");
return 0;
}
void quicksort(int a[], int l , int r)
{
//
if (r <= l) {return;} // The max position and least position are now overlapping
int i = partition(a, l, r); // send the array and the two positions to partition
// i gives me the next position
quicksort(a,l,i-1); // sort left side
quicksort(a,i+1,r); // sort right side
}
int partition(int a[], int l, int r)
{
//Declarations
int i = l-1, j = r; int v = a[r];
for(;;) // Infinite ForLoop
{
// go through till you find a value in the array that is less than v = our pivot
while(a[++i] < v) ;
while (v < a[--j]) if (j == 1) break; // THis condition is to go thorugh and check for a number that is larger than v then if j is not at 1 then we break
if ( i >= j) break; // Overlap array
exchange(a, i , j); // swap the values
}
exchange(a,i,j); // swap the values
return i;
}
void exchange(int a[], int i, int j )
{
int temp = a[i];
a[i] = a[j];
a[j] = temp;
}
My first question is l and r, those are the min and max of the array? or is it any place within the left and right side of the array.
No, those are the left and right borders of the current sub-array being sorted. I have no idea why you invoke method with parameters 4 and 7: it means none of the elements before 4-th or after 7-th will be sorted.
first, quicksort(numArray, 4, 7); should be quicksort(numArray, 0, 8);
second, to make it a little bit faster, you can set a cutoff number like 10 on which you switch to insertion sort. Insertion sort is faster than quick sort for small input.
Related
I am working towards displaying intermediate steps of sorting while my program on quicksort executes.
In Essence, after every iteration the console window must show the current situation of the sorting of the array in progress.
I was able to add the total counts of Swaps and Comparisons in my Program but am not able to figure out a way to add logic in the existing code whereby the program also displays the intermediate steps after each iteration.
#include <cstdlib>
#include <iostream>
using namespace std;
void quick_sort(int C[],int low,int high, int & quick_count);
void partition ( int C[], int low, int high, int &m, int &n, int & quick_count );
void swap(int* a, int* b);
int main()
{
int num_of_items;
int quick_count = 0;
cout<<"Enter The Number Of Elements To Be Sorted: ";
cin>>num_of_items;
int quick[num_of_items];
for(int i=0;i<num_of_items;i++)
{
cout<<"Element "<<i<<": ";
cin>>quick[i];
}
cout<<endl;
cout<<"Unsorted: "<<endl;
for(int i=0;i<num_of_items;i++)
cout<<quick[i]<<endl;
cout<<"----------------------------------------"<<endl<<endl;
cout<<"Sorted: "<<endl;
quick_sort(quick,0,num_of_items-1, quick_count);
for(int i=0;i<num_of_items;i++)
cout<<quick[i]<<endl;
cout<<"Quick sort count: "<<quick_count<<endl;
}
//preconditions: an array of integers is passed to the function,an integer that represents the low value, an integer that
// represents the high value in the array, an integer that is passed by reference that acts as the step counter for the sort
//postcondition: the array is sorted and the step counter is maintained back to the main since it was passed by reference.
void quick_sort (int C[], int low, int high, int & quick_count )
{
int m, n;
if ( low < high )
{
partition ( C, low, high, m, n, quick_count );
quick_sort ( C, low, m, quick_count );
quick_sort ( C, n, high, quick_count );
}
}
//preconditions: an array of integers is passed to the function,an integer that represents the low value,an integer that
// represents the mid value in a section and an integer that represents the high value in the array,
// an integer that is passed by reference that acts as marker for one section, an integer that is passed by reference that acts as another marker,
// and an integer that is passed by reference that acts as the step counter for the sort.
//Postconditions: The array is shifted into the partitions that make the quick sort function.
void partition ( int C[], int low, int high, int &m, int &n, int & quick_count)
{
int pivot = C[low];
int lastS1 = low - 1;
int firstU = low;
int firstS3 = high + 1;
while ( firstU < firstS3 )
{
quick_count++;
if ( C[firstU] < pivot ) // S1
{
++lastS1;
swap ( C[firstU],C[lastS1] );
++firstU;
}
else if ( C[firstU] == pivot ) // S2
{++firstU;}
else // C[firstU] > pivot // S3
{
--firstS3;
swap ( C[firstU], C[firstS3] );
}
}
m = lastS1;
n = firstS3;
}
//preconditions: two integer pointer variables are passed to the function
//postconditions: The values that are pointed to by the pointers, swap address locations.
void swap(int* a, int* b)
{
int temp = *a;
*a = *b;
*b = temp;
}
In terms of being specific to the desired output,
I am trying to have it as follows,
say for array of size 5
Initial Array: 12,3,54,6,32,87
Iteration 1:
Iteration 2:
....
....
....
so on...
till
Sorted Array: 3,6,12,32,64,87
I have an implementation in Java where the console displays steps of literally everything that is going on within the program.
Since it also includes printing intermediate steps of arrays while sorting, I am sure it will be helpful to you.
import java.util.Arrays;
public class QuicksortDemo
{
//Passes an array, the starting index and final idex.
public static void quickSort(int[] arr, int start, int end)
{
//The following is used to recursively call the quickSort method.
int partition = partition(arr, start, end);
//Left partition
if(partition-1>start)
{
int indexToPrint=partition - 1;
System.out.println("*** Quicksort occurs recursively with starting position "+start +" and ending position "+indexToPrint + " ***");
quickSort(arr, start, partition - 1);
System.out.println("Using partition "+ partition + " after quicksort. Array is now "+Arrays.toString(arr));
}
//Right partition
if(partition+1<end) {
int indexToPrint=partition + 1;
System.out.println("*** Quicksort occurs recursively with starting position " + indexToPrint + " end position "+end + " ***");
quickSort(arr, partition + 1, end);
System.out.println("Using partition " + partition + " after quicksort. Array is now "+Arrays.toString(arr));
}
}
//Partitions the array.
public static int partition(int[] arr, int start, int end)
{
//Last element is taken as the index.
int pivot = arr[end];
System.out.println("Pivot is "+pivot +" based on array start position "+start+ " and end position "+end);
//Goes through each element of the array.
for(int i=start; i<end; i++)
{
System.out.println ("Is the element " + arr[i] + " at position " + i +" less than the pivot " + pivot + "?");
if(arr[i]<pivot)
{
int temp= arr[start];
arr[start]=arr[i];
System.out.println ("Yes it is, swapping " + temp + " at the comparison position " + start + " and " + arr[i] + " at position " + i);
arr[i]=temp;
//Increments the 'start' or 'i' value, which is used for swapping.
start++;
System.out.println("After swap, incremented the comparison position to "+start+". Array is now "+Arrays.toString(arr));
System.out.println ();
}
else
{
System.out.println("No, do nothing.");
System.out.println ();
}
}
System.out.println("Reached end of array, swapping values at position " + start + " and pivot position "+end);
int temp = arr[start];
arr[start] = pivot;
arr[end] = temp;
//Prints array after each iteration.
System.out.println("The array is now "+Arrays.toString(arr));
return start;
}
public static void main(String[] args)
{
long start = System.currentTimeMillis();
// int[] arr = {331,57,96,3,4,5,66};
int[] arr = {1,2,3,4,5,6,7};
System.out.println("Unsorted array "+Arrays.toString(arr));
quickSort(arr, 0, arr.length-1);
long end = System.currentTimeMillis();
long timeElapsed = end - start;
System.out.println("Final sorted array "+Arrays.toString(arr));
System.out.println ("The total elapsed time is : " + timeElapsed + "ms.");
}
}
[UPDATE]
On further research, it was found that there is a way to display intermediate steps of Quicksort using an efficient technique called Lomuto Partitioning Method
The final program I could come up with is as follows:
[Feel free to improvise it further if need be]
Code:
#include <iostream>
using namespace std;
int n;
// Function to print intermediate steps Array
void printArr(int A[])
{
cout<<"-----------------------"<<endl;
for(int i=0;i<n;i++)
{
cout<<A[i]<<' ';
}
cout<<endl;
}
// Partition Function for Quicksort
int partition(int A[], int l, int r){
int pivotValue = A[r];
int storeIndex = l;
for(int i=l; i<=r-1; i++){
if(A[i] < pivotValue){
swap(A[i], A[storeIndex]);
storeIndex++;
}
}
swap(A[storeIndex], A[r]); // Move pivot to its final place
return storeIndex;
}
void quick(int A[], int l, int r)
{
if(l<r){
int p = partition(A, l, r);
printArr(A);
quick(A, l, p-1);
quick(A, p+1, r);
}
}
int main()
{
cout<<"Enter The Number Of Elements: ";
cin>>n;
int A[n];
for(int i=0;i<n;i++)
{
cout<<"Element "<<i<<":";
cin>>A[i];
}
quick(A, 0, n-1);
cout<<"\nSorting Completed !"<<endl;
return 0;
}
this is the code given in the editorial to print the possible combinations print all possible combinations of r elements in a given array of size n.I am asking about the for loop used inside the combinationuntil() function.what is the condition used inside the for loop i cannot understand.
#include<bits/stdc++.h>
using namespace std;
void combinationUtil(int arr[], int data[],
int start, int end,
int index, int r);
// The main function that prints
// all combinations of size r
// in arr[] of size n. This function
// mainly uses combinationUtil()
void printCombination(int arr[], int n, int r)
{
// A temporary array to store
// all combination one by one
int data[r];
// Print all combination using
// temprary array 'data[]'
combinationUtil(arr, data, 0, n-1, 0, r);
}
/* arr[] ---> Input Array
data[] ---> Temporary array to
store current combination
start & end ---> Staring and
Ending indexes in arr[]
index ---> Current index in data[]
r ---> Size of a combination to be printed */
void combinationUtil(int arr[], int data[], int start, int end,
int index, int r)
{
// Current combination is ready
// to be printed, print it
if (index == r)
{
for (int j = 0; j < r; j++)
cout << data[j] << " ";
cout << endl;
return;
}
// replace index with all possible
// elements. The condition "end-i+1 >= r-index"
// makes sure that including one element
// at index will make a combination with
// remaining elements at remaining positions
for (int i = start; i <= end && end - i + 1 >= r - index; i++)
{
data[index] = arr[i];
combinationUtil(arr, data, i+1,
end, index+1, r);
}
}
// Driver code
int main()
{
int arr[] = {1, 2, 3, 4, 5};
int r = 3;
int n = sizeof(arr)/sizeof(arr[0]);
printCombination(arr, n, r);
}
`
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
Input : {10,9,8,7,6,5,4,3,2,1}
Output : {8,7,6,9,10,5,4,3,2,1}
I'm not sure what the issue is. I think it has something to do with the recursion in mergesort. I'm new to recursion so my understanding is not too good. Any hints?
#include <iostream>
void mergeSort(int a[], int w[], int n);
void merge(int a[], int w[], int n);
using namespace std;
void mergeSort(int a[], int t[], int n) {
if (n > 1) {
for (int i = 0; i < n/2; i++) {
t[i] = a[i];
}
mergeSort(a, t, n/2);
for (int i = n/2; i < n; i++) {
t[i] = a[i];
}
mergeSort(a, t, n/2);
merge(a, t, n/2);
}
}
void merge(int a[], int t[], int n) {
int leftIndex = 0, leftEnd = n/2;
int rightIndex = n/2, rightEnd = n;
int targetIndex = 0;
while (leftIndex < leftEnd && rightIndex < rightEnd) {
if (t[leftIndex] < t[rightIndex])
a[targetIndex++] = t[leftIndex++];
else
a[targetIndex++] = t[rightIndex++];
}
while (leftIndex < leftEnd) {
a[targetIndex++] = t[leftIndex++];
}
while (rightIndex < rightEnd) {
a[targetIndex++] = t[rightIndex++];
}
}
int main() {
const int SIZE = 10;
int a[] = {10,9,8,7,6,5,4,3,2,1};
int w[SIZE];
mergeSort(a,w,SIZE);
for (int i = 0; i < SIZE; i++) {
cout << a[i] << " ";
}
cout << endl;
}
The general problem is pointer confusion. One of the C language quirks that is not immediately obvious is that in
void mergeSort(int a[], int t[], int n);
both a and t are not arrays, but pointers. There is a special rule for this in the language standard. What this means is that in all instantiations of mergeSort on the call stack, t and a refer to the same areas of memory, and this means that every time you do something like
for (int i = 0; i < n/2; i++) {
t[i] = a[i];
}
you're changing the same region of memory. After you've done so and returned to the previous call frame, this region no longer contains the data you expect it to contain.
The way to solve this is to define a temporary local buffer where you need it, which is in merge. For example:
const int SIZE = 10;
// mergeSort is much simpler now:
void mergeSort(int a[], int n) {
if (n > 1) {
// sort the left side, then the right side
mergeSort(a , n / 2);
mergeSort(a + n / 2, n - n / 2);
// then merge them.
merge(a, n);
}
}
// Buffer work done in merge:
void merge(int a[], int n) {
// temporary buffer t, big enough to hold the left side
int t[SIZE];
int leftIndex = 0 , leftEnd = n / 2;
int rightIndex = n / 2, rightEnd = n ;
int targetIndex = 0;
// copy the left side of the target array into the temporary
// buffer so we can overwrite that left side without worrying
// about overwriting data we haven't yet merged
for(int i = leftIndex; i < leftEnd; ++i) {
t[i] = a[i];
}
// then merge the right side and the temporary buffer to
// the left side. By the time we start overwriting stuff on
// the right side, the values we're overwriting will have been
// merged somewhere into the left side, so this is okay.
while (leftIndex < leftEnd && rightIndex < rightEnd) {
if (t[leftIndex] < a[rightIndex]) {
a[targetIndex++] = t[leftIndex++];
} else {
a[targetIndex++] = a[rightIndex++];
}
}
// If there's stuff in the temporary buffer left over,
// copy it to the end of the target array. If stuff on the
// right is left over, it's already in the right place.
while (leftIndex < leftEnd) {
a[targetIndex++] = t[leftIndex++];
}
}
Before explaining the errors, let me first emphasize that a function argument like int a[] is nothing more than a pointer passed to the function. It points to a region of memory.
Now, mergesort requires some temporary memory and works by
copying the data to the temporary memory;
sorting each half of the data in temporary memory;
merging the two halves, whereby writing into the original array.
In step 2, the original array is not needed and can serve as temporary memory for the recursion.
In view of these facts, your code contains two errors:
You don't use the arrays t[] and a[] appropriately. The idea is that a[] is both input and output and t[] a temporary array. Internally, data are first copied to the temporary array, each half of which is sorted, before merging them fills the original array a[].
You don't sort the second half of the temporary array, but the first half twice.
A correct implementation is, for example,
void mergeSort(int*a, int*t, int n) {
if (n > 1) {
for (int i = 0; i < n; i++)
t[i] = a[i]; // copy to temporary
mergeSort(t , a , n/2); // sort 1st half of temporary
mergeSort(t+n/2, a+n/2, n-n/2); // sort 2nd half of temporary
merge(a, t, n);
}
}
Note that since t[] and a[] are pointers, the operation t+n/2 simply obtains the pointer to the second half of the array. The result of your code with this alteration is 1 2 3 4 5 6 7 8 9 10.
Problem:
Find the 3 quartils of a set;
The first line contains an integer, n , denoting the number of elements in the array.
The second line contains n space-separated integers describing the array's elements.
So what are quartils? There are 3 quartiles, the 2nd one is the median, the middle element of your set, if n%2==0 is the sum of the middle 2 devided by 2, the 1st and the 3rd one, we get the first and the second half of our set and we find the medians of these sets, that basicly all, here is full info( https://en.wikipedia.org/wiki/Quartile ).
So I want to submit my code in hackerrank and I can't seem to find my mistake, the test case passes, I made my test and everything is working find but I can't seem to find my mistake, can you help me find it but generally.. what is the way to debug this type of problem where everything is working but the output is not fine for some output ? Can unit testing help me out here? Here is my code:
#include <cmath>
#include <cstdio>
#include <vector>
#include <iostream>
#include <algorithm>
// A utility function to swap two elements
void swap(int* a, int* b)
{
int t = *a;
*a = *b;
*b = t;
}
/* This function takes last element as pivot, places
the pivot element at its correct position in sorted
array, and places all smaller (smaller than pivot)
to left of pivot and all greater elements to right
of pivot */
int partition (int arr[], int low, int high)
{
int pivot = arr[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 (arr[j] <= pivot)
{
i++; // increment index of smaller element
swap(&arr[i], &arr[j]);
}
}
swap(&arr[i + 1], &arr[high]);
return (i + 1);
}
/* The main function that implements QuickSort
arr[] --> Array to be sorted,
low --> Starting index,
high --> Ending index */
void quickSort(int arr[], int low, int high)
{
if (low < high)
{
/* pi is partitioning index, arr[p] is now
at right place */
int pi = partition(arr, low, high);
// Separately sort elements before
// partition and after partition
quickSort(arr, low, pi - 1);
quickSort(arr, pi + 1, high);
}
}
int getQuartil(int arr[],int len){
int q=0;
if(len%2){
q=arr[len/2];
}else{
q=(arr[len/2]+arr[len/2-1])/2;
}
return q;
}
int main() {
int n;
std::cin >> n;
int arr[n];
for(int i =0; i < n; i++){
std::cin >> arr[i];
}
quickSort(arr,0,n);
int q1=getQuartil(arr,n/2);
int q2=getQuartil(arr, n);
int q3=getQuartil(arr, (n+n/2+1));
std::cout << q1 << std::endl;
std::cout << q2 << std::endl;
std::cout << q3 << std::endl;
return 0;
}