I am trying to implement Quick Sort algorithm. Following code works for unique elements but it doesn't working for arrays having duplicate elements. Please tell me where I am doing wrong. Also when I change value of pivot to some other number other than 0 , program crashes. Here is the code:
#include <iostream>
#include <cstdlib>
using namespace std;
void swapme(int &a, int &b)
{
int temp = a;
a = b;
b = temp;
}
void quicksort(int *arr, int size)
{
// these two variables will take care of position of comparison
int lower = 0, upper = size - 1;
int pivot = 0; // assigns pivot
if (size <= 1)
return;
while (lower < upper)
{
while (arr[lower] < arr[pivot])
{
++lower;
}
}
while (arr[upper] > arr[pivot])
{
--upper;
}
if (upper > lower)
{
swapme(arr[upper], arr[lower]);
// upper--;
// lower++;
}
quicksort(arr, lower);
quicksort(&arr[lower + 1], size - 1 - lower);
}
int main()
{
int arr[30];
for(int j = 0; j < 30; j++)
{
arr[j] = 1 + rand() % 5000;
}
for(int j = 0; j < 30; j++)
{
cout << arr[j] << "\t";
}
cout << endl;
quicksort(arr, 30);
for(int j = 0; j < 30; j++)
{
cout << arr[j] << "\t";
}
cout << endl;
cin.get();
cin.get();
}
Update: I have finally managed to make it work. Here is the fixed version:
void swapme(int &a, int &b )
{
int temp = a;
a = b;
b = temp;
}
void quicksort(int *arr, int size)
{
if (size <= 1)
return;
// These two variables will take care of position of comparison.
int lower = 0;
int upper = size-1;
int pivot = arr[upper/2]; // assigns pivot
while (lower <= upper)
{
while (arr[lower] < pivot)
++lower;
while (arr[upper] > pivot)
--upper;
if (upper >= lower)
{
swapme(arr[upper],arr[lower]);
if(arr[upper] == arr[lower])
{
// Can either increment or decrement in case of duplicate entry
upper--; // lower++;
}
}
}
quicksort(arr, lower);
quicksort( &arr[lower+1], size-1-lower);
}
You are storing the index of your pivot element in the pivot variable, so swapping the elements can potentially change the choice of pivot element during the loop. Not a very good idea. I would suggest storing the actual value of the pivot element inside pivot instead.
Also, if this really isn't homework, why don't you simply use the standard library facilities?
#include <algorithm>
// ...
std::sort(arr + 0, arr + 30);
You will get heavily optimized and tested code that will outperform your handwritten Quicksort anytime.
Quick Sort that can implement any number of i/p integers. it also deal with duplicate keys
#include <conio.h>
#include <string>
using namespace std;
void InputArray(int*,int);
void QuickSort(int *,int,int);
int partition(int *,int,int);
void swap(int *,int,int);
void printArr(int *,int Siz=11);
void main(){
int siz;
cout<<"Enter Array length : "; cin>>siz;
int *a=new int[siz];
InputArray(a,siz);
QuickSort(a,0,siz-1);
int i=0,j=11;
printArr(a,siz);
system("pause");
}
void InputArray(int*a,int s){
for(int i=0; i<s; i++){
cout<<"ELement ["<<i<<"] = "; cin>>a[i];
}
}
void QuickSort(int *a,int start,int end){
if(start<end){
int pivot=partition(a,start,end);
QuickSort(a,start,pivot);
QuickSort(a,pivot+1,end);
}
}
int partition(int *a,int start,int end){
int currentPivotValue=a[start];
int i=start-1, j=end+1;
while(true){
i++;
while(i<j && a[i]<currentPivotValue){ i++; }
j--;
while(j>start && a[j]>currentPivotValue) {j--;}
if(i<j) swap(a,i,j);
else return j;
}
}
void swap(int *b,int i,int j){
int t=b[i];
b[i]=b[j];
b[j]=t;
}
void printArr(int *a,int Siz){
for(int i=0; i<Siz; i++) cout<<a[i]<<" ";
}
Related
This question already has answers here:
How do I use arrays in C++?
(5 answers)
Why aren't variable-length arrays part of the C++ standard?
(10 answers)
Closed 1 year ago.
I am trying to make a program that reads files with numbers and sort the numbers with different algorithms and there is multiple files that are going to be read and each file has a different amount of integers. so what i need to do is read those integers and cast them into a array.
but for some reason in c++ you cant have a array with an undefined size so what is a solution that i can use? And i can't use vectors (school project)
Here is my program
#ifndef SORT_H
#define SORT_H
#include <iostream>
#include <fstream>
#include <string>
using namespace std;
// =============================================================================
// FILE READER
// =============================================================================
void fileReader(string fileName, int arr[]){
ifstream myfile(fileName);
int pos = 0;
string number;
if(myfile.is_open()){
while (getline(myfile, number))
{
arr[pos] = stoi(number);
pos++;
}
}
}
// =============================================================================
// SWAPER
// =============================================================================
void swap(int* a, int* b)
{
int temp = *a;
*a = *b;
*b = temp;
}
// =============================================================================
// QUICKSORT
// =============================================================================
int partition(int arr[], int beg, int end){
int pivot = arr[end];
int index = beg - 1;
for(int j = beg; j < end; j++){
if(arr[j] <= pivot){
index++;
swap(&arr[index], &arr[j]);
}
}
swap(&arr[index+1], &arr[end]);
return (index+1);
}
void quicksortAlgo(int arr[], int beg, int end){
if(beg < end){
int pi = partition(arr, beg, end);
quicksortAlgo(arr, beg, pi-1);
quicksortAlgo(arr, pi+1, end);
}
}
template <typename T>
void quicksort(T arr[], int n)
{
quicksortAlgo(arr, 0, n-1);
for(int x = 0; x < n; x++)
cout << arr[x] << endl;
}
// =============================================================================
// HEAPSORT
// =============================================================================
void heapify(int arr[], int n, int i){
int max = i;
int left = 2*i + 1; // Left side
int right = 2*i + 2; // Right side
cout << "max: " << arr[max] << endl;
// if there is a left child for root and if is
// bigger then root
if(left < n && arr[max] < arr[left]){
max = left;
}
// If there is a right child of root and if is
// bigger then root
if(right < n && arr[max] < arr[right]){
max = right;
}
if(max != i){
swap(&arr[i], &arr[max]);
heapify(arr, n, max);
}
}
void heapsortAlgo(int arr[], int n){
for (int i = n/2 - 1; i >= 0; i--){
heapify(arr, n, i);
}
for (int i = n-1; i >= 0; i--){
swap(&arr[0], &arr[i]);
heapify(arr, i, 0);
}
}
template <typename T>
void heapsort(T arr[], int n)
{
heapsortAlgo(arr, n);
for (int i = 0; i < n; i++){
cout << arr[i] << " ";
}
}
// =============================================================================
// INTSERTIONSORT
// =============================================================================
template <typename T>
void insertionsort(T arr[], int n)
{
int holePostion;
int valueToInsert;
for (int i = 1; i < n; i++){
valueToInsert = arr[i];
holePostion = i;
while(holePostion > 0 && arr[holePostion-1] > valueToInsert){
arr[holePostion] = arr[holePostion - 1];
holePostion = holePostion - 1;
}
arr[holePostion] = valueToInsert;
}
}
int main(){
string filedest;
string arrSize;
cout << "enter file destenation: ";
cin >> filedest;
int arr[];
int n = sizeof(arr) / sizeof(arr[0]);
fileReader(filedest, arr);
quicksort(arr, n);
return 0;
}
#endif
As #MikeCAT mentioned, you can use std::vector<T>.
You can add push elements at the back of the vector by std::vector<T>::push_back().
Alternatively, you can also resize the vector array by using std::vector<T>::resize() and then add elements at a specific location similar to what you are doing in your fileReader() function. You can also insert elements at a specific location by calling std::vector<T>::insert()
.
Do have a look at the time complexities if you have a time constraint in your programming task.
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.
Right now I'm learning about algorithms, and I was encouraged to go back through all the different sorting methods to find out how many comparisons each kind takes to sort through an array of numbers. I need to implement a count inside this Merge Sort program which works, but I'm getting a little lost as far as where it needs to go. If anyone could point me in the right direction, I'd really appreciate it.
//MergeSort.h
#include <iostream>
using namespace std;
void merge_sort(int A[], int low, int high);
void merge(int A[], int low, int mid, int high);
void merge_sort(int A[], int low, int high)
{
int mid;
if(low<high)
{
mid=(low+high)/2;
merge_sort(A,low,mid);
merge_sort(A,mid+1,high);
merge(A,low,mid,high);
}
}
void merge(int A[], int low, int mid, int high)
{
int h, i, j, B[100], k;
h = low;
i = low;
j = mid + 1;
while ((h <= mid) && (j <= high))
{
if (A[h] <= A[j])
{
B[i] = A[h];
h++;
}
else
{
B[i] = A[j];
j++;
}
i++;
}
if (h > mid)
{
for (k = j;k <= high;k++)
{
B[i] = A[k];
i++;
}
}
else
{
for (k = h;k <= mid;k++)
{
B[i] = A[k];
i++;
}
}
for (k = low;k <= high;k++)
{
A[k] = B[k];
}
}
and
//MergeSort.cpp
#include <iostream>
using namespace std;
#include "MergeSort.h"
#include <ctime>
int main()
{
int A[1000], n = 100, i;
srand(time(NULL));
cout << "Here are " << n << " random numbers: \n";
for (i = 0; i < n; i++)
{
A[i] = rand() % 100;
cout << " " << A[i];
}
merge_sort(A, 0, n-1);
cout << "\n\nThe sorted array is: ";
for (int i=0;i<n;i++)
cout << A[i] <<" ";
cout<<endl<<endl;
system("pause");
}
One simple way to count number of comparisons is to change your merge and merge-sort functions from void to return number of comparisons within them and counting recursively.
The array of B 's length is only 100.it will be bound.
The simplest way to do this is to use a static global variable, and increment it with each compare of A[] in merge(), then have the main program display the count after a sort. This avoids having to change the interface for the existing functions.
I'm trying to create a program merge-sort on an array of int butI keep having troubles running this merge sort, it gives me a segment fault but I couldn't find anything wrong with it. In void mergesort when I put first <= last then the segment fault appears if not, then 5 5 5 5 is being print.
#include <iostream>
using namespace std;
void merge(int *arr, int size, int first, int middle, int last)
{
int temp[size];
for(int i = first; i<=last; i++)
{
temp[i] = arr[i];
}
int i=first, j=middle+1, k=0;
while(i<=middle && j<=last)
{
if(temp[i] <= temp[j])
{
arr[k] = temp[i];
i++;
}
else
{
arr[k]=temp[i];
j++;
}
k++;
}
while(i<=middle)
{
arr[k]=temp[i];
k++;
i++;
}
}
void mergesort(int *arr, int size, int first, int last)
{
if(first<last)
{
int middle = ( first + last )/2;
mergesort(arr,size,first,middle);
mergesort(arr,size,middle+1,last);
merge(arr,size,first,middle,last);
}
}
int main()
{
cout <<"Him";
const int size = 10;
int numbers [] = {5,10,1,6,2,9,3,8,7,4};
mergesort(numbers,size,0,9);
for( int i= 0; i<size; ++i)
{
cout << numbers[i] << " ";
}
return 0;
}
There are (at least) two bugs. This:
else
{
arr[k]=temp[i];
j++;
}
should be this:
else
{
arr[k]=temp[j];
j++;
}
and this:
int i=first, j=middle+1, k=0;
should be this:
int i=first, j=middle+1, k=first;
In general, you ought to learn to step through the code, at least by putting diagnostic output statements here and there. Once you have the hang of that you can move up to a good debugger.
The standard library already implements a function that merges correctly: std::inplace_merge. Implementation adapted from this more general post
void mergesort(int * first, int * last)
{
std::ptrdiff_t N = std::distance(first, last);
if (N <= 1) return;
int * middle = std::next(first, N / 2);
mergesort(first, middle);
mergesort(middle, last);
std::inplace_merge(first, middle, last);
}
int main()
{
cout <<"Him";
const int size = 10;
int numbers [] = {5,10,1,6,2,9,3,8,7,4};
mergesort(numbers, numbers+size);
for( int i= 0; i<size; ++i)
{
cout << numbers[i] << " ";
}
return 0;
}
Suggestion 1:
Instead of that line:
int temp[size];
If you need a dynamic size array use:
int temp = new int[size];
Then once you are done with it
delete[] temp;
Edit: As Neil suggested using std::vector is may be more useful than arrays in such situations (if you are allowed to use it).
Your code has 3 bugs, Also you can reduce your code length too if required.
void merge(int *arr, int size, int first, int middle, int last)
{
int temp[size];
for(int i = first; i<=last; i++)
temp[i] = arr[i];
int i=first, j=middle+1, k=first; // 1st Change, Set k to first instead of 0
while(i<=middle && j<=last)
{
if(temp[i] <= temp[j])
arr[k++] = temp[i++];
else
arr[k++]=temp[j++]; // 2nd Change, use j instead of i
}
while(i<=middle)
arr[k++]=temp[i++];
while(j<=last) // 3rd Change you missed this case
arr[k++]=temp[j++];
}
Live Code
I'm trying to count the number of comparisons my quicksort algorithm makes for an array size of 500. I know that the best case for quicksort with partition is nlogn-n+1. So for an array size of 500, the best case number of component wise comparisons would be about 3983. However, when I run my code, I'm getting 2400 comparisons or so, depending on the array the random function generates. Am I counting the number of component wise comparisons wrong? Please help.
#include <iostream>
#include <string>
#include <stdlib.h>
using namespace std;
int count_500 = 0;
int partition(int *S,int l, int u);
void swap(int &val1, int &val2);
void Quicksort(int S[],int low, int hi);
void exchange(int list[], int p, int q);
int median_of_3(int list[], int p, int r);
void Quicksort_M3(int S[], int low, int hi);
int main()
{
int S1_500[500];
int S2_500[500];
int S3_500[500];
int S1_200[200];
int S2_200[200];
int S3_200[200];
int S1_8[8];
int S2_8[8];
int S3_8[8];
srand ( time(NULL) );
for(int i=0; i<500; i++)
{
S1_500[i] = rand()%1000;
S2_500[i] = rand()%1000;
S3_500[i] = rand()%1000;
}
for(int i=0; i<200; i++)
{
S1_200[i] = rand()%500;
S2_200[i] = rand()%500;
S3_200[i] = rand()%500;
}
for(int i=0; i<8; i++)
{
S1_8[i] = rand()%100;
S2_8[i] = rand()%100;
S3_8[i] = rand()%100;
}
Quicksort(S1_500,0,499);
for(int i=0; i<500; i++)
{
cout << S1_500[i] << endl;
}
cout << "Number of component wise comparisons is: " << count_500 << endl;
}
int partition(int *S,int l, int u)
{
int x = S[l];
int j = l;
for(int i=l+1; i<=u; i++)
{
if(S[i] < x)
{
count_500++; // Count the component wise comparison
j++;
swap(S[i],S[j]);
}
}
int p = j;
swap(S[l],S[p]);
return p;
}
void swap(int &val1, int &val2)
{
int temp = val1;
val1 = val2;
val2 = temp;
}
void Quicksort(int S[],int low, int hi)
{
if (low < hi)
{
int p = partition(S,low,hi);
Quicksort(S,low,p-1);
Quicksort(S,p+1,hi);
}
}
You want the count_500++; outside the if statement. You're only counting the comparisons, where the result is true.
Change
if(S[i] < x)
{
count_500++; // Count the component wise comparison
...
}
to
count_500++; // Count the component wise comparison
if(S[i] < x)
{
...
}