What is wrong with my comparison function? - c++

I am trying to sort vector of pair of pair and int as below. But not getting expected output. In the actual output, the last element is supposed to come before the second element.Can someone please explain what i am missing?
int main()
{
using elem_type = std::pair<std::pair<int,int>,int>;
std::vector<elem_type> vec;
vec.push_back(std::make_pair(std::make_pair(3, 1), 2));
vec.push_back(std::make_pair(std::make_pair(6, 5), 4));
vec.push_back(std::make_pair(std::make_pair(6, 4), 7));
vec.push_back(std::make_pair(std::make_pair(5, 4), 6));
auto cmp = [](const elem_type & left, const elem_type & right){
return ((left.first.first< right.first.first)
&&
(left.first.second < right.first.second));
};
std::sort(vec.begin(), vec.end(), cmp);
//print sorted vector
for(size_t i = 0; i < vec.size(); ++i){
std::cout << vec[i].first.first << " " << vec[i].first.second << " " << vec[i].second << "\n";
}
}
Expected output
3 1 2
5 4 6
6 4 7
6 5 4
Actual output
3 1 2
6 5 4
6 4 7
5 4 6

You haven't explained how you want to sort your triples, so all I can say is that your expectations are wrong.
Your comparison function considers your last three elements to be equal.
A triple (x0,x1,x2) is considered less than another triple (y0,y1,y2) if x0 < y0 and x1 < y1. For example, when comparing (6,4,7) and (6,5,4), neither triple is considered less than the other because the first number in each triple is the same (6 < 6 is false). Similarly, (5,4,6) is considered equal to (6,4,7) because neither is less than the other (4 < 4 is false).
The only thing you might reasonably expect is that (5,4,6) < (6,5,4), but your comparison function also says both of those are equal to (6,4,7). In other words, the function claims there are values a, b, c where a = b and b = c but a < c. This makes no sense, so your comparison function is broken.
If all you want is a lexicographical ordering, you don't need to do anything special:
std::sort(vec.begin(), vec.end());
std::pair sorts by its first component first; if those are equal, it compares the second components. That seems to be exactly the behavior you expect.

Related

Arranging odd and even numbers in a vector C++

