Here is the code. I simply did a merge sorting using a Divide and Conquer algorithm but it doesn't work and i haven't found why. I'm passing an unordered vector, 0 and vector.size() to the mergeSort function.
#include <iostream>
#include <vector>
#include <algorithm>
template<typename T>
void directInsertion(std::vector<T>& vec, int start, int end);
template<typename T>
void merge (std::vector<T>& vec, int left, int middle, int right);
template<typename T>
void mergeSort(std::vector<T>& vec, int left, int right);
template<typename T>
void directInsertion(std::vector<T>& vec, int start, int end)
{
T value = T();
int i;
int j;
for(i = start + 1; i < end; ++i)
{
value = vec[i];
for(j = i - 1; j >= 0 && !(vec[j] < value); --j)
vec[j + 1] = vec[j];
vec[j + 1] = value;
}
}
template<typename T>
void mergeSort(std::vector<T>& vec, int left, int right)
{
int length = right - left;
if(length <= 3)
directInsertion(vec, left, right);
else
{
int middle = left + (length >> 1);
mergeSort(vec, left, middle);
mergeSort(vec, middle, right);
merge(vec, left, middle, right);
}
}
template<typename T>
void merge (std::vector<T>& vec, int left, int middle, int right)
{
int length = right - left;
int p = left;
int q = middle + 1;
std::vector<T> tmp;
for(size_t l = 0; l < length; ++l) {
if (p <= middle && (q >= right || vec.at(p) <= vec.at(q)))
tmp.push_back(vec.at(p++));
else
tmp.push_back(vec.at(q++));
}
for(size_t l = 0; l < length; ++l)
vec.at(left + l) = tmp.at(l);
}
void printMessage(bool passed, const char* message)
{
if(passed)
std::cout << message << "............... PASS" << std::endl;
else
std::cout << message << "............... FAIL" << std::endl;
}
void printVector(std::vector<int>& v)
{
std::cout << "[";
for(auto i: v)
std::cout << " " << i << " ,";
std::cout << "]";
}
int main()
{
std::vector<int> v = {1, 2, 3, 4};
std::vector<int> orderedVector = v;
std::vector<int> aux;
bool passed = true;
do {
aux = v;
mergeSort(aux, 0, aux.size());
if(aux != orderedVector)
{
printVector(aux);
std::cout << " != ";
printVector(orderedVector);
std::cout << std::endl;
passed = false;
}
} while(std::next_permutation(v.begin(), v.end()) && passed);
printMessage(passed, "MERGE SORT");
}
There may be other problems, but this line needs to be fixed:
mergeSort(vec, middle + 1, right);
changed to
mergeSort(vec, middle, right);
I would also suggest using the names begin and end instead of left and right, to be consistent with the naming convention used for vector iterators, and because the "right" iterator or index points to the "end" of a vector or array, 1 past the last element of the array.
Related
I am not too sure what I did wrong in this Mergesort algorithm I made.
my output I am receiving is
4 3 5 5 4 3 8 8 8
I am speculating my int mid value could be causing this but then again I don't think it really matters as I am being consistent in merger func.
#include <iostream>
#include <vector>
using namespace std;
void merger(vector<int> &arr, int beg, int end) {
vector<int> temp;
int mid = (beg + end-1) / 2;
int right=mid+1;
int left = beg;
while (left <= mid && right <= end) {
if (arr[left] <= arr[right]) {
temp.push_back(arr[left++]);
}
else temp.push_back(arr[right++]);
}
if(left<mid){
while (left <= mid) {
temp.push_back(arr[left++]);
}
}
else{
while (right <= end) {
temp.push_back(arr[right++]);
}
}
int j = 0;
for (auto x : temp) {
arr[j++] = x;
}
// temp.clear();
}
void mergesort(vector<int> &arr, int beg, int end) {
//base case
if (beg >= end)return;
//make mid
int mid = (beg+end-1) / 2;
mergesort(arr, beg, mid);
mergesort(arr, mid+1, end);
merger(arr, beg, end);
}
int main() {
vector<int> arr1 = { 7,5,2,4,10,5,4,3,8 };
mergesort(arr1, 0, arr1.size()-1);
for (auto x : arr1) {
cout << x << " ";
}
cout << endl;
return 0;
}
```````````````````````````````````````
In merger, the index variable j needs to start at beg because the elements you copy into temp start with arr[beg]. Change the declaration to
int j = beg;
right before you loop to copy the sorted temp array back into arr.
I am using quicksort 3 way partition, but it is turning out to be too slow as and when the vector size is greater than 10000.
What am I doing wrong? Please guide me! Any help will be appreciated
The answer should be computed in less than 2.2 sec.
#include <iostream>
#include <vector>
#include <cstdlib>
#include <algorithm>
using std::vector;
using std::swap;
void print(vector<int> v)
{
for(int i = 0; i < v.size(); i++) std::cout << v[i] << " ";
std::cout << std::endl;
}
void partition2(vector<int> &a, int l, int r, int &i, int &j) {
int k;
int middle=(l+r)/2;
/*Selecting pivot as median of low, high and middle*/
if(((a[l]<=a[middle]) && (a[middle]<=a[r])) || ((a[r]<=a[middle]) && (a[middle]<=a[l])))
k=middle;
else if(((a[middle]<=a[l]) && (a[l]<=a[r])) || ((a[r]<=a[l]) && (a[l]<=a[middle])))
k=l;
else if(((a[middle]<=a[r]) && (a[r]<=a[l])) || ((a[l]<=a[r]) && (a[r]<=a[middle])))
k=r;
swap(a[l], a[k]);
//print(a);
int low_value = a[l];
int index_low = l;
int index_high = l;
int counter=l;
for (int i = l + 1; i <= r; i++) {
if (a[i] < low_value) {
swap(a[i], a[index_low]);
counter++;
low_value=a[l];
}
else if(a[i]==low_value)
{
index_high++;
swap(a[i], a[index_high]);
}
//print(a);
}
i=counter;
j=index_high;
//swap(a[l], a[j]);
//return j;
}
void randomized_quick_sort(vector<int> &a, int l, int r) {
if (l >= r) {
return;
}
int i,j;
partition2(a, l, r, i, j);
randomized_quick_sort(a, l, i-1);
randomized_quick_sort(a, j+1, r);
}
int main() {
int n;
std::cin >> n;
//while(1){
//n=100+rand()%99999;
//std::cout<<n<<std::endl;
vector<int> a(n);
for (size_t i = 0; i < a.size(); ++i) {
std::cin >> a[i];
//a[i]=1+rand()%99999999;
}
randomized_quick_sort(a, 0, a.size() - 1);
for (size_t i = 0; i < a.size(); ++i) {
std::cout << a[i] << ' ';
}
//std::cout<<"Pass\n";
//}
return 0;
}
Everything at first glance is correct. However, there are probably just too many comparison operations. Try this option - it works on my computer for 1.6 seconds on average.
#include <stdlib.h>
#include <stdio.h>
#include <iostream>
#include <vector>
#include <ctime>
#include <random>
#include <chrono>
#include <iomanip>
using namespace std;
using namespace std::chrono;
//======= quick_sort =======//
template<typename T>
int partition(vector<T>& numbers, const int& left, const int& right)
{
swap(numbers[left], numbers[left + (right - left) / 2]);
T mid = numbers[left];
int i(left + 1), j(right);
while (i <= j)
{
while ( i <= j && numbers[i] <= mid ) i++;
while ( i <= j && numbers[j] > mid ) j--;
if ( i < j ) swap(numbers[i], numbers[j]);
}
swap(numbers[i - 1], numbers[left]);
return i - 1;
}
template<typename T>
void quick_sort_rec(vector<T>& numbers, const int& left, const int& right)
{
if (left >= right) return;
int p = partition(numbers, left, right);
quick_sort_rec(numbers, left , p - 1);
quick_sort_rec(numbers, p + 1 , right);
}
//=========================//
template<typename T>
T random_T(long min, long max)
{
return (T)min + static_cast<T>(rand()) / (static_cast<T>(RAND_MAX / ((T)(max - min))));
}
template<typename T>
float time_func(void (*f)(vector<T>&, const int&, const int&), vector<T>& a)
{
high_resolution_clock::time_point t1 = high_resolution_clock::now();
f(a, 0, a.size() - 1);
high_resolution_clock::time_point t2 = high_resolution_clock::now();
return 1000.0 * (duration_cast<microseconds>(t2 - t1).count()) / (float)(CLOCKS_PER_SEC); /// CLOCKS_PER_SEC;
}
int main()
{
srand((unsigned)(777));
vector<int> a;
for (int i = 0; i < 10000; i++)
{
a.push_back(random_T<int>(0, 1000));
}
cout << setprecision(10) << "quick sort rec = " << time_func(quick_sort_rec, a) << endl;
return 0;
}
I run the following code to test partition2
int main(){
vector<int> a = {2, 1, 1, 9, 5, 3, 4, 2, 7};
int i, j;
partition2(a, 0, a.size() - 1, i, j);
for (auto i : a)
cout << i << ' ';
cout << '\n';
return 0;
}
And the results are
1 1 5 9 2 3 4 2 7
If the partition2 selecting median of low, high and middle as pivot, then the pivot should be 5 and the results should be something like
2 1 1 3 4 2 5 9 7
Then I check the code
if (a[i] < low_value) {
swap(a[i], a[index_low]);
counter++;
low_value=a[l];
}
else if(a[i]==low_value)
{
index_high++;
swap(a[i], a[index_high]);
}
It seems to be that the code try to find the minimum value of array and then move them to beginning of array. It seems that it is doing selection sort instead of quicksort. It explains why it is slow when input size is large.
I have implemented a heap data structure, and use it to sort. My understanding is that it is O(nlogn) complexity. However, when compared to bubble sort, it is order of magnitude slower -- and yeah, I tried running it for larger arrays. I checked some answers at SO (in particular this and this), but still lost. Could anyone point out what am I doing wrong here, please?
The results are:
HEAP SORT: 12415690ns
QUICK SORT: 71ns
BUBBLE SORT: 541659ns
Here are the codes:
main.cpp:
#include <chrono>
#include <iostream>
#include <stdexcept>
#include <vector>
// #include "heap.cpp"
// #include "pqueue.cpp"
#include "sort.cpp"
using namespace std;
using namespace std::chrono;
template <class T>
void printVector (vector<T> A) {
for (std::vector<int>::iterator it = A.begin(); it != A.end(); ++it) {
std::cout << *it << ' ';
}
cout << endl;
}
template <class T>
vector<T> constructVector(int A[], std::size_t len, std::size_t num) {
vector<T> res (A, A+len);
for (std::size_t idx = 0; idx < num-1; ++idx) {
res.push_back(A[idx%len]);
}
return res;
}
int main() {
high_resolution_clock::time_point t1;
high_resolution_clock::time_point t2;
int a[] = {4, 1, 3, 2, 16, 9, 10, 14, 8, 7};
std::size_t len = sizeof(a) / sizeof(int);
vector<int> HEAP = constructVector<int>(a, len, 32000); // (a, a + sizeof(a) / sizeof(int));
vector<int> QUICK = constructVector<int>(a, len, 32000); // (a, a + sizeof(a) / sizeof(int));
vector<int> BUBBLE = constructVector<int>(a, len, 32000);
// cout << "Original Array: "; printVector(HEAP);
cout << "HEAP SORT: ";
t1 = high_resolution_clock::now();
heapsort(HEAP);
t2 = high_resolution_clock::now();
cout << duration_cast<nanoseconds>( t2 - t1 ).count() << "ns\n";
// cout << "New Array: "; printVector(HEAP);
// cout << "Original Array: "; printVector(QUICK);
cout << "QUICK SORT: ";
t1 = high_resolution_clock::now();
quicksort(QUICK, 0, QUICK.size());
t2 = high_resolution_clock::now();
cout << duration_cast<nanoseconds>( t2 - t1 ).count() << "ns\n";
// cout << "New Array: "; printVector(HEAP);
// cout << "Original Array: "; printVector(QUICK);
cout << "BUBBLE SORT: ";
t1 = high_resolution_clock::now();
bublesort(BUBBLE);
t2 = high_resolution_clock::now();
cout << duration_cast<nanoseconds>( t2 - t1 ).count() << "ns\n";
// cout << "New Array: "; printVector(HEAP);
}
sort.cpp:
#ifndef __SORT_CPP_INCLUDED_
#define __SORT_CPP_INCLUDED_
#include <vector>
#include "heap.cpp"
template <class T>
void heapsort(std::vector<T> &A, bool increasing = true) {
Heap<T> H(A, increasing);
H.sort();
A = H.get();
}
template <class T>
std::size_t partition(std::vector<T> &A, std::size_t p, std::size_t r) {
T x = A[r-1];
std::size_t i = p - 1;
for (std::size_t j = p; j < r; ++j) {
if (A[j] <= x) {
++i;
A[i] ^= A[j];
A[j] ^= A[i];
A[i] ^= A[j];
}
}
A[i+1] ^= A[r-1];
A[r-1] ^= A[i+1];
A[i+1] ^= A[r-1];
return i + 1;
}
template <class T>
void quicksort(std::vector<T> &A, std::size_t p, std::size_t r) {
if (p-1 < r) {
std::size_t q = partition(A, p, r);
quicksort(A, p, q);
quicksort(A, q+1, r);
}
}
template <class T>
void bublesort(std::vector<T> &A) {
bool swapped = false;
do {
swapped = false;
for (std::size_t idx = 1; idx < A.size(); ++idx) {
if (A[idx-1] > A[idx]) {
// swap them
A[idx] = A[idx-1];
A[idx-1] = A[idx];
A[idx] = A[idx-1];
swapped = true;
}
}
} while (swapped);
}
#endif
heap.cpp:
#ifndef __HEAP_CPP_INCLUDED__
#define __HEAP_CPP_INCLUDED__
#include <vector>
template <class T>
class Heap {
public:
Heap(bool maxHeap = true) : heap_size(0), max_heap(maxHeap) {}
Heap(const std::vector<T> &a, bool maxHeap = true) : A(a), max_heap(maxHeap) {
if (maxHeap) this->build_max_heap(); else this->build_min_heap(); }
~Heap() {}
protected:
std::vector<T> A;
std::size_t heap_size;
bool max_heap;
public:
std::size_t parent(std::size_t idx) { return (idx - 1) >> 1; }
std::size_t left(std::size_t idx) { return (idx << 1) + 1; }
std::size_t right (std::size_t idx) { return (idx + 1) << 1; }
public:
std::vector<T> get() { return A; }
std::size_t size() { return heap_size; }
void sort();
void build_max_heap();
void build_min_heap();
void max_heapify(std::size_t idx);
void min_heapify(std::size_t idx);
};
template <class T>
void Heap<T>::sort() {
if (this->heap_size <= 0) return; // Already sorted or empty
if (this->heap_size != this->A.size()){ // Not sorted and not heapified
max_heap ? build_max_heap() : build_min_heap();
}
for (std::size_t idx = this->A.size()-1; idx > 0; --idx) {
A[0] ^= A[idx];
A[idx] ^= A[0];
A[0] ^= A[idx];
--this->heap_size;
max_heap ? max_heapify(0) : min_heapify(0);
}
}
template<class T>
void Heap<T>::build_max_heap() {
this->heap_size = this->A.size();
for (std::size_t idx = (this->A.size() - 1) >> 1; idx > 0; --idx)
this->max_heapify(idx);
this->max_heapify(0);
}
template<class T>
void Heap<T>::build_min_heap() {
this->heap_size = this->A.size();
for (std::size_t idx = (this->A.size()-1) >> 1; idx > 0; --idx)
this->min_heapify(idx);
this->min_heapify(0);
}
template <class T>
void Heap<T>::max_heapify(std::size_t idx) {
std::size_t l = this->left(idx);
std::size_t r = this->right(idx);
std::size_t largest;
if (l < this->heap_size && A[l] > A[idx]) largest = l;
else largest = idx;
if (r < this->heap_size && A[r] > A[largest]) largest = r;
if (largest != idx) {
this->A[idx] ^= this->A[largest];
this->A[largest] ^= this->A[idx];
this->A[idx] ^= this->A[largest];
this->max_heapify(largest);
}
}
template <class T>
void Heap<T>::min_heapify(std::size_t idx) {
std::size_t l = this->left(idx);
std::size_t r = this->right(idx);
std::size_t smallest;
// std::cout << "DEBUG: " << idx << std::endl;
if (l < this->heap_size && A[l] < A[idx]) smallest = l;
else smallest = idx;
if (r < this->heap_size && A[r] < A[smallest]) smallest = r;
if (smallest != idx) {
this->A[idx] ^= this->A[smallest];
this->A[smallest] ^= this->A[idx];
this->A[idx] ^= this->A[smallest];
this->min_heapify(smallest);
}
}
#endif
Your bubble sort doesn't swap, but only copy. This would make it somewhat faster. Not sure this alone explains being so fast, though.
Your Heap<T> makes a copy of the array. This can explain the slowness. I guess you forgot a &.
You should have noticed 71ns to sort 32k array is not real. Your quicksort never sorts anything. You can use std::sort for a reliable quicksort.
Too much is known at compile time and the numbers are far from random. Switch to arrays with random numbers in this kind of testing.
Problem is from the Elements of Programming Interviews Book (2012).
Problem 6.1 pg 53: "Write a functions that take an array A (I used vector) and an index i into A, and rearranges the elements such that all elements less than A[i] appear first, followed by elements equal to A[i], followed by elements greater than A[i]. Your algorithm should have O(1) space complexity and O(|A|) time complexity.
My code doesn't do anything to the vector.
#include <iostream>
#include <vector>
using namespace std;
template <typename T>
void swapit(vector<T> v, int i, int j)
{
T temp;
temp = v[i];
v[i] = v[j];
v[j] = temp;
}
template <typename T>
void dutch_flag_partition(vector<T> &v, int pivotindex)
{
T pivot = v[pivotindex];
int lower = 0;
int equals = 0;
int larger = v.size() - 1;
while(equals <= larger)
{
cout << equals << " " << larger<< endl;
if(v[equals] < pivot)
{
swapit(v, lower++, equals++);
}
else if(v[equals] == pivot)
{
++equals;
}
else
{
swapit(v, equals, larger--);
}
}
}
int main()
{
int arr[] = {1,11,3,5,3,10,0,22,50,33,4,22,23,100,9};
vector<int> v (arr, arr + sizeof(arr)/sizeof(arr[0]));
dutch_flag_partition(v, 5);
for(int i = 0; i < v.size(); ++i)
{
cout << v[i] << " ";
}
cout << endl;
return 0;
}
void swapit(vector<T> v, int i, int j) { ... }
This does not modify the vector you passed in. Instead, it creates a copy for this function. You probably want to use a reference:
void swapit(vector<T> & v, int i, int j) { ... }
So I'm trying to implement a quickselect algorithm in C++ in order to find the median value in a vector, however it is not properly partially-sorting the list and is also not returning the correct median value.
I can't seem to find where the error is. I'm new to this algorithm and it's my first time trying to implement it. I've included my code below so if anyone more knowledgable than me has any idea on what is going wrong, I would very much appreciate your input.
//Returns the index of the object with the kth largest value
int QuickSelect(vector<Object *> & list, int left, int right, int k){
/*-Base case-*/
if(left == right) /*List only contains a single element*/
return left; /*Return that index*/
int pivotIndex = left + (rand() % (int)(right - left + 1));
int pivotNewIndex = Partition(list, level, left, right, pivotIndex);
int pivotDist = pivotNewIndex - left + 1;
if(pivotDist == k)
return pivotNewIndex;
else if (k < pivotDist)
return QuickSelect(list, level, left, pivotNewIndex-1, k);
else
return QuickSelect(list, level, pivotNewIndex+1, right, k-pivotDist);
}
int Partition(vector<Object *> & list, int left, int right, int pivotIndex){
int pivotValue = list.at(pivotIndex)->value;
std::swap(list[pivotIndex], list[right]);
int storeIndex = left;
for(int i = left; i < right; i++){
if(list.at(i)->value < pivotValue){
std::swap(list[storeIndex], list[i]);
storeIndex++;
}
}
std::swap(list[right], list[storeIndex]);
return storeIndex;
}
int pivotDist = pivotNewIndex - left + 1;
should be
int pivotDist = pivotNewIndex - left;
Also
return QuickSelect(list, pivotNewIndex+1, right, k-pivotDist);
should be
return QuickSelect(list, pivotNewIndex+1, right, k-pivotDist-1);
My test code was:
int main() {
int d[] = {0, 1, 2, 3, 4};
do {
std::vector<Object*> v;
v.push_back(new Object(d[0]));
v.push_back(new Object(d[1]));
v.push_back(new Object(d[2]));
v.push_back(new Object(d[3]));
v.push_back(new Object(d[4]));
for (int i = 0; i < v.size(); ++i) {
std::cout << v[i]->value << " "; }
std::cout << std::endl;
int n = QuickSelect(v, 0, 4, 2);
if (v[n]->value != 2) {
std::cout << "error: ";
for (int i = 0; i < v.size(); ++i) {
std::cout << v[i]->value << " "; }
std::cout << std::endl;
}
}
while (std::next_permutation(&d[0], &d[sizeof(d)/sizeof(int)]));
}