median 3 quick sort implementation - c++

my median 3 implementation is not working fine here. i have to choose 3 numbers randomly for medium here is my code please help me.
#include"stdafx.h"
#include <iostream>
#include<algorithm>
using namespace std;
#define size 10
int i;
void show(int* array, int n);
int partition(int* array, int pValue, int left, int right);
void QuickSort(int* array, int left, int right);
int main(void)
{
int array[size];
int i;
for( i = 0; i < size; i++)
{
array[i]=rand()%100;
}
cout<<endl<<"The random generated numbers are: "<<endl;
show(array, size);
QuickSort(array,0,size - 1);
cout<<endl<<"The sorted numbers are : "<<endl;
show(array, size);
system("pause");
return 0;
}
void show(int* array, int n)
{
int i;
for( i = 0; i < n; i++) cout<<array[i]<<'\t';
}
void QuickSort(int* array, int left, int right)
{
for(i=0;i<3;i++)
{
array[i]=array[rand()%100];
}
stable_sort(array,array+3);
int p=array[(i+1)/2];
//int p = array[left];
int split;
if(right > left)
{
split = partition(array, p, left, right);
array[split] = p;
QuickSort(array, left, split-1);
QuickSort(array, split+1, right);
}
}
int partition(int* array, int p, int left, int right)
{
int lb = left;
int rb = right;
while(lb < rb)
{
while( p < array[rb]&& rb > lb)
{
rb--;
}
swap(array[lb], array[rb]);
while( p >= array[lb]&& lb < rb)
{
lb++;
}
swap(array[rb], array[lb]);
}
return lb;
}

Your code was way too complex for this simple algorithm, check code below:
void QuickSortMedian(int a[],int start,int end) {
int q;
count++;
if (end-start<2) return;
q=MedianOfThreePartition(a,start,end);
QuickSortMedian(a,start,q);
QuickSortMedian(a,q,end);
}
int MedianOfThreePartition(int a[],int p, int r) {
int x=a[p],y=a[(r-p)/2+p],z=a[r-1],i=p-1,j=r;
if (y>x && y<z || y>z && y<x ) x=y;
else if (z>x && z<y || z>y && z<x ) x=z;
while (1) {
do {j--;count++;} while (a[j] > x);
do {i++;count++;} while (a[i] < x);
if (i < j) swap(&a[i],&a[j]);
else return j+1;
}
}
void QuickSortRandomAndMedian(int a[],int start,int end) {
int q;
count++;
if (end-start<2) return;
q=RandomAndMedianPartition(a,start,end);
QuickSortRandomAndMedian(a,start,q);
QuickSortRandomAndMedian(a,q,end);
}
int RandomAndMedianPartition(int a[],int p, int r) {
int t,x=a[t=((rand()%(r-p))/2)+p+(r-p)/4],y=a[t+1],z=a[t-1],i=p-1,j=r;
if (y>x && y<z || y>z && y<x ) x=y;
else if (z>x && z<y || z>y && z<x ) x=z;
while (1) {
do {j--;count++;} while (a[j] > x);
do {i++;count++;} while (a[i] < x);
if (i < j) swap(&a[i],&a[j]);
else return j+1;
}
}
The second algorithm is just a boost that I wrote for the optimization of quick sort, for example on a 40000 elements array regular quick sorts did about 800k actions, the median one did 650k and the random median one did about 620k. That's the best I got so far. :)

Maybe the problem is here:
array[i]=array[rand()%100];
First, you're changing some elements of the array, when you should be swapping them with others. If you don't you are destroying data.
Second, your array has size 10, but you're asking for an index at a random position between 0 and 99. Obviously, you can't do that, and that's why you're getting garbage.

Related

What is wrong with my merge sort implementation refer to CLRS?

