Sorting Of two arrays - c++

Suppose I have been given two array.For ex- Process With their Arrival Time and Finish Time.
I want to sort it on the basis of finish time.On the basis of Finish Time,Arrival Time Should also be sorted.
I can use bubble sort or selection sort for this purpose.
But Is there any STL for this purpose?
Can I use sort() function with some modifications?

One way to do it would be to create a vector of (end, start) pairs (in this order - explanation below), sort it, then split the pairs of the sorted output:
#include <utility> // For pair
#include <algorithm> // For sort
std::vector<std::pair<size_t, size_t>> intervals;
for(size_t i = 0; i < start.size(); ++i)
intervals.push_back(std::make_pair(end[i], start[i]));
std::sort(std::begin(intervals), std::end(intervals)); // (*)
start.clear();
end.clear();
for(size_t i = 0; i < start.size(); ++i)
{
end[i] = intervals[i].first;
start[i] = intervals[i].second;
}
Note the line with the (*) comment. STL pairs' order is lexicographic, which we exploit here (sorting pairs will sort by the firsts for free).

You can pass a functor to std::sort or provide operator < for your data:
struct MyClass
{
std::size_t arrivalTime;
std::size_t finishTime;
};
std::vector<MyClass> myClasses = //..
std::sort(myClasses .begin(), myClasses.end(),
[](const MyClass& lhs, const MyClass& rhs) {
return std::tie(lhs.finishTime, lhs.arrivalTime)
< std::tie(rhs.finishTime, rhs.arrivalTime);
});
or simply
bool operator< (const MyClass& lhs, const MyClass& rhs)
{
return std::tie(lhs.finishTime, lhs.arrivalTime)
< std::tie(rhs.finishTime, rhs.arrivalTime);
}
and later:
std::sort(myClasses .begin(), myClasses.end());

Related

C++ sorting a vector of structs

