How to simplify two functions that similar with each other - c++

I'm a student studying computer engineering.
today I was learning quick sort using C++.
It is so awesome algorithm and I recognized that quick sort needs
two function for ascending order and the opposite.
Following is my codes!
#include <iostream>
#define ASCENDING 0
#define DESCENDING 1
#define MAX_SIZE 50001
using namespace std;
int numberCnt;
int sortManner;
int list[MAX_SIZE];
void GetInput();
void QuickSort(int* list, int left, int right, int(*partition)(int*, int, int));
int PartitionAscending(int* list, int left, int right);
int PartitionDescending(int* list, int left, int right);
void Swap(int &a, int &b);
int main(){
GetInput();
QuickSort(list, 0, numberCnt - 1, sortManner == ASCENDING ? PartitionAscending : PartitionDescending);
for (int i = 0; i < numberCnt; i++){
cout << list[i] << endl;
}
return 0;
}
void QuickSort(int* list, int left, int right, int (*partition)(int*,int,int)){
if (left < right){
int pivot = partition(list, left, right);
QuickSort(list, left, pivot - 1, partition);
QuickSort(list, pivot + 1, right, partition);
}
}
int PartitionAscending(int* list, int left, int right){
int pivotVal = list[left];
int pivotIdx = left;
int low = left;
int high = right + 1;
do{
do{
low++;
} while (list[low] < pivotVal);
do{
high--;
} while (list[high] > pivotVal);
if (low < high)
Swap(list[low], list[high]);
} while (low < high);
Swap(list[pivotIdx], list[high]);
return high;
}
int PartitionDescending(int* list, int left, int right){
int pivotVal = list[left];
int pivotIdx = left;
int low = left;
int high = right + 1;
do{
do{
low++;
} while (list[low] > pivotVal);
do{
high--;
} while (list[high] < pivotVal);
if (low < high)
Swap(list[low], list[high]);
} while (low < high);
Swap(list[pivotIdx], list[high]);
return high;
}
void Swap(int &a, int &b){
int temp = a;
a = b;
b = temp;
}
void GetInput(){
cin >> numberCnt >> sortManner;
for (int i = 0; i < numberCnt; i++)
cin >> list[i];
}
You know the functions is very similar with each other!
It seems that wasteful to me!
How to simplify the functions?
If you don't understand my pool English
Plz, don't hesitate to let me know :)

Your partition can take a comparison functor, something like:
template <typename Comp>
int Partition(int* list, int left, int right, Comp comp){
int pivotVal = list[left];
int pivotIdx = left;
int low = left;
int high = right + 1;
do{
do{
low++;
} while (comp(list[low], pivotVal));
do{
high--;
} while (!comp(list[high], pivotVal));
if (low < high)
Swap(list[low], list[high]);
} while (low < high);
Swap(list[pivotIdx], list[high]);
return high;
}
int PartitionAscending(int* list, int left, int right){
return Partition(list, left, right, [](int l, int r){ return l < r; });
// or return Partition(list, left, right, std::less<int>());
}
int PartitionDescending(int* list, int left, int right){
return Partition(list, left, right, [](int l, int r){ return l > r; });
// or return Partition(list, left, right, std::greater<int>());
}

Add an other argument to your function that would specify if you need a ascending or descending call, a boolean ascending can do that, and calculate the loop condition like this :
do{
low++;
} while ( ascending ? (list[low] < pivotVal) : (list[low] > pivotVal));

Related

Merge sort algorithm compilation error [HELP]