I tried to implement merge sort using C++, however, something went wrong. I have no idea what is wrong.
The following code is what I wrote based on CLRS. I think it is quite easy to understand the meaning.
#include <iostream>
#include <vector>
using namespace std;
void merge(vector<int>& nums, int p, int q, int r);
void mergeSort(vector<int>& nums, int p, int r){
if (p < r) {
int q = (p + r) / 2;
mergeSort(nums, p, q);
mergeSort(nums, q + 1, r);
merge(nums, p, q, r);
}
}
void merge(vector<int>& nums, int p, int q, int r) {
int s1 = p, s2 = q + 1;
vector<int> l1, l2;
for (int i = s1; i <= q; i++) {
l1.push_back(nums[i]);
}
for (int i = s2; i <= r; i++) {
l2.push_back(nums[i]);
}
int left = 0, right = 0;
int idx = 0;
while (left < l1.size() && right < l2.size()) {
if (l1[left] < l2[right]) {
nums[idx] = l1[left++];
}
else {
nums[idx] = l2[right++];
}
idx++;
}
while (left < l1.size()) {
nums[idx++] = l1[left++];
}
while (right < l2.size()) {
nums[idx++] = l2[right++];
}
}
int main() {
vector<int> vect;
vect.push_back(1);
vect.push_back(3);
vect.push_back(12);
vect.push_back(23);
vect.push_back(4);
vect.push_back(11);
vect.push_back(44);
vect.push_back(322);
mergeSort(vect, 0, vect.size() - 1);
for (int i = 0; i < vect.size(); i++) {
cout << vect[i] << endl;
}
return 0;
}
I want to use the program to sort some integers, however, it only shows many duplicate numbers. What's going on? I don't think there is a problem of the merge function.
The code needs a one line fix:
int idx = p; // not idx = 0
Optimized top down using arrays from Wiki article (note bottom up is slightly faster):
void TopDownMerge(int A[], int bgn, int mid, int end, int B[])
{
int i, j, k;
i = bgn, j = mid, k = bgn;
while(1){
if(A[i] <= A[j]){ // if left smaller
B[k++] = A[i++]; // copy left element
if(i < mid) // if not end of left run
continue; // continue
do // else copy rest of right run
B[k++] = A[j++];
while(j < end);
break; // and break
} else { // else right smaller
B[k++] = A[j++]; // copy right element
if(j < end) // if not end of right run
continue; // continue
do // else copy rest of left run
B[k++] = A[i++];
while(i < mid);
break; // and break
}
}
}
void TopDownSplitMerge(int B[], int bgn, int end, int A[])
{
if (end - bgn <= 1) // if run size == 1
return; // consider it sorted
int mid = (end + bgn) / 2;
TopDownSplitMerge(A, bgn, mid, B);
TopDownSplitMerge(A, mid, end, B);
TopDownMerge(B, bgn, mid, end, A);
}
void TopDownMergeSort(int A[], int n) // n = size (not size-1)
{
if(n < 2)
return;
int *B = new int [n]; // 1 time allocate and copy
for(size_t i = 0; i < n; i++)
B[i] = A[i];
TopDownSplitMerge(B, 0, n, A); // sort data from B[] into A[]
delete B;
}
Afterwards, I finally get to fix the bugs of my program. After modification, here is the code:
class Solution {
public:
vector<int> temp;
vector<int> sortArray(vector<int>& nums) {
temp.resize((int)nums.size(), 0);
mergeSort(nums, 0, nums.size() - 1);
return nums;
}
void mergeSort(vector<int>& nums, int start, int end) {
if (start >= end) return;
int middle = (start + end) / 2;
mergeSort(nums, start, middle);
mergeSort(nums, middle + 1, end);
merge(nums, start, middle, end);
}
void merge(vector<int>& nums, int leftStart, int middle, int rightEnd) {
int leftEnd = middle;
int rightStart = middle + 1;
int i = leftStart, j = rightStart;
int index = 0;
while (i <= leftEnd && j <= rightEnd) {
if (nums[i] < nums[j]) {
temp[index] = nums[i++];
}
else {
temp[index] = nums[j++];
}
index++;
}
while (i <= leftEnd) {
temp[index++] = nums[i++];
}
while (j <= rightEnd) {
temp[index++] = nums[j++];
}
for (int i = 0; i < rightEnd - leftStart + 1; i++) {
nums[i + leftStart] = temp[i];
}
}
};
Here is something should be careful next time:
In the merge part, it is difficult to merge in place. It'd be better to use another temp array to store the merged results and update to the target array (nums in this case).
Readable identifers is very recommended (Although the pseudocode of CLRS may not use that part).
Need to use debuggers to find the bug of program {However, it takes like forever to load local variables of VS Code debugers.

heap sort,I can't figure out what's wrong with my code,which doesn't output right order

#include<iostream>
using namespace std;
int heapSize;
void maxHeapify(int a[],int n,int i)
{
int l=2*i+1;
int r=2*i+2;
int largest=i;
if(l<heapSize&&a[l]>a[i]) largest=l;
if(r<heapSize&&a[r]>a[i]) largest=r;
if(largest!=i)
{
swap(a[i],a[largest]);
maxHeapify(a,n,largest);
}
}
void heapSort(int a[],int n)
{
heapSize=n;
for(int i=n/2;i>=0;i--)maxHeapify(a,n,i);
for(int i=n-1;i>=1;i--)
{
swap(a[0],a[i]);
heapSize--;
maxHeapify(a,n,0);
}
}
int main()
{
int a[]={1,2,3,7,9,15,13,11};
heapSort(a,8);
for(int i=0;i<8;i++)cout<<a[i]<<" ";
return 0;
}
output:1 2 7 11 15 3 9 13
I want to achieve a heap sort,but something went wrong,i have tried to debug it for hours,i can't find any more bugs,maybe something wrong with the logic as well as can't figure out what's wrong with my code, which doesn't output right order.
In your maxHeapify fucntion you missed to compare your heap's right child with current largest. Your function will be
void maxHeapify(int a[], int n, int i) {
int l = 2 * i + 1;
int r = 2 * i + 2;
int largest = i;
if(l < heapSize && a[l] > a[i]) largest = l;
if(r < heapSize && a[r] > a[largest]) largest = r;
if(largest! = i)
{
swap(a[i], a[largest]);
maxHeapify(a, n, largest);
}
}

Two sorting algorithms give me two different outputs on the same array (quickSort and heapSort)!

I don't understand why they give me different output when I compile them. For example ... when I compile only one algorithm the answer is good, the same is for the other one, but when I compile them both at the same time they give me some weird output.
My code:
#include <iostream>
using namespace std;
int parent(int i){
return i/2;
}
int leftChild(int i){
return 2*i+1;
}
int rightChild(int i){
return 2*i+2;
}
void maxHeapify(int a[], int i, int n){
int largest;
int temp;
int l = leftChild(i);
int r = rightChild(i);
// p.countOperation("CMPbottomUp",n);
if (l <= n && (a[l] > a[i]))
largest = l;
else
largest = i;
// p.countOperation("CMPbottomUp",n);
if (r <= n && (a[r] > a[largest]))
largest = r;
if (largest != i){
// p.countOperation("ATTbottomUp",n);
temp = a[i];
// p.countOperation("ATTbottomUp",n);
a[i] = a[largest];
//p.countOperation("ATTbottomUp",n);
a[largest] = temp;
maxHeapify(a, largest, n);
}
}
void buildMaxHeap(int a[], int n){
for (int i=n/2; i>=0; i--){
maxHeapify(a, i, n);
}
}
void heapSort(int a[],int n){
buildMaxHeap(a,n);
int n1=n;
int temp;
for(int i=n1;i>0;i--){
temp = a[0];
a[0] = a[i];
a[i] = temp;
n1--;
maxHeapify(a,0,n1);
}
}
int partitionArray(int arr[], int left, int right){
int i = left, j = right;
int tmp;
int pivot = arr[(left + right) / 2];
while (i <= j) {
while (arr[i] < pivot)
i++;
while (arr[j] > pivot)
j--;
if (i <= j) {
tmp = arr[i];
arr[i] = arr[j];
arr[j] = tmp;
i++;
j--;
}
}
return i;
}
void quickSort(int arr[], int left, int right) {
int index;
index = partitionArray(arr, left, right);
if (left < index - 1)
quickSort(arr, left, index - 1);
if (index < right)
quickSort(arr, index, right);
}
int main(){
int x[8]= {5,87,21,4,12,7,44,3};
int a[8];
for(int i=0;i<8;i++){
a[i] = x[i];
}
heapSort(x,8);
quickSort(a,0,8);
for(int i=0;i<8;i++){
cout<<a[i]<<' ';
}
cout<<endl;
for(int j=0;j<8;j++){
cout<<x[j]<<' ';
}
return 0;
}
Example output:
1) When I compile only one algorithm the output is : 3,4,5,7,12,21,44,87 (which is good)
2) When I compile both of them in the code the output is: 87,4,5,7,12,21,44,87 (quickSort) and 3,3,4,5,7,12,21,44 (heapSort)
I think that should work:
heapSort(x,7);
quickSort(a,0,7);
Arrays a and x are right next to each others in stack. Seeing how you have duplicate value 87 in output, it seems your sort functions access memory outside the array you give to them. This is buffer overrun, a type of Undefined Behaviour. With that, your code could do anything because you have corrupted variable values (or worse, corrupted addresses/pointers).
Double check how you access arrays. Remember that C array indexes for your arrays of length 8 are 0..7!