I am new to C++ and am trying to sort a vector based on values in another vector. I am trying to implement this by creating a vector of structs and sorting the vector of stucts using the STL. The structs have 2 data items, one a CustomType and the other an int. I want this sorted in decreasing order of the int field, and have therefore included a boolean operator overloading to be able to use the STL sort (algorithm).
The struct is constructed in the function using references to the CustomType vector and an initially uninitialised int vector, and combining them into a vector of structs. The values for the ints are obtained by calling a separate member function of SomeClass (SomeFunc) on each item of the CustomType vector and another u_int8_t param (this function works fine by itself).
In the end, I want to replace the sorted CustomType objects based on the sorted struct sequence.
The implementation file (.cpp) has the following function:
void SomeClass::orderFunc(std::vector<CustomType>& x, std::vector<int>& y, u_int8_t param){
std::vector<CustomStruct> xy_vec;
y.assign(x.size(), 0);
int count = int(x.size());
for(int i=0; i != count; ++i){
y[i] = SomeFunc(x[i], param);
}
for(int i = 0; i != count; ++i){
xy_vec[i].var1 = x[i];
xy_vec[i].var2 = y[i];
}
std::sort(xy_vec.begin(), xy_vec.end());
for(int i = 0; i != count; ++i){
x[i] = xy_vec[i].var2;
}
}
The struct is defined in the SomeClass header file as below:
struct CustomStruct{
CustomType var1;
int var2;
bool operator>(const CustomStruct& a) const{
return (this->var2 > a.var2);
}
};
When this function is called, I get the following error:
invalid operands to binary expression
bool operator()(const _T1& __x, const _T1& __y) const {return __x < __y;}
I can't understand why the bool operator overloading is invalid given that this is being defined for the int field of the struct.
What am I missing? Any help would be appreciated. Also, any suggestions for a more elegant way to do this would be great as well.
You need to overload operator< and not operator>
bool operator<(const CustomStruct& a) const
{
return (this->var2 < a.var2);
}
EDIT: For sorting in reverse order, you need to call std::sort with rbegin() and rend() (reverse) iterators:
std::sort(xy_vec.rbegin(), xy_vec.rend());
EDIT (again, as the question is too long, has 2 problems):
The vector xy_vec is empty, you need to call resize:
std::vector<CustomStruct> xy_vec;
// Resize here
xy_vec.resize(count);
for(int i = 0; i != count; ++i){
xy_vec[i].var1 = x[i];
xy_vec[i].var2 = y[i];
Or you can call push_back - I am not telling you all that. Please find!
std::sort has two main overloads, one without a sort predicate that defaults to using operator < and one with a sort predicate (details here).
So you could write something like
struct CustomStructCmp {
bool operator()(const CustomStruct& a, const CustomStruct& b) const
{
return a.var2 > b.var2;
}
};
std::sort(xy_vec.begin(), xy_vec.end(), CustomStructCmp());
(if you are using C++11 then you could use a lambda instead).
Alternatively you could write
std::sort(xy_vec.begin(), xy_vec.end(), std::greater<CustomStruct>());
but I feel that it is more natural to directly use a functor/lambda rather than define operator> and use the std::greater functor.

How to compare vector with array in specific way in efficient way?

I would like to compare a vector with an array assuming that elements are in different order.
I have got a struct like below (this struct hasn't got "operator==" and "operator<" -> so I can't use sort):
struct A
{
int index;
A(int p_i) : index(p_i) {}
};
The size of the vector and the array is the same:
std::vector<A> l_v = {A(1), A(2), A(3)};
A l_a[3] = {A(3), A(1), A(2)};
I am looking for some function from std like below "some_function_X" which can find element in specific way using lambda, or function which can compare only specific field like "lhs.index == rhs.index" -> by specific field in class without "operator==" and "operator>" etc.
bool checkIfTheSame(const std::vector<A>& l_v, const A& l_a)
{
for(usigned int i=0; i< 3; ++i)
{
if(!std::some_function_X(l_v.begin(), l_v.end(), l_a,
[](const A& lhs, const A& rhs){
return lhs.index == rhs.index;
})) return false;
}
return true;
}
Thanks.
this struct hasn't got "operator==" and "operator<" -> so I can't use sort
Firstly, only operator< is required. Secondly, it doesn't have to be defined as a member function. The following free function works with std::less (which is what std::sort uses if you don't pass a functor for comparison).
bool operator<(const A& a, const A& b) {...}
Or, you can use a custom comparison functor instead of std::less.
Sorting the array and the vector and then comparing should have better asymptotic runtime complexity than trivially iterating one and checking if the element exists in the other using linear search.
Another idea would be to sort only one of them, iterate the unordered and test the existence in sorted container with binary search. That has same asymptotic complexity as sorting both.
If you can't modify either container, then you can make a copy for sorting. That costs some memory, but is still asymptotically faster than the trivial approach. std::partial_sort_copy can save you a few copies by sorting directly to the copy.
look here : http://www.cplusplus.com/reference/algorithm/
find with lambda expression find if
function which can compare only specific field like "lhs.index == rhs.index" -> by specific field in class without "operator==" and "operator>" etc.
to check if your 2 containers contains same datas with a predicate : equal with a custom predicate
if you just want to check if your container container a specific value, have a look here : How to find if an item is present in a std::vector?
I'm not sure I fully understand what you want but I'll take a guess that you want to check whether two arrays (which have different container types) are equivalent, that is for each item in array A there is a corresponding item somewhere in array B for which some predicate returns true.
You want to do this on two arrays that are not only of different types, but also possibly in a different order.
This is one way to do it:
struct Foo
{
Foo(int i) : _index { i } {}
int index() const {
return _index;
}
private:
int _index;
};
// params:
// first1, last1 bound the first array
// first2, last2 bound the second array
// pred is a predicate that checks for equivalents
// order is a predicate that performs weak ordering
template<class Iter1, class Iter2, class Pred, class Order>
bool checkIfTheSame(Iter1 first1, Iter1 last1, Iter2 first2, Iter2 last2, Pred pred, Order order)
{
const auto len1 = last1 - first1;
const auto len2 = last2 - first2;
if (len1 != len2)
return false;
using namespace std;
using item1_type = typename std::iterator_traits<Iter1>::value_type;
using item2_type = typename std::iterator_traits<Iter2>::value_type;
std::vector<std::reference_wrapper<item1_type>> refs1 { first1, last1 };
std::sort(begin(refs1), end(refs1), order);
std::vector<std::reference_wrapper<item2_type>> refs2 { first2, last2 };
std::sort(begin(refs2), end(refs2), order);
for (size_t i = 0 ; i < len1 ; ++i) {
if (!pred(refs1[i], refs2[i]))
return false;
}
return true;
}
simple example:
using namespace std;
bool same_indexes(const Foo& f1, const Foo& f2) {
return f1.index() == f2.index();
}
bool sort_indexes(const Foo& f1, const Foo& f2) {
return f1.index() < f2.index();
}
int main(int argc, const char * argv[])
{
vector<Foo> x { 1, 2, 3 };
Foo y[] = { 3, 2, 1 };
cout << checkIfTheSame(begin(x), end(x), begin(y), end(y), same_indexes, sort_indexes) << endl;
return 0;
}
If you do not have any way to sort the array or the vector, but you are only able to know if two elements are equal, the only method is an exhaustive search.