#include <iostream>
#include <cstdlib>
using namespace std;
void print(int a[], int sz)
{
for (int i = 0; i < sz; i++) cout << a[i] << " ";
cout << endl;
}
void merge(int a[], const int low, const int mid, const int high)
{
int *temp = new int[high-low+1];
int left = low;
int right = mid+1;
int current = 0;
// Merges the two arrays into temp[]
while(left <= mid && right <= high)
{
if(a[left] <= a[right])
{
temp[current] = a[left];
left++;
}
else { // if right element is smaller that the left
{
// if right element is smaller that the left
temp[current] = a[right];
right++;
}
current++;
}
// Fills the array
// The temp array has already been filled
// Use the right side of array to fill temp
if(left > mid)
{
for(int i=right; i <= high;i++)
{
temp[current] = a[i];
current++;
}
}
// Use the left side of array to fill temp
else
{
for(int i=left; i <= mid; i++)
{
temp[current] = a[i];
current++;
}
}
//Fill into original array
for(int i=0; i<=high-low;i++)
{
a[i+low] = temp[i];
}
delete[] temp;
}
void merge_sort(int a[], const int low, const int high)
{ // <-- Error #68
if(low >= high) return;
int mid = (low+high)/2;
merge_sort(a, low, mid); //left half
merge_sort(a, mid+1, high); //right half
merge(a, low, mid, high); //merge them
}
int main()
{ //<-- Error #77
int a[] = {26, 5, 33, 6, 19, 69, 99};
int arraySize = sizeof(a)/sizeof(int);
print(a, arraySize);
merge_sort(a, 0, (arraySize-1));
print(a, arraySize);
return 0;
} //<-- Error #87
// This code is supposed to implement the Merge sort algorithm in c++.
However when ever i compile my code it runs into a bunch of errors.
mergesort.cpp: In function ‘void merge(int*, int, int, int)’:
mergesort.cpp:68: error: a function-definition is not allowed here before ‘{’ token
mergesort.cpp:77: error: a function-definition is not allowed here before ‘{’ token
mergesort.cpp:87: error: expected ‘}’ at end of input
I have indicated where the erros are in the code
Can anyone help me please?
#include <iostream>
#include <cstdlib>
using namespace std;
void print(int a[], int sz)
{
for (int i = 0; i < sz; i++) cout << a[i] << " ";
cout << endl;
}
void merge(int a[], const int low, const int mid, const int high)
{
int *temp = new int[high-low+1];
int left = low;
int right = mid+1;
int current = 0;
// Merges the two arrays into temp[]
while(left <= mid && right <= high)
{
if(a[left] <= a[right])
{
temp[current] = a[left];
left++;
}
else
{
// if right element is smaller that the left
temp[current] = a[right];
right++;
}
current++;
}
// Fills the array
// The temp array has already been filled
// Use the right side of array to fill temp
if(left > mid)
{
for(int i=right; i <= high;i++)
{
temp[current] = a[i];
current++;
}
}
// Use the left side of array to fill temp
else
{
for(int i=left; i <= mid; i++)
{
temp[current] = a[i];
current++;
}
}
//Fill into original array
for(int i=0; i<=high-low;i++)
{
a[i+low] = temp[i];
}
delete[] temp;
}
void merge_sort(int a[], const int low, const int high)
{
if(low >= high) return;
int mid = (low+high)/2;
merge_sort(a, low, mid); //left half
merge_sort(a, mid+1, high); //right half
merge(a, low, mid, high); //merge them
}
main()
{
int a[] = {26, 5, 33, 6, 19, 69, 99};
int arraySize = sizeof(a)/sizeof(int);
print(a, arraySize);
merge_sort(a, 0, (arraySize-1));
print(a, arraySize);
}
You are getting this error because you write an extra { on line 27, which will mess up all those { } matching.
Delete that you will pass the compile.
Hope this helps.

Tip for worst case of quicksort implementation

I'm trying to implement quick sort and figuring out the handling part for worst case of it. When pivot choose largest or lowest of element in the array, I got stuck in the middle of my algorithm and have no idea how to handle it.
#include <iostream>
void swap(int item1, int item2)
{
int temp = item1;
item1 = item2;
item2 = temp;
}
int partition(int array[], unsigned int left, unsigned int right)
{
int pivot = array[left];
int pivot_index = left;
for(++left, right; left <= right;)
{
if(array[left] >= pivot && array[right] < pivot)
swap(array[left], array[right]);
if(array[left] < pivot)
left++;
if(array[right] >= pivot)
right++;
}
swap(array[right], pivot_index);
return right;
}
void quicksort(int array[], unsigned int left, unsigned int right)
{
if(left < right)
{
int index = partition(array, left, right);
quicksort(array, 0, index - 1);
quicksort(array, index + 1, right);
}
}
int main()
{
int unsortedarray[] = {10, 0, 9, 3, 4, 5, 8, 1};
int length = sizeof(unsortedarray) / sizeof(int);
quicksort(unsortedarray, 0, length - 1);
for(unsigned int index = 0; index < static_cast<unsigned int>(length); ++index)
std::cout << unsortedarray[index] << std::endl;
return 0;
}
Your swap is working with local copies of the values to be swapped; it isn't making any changes to the arguments.

c++ quicksort sort string text

I am doing my homework, and completed quicksort recursive, however it doesn't sort in a correct way. Seems to be it doesn't swap correctly.
Here is my code
#include<iostream>
#include<ctime>
#include<string>
using namespace std;
int quick_sort_help(string &text,int left, int right, int pivot){
char val = text[pivot];
char temp;
//swap
// temp =text[pivot];
//text[pivot]= text[right];
//text[right]=temp;
//swap(&text[left],&text[right]);
int l = left;
int r = right;
int i=left;
while (i<=r)
{
while (text[i]<val)
i++;
while (text[right]>val)
r--;
if (i<=r)
{
temp=text[i];
text[i]=text[r];
text[r]=temp;
i++;
r--;
}
}
return l;
}
void quicksort(string &text,int left, int right){
if (left < right){
int pivot=(left+right)/2;
int pivottwo = quick_sort_help(text, left, right, pivot);
quicksort(text, left, pivottwo - 1);
quicksort(text, pivottwo + 1, right);
}
}
void quick_sort(string &text,int size){
quicksort(text,0,size);}
int main()
{
string text="this is a test string text,.,!";
int size = text.length();
float t1, t2;
t1 = clock();
quick_sort(text,size);
t2=clock();
cout<<"quicksort Sort: "<<(t2-t1)/CLK_TCK*1000<<" msec\n";
cout<<text<<endl;
system("pause");
return 0;
}
the output I am getting:
hi a e e,g.nii,r!tssssxttttt
You have to:
1) Don't use size but size-1 value
void quick_sort(string &text,int size){
quicksort(text,0,size-1);}
2) Pivot is not (left+right)/2 but it's the value returned by quick_sort_help, and pivottwo is not necessary:
void quicksort(string &text,int left, int right)
{
if (left < right)
{
int pivot = quick_sort_help(text, left, right);
quicksort(text, left, pivot - 1);
quicksort(text, pivot + 1, right);
}
}
3) Test my j value (your r) in the second while and make the exchange before returning the pivot (the i value):
int quick_sort_help(string &text,int left, int right)
{
char val = text[right];
char temp;
int j = right;
int i = left - 1;
while (true)
{
while (text[++i] < val);
while (text[--j] > val) {
if(j == left)
break;
}
if(i >= j)
break;
temp=text[i];
text[i]=text[j];
text[j]=temp;
}
temp=text[i];
text[i]=text[right];
text[right]=temp;
return i;
}
Take a look at this : Quicksort implementation
while (text[right]>val)
r--;
That doesn't seem likely. You're decrementing r, but the condition you test never changes (should depend on r, probably...)
Also
return l;
looks suspicious, since the calling function seem to expect it to be the new position of the pivot, whereas it is the old left.
Another one, you use closed intervals (see why you shouldn't), which means you're accessing the string out-of bounds (which is UB).

C++ quick sort algorithm

I'm not looking to copy a qsort algorithm. I'm practicing writing qsort and this is what I've come up with and I'm interested in what part of my code is wrong. Please don't tell me that this is homework cause I could just use the code in the link below.
Reference: http://xoax.net/comp/sci/algorithms/Lesson4.php
When this runs I get this in the console:
Program loaded.
run
[Switching to process 10738]
Running…
Current language: auto; currently c++
Program received signal: “EXC_ARITHMETIC”.
void myQSort(int min, int max, int* myArray)
{
// Initially find a random pivot
int pivotIndex = rand() % max;
int pivot = myArray[pivotIndex];
int i = 0 , j = max-1;
// Pointer to begining of array and one to the end
int* begin = myArray;
int* end = &myArray[max-1];
// While begin < end
while( begin < end )
{
// Find the lowest bound number to swap
while( *begin < pivot )
{
begin++;
}
while( *end > pivot )
{
// Find the highest bound number to swap
end--;
}
// Do the swap
swap(begin,end);
}
// Partition left
myQSort(0, pivotIndex-1, myArray);
// Partiion right
myQSort(pivotIndex+1,max, myArray);
}
EDIT--
Code for Swap:
void swap(int* num, int* num2)
{
int temp = *num;
*num = *num2;
*num2 = temp;
}
// sort interval [begin, end)
void myQSort(int* begin, int* end)
{
if(end - begin < 2)
return;
int* l = begin;
int* r = end - 1;
// Initially find a random pivot
int* pivot = l + rand() % (r - l + 1);
while(l != r)
{
// Find the lowest bound number to swap
while(*l < *pivot) ++l;
while(*r >= *pivot && l < r) --r;
// Do the swap
if(pivot == l) { pivot = r; }
std::swap(*l, *r);
}
// Here l == r and numbers in the interval [begin, r) are lower and in the interval [l, end) are greater or equal than the pivot
// Move pivot to the position
std::swap(*pivot, *l);
// Sort left
myQSort(begin, l);
// Sort right
myQSort(l + 1, end);
}
You're not using the min parameter in your code, anywhere. You need to set begin and your pivot value using that.
I tried working out the codes above. But, they don't compile.
#Mihran: Your solution is correct algorithmically but the following line generates an error:
myQSort(min, begin - myArray, myArray);
This is because begin is of type int* and myArray is of type long, following which the compiler shows this error message:
implicit conversion loses integer precision
Here's a working solution in C++:
#include <iostream>
using namespace std;
void mySwap(int& num1, int& num2){
int temp = num1;
num1 = num2;
num2 = temp;
}
void myQsort(int myArray[], int min, int max){
int pivot = myArray[(min + max) / 2];
int left = min, right = max;
while (left < right) {
while (myArray[left] < pivot) {
left++;
}
while (myArray[right] > pivot) {
right--;
}
if (left <= right) {
mySwap(myArray[left], myArray[right]);
left++;
right--;
}
}
if (min < right) {
myQsort(myArray, min, right);
}
if (left < max) {
myQsort(myArray, left, max);
}
}
int main()
{
int myArray[] = {1, 12, -5, 260, 7, 14, 3, 7, 2};
int min = 0;
int max = sizeof(myArray) / sizeof(int);
myQsort(myArray, min, max-1);
for (int i = 0; i < max; i++) {
cout<<myArray[i]<<" ";
}
return 0;
}
Here's a clear C++ implementation, for reference:
#include <iostream>
#include <vector>
using namespace std;
int partition(std::vector<int>& arr, int low, int high) {
// set wall index
int wall_index = low;
int curr_index = low;
int pivot_elem = arr[high]; // taking last element as pivot_element
// loop through the entire received arr
for (int i = curr_index; i < high; ++i) {
// if element is less than or equal to pivot_elem
// swap the element with element on the right of the wall
// i.e swap arr[i] with arr[wall_index]
if (arr[i] <= pivot_elem) {
// swap
int temp = arr[wall_index];
arr[wall_index] = arr[i];
arr[i] = temp;
// move the wall one index to the right
wall_index++;
curr_index++;
} else {
// if the element is greater than the pivot_element
// then keep the wall at the same point and do nothing
curr_index++;
}
}
// need to swap the pivot_elem i.e arr[high] with the element right of the wall
int temp = arr[wall_index];
arr[wall_index] = arr[high];
arr[high] = temp;
return wall_index;
}
void quick_sort(std::vector<int>& arr, int low, int high) {
if (low < high) { // element with single arr always have low >= high
int split = partition(arr, low, high);
quick_sort(arr, low, split-1);
quick_sort(arr, split, high);
}
}
int main() {
std::vector<int> data = {6,13,8,4,2,7,16,3,8};
int N = data.size();
quick_sort(data, 0, N-1);
for (int i : data) {
cout << i << " ";
}
return 0;
}
I don't see a clean implementation of Quicksort on SO, so here is my easy to understand implementation
PLEASE DONT USE IN PRODUCTION CODE
This is only for your understanding
// Swap position a with b in an array of integer numbers
void swap(int *numbers, int a, int b){
int temp = numbers[a];
numbers[a] = numbers[b];
numbers[b] = temp;
}
static int partition(int *data, int low, int high) {
int left = low, right = high, pivot = data[low];
while (left < right) {
// Everthing on the left of pivot is lower than the pivot
while ((left <= right) && data[left] <= pivot) // <= is because left is the pivot initially
left++;
// Everything on the right of the pivot is greater than the pivot
while((left <= right) && data[right] > pivot)
right--;
if (left < right)
swap(data, left, right);
}
// Put the pivot in the 'rigthful' place
swap(data, low, right);
return right;
}
// Quicksort
static void quick_sort(int *numbers, int low, int high)
{
if (high > low) {
int p_index = partition(numbers, low, high);
quick_sort(numbers, low , p_index - 1);
quick_sort(numbers, p_index + 1, high);
}
}

median 3 quick sort implementation

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.