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;
}
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;
}
I have been trying to write a code to randomly shuffle the array elements, and then use the quick sort algorithm on the array elements. This is the code I wrote:
#include <iostream>
#include <cstdlib>
#include <ctime>
using namespace std;
void swap(int *a, int *b)
{
int temp = *a;
*a = *b;
*b = temp;
}
void randomise(int arr[], int s, int e)
{
int j;
srand(time(NULL));
for (int i = e; i >= s; i--)
{
int j = rand() % (i + 1);
swap(&arr[i], &arr[j]);
}
}
int Partition(int arr[], int s, int e)
{
int pivot = arr[e];
int i = s - 1;
int j;
for (j = s; j <= e; j++)
{
if (arr[j] <= pivot)
{
i++;
swap(&arr[i], &arr[j]);
}
}
swap(&arr[i + 1], &arr[e]);
return i + 1;
}
void QuickSort(int arr[], int s, int e)
{
if (s >= e)
return;
int x = Partition(arr, s, e);
QuickSort(arr, s, x - 1);
QuickSort(arr, x + 1, e);
}
int main()
{
int b[] = {1, 2, 3, 4, 5};
randomise(b, 0, 4);
cout << "Elements of randomised array are:";
for (int i = 0; i <= 4; i++)
{
cout << b[i] << endl;
}
QuickSort(b, 0, 4);
cout << "Elements after quick sort are:";
for (int i = 0; i <= 4; i++)
{
cout << b[i] << endl;
}
return 0;
}
However, on debugging on GDB, I found out that this program gives segmentation fault. On execution, this program gives the output as:
Elements of randomised array are:4
5
2
3
1
Can someone tell me what is the bug in this code (I have tried debugging it on GDB, but I am still clueless).
Basically, when the error is segmentation fault, you should be looking for a bug which you will feel like crashing your head into wall, after finding it. On line 26. change <=, to < . It's in your partition function. for (j = s; j < e; j++)
A little explanation about quick sort; After each time quickSort function runs on a partiotion, the last element of the partition, called pivot, will reach its' real place in array. The partition function, returns the real place of the pivot in the array. Then the main array will be split into two more partitions, before the pivot place, and after that. Your bug is returning real-pivot-place + 1, as the output of partition function. So you will run quickSort on wrong partition; the partition that is already sorted but the program will keep trying to sort it over and over because of wrong partitioning. As you may know, each time you run a function, its' variables will be saved into a stack in computer. Since your calling a recursive function over and over(that isn't supposed to stop), this stack will get full and will overflow. After that, computer will represent some undefined behavior and maybe throw an exception that can not describe the problem correctly. This is why your getting segmentation fault. But why you return real-pivot-place + 1? Because in your for loop in partition function, you will visit the pivot too, which you shouldn't. Because pivot isn't supposed to be compared with itself. So you will increase i variable unnecessarily. https://en.wikipedia.org/wiki/Call_stack Check this link for additional information about stack and how a function runs in computer.
This is a code for sorting array elements using Quick Sort..
void QuickSort(int a[], int beg, int end)
{
if(beg<end)
{
int p=Partition(a,beg,end);
QuickSort(a,beg,p-1);
QuickSort(a,p+1,end);
}
}
you can observe:
int p=Partition(a,beg,end);
QuickSort(a,beg,p-1);
QuickSort(a,p+1,end);
I haven't understood in this function how those recursive calls are working, how the partitioned array is given to QuickSort(a,beg,p-1); and QuickSort(a,p+1,end);. I end up in between and when I dry run or debug it, I get confused as it looks like a merge sort. Also I know visual representation of Quick Sort (saw on youtube).
Can anyone explain to me by taking x[5] all the iterations?
#include<iostream>
#include<time.h>
using namespace std;
int z = 0;
int Partition(int a[], int beg, int end) //Function to Find Pivot Point
{
int p = beg, pivot = a[beg], loc;
for (loc = beg + 1; loc <= end; loc++) {
if (pivot > a[loc]) {
a[p] = a[loc];
a[loc] = a[p + 1];
a[p + 1] = pivot;
p = p + 1;
}
}
return p;
}
void QuickSort(int a[], int beg, int end) {
if (beg < end) {
int p = Partition(a, beg, end); //Calling Procedure to Find Pivot
QuickSort(a, beg, p - 1); //Calls Itself (Recursion)
QuickSort(a, p + 1, end); //Calls Itself (Recursion)
}
}
int function_Random(int x[1000], int i) {
if (i == 1001)
return 0;
x[z] = rand() % 100;
cout << x[z] << "\t";
z++;
function_Random(x, i += 1);
//return x;
}
int main() {
int s;
static int i;
int x[1000];
begin = clock();
function_Random(x, i);
QuickSort(x, 0, 1000);
cout << "\n\nAfter";
for (i = 0; i < 1000; i++) {
cout << "\t" << x[i];
}
return 0;
}
I am not sure what the exact concern is, but it might help if you think of QuickSort in a very high level view.
Quicksort works by selecting an element as the pivot and reordering the elements in the sequence into two subsequences, of smaller and larger values, separated by the pivot. At this point the pivot is in place and you only need to sort both sequences independently.
The heavy work is done by partition that goes over the sequence separating the original sequence into the two subsequences and yielding the final location of the pivot. Note that after partition completes, the pivot is in it's final location, it need not be moved.
In your case the pivot is selected as the first element, so you would have:
initial: [ pivot, other elements... ]
partitioned: [ smaller..., pivot, larger... ]
At this point you quicksort the subsequences [ smaller... ] and [ larger... ].
Note that this is not like mergesort, in mergesort you have a fixed split point, you sort both subsequences independently and then build the overall solution by merging the results. In quicksort you pick an element move it to the right location separating the universe into smaller/larger values that form the two subsequences, the split point is determined by the value of the pivot and the relative values of all other elements.
I'm trying to use the following merge sort function to sort an array. However it is not giving me the expected output.
It will not print out correct/expected output i.e
Input: 5,4,3,2,1
Output: 1,2,3,4,5
Instead it gives: 2,3,4,5,1,9,8,7,8,4,1,8,8,2.
#include <iostream>
#include <cmath>
#include <ctime>
#include <cstdlib>
using namespace std;
void mergeSort(int a[], int low , int high,int res[]);
void merge(int a[], int low , int mid , int high,int res[]);
void mergeSort(int numbers[], int temp[], int array_size);
const int SIZE=5;
int main () {
int sorted[SIZE];
for (int i=0; i<SIZE; i++) {
cout << "input numbers" <<endl;
cin >>sorted[i];
}
int merge[SIZE];
mergeSort(sorted,merge,SIZE);
for (int i=0; i<SIZE; i++) {
cout << merge[i];
}
return 0;
}
void mergeSort(int numbers[], int temp[], int array_size)
{
mergeSort(numbers, 0, array_size-1, temp);
}
void mergeSort(int a[], int low , int high,int res[])
{
int mid = (low + high) /2;
if (low + 1 < high)
{
// Sort sub-parts
mergeSort(a,low,mid,res);
mergeSort(a,mid,high,res);
// Merge back to "res"
merge(a,low,mid,high,res);
}else{
res[low] = a[low];
}
}
void merge(int a[], int low , int mid , int high,int res[])
{
int i = low;
int j = mid;
int k = low; // Use "low" instead of 0.
while (i < mid && j < high)
if(a[i] < a[j])
res[k++] = a[i++];
else
res[k++] = a[j++];
while (i < mid)
res[k++] = a[i++];
while (j < high)
res[k++] =a[j++];
// Copy back to "a"
for (int c = low; c < high; c++){
a[c] = res[c];
}
}
I think this is causing the problem --
// Sort sub-parts
mergeSort(a,low,mid,res);
mergeSort(a,mid,high,res);
It should be
// Sort sub-parts
mergeSort(a,low,mid,res);
mergeSort(a,mid+1,high,res);
Also if (low + 1 < high) should be changed to if (low < high)
Furthermore while (i < mid && j < high) should be while (i <= mid && j <= high) and single while loops below it too need to be updated with <=
There is a bit of confusion in your handling of indexing limits.
Two very common ways to represent ranges are:
range limits are pointing between elements
range limits are pointing to elements
In the picture the numbering above is using the "pointing between elements" approach and the grayed out range is (2, 5).
The numbering below is instead using the "pointing to elements" approach and the same range is (2, 4).
As a personal preference I like the "between elements" approach much more: for example the size of a range is high-low and you can represent easily empty ranges or even inverted ranges. The important thing is however that you keep always clear in your mind if you're using the first or the second approach when writing code that is managing ranges.
In your code there's that kind of confusion; for example in mergesort you are checking if
low + 1 < high
and this means that you're using the "between elements" approach because when high - low = 1 means there is only one element and no sorting is needed. Also you recurse passing (low, mid) and (mid, high): another clear sign that the "between elements" approach is used because you surely don't want to move around array[mid] twice.
In the same code however you're passing the function 0 and array_size-1 in the main program, a clear sign that in this case you're using the "pointing to elements" approach instead.
Just double-check that all your index and range usage is coherent and the code will be fine.
According to your sample code, only 5 numbers should be printed as result (because of const int SIZE=5).
That aside, note that you provide the position of the last element of your list as "high" parameter.
However, in your merge function, your while(j < high) conditions make sure that this last element in the list will not be sorted, because sorting stops just before reaching it.
Update: The for loop at the end of the merge function needs to be adapted to also copy the last ("high") element back into the array a.
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.