Iterating in a sorted manner over a std::vector<std::pair<T,U> > object

I am reading a object from a database of type Foo, as defined below. This object is a vector of Foo Members, where a Foo Members consists of a string id and a container object.
typedef std::pair<std::string, Container> FooMember;
typedef std::vector<FooMember> Foo;
I wish to iterate over a Foo object in its sorted form, where sorting is done with respect to the id. To do this I am using the following function to create first a sorted version of the object. As you can see, the object is sorted in a case insensitive manner. Is there a better way for me to iterate over this object compared to how I am currently doing it?
Foo sortedFoo(Foo& value) const {
Foo returnValue;
returnValue.reserve(value.size());
// use a map to sort the items
std::map<std::string, FooMember> sortedMembers;
{
Foo::iterator i = value.begin();
Foo::iterator end = value.end();
for(; i!=end; ++i) {
std::string name = i->first;
boost::algorithm::to_lower(name);
sortedMembers[name] = *i;
}
}
// convert the map to a vector of its values in sorted order
std::map<std::string, FooMember >::iterator i = sortedMembers.begin();
std::map<std::string, FooMember >::iterator end = sortedMembers.end();
for(; i!=end; ++i) {
returnValue.push_back(i->second);
}
return returnValue;
}
Yes: Copy the vector, then use std::sort with a custom comparison predicate:
struct ByIdCaseInsensitive {
bool operator ()(const FooMember& lhs, const FooMember& rhs) const {
return boost::algorithm::to_lower_copy(lhs.first) <
boost::algorithm::to_lower_copy(rhs.first);
}
};
Way more efficient than filling a map, and then copying back to a vector.
The predicate would be even better if it used a proper Unicode collation algorithm, but that isn't available in the standard library or Boost.
You can use std::sort
#include <algorithm>
bool comparator(const FooMember& i, const FooMember& j)
{
std::string str1 = i.first;
boost::algorithm::to_lower(str1);
std::string str2 = j.first;
boost::algorithm::to_lower(str2);
return (str1 < str2);
}
void sortFoo(Foo& value) {
std::sort (value.begin(), value.end(), comparator);
}
Or, you can keep Foo objects in a std::map<std::string, Foo> from the beginning so they remain always sorted.
The best way would be to use std::sort with a custom comparator for FooMembers:
bool cmp(const FooMember& lhs, const FooMember& rhs);
Foo sortedFoo(const Foo& value) const
{
Foo tmp = value;
return std::sort(tmp.begin(), tmp.end(), cmp);
}
where the comparison can be implemented with the help of std::lexicographical_compare and tolower:
#include <cctype> // for std::tolower
bool ci_cmp(char a, char b)
{
return std::tolower(a) < std::tolower(b);
}
#include <algorithm> // for std::sort, std::lexicographical_compare
bool cmp(const FooMember& lhs, const FooMember& rhs)
{
return std::lexicographical_compare(lhs.first.begin(),
lhs.first.end(),
rhs.first.begin(),
rhs.first.end(),
ci_cmp);
}
You can also use std::sort with a lambda expression:
std::sort(value.begin(), value.end(), [](const FooMember &lhs, const FooMember &rhs)
{
std::string str1 = i.first, str2 = j.first;
boost::algorithm::to_lower(str1);
boost::algorithm::to_lower(str2);
return str1 < str2;
});
Or use the version provided by erelender. It's up to you.
Semantically std::vector<std::pair<T,U> > is a std::map<T,U> (but implementations are usually different). If you can re-design Foo, you probably better do it. As side effect, you will get sorting for free.
typedef std::map<std::string, Container> Foo;