I have this problem: Given a vector with n numbers, sort the numbers so that the even ones will be on odd positions and the odd numbers will be on even positions. E.g. If I have the vector 2 6 7 8 9 3 5 1, the output should be 2 7 6 9 8 3 5 1 . The count should start from 1. So on position 1 which is actually index 0 should be an even number, on position 2 which is actually index 1 should be an odd number and so on. Now this is easy if the odd and even numbers are the same, let's say 4 even number and 4 odd numbers in the vector, but what if the number of odd numbers differs from the number of even numbers like in the above example? How do I solve that. I attached the code with one of the tries I did, but it doesn't work. Can I get some help please. I ask you to keep it simple that means only with vectors and such. No weird methods or anything cause I'm a beginner and I only know the basics. Thanks in advance!
I have to mention that n initial is globally declared and is the number of vector elements and v_initial is the initial vector with the elements that need to be rearranged.
The task says to add the remaining numbers to the end of the vector. Like if there are 3 odd and 5 even numbers, The 2 extra even numbers should be thrown at the end of the vector
void vector_pozitii_pare_impare(int v_initial[])
{
int v_pozitie[50],c1=0,c2=1;
for (i = 0; i < n_initial; i++)
{
if (v_initial[i] % 2 == 0)
{
bool isTrue = 1;
for (int k = i + 1; k < n_initial; k++)
{
if (v_initial[k] % 2 != 0)
isTrue = 0;
}
if (isTrue)
{
v_pozitie[c1] = v_initial[i];
c1++;
}
else
{
v_pozitie[c1] = v_initial[i];
c1 += 2;
}
}
else
{
bool isTrue = 1;
for (int j = i + 1; j < n_initial; j++)
{
if (v_initial[j] % 2 == 0)
{
isTrue = 0;
}
if (isTrue)
{
v_pozitie[c2] = v_initial[i];
c2++;
}
else
{
v_pozitie[c2] = v_initial[i];
c2 += 2;
}
}
}
}
This may not be a perfect solution and it just popped out right off my mind without being tested or verified, but it's just to give you an idea.
(Let A,B,C,D be odd numbers and 0,1,2 even numbers correspondingly)
Given:
A 0 B C D 1 2 (random ordered list of odd/even numbers)
Wanted:
A 0 B 1 C 2 D (input sequence altered to match the wanted odd/even criteria)
Next, we invent the steps required to get from given to wanted:
// look at 'A' -> match, next
// Result: A 0 B C D 1 2
// look at '0' -> match, next
// Result: A 0 B C D 1 2
// look at 'B' -> match, next
// Result: A 0 B C D 1 2
// look at 'C' -> mismatch, remember index and find first match starting from index+1
// Result: A 0 B C D ->1<- 2
// now swap the numbers found at the remembered index and the found one.
// Result: A 0 B 1 D C 2
// continue until the whole list has been consumed.
As I said, this algorithm may not be perfect, but my intention is to give you an example on how to solve these kinds of problems. It's not good to always think in code first, especially not with a problem like this. So you should first think about where you start, what you want to achieve and then carefully think of how to get there step by step.
I feel I have to mention that I did not provide an example in real code, because once you got the idea, the execution should be pretty much straight forward.
Oh, and just a small remark: Almost nothing about your code is C++.
A simple solution, that is not very efficient would be to split the vector into 2 vectors, that contain even and uneven numbers and then always take one from the even, one from the uneven and then the remainder, from the one that is not completely entered.
some c++ (that actually uses vectors, but you can use an array the same way, but need to change the pointer arithmetic)
I did not test it, but the principle should be clear; it is not very efficient though
EDIT: The answer below by #AAAAAAAAARGH outlines a better algorithmic idea, that is inplace and more efficient.
void change_vector_even_uneven(std::vector<unsigned>& in_vec){
std::vector<unsigned> even;
std::vector<unsigned> uneven;
for (auto it = in_vec.begin(); it != in_vec.end(); it++){
if ((*it) % 2 == 0)) even.push_back(*it);
else uneven.push_back(*it);
}
auto even_it = even.begin();
auto uneven_it = uneven.begin();
for (auto it = in_vec.begin(); it != in_vec.end(); it++){
if (even_it == even.end()){
(*it) = (*uneven_it);
uneven_it++;
continue;
}
if (uneven_it == uneven.end()){
(*it) = (*even_it);
even_it++;
continue;
}
if ((it - in_vec.begin()) % 2 == 0){
(*it) = (*even_it);
even_it++;
}
else{
(*it) = (*uneven_it);
uneven_it++;
}
}
}
The solutions is simple. We sort the even and odd values into a data structure. In a loop, we iterate over all source values. If they are even (val & 2 == 0) we add them at the end of a std::deque for evens and if odd, we add them to a std::deque for odds.
Later, we we will extract the the values from the front of the std::deque.
So, we have a first in first out principle.
The std::deque is optimized for such purposes.
Later, we make a loop with an alternating branch in it. We, alternatively extract data from the even queue and then from the odd queue. If a queue is empty, we do not extract data.
We do not need an additional std::vector and can reuse the old one.
With that, we do not need to take care for the same number of evens and odds. It will of course always work.
Please see below one of millions of possible solutions:
#include <iostream>
#include <vector>
#include <deque>
int main() {
std::vector testData{ 2, 6, 7, 8, 9, 3, 5, 1 };
// Show initial data
std::cout << "\nInitial data: ";
for (const int i : testData) std::cout << i << ' ';
std::cout << '\n';
// We will use a deques to store odd and even numbers
// With that we can efficiently push back and pop front
std::deque<int> evenNumbers{};
std::deque<int> oddNumbers{};
// Sort the original data into the specific container
for (const int number : testData)
if (number % 2 == 0)
evenNumbers.push_back(number);
else
oddNumbers.push_back(number);
// Take alternating the data from the even and the odd values
bool takeEven{ true };
for (size_t i{}; !evenNumbers.empty() && !oddNumbers.empty(); ) {
if (takeEven) { // Take even numbers
if (not evenNumbers.empty()) { // As long as there are even values
testData[i] = evenNumbers.front(); // Get the value from the front
evenNumbers.pop_front(); // Remove first value
++i;
}
}
else { // Now we take odd numbers
if (not oddNumbers.empty()) { // As long as there are odd values
testData[i] = oddNumbers.front(); // Get the value from the front
oddNumbers.pop_front(); // Remove first value
++i;
}
}
// Next take the other container
takeEven = not takeEven;
}
// Show result
std::cout << "\nResult: ";
for (const int i : testData) std::cout << i << ' ';
std::cout << '\n';
return 0;
}
Here is yet another solution (using STL), in case you want a stable result (that is, the order of your values is preserved).
#include <algorithm>
#include <vector>
auto ints = std::vector<int>{ 2, 6, 7, 8, 9, 3, 5, 1 };
// split list to even/odd sections -> [2, 6, 8, 7, 9, 3, 5, 1]
const auto it = std::stable_partition(
ints.begin(), ints.end(), [](auto value) { return value % 2 == 0; });
auto results = std::vector<int>{};
results.reserve(ints.size());
// merge both parts with equal size
auto a = ints.begin(), b = it;
while (a != it && b != ints.end()) {
results.push_back(*a++);
results.push_back(*b++);
}
// copy remaining values to end of list
std::copy(a, it, std::back_inserter(results));
std::copy(b, ints.end(), std::back_inserter(results));
The result ist [2, 7, 6, 9, 8, 3, 5, 1]. The complexity is O(n).
This answer, like some of the others, divides the data and then reassembles the result. The standard library std::partition_copy is used to separate the even and odd numbers into two containers. Then the interleave function assembles the result by alternately copying from two input ranges.
#include <algorithm>
#include <iostream>
#include <vector>
template <typename InIt1, typename InIt2, typename OutIt>
OutIt interleave(InIt1 first1, InIt1 last1, InIt2 first2, InIt2 last2, OutIt dest)
{
for (;;) {
if (first1 == last1) {
return std::copy(first2, last2, dest);
}
*dest++ = *first1++;
if (first2 == last2) {
return std::copy(first1, last1, dest);
}
*dest++ = *first2++;
}
}
void reorder_even_odd(std::vector<int> &data)
{
auto is_even = [](int value) { return (value & 1) == 0; };
// split
std::vector<int> even, odd;
std::partition_copy(begin(data), end(data), back_inserter(even), back_inserter(odd), is_even);
// merge
interleave(begin(even), end(even), begin(odd), end(odd), begin(data));
}
int main()
{
std::vector<int> data{ 2, 6, 7, 8, 9, 3, 5, 1 };
reorder_even_odd(data);
for (int value : data) {
std::cout << value << ' ';
}
std::cout << '\n';
}
Demo on Compiler Explorer
As suggested, I am using vectors and STL.
No need to be a great mathematician to understand v_pozitie will start with pairs of odd and even and terminate with the integers not in the initial pairs.
I am then updating three iterators in v_positie (no need of temporary containers to calculate the result) : even, odd and end,(avoiding push_back) and would code this way :
#include <vector>
#include <algorithm>
void vector_pozitii_pare_impare(std::vector<int>& v_initial, std::vector<int>& v_pozitie) {
int nodd (0), neven (0);
std::for_each (v_initial.begin (), v_initial.end (), [&nodd] (const int& n) {
nodd += n%2;
});
neven = v_initial.size () - nodd;
int npair (neven < nodd ?neven:nodd);
npair *=2;
std::vector<int>::iterator iend (&v_pozitie [npair]), ieven (v_pozitie.begin ()), iodd (&v_pozitie [1]);
std::for_each (v_initial.begin (), v_initial.end (), [&iend, &ieven, &iodd, &npair] (const int& s) {
if (npair) {
switch (s%2) {
case 0 :
*ieven++ = s;
++ieven;
break;
case 1 :
*iodd++ = s;
++iodd;
break;
}
--npair;
}
else *iend++ = s;
});
}
int main (int argc, char* argv []) {
const int N = 8;
int tab [N] = {2, 6, 7, 8, 9, 3, 5, 1};
std::vector<int> v_initial (tab, (int*)&tab [N]);
std::cout << "\tv_initial == ";
std::for_each (v_initial.begin (), v_initial.end (), [] (const int& s) {std::cout << s << " ";});
std::cout << std::endl;
std::vector<int> v_pozitie (v_initial.size (), -1);
vector_pozitii_pare_impare (v_initial, v_pozitie);
std::cout << "\tv_pozitie == ";
std::for_each (v_pozitie.begin (), v_pozitie.end (), [] (const int& s) {std::cout << s << " ";});
std::cout << std::endl;
}