Merge sort not working completely

The code that I have made for merge sort is given below. The thing is that on giving the input the output is 3 2 1 5 0. What is going wrong?
#include <iostream>
#include <cmath>
using namespace std;
int d[100];
void merge(int a[], int b[], int c[], int n)
{
int n2=floor(n/2);
int i=0, j=0, k=0;
while(i<n2 && j<(n-n2))
{
if(b[i]<c[j])
{
d[k++]=b[i++];
}
else if(b[i]>c[j])
{
d[k++]=c[j++];
}
}
if(i==n2)
{
if(j<(n-n2))
{
d[k++]=c[j++];
}
}
if(i<n2)
{
d[k++]=b[i++];
}
}
void mergesort(int a[], int n)
{
int n2=floor(n/2);
int b[50],c[50];
int i,j=0,k=0;
for(i=0;i<n2;i++)
{
b[i]=a[k++];
}
while(k<n)
{
c[j++]=a[k++];
}
merge(a,b,c,n);
}
int main()
{
int a[]={5,4,3,2,1};
int n=5;
mergesort(a,n);
for(int i=0;i<n;i++)
{
cout<<d[i]<<endl;
}
}
The main problem is that the arrays (b and c) passed to merge are not sorted.
Other problems are that the algorithm is not recursive and that merge
does not always put all numbers from b and c into a.
A version that seems to work with minimal changes to your code would be
void merge(int a[], int b[], int c[], int n)
{
int n2=floor(n/2);
int i=0, j=0, k=0;
while(k<n)
{
if((j == (n-n2) || b[i]<c[j]) && i < n2)
{
a[k++]=b[i++];
}
else
{
a[k++]=c[j++];
}
}
}
void mergesort(int a[], int n)
{
int n2=floor(n/2);
int b[50],c[50];
int i,j=0,k=0;
for(i=0;i<n2;i++)
{
b[i]=a[k++];
}
while(k<n)
{
c[j++]=a[k++];
}
if(n2 > 1) {
mergesort(b, n2);
}
if(n - n2 > 1) {
mergesort(c, n - n2);
}
merge(a,b,c,n);
}
int main()
{
int a[]={5,4,3,2,1};
int n=5;
mergesort(a,n);
for(int i=0;i<n;i++)
{
cout<<a[i]<<endl;
}
}
It is conventional to call merge_sort recursively in order to sort each subrange until the subrange is just one long then merge these together.
In your mergesort, b takes the first n/2 values of a, that is 5 and 4.
c takes the remaining values 3,2,1.
You then call merge (BTW Why do you pass a[] to this? It isn't used)
The first loop
while(i<n2 && j<(n-n2))
will have n2 = 2 and n-n2 = 5-2 = 3
This puts 3 at the start since b[0]>c[0]=3 and 2 next since b[1]>c[1]=2 and 1 at d[2] for similar reasons.
Since you don't recurse you won't sort these.
You then finish the while loop with i = 0 which is less than n2.
You just say
if(i<n2)
so you just copy the first thing from b which is 5.
All this gives 3, 2, 1, 5, and 0 because you made d global.
The input for merge need to be sorted arrays, as Philip mentioned before. Mergesort is recursive. For this you need to divide them till you reach a point where you only have one element in the array (so it is sorted) and merge all arrays to become the sorted result for the input. Wikipedia is your friend to understand the algorithm: Mergesort
Btw: You need to ensure that one of both cases in the comparison in the merge checks also on equality of the values.
Philip is right, there's no recursive in your code at all.
However, there are some more errors. I've marked it with annotations, just as a postscript of Philip's.
#include <iostream>
#include <cmath>
using namespace std;
int d[100];
void merge(int a[], int b[], int c[], int n)
{
int n2=floor(n/2);
int i=0, j=0, k=0;
while(i<n2 && j<(n-n2))
{
if(b[i]<c[j])
{
d[k++]=b[i++];
}
else if(b[i]>c[j])
{
d[k++]=c[j++];
}
/***************************************************/
/* What if b[i] == c[j] here? */
/* Your code will drop into an infinity loop. */
/***************************************************/
}
if(i==n2)
{
if(j<(n-n2))
/****************************************************/
/* Use **while** here? */
/* Because there may be more than one elements left */
/* in c[]. */
/****************************************************/
{
d[k++]=c[j++];
}
}
if(i<n2)
/***************************************************/
/* Use **while** here? - With the same reason */
/***************************************************/
{
d[k++]=b[i++];
}
}
void mergesort(int a[], int n)
{
int n2=floor(n/2);
int b[50],c[50];
int i,j=0,k=0;
for(i=0;i<n2;i++)
{
b[i]=a[k++];
}
while(k<n)
{
c[j++]=a[k++];
}
merge(a,b,c,n);
}
int main()
{
int a[]={5,4,3,2,1};
int n=5;
mergesort(a,n);
for(int i=0;i<n;i++)
{
cout<<d[i]<<endl;
}
}
template <typename T>
void merge(T arr[], int begin, int mid, int end)
{
int len = end - begin;
T *temp = new T[len];
int i = begin;
int j = mid + 1;
int k = 0;
while (i <= mid && j <= end)
{
if(arr[i] <= arr[j])
temp[k++] = arr[i++];
else
temp[k++] = arr[j++];
}
while (i <= mid)
temp[k++] = arr[i++];
while(j <= end)
temp[k++] = arr[j++];
memcpy(arr + begin, temp, len*sizeof(T));
delete []temp;
}
template <typename T>
void mergeSort(T arr[], int begin, int end)
{
if (begin >= end)
return;
int mid = (end + begin) / 2;
mergeSort(arr, begin, mid);
mergeSort(arr, mid + 1, end);
merge(arr, begin, mid, end);
}

Quicksort algorithm with duplicate keys

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]<<" ";
}