Sorting Subsets of a Sorted Vector

I'm trying to figure out the best way to sort an array under multiple criteria. I want to sort an array, then sort a subset of that array if they were equal under the first criteria.
Example:
Say we have the data: { ("cat", 2), ("dog", 4), ("cat", 1), ("dog", 3) }
We sort this first according to alphabetical order of the string:
{ ("cat", 2), ("cat", 1), ("dog", 4), ("dog", 3) }
Then we sort the two subsets (set of cats and the set of dogs) in increasing order of their numbers:
{ ("cat", 1), ("cat", 2), ("dog", 3), ("dog", 4) }
Also, I'm using a recursive quicksort method that has the following header:
void quickSort(vector<Type*>, int left, int right)
where left and right are the bounding indices by which the vector should be sorted.
Should I add code to the sorting method itself or should i call the sorting method again somehow?
Generally, you want a custom comparator to sort with.
struct Foo {
std::string name;
int count;
struct Less {
bool operator()(const Foo &lhs, const Foo &rhs) const {
if ((int c = lhs.name.compare(rhs.name)) != 0)
return c < 0;
return lhs.count < rhs.count;
}
};
};
std::vector<Foo> foos;
// ...
std::sort(foos.begin(), foos.end(), Foo::Less());
If you can't just use a single custom operator, you can use a stable sort.
As pointed out by Mark, std::sort is not a stable sort. Instead you would need to use std::stable_sort.
You want to sort them independently in order of increasing importance. So, you sort by numbers and then by the string.
struct Foo {
std::string name;
int count;
struct NameLess {
bool operator()(const Foo &lhs, const Foo &rhs) const {
return lhs.name.compare(rhs.name) < 0;
}
};
struct CountLess {
bool operator()(const Foo &lhs, const Foo &rhs) const {
return lhs.count < rhs.count;
}
};
};
std::vector<Foo> foos;
// ...
std::stable_sort(foos.begin(), foos.end(), Foo::CountLess());
std::stable_sort(foos.begin(), foos.end(), Foo::NameLess());
You would prefer the first obviously, but the latter can come in handy for keeping combinatorial and/or run-time configurable algorithms simplistic.
For reference:
cplusplus.com C++ : Reference : STL Algorithms : stable_sort
cplusplus.com C++ : Reference : STL Algorithms : sort
If you store your data as a vector<pair<string, int> > then you can just use std::sort(vec.begin(), vec.end()); and it will just work because pair's operator< will already use both parts of the object to do the sorting.
you could overload your < operator then you could use vector.unique() and then vector.sort()
In your case you need a custom comparator cause you are mixing data Types you couldn't compare your standart comparator could only compare same data Types and doesn't know with which criteria you would sort.

Sorting an STL vector on two values

How do I sort an STL vector based on two different comparison criterias? The default sort() function only takes a single sorter object.
You need to combine the two criteria into one.
Heres an example of how you'd sort a struct with a first and second field
based on the first field, then the second field.
#include <algorithm>
struct MyEntry {
int first;
int second;
};
bool compare_entry( const MyEntry & e1, const MyEntry & e2) {
if( e1.first != e2.first)
return (e1.first < e2.first);
return (e1.second < e2.second);
}
int main() {
std::vector<MyEntry> vec = get_some_entries();
std::sort( vec.begin(), vec.end(), compare_entry );
}
NOTE: implementation of compare_entry updated to use code from Nawaz.