Array and simple queries using vector

I am solving "https://www.hackerrank.com/challenges/array-and-simple-queries/copy-from/145435292" problem. while solving this problem I got stuck in one logical error.
I have tried to solve this problem in this way.
int main()
{
long long int i,j,k,l,x,n,m,a[3],c;
vector<long long int> g1;
cin>>n>>m;
for (i=0;i<n;i++)
{
cin>>x;
g1.push_back(x);
}
for(i=0;i<m;i++)
{
for(j=0;j<3;j++)
{
cin>>a[j];
}
if(a[0]==1)
{
c=0;
g1.insert(g1.begin(),g1.begin()+(a[1]-1),g1.begin()+a[2]);
c=a[2]-a[1];
c++;
g1.erase(g1.begin() + a[1]+(c-1), g1.begin() + a[2]+c);
}
else
{
g1.insert(g1.end(),g1.begin()+(a[1]-1),g1.begin()+a[2]);
g1.erase(g1.begin() + a[1]-1, g1.begin() + a[2]);
}
cout<<"\n";
for (auto y = g1.begin(); y != g1.end(); ++y)
cout << *y << " ";
}
// c=g1[0]-g1[n-1];
// if(c<0)
// {
// c=c*-1;
// }
// cout<<c<<"\n";
// cout<<"\n";
// for (auto y = g1.begin(); y != g1.end(); ++y)
// cout << *y << " ";
return 0;
}
The input format is-
n,m: where n is the total number and m is the total number of queries.
The next line is n numbers.
The next lines contain m queries.
Type 1 queries are represented as 1 i j : Modify the given array by removing elements from i to j and adding them to the front.
Type 2 queries are represented as 2 i j : Modify the given array by removing elements from i to j and adding them to the back
For Input:
7 2
1 2 3 4 5 6 7
1 3 6
1 3 6
My output is:
3 4 5 6 1 2 7
5 6 3 4 3 4 7
But my output should be:
3 4 5 6 1 2 7
5 6 1 2 3 4 7
Please help me out.
Regarding this line:
g1.insert(g1.begin(),g1.begin()+(a[1]-1),g1.begin()+a[2]);
// ^^ ^^ ^^ It's the same
I can't find a specific quote from the Standard, but in 22.3.11.5 [Containers.sequences.vector.modifiers (insert, emplace_back, emplace, push_back)] it's specified:
Causes reallocation if the new size is greater than the old capacity.
Reallocation invalidates all the references, pointers, and iterators referring to the elements in the sequence, as well as the past-the-end iterator. If no reallocation happens, then references, pointers, and iterators before the insertion point remain valid but those at or after the insertion point, including the past-the-end iterator, are invalidated.
The cppreference.com page about std::vector::insert has the following clarifications (emphasis mine)
template< class InputIt >
iterator insert( const_iterator pos, InputIt first, InputIt last );
Inserts elements at the specified location in the container.
...
The behavior is undefined if first and last are iterators into *this.
...
first, last - the range of elements to insert, can't be iterators into container for which insert is called.
It's also worth noting that inserting at the beginnning and then erasing the elements in the middle of a vector may be a rather inefficient method.
The expected results could be easily achieved using another algorithm, std::rotate:
if (a[0] == 1)
{
std::rotate(
g1.begin(), // First element of the range to be left rotated.
g1.begin() + (a[1] - 1), // Element which will become the first
g1.begin() + a[2] // Last element of the range to be modified.
);
}
else
{
std::rotate(
g1.begin() + (a[1] - 1),
g1.begin() + a[2],
g1.end()
);
}

Swapping values between two vectors so that sum of max_elements of two vectors is minimum

This is a question from Codechef but please bear with me.
https://www.codechef.com/ZCOPRAC/problems/ZCO16001
The contest is for the preparation of the Zonal Computing Olympiad held in India, so its not a competitive contest from which I'd earn something as such. Just need a little help to see what is wrong with my code, because I have a feeling I've overlooked something big and stupid. :P
So basically the question is summed up as this.
Lets say that there are two vectors or arrays. You need to swap
elements between them such that the sum of their maximum elements
is minimum. However you can swap at most K times. Then output
the value of this sum.
My approach was simple. Take the highest number from Vector1 (V1) and swap it with the lowest from V2. Add the highest values of each. Do the same, but this time swap the highest number from V2 with the lowest from V1. Add the highest values of each. The better swapping will be the one with the lowest sum and continue from there K times.
So for example:
V1 = 5 6 7 9
V2 = 9 10 5 4
In this case, if K = 1
I would first swap V1's 9 with V2's 4. This gives:
V1 = 5 6 7 4
V2 = 9 10 5 9
Sum of highest number as 17, as compared to earlier's 19. The second swap I could do is 10 from V2 with 5 from V1 giving:
V1 = 10 6 7 4
V2 = 9 5 5 9
This gives sum as 19, so better was the first swap and the output should be 17.
Here is my solution:
#include <iostream>
#include <vector>
#include <algorithm>
#define print(vec) for (int i = 0; i < vec.size(); i++) { cout << vec[i] << " "; } cout << endl;
using namespace std;
vector <long long int> s1, s2;
inline long long int calc(vector <long long int> v1, vector<long long int> v2) {
return *max_element(v1.begin(), v1.end()) + *max_element(v2.begin(), v2.end());
}
int main(){
long long int n, k;
cin >> n >> k;
long long int x;
for (unsigned int i = 0; i < n; i++) {
cin >> x;
s1.push_back(x);
}
for (unsigned int i = 0; i < n; i++) {
cin >> x;
s2.push_back(x);
}
while (k--) {
vector <long long int> b1(s1);
vector <long long int> b2(s2);
long long int skewb = calc(b1,b2);
vector <long long int> v1(s1);
vector <long long int> v2(s2);
auto mn1 = minmax_element(v1.begin(), v1.end());
auto mn2 = minmax_element(v2.begin(), v2.end());
iter_swap(mn1.second, mn2.first);
b1 = vector <long long int> (v1);
b2 = vector <long long int> (v2);
skewb = calc(v1,v2);
v1 = vector <long long int> (s1);
v2 = vector <long long int> (s2);
mn1 = minmax_element(v1.begin(), v1.end());
mn2 = minmax_element(v2.begin(), v2.end());
iter_swap(mn2.second, mn1.first);
if (calc(v1,v2) <= skewb) {
b1 = vector <long long int> (v1);
b2 = vector <long long int> (v2);
}
if (b1 == s1 && b2 == s2) cout << "LOL" << endl;
s1 = vector <long long int> (b1);
s2 = vector <long long int> (b2);
}
cout << calc(s1, s2) << endl;
}
Please note that this does all swaps i.e K. So even if the current arrangement was the best, it would still swap some values. Earlier I was breaking when the current arrangement was the best. The reason for doing this is because I was getting all test cases right except TWO! And guess what was even more annoying, one was from each task! :(
So I realised it must be necessary to complete all K switches. However even now I am getting 2 testcases wrong, there must be something I have overlooked.
Any idea what it is?
Link to solution: https://www.codechef.com/viewsolution/11574501
And btw, Task 1 has K = 1.
The problem with your code is you change the arrays between swaps and therefore there is the possibility of swapping one item back and forth between arrays. I mean in the first swap you place element x from array1 to array2 and in the next swap it is possible that you swap it back again.
Also you do a lot of vector copying which make the code inefficient. Even if the logic of your code was correct your code wouldn't have passed the time limit because your approach is O(n2).
First note that optimal answer is when all the elements in one array are bigger than all the elements in the other array.
Sort both arrays
for x from 0 to k
hypothetically swap x minimum elements of first array with x maximum elements of the second array.
result = min(result, max(result, max(first array) + max(second array) )
hypothetically swap x maximum elements of first array with x minimum elements of the second array.
result = min(result, max(result, max(first array) + max(second array) )
result will hold the final answer
Since both arrays are sorted you can find maximum elements of the arrays after hypothetical swap with one comparison.
V1 = 5 6 7 9 -> 5 6 7 9
V2 = 9 10 5 4 -> 4 5 9 10
x = 0 no swaps: result = V1[size-1] + V2[size-1]
x = 1
result = max(V1[size-1], V2[size-1]) + max(V1[0], V2[size-2])
result = max(V1[size-2], V2[0]) + max(V1[size-1],V2[size-1])
x = 2
result = max(V1[size-1], V2[size-1]) + max(V1[1], V2[size-3])
result = max(V1[size-3], V2[1]) + max(V1[size-1],V2[size-1])
...
This is the accepted implementation:
#include <iostream>
#include <algorithm>
#include <queue>
#include <vector>
#include <map>
using namespace std;
int main()
{
int n,k;
cin>>n>>k;
vector<int> v[2];
for ( int i=0;i < 2;++i ){
for ( int j=0;j<n;++j ){
int temp; cin>> temp;
v[i].push_back(temp);
}
}
sort(v[0].begin(),v[0].end());
sort(v[1].begin(),v[1].end());
int result = v[0].back() + v[1].back();
for ( int i=1; i<=k; ++i ){
int t = max(v[0][n-1],v[1][n-1]) + max(v[0][i-1],v[1][n-1-i]);
result = min(result,t);
t = max(v[0][n-1-i],v[1][i-1]) + max(v[0][n-1],v[1][n-1]);
result = min(result,t);
}
cout << result << endl;
}
If I understand you correctly, you want to minimize the sum of the two maximum elements, one from each array.You can do only K swaps.
Let's assume arrays are sorted (this will not change the algorithm).
Choose the array where the k element in order is smaller. Let's call this array S and the other array B.
In each swap take the biggest element from array S and swap with the smallest in array B.
If at some time all elements in array S are smaller then in B stop.
Explanation: We know that the maximum element from both array will be in the solution.So we want the other array have the smallest possible maximum element.
This is what this algorithm does.
The logic of this question is
For K=1 the lowest skew would be largest value (suppose found in V1) + second largest value of the other vector(called V2)
I have given way below how to do it
For K=1 you swap for ones ,now you get two new vectors and you again calulate for K=1 ,that means if you know how to get minimum skew for k=1 ,you can repeat same steps for k times ,so below i have given the steps to find minimum skew --->
There are two vectors V1 and V2
Step 1 --> find the largest element of all ,suppose its in V1
Step 2 --> find the second largest element of the other vector i.e. in this case (second largest element of V2) suppose its name is e2
Step 3 -->find the largest of V2 suppose its name is e1
Step 4 --> swap largest of V2 i.e e1 with a element of V1 (where the element of V1 is less then e2)
Above steps are for k=1
if you repeat these steps you can have lowest skew
E.g. given in question -->
V1 --> 1 14 2 3 10 4
V2---> 5 1 3 5 2 7
find largest of all--> its 14 in V1
cause largest element is in V1 so find second largest of V2 --> Its 5
find largest of V2 ---> its 7
Swap 7 of V2 with 3 of V1 (Its less then 5)
Calculate skew
Repeat the steps

Quick sort apparently taking O(n^2) when left or right-most element is selected as pivot

So um, I'm trying to learn Quick sort and have implemented the below code for it. However, it seems to run in O(n^2) instead of O(nlogn) when I take leftmost or rightmost element as pivot...
I am unable to figure out what's wrong with my code but I'm most likely making some very basic stupid mistake; can anyone please help and explain me where I'm going wrong?
Thanks a lot in advance! Here's my code:
#include <iostream>
#include <vector>
typedef int64_t int64;
int64 numberOfComparisons;
using namespace std;
int partitionAroundPivot(vector<int64>& a, int l, int r) {
numberOfComparisons = numberOfComparisons + (r - l) - 1 ;
int ppos;
ppos = l;
int64 p = a[ppos]; //Gives pivot
if(ppos != l)
swap(a[ppos], a[l]);
int i = l + 1, j;
for(j = l + 1; j <= r; j++){
if(a[j] < p)
{
swap(a[j], a[i]); //Swap with leftmost element bigger than pivot, i.e. v[i]
i++;
}
}
//Now pivot needs to go to its proper place
swap(a[l], a[i - 1]);
return ppos; //WRONG, will return l always, need to return i-1
}
void quickSort(vector<int64>& a, int l, int r) //Inplace so no return stuff
{
if( r - l <= 0)
return ;
int pivotPosition = partitionAroundPivot(a, l, r);
cout << "Called Qsort with positions l " <<l << " r " << r << " Pivot pos " << pivotPosition << endl;
for (int i = l; i < r; i++)
cout << a[i] <<" " ;
cout << endl;
quickSort(a, l , pivotPosition - 1 );
quickSort(a, pivotPosition + 1 , r );
}
int main() {
vector<int64> x = {3, 2, 1, 8, 6, 7, 6, 4};
quickSort(x, 0, x.size() -1);
return 0;
}
Part of the output is below:
Called Qsort with positions l 0 r 9 Pivot pos 0
1 2 3 4 6 10 9 5 7
Pivot: 2
Called Qsort with positions l 1 r 9 Pivot pos 1
2 3 4 6 10 9 5 7
Pivot: 3
EDIT: Part of the reason why I asked this was because I am supposed to calculate the number of comparisons done in total theoritically, and I simply used a (size of subarray at each partition call - 1) as the value (the actual ones will be different, I know since only part of the comparisons actually happen). This is seen in the numberOfComparisons variable above.
Now the thing is, for sorting 100 numbers, all from 1-100, none unique and mostly random, it shows the number of computations as 4851, that's close to 100*99/2 aka n*(n-1)/2 where n = 100. This led me to believe that it's doing O(n^2) time. Is this correct...?
EDIT2: I was being so stupid after all. The partitionAroundPivot was always returning l aka the first position of the subarray, resulting in one of the splits being a zero length subarray and another, the rest of the array. I need to pass back the position where a[l] actually goes and not l; i-1 in this case. Lesson learnt, I guess.
Thank you very much for the help, guys!
Qucksort is O(n log n) but in average, it is O(n^2) in worst case and O(nlogn) in best-case. The most important aspect to get a good efficiency is to select a good pivot.
In your program, you have selected one of the worst pivots because if you select the first or the last one, in case of ordered (or reverse-ordered) vectors, your algorithm is in the worst case efficiency.
This is why you have to think about your algorithm to select the pivot. One of the most used methods is to select the median of three, for example, the first, middle and last elements. Thus, you algorithm applied to a ordered vector is O(nlogn).
UPDATE: The complexity is determined by a profile of growth, not a specific case. In fact, you could have a very high value for a particular size of the problem, while the profile increases more smoothly when the problem size becomes very large. Before checking anything, run the program with several individual values reaching a very large n.

std::set::equal_range for a container of std::pair

I'm trying to find all the ranges [a,b] enclosing int values i, where a <= i <= b. I'm using set<std:pair<int,int>> for the set of ranges.
In the following, using equal range on a vector<int> yields the start and one past the end of the range.
When I do the same for a set<pair<int,int>>, the result starts and ends at one past the end of the range and therefore doesn't include the range enclosing the value.
#include <set>
#include <iostream>
#include <algorithm>
using namespace std;
int main()
{
int ia[] = {1,2,3,4,5,6,7,8,9,10};
set<int> s1(begin(ia),end(ia));
auto range1 = s1.equal_range(5);
cout << *range1.first << " " << *range1.second << endl; //prints 5 6
pair<int,int> p[] = {make_pair(1,10),
make_pair(11,20),
make_pair(21,30),
make_pair(31,40)};
set<pair<int,int>> s(begin(p), end(p));
auto range = s.equal_range(make_pair(12,12));
cout << range.first->first << " " << range.first->second << endl; //prints 21 30, why?
cout << range.second->first << " " << range.second->second << endl; //prints 21 30
}
prints 5 6
21 30
21 30
Why does equal_range on the set<pair<int,int>> not include the range that encloses the value (12), namely [11.20]
equal_range is behaving completely correctly:
assert( std::make_pair(11, 20) < std::make_pair(12, 12) );
assert( std::make_pair(12, 12) < std::make_pair(21, 30) );
[11,20] is not a range, it's a pair. The pair [12,12] is not "within" another pair, that makes no sense to even say.
[12,12] is not "within" [11,20], it's greater than it. The less-than operator for std::pair compares the first elements first, and only if they're equal does it look at the second elements, so make_pair(11,x) is less than make_pair(12, y) for any x and y
So equal_range tells you that [12,12] would be inserted after [11,20] and before [21,30], which is correct.
If you want to treat pairs as ranges of values you need to write code to do that, not assume the built-in comparisons for pairs does that. You're actually trying to find an int 12 in a range of pairs of ints, but have written code to find a pair [12,12] in a range of pairs of ints. That's not the same thing.
It does not include [11, 20] in the range, because it doesn't include anything in the range. There are no equal elements to [12, 12], so it returns an empty range (represented by the half-open interval [x, x)).
BTW dereferencing the upper bound of the range may invoke undefined behavior, since that may be equal to s.end().
The pair [12, 12] is sorted after [11, 20] and before [21, 30].
std::set::equal_range() includes a range of equal elements. There is no equal element in your set (especially not [11, 20]), so equal_range() returns [21, 30], [21, 30].
equal_range is implemented as to call lower_bound first then call upper_bound to search the rest data set.
template <class ForwardIterator, class T>
pair<ForwardIterator,ForwardIterator>
equal_range ( ForwardIterator first, ForwardIterator last, const T& value )
{
ForwardIterator it = lower_bound (first,last,value);
return make_pair ( it, upper_bound(it,last,value) );
}
Look at your sample:
It calls lower_bound to locate the lower bound of value(which is pair(12,12), which arrives at
pair<int,int> p[] = {make_pair(1,10),
make_pair(11,20),
make_pair(21,30), // <--- lower_bound() points to here
make_pair(31,40)};
Then it calls upper_bound() to search on (21,30),(31,40) and it cound't find it, it returns (21,30)
http://www.cplusplus.com/reference/algorithm/upper_bound/
I don't think your std::set<std::pair<int, int> > won't help you much in intersecting it with your integer: You can find the s.lower_bound(std::make_pair(i + 1, i + 1) to cut off the search but all ranges starting at an index lower than i + 1 can potentially include the value i if the second boundary is large enough. What might help is if you know the maximum size of the ranges in which case you can bound the search towards the front by s.lower_bound(std::make_pair(i - max_range_size, i - max_range_size)). You'll need to inspect each of the ranges in turn to identify if your i falls into them:
auto it = s.lower_bound(std::make_pair(i - max_range_size, i - max_range_size));
auto upper = s.lower_bound(std::make_pair(i + 1, i + 1));
for (; it != upper; ++it) {
if (i < it->second) {
std::cout << "range includes " << i << ": "
<< [" << it.first << ", " << it->second << "]\n";
}
(or something like this...)