C++ Sorting Array Class
I have an array object that record the following..
This is at classone.h
ClassOne
{
string name;
int data;
float valueData;
}
and the constructor are created at classone.cpp
At main.cpp I created ClassOne Array of Size 10
#include "classone.h"
ClassOne cone[10];
Next is i recorded several value to the object
and now ClassOne got 3 objects
cone[0]
name = "hello"
data = 1
valueData = 20
cone[1]
name = "panda"
data = 2
valueData = 15
cone[2]
name = "joe"
data = 3
valueData = 25
What i want to achieve is do a sort that can rearrange this array by valueData highest ascending form so.. it will be
cone[2] then cone[0] then cone[1] ..
but the issue if i use bubble sort , i tried google and find some, they are sorting by e.g int a[]={9,6,5,23,2,6,2,7,1,8};
but i wanna sort by class array object. and re-arrange the value together , how do i achieve this.
So when i cout it will be
-- Highest to lowest --
1) Name: Joe , Data = 3, Value =25
2) Name: Hello , Data =1 , Value = 20
3) Name: Panda, Data = 2, Value = 15
Thanks for all help and guide!!
The easiest way is to use the standard library:
#include <algorithm>
std::sort(cone, cone + 10,
[](ClassOne const & a, ClassOne const & b) -> bool
{ return a.value < b.value; } );
If you're willing to define a comparison operator globally, you don't even need the lambda:
bool operator<(ClassOne const & a, ClassOne const & b)
{
return a.value < b.value;
}
std::sort(cone, cone + 10);
Or you could make the comparator a member function. Or you could give the comparator function a custom name and pass that as the third argument of sort. This might be a good idea in the case where the comparison is specific to your situation and not "natural":
bool ValueCmp(ClassOne const & a, ClassOne const & b)
{
return a.value < b.value;
}
std::sort(cone, cone + 10, ValueCmp);
The last version is useful if you don't have C++11 support (for lambdas, as in the first case), or if you want to reuse the comparator in multiple different situations.
Use std::sort and a suitable sort function/functor:
bool comp(const ClassOne& lhs, const ClassOne& rhs)
{
return lhs.valueData < rhs.valueData;
}
std::sort(cone, cone+10, comp);
or, in C++11,
std::sort(std::begin(cone), std::end(cone), comp);
You can make a struct that implements the operator < method that std::sort in the <algorithm> header uses to sort iterated items.
struct One {
string name;
int data;
float valueData;
bool operator < (const one &a) const{
return valueData <a.valueData;
}
};
then all you have to do is to make an array of this struct and sort it using the sort function
Look at your Bubble sort source. At some point, it will be comparing one int to another, probably with either the less than operator (<) or the greater than operator (>). That's where the sort function determines the relative order of those two items. By repeating that comparison many times, the sort function is able to determine the total order of the collection.
You need to replace that operation with your own comparison function. A function that takes two objects of your class, and returns true if the first should be considered less than the second, false if the second should be considered less than the first, and false if they should be considered equivalent.
You must define a comparison operator for your class. How you determine whether one object is less than another isn't clear from your question.
Try this
...
....
void ClassOne::sort(ClassOne *obj,int n)
{
ClassOne temp;
int i, j;
for (i = 0; i < n; i++)
for (j = n - 1; j > i; j--)
if (obj[j].valueData <obj[j - 1].valueData )
{
temp = obj[j];
obj[j] = obj[j - 1];
obj[j - 1] = temp;
}
}
...
int main()
{
ClassOne obj[3],a;
for(int i=0;i<3;i++)
obj[i].readdata();
a.sort(obj,3);
...
}
Related
I'm implementing an algorithm that implies a lot of checking whether elements are in a set/list. I was using std::vector containers but time was increasing exponentially as the vector would grow.
I've decided I would try using std::set containers in order not to have to explore the entire container to know whether it contains a certain element.
I implemented the following function that checks whether an element is part of a given set:
bool in_set(set<Node> node_set){
return node_set.find(*this) != node_set.end();
}
However, that function is taking around 2s for very small sets (1-3 elements) which makes my entire algorithm unusable.
The custom class I'm using look like this:
class Node{
public:
int d;
int h_score;
int coordinates [3];
Node* parent_address;
};
The comparison operator that I implemented look like this:
bool operator<(Node other) const{
return concatenate(concatenate(this->coordinates[0], this->coordinates[1]), this->coordinates[2]) <
concatenate(concatenate(other.coordinates[0], other.coordinates[1]), other.coordinates[2]);
}
Edit: The concatenate function does not seem to take a lot of time while executing, it looks like this:
int concatenate(int i, int j) {
int result = 0;
for (int x = i; x <= j; x++) {
result = result * 10 + x;
}
return result;
}
Do you know why it is taking so much time, and more importantly, how to make it faster?
First of all, you can try to pass Set as const & and not in operator< also as const &.
bool in_set(const set<Node>& node_set){
return node_set.find(*this) != node_set.end();
}
And
bool operator<(const Node& other) const
It will use ref instead of a copy of your set and Node objects.
Do you know why it is taking so much time
concatenate(1, 100000000) takes 1.3 second on my raspberry pi, that way to do is too slow, and in fact useless
Note also that because of the possible overflows concatenate can give the same result for different nodes, this is non compatible for an operator<
how to make it faster?
you have to find something else than these calls of concatenate to implement your operator<
What is your need ? is the order in the set is important or it can be replaced by any one else ?
It is not mandatory to create a unique identifier to compare two nodes, compare them directly, for instance :
bool operator<(const Node & other) const{
if (coordinates[0] < other.coordinates[0])
return true;
if (coordinates[0] >= other.coordinates[0])
return false;
if (coordinates[1] < other.coordinates[1])
return true;
if (coordinates[1] >= other.coordinates[1])
return false;
return (coordinates[2] < other.coordinates[2]);
}
To understand that operator< works you can consider node.coordinates supports a big number having 3 times the size of an int, so I compare the higher bits, then if equals the medium bits, then if equals the lower bitsused for a set
Your operator< takes a copy of the Node. There's also no need to create strings to compare, the built-in tuple class can do that:
How about:
bool operator<(const Node& other) const {
return std::make_tuple(coordinates[0], coordinates[1], coordinates[2]) <
std::make_tuple(other.coordinates[0], other.coordinates[1], other.coordinates[2]);
}
void insertion_sort(int *data, unsigned int n) {
for (unsigned int uns = 1; uns < n; ++uns ) {
int next = data[uns];
unsigned int idx;
for (idx = uns; idx > 0 && data[idx - 1] > next; --idx) {
data[idx] = data[idx - 1];
}
data[idx] = next;
}
}
int main()
{
vector<Person> crew= ucitaj_osobe("osobe.txt"); /*this reads the file osobe.tx and stores it in vector crew,this works */
Person o;
insertion_sort(polje, 100); // ???
ispisi_osobe(popis); /* this prints out the vector,this works too*/
return 0;
}
how do I send this vector to insertion sort,and sort it?
please help,the code for insertion sort was implemented from another source
Your function insertion_sort is implemented to sort arrays of int and the function will not work for sorting of your vector of Person objects.
If you want to sort your vector of Person objects I suggest you use std::sort from the standard library. To use it you must implement the < operator for Person objects.
Example:
// Only to demonstrate.
struct Person {
std::string name;
int age;
};
// Implement according to your needs.
bool operator< (const Person& lhs, const Person& rhs) {
return lhs.name < rhs.name;
}
int main() {
vector<Person> crew = ucitaj_osobe("osobe.txt");
std::sort(begin(crew), end(crew));
ispisi_osobe(popis);
// return 0; Unnecessary in main function.
}
Live example: http://ideone.com/YEL7IV
Note that std::sort is not guaranteed to use insertion sort.
You can pass a pointer to the array within a vector by passing the address of the first element within the vector.
insertion_sort(&crew[0], crew.size());
Your insertion_sort is designed to sort arrays of int, and
only arrays of int. You cannot use it on arrays of Person.
You don't say why you want to use this insertion sort, instead
of std::sort. But if you want to use it on vector of
Person, you'll have to change its first argument to Person*,
and pass it &crew[0], crew.size(). A better solution would be
to convert it to take an std::vector<Person> directly, rather
than a pointer and a size. An even better solution would be
a template taking two bidirectional iterators, and invoke it
with crew.begin(), crew.end().
I wrote an IntegerMatrix class to add my own methods to work with matrices. Now I've written a function like this:
IntegerMatrix** IntegerMatrix::multiplyMatrix(IntegerMatrix** table2)
(It's a double pointer because I'm holding a huge array of pointers to 4x4 2D arrays.) so I simply could do this:
matrix1.multplyMatrix(matrix2)
One little problem is the * isn't defined for my own class. So I thought to overload this operator that I could do something like this:
sum += this->table[i][k] * table2[k][j];
But how can I get the right i and k in the overloaded operator, which is defined like this:
IntegerMatrix IntegerMatrix::operator*(const IntegerMatrix & k);
The only problem I can't figure out right now is how to get the right values ?
EDIT:
I've rewrote this and now I have:
IntegerMatrix IntegerMatrix::operator*(const IntegerMatrix & table2)
{
int i, j, k;
int sum;
IntegerMatrix * result = new IntegerMatrix(SIZE);
for (i = 0; i < SIZE; i++) {
for (j = 0; j < SIZE; j++) {
sum = 0;
for (k = 0; k < SIZE; k++) {
sum += this->table[i][k] * table2[k][j];
}
result[i][j] = sum;
}
}
return *result;
}
That gives me just an error on the [] :
Binary '[' : 'IntegerMatrix' does not define this operator or a conversiont o a type acceptable to the predefined operator.
I don't understand your question, but here's a brief demo of how matrix multiplication normall works:
class IntegerMatrix {
int table[3][3];
public:
IntegerMatrix& operator*=(const IntegerMatrix& rhs) {
//multiply table by rhs.table, store in data.
return *this;
}
};
IntegerMatrix operator*(IntegerMatrix lhs, const IntegerMatrix& rhs)
{return lhs*=rhs;} //lhs is a copy, so we can alter and return it
FOR YOUR EDIT
You have the code
IntegerMatrix * result = new IntegerMatrix(SIZE); //pointer to an IntegerMatrix
...
result[i][j] = sum; //assign sum to the jth index of matrix # i
when in actuality, I presume you wanted
result->table[i][j] = sum; //sum to the ixj index of the result matrix.
Also, your function is leaky, because you have a new, but no delete. This is easy to fix in your case, since you don't need the new. (Are you from a Java or C# background?)
IntegerMatrix result(SIZE);
...
result[i][j] = sum;
...
return result;
Unrelated to all of the above, you might actually want to provide a [] operator for your Integer Matrix.
class row {
int* data;
int size;
public:
row(int* d, int s) :data(d), size(s) {}
int& operator[](int offset) {
assert(offset<size);
return data[offset];
}
};
row operator[](int column) {
assert(column<SIZE);
return row(table[column], SIZE);
}
And this would allow you to write:
IntegerMatrix result;
result[i][j] = sum;
You may be carrying over some artifacts, in sort of a Cargo-Cult programming sense. :-/
For instance: I'm guessing that the double indirections (**) on your prototype for multiplyMatrix are there because you saw multidimensional arrays of integers around somewhere...stuff like:
void printMatrix(int ** myMatrix, int rows, int columns);
The double-indirection is just a pointer-to-a-pointer. It's a way of achieving the specific implementation point of passing low-level C-style 2D arrays as parameters. But it's not something you have to tack on any time you're working with an abstract class that happens to represent a Matrix. So once you've encapsulated the matrix size and data itself inside the IntegerMatrix class, you don't want something like this:
void printMatrix(IntegerMatrix ** myMatrix);
More likely you'd want to pass in a simple reference to the class which is encapsulating the data, like this:
void printMatrix(IntegerMatrix const & myMatrix);
You should actually return a new matrix from your multiplication function, at least if you're using it to implement an operator overload...because semantically it does not make sense for people to write things like a * b; and have that modify a. (It can, but you shouldn't.) So you are left with either the choice of returning a matrix value instance:
IntegerMatrix IntegerMatrix::multiplyMatrix(IntegerMatrix const & rhs);
...or returning a pointer to a new object:
IntegerMatrix * IntegerMatrix::multiplyMatrix(IntegerMatrix const & rhs);
Returning by pointer has historically been chosen by many libraries because returning by value from a local variable in the function would involve making a copy at the time of return. Returning a pointer is fast (it "copies" only one 32-bit/64-bit number) while copying an instance of an object and large blocks of data inside it is slow. So a lot of libraries would just use Matrix pointers everywhere...with the problem that it becomes hard to know whose responsibility it is to ultimately delete the object. Smart pointers are one way of ensuring this:
unique_ptr<IntegerMatrix> IntegerMatrix::multiplyMatrix(IntegerMatrix const & rhs);
But C++11 has some sneaky ability to be just as fast without the mess. If you return something by value from a function and the compiler is sure that value isn't going to be used again (since it's going out of scope), then it can be "moved" about as fast as a pointer could. This requires that you support move construction by RValue reference, and there's all kinds of trickiness in that.
There's really a lot of nuance. If you're doing this as an educational exercise, I'd suggest taking it slowly and going through a tutorial that walks you through every step instead of jumping straight into the fire. And if you're using low-level C arrays and dynamic allocations inside your matrix, change them to a std::vector of std::vector.
For one IntegerMatrix object you're using this->table[i][k] to refer to the array where you're holding the matrix data, while for the table2 object reference and the result pointer, you're using table2[k][j] and result[i][j].
I think that what you want to do is something like:
IntegerMatrix IntegerMatrix::operator*(const IntegerMatrix & table2)
{
int i, j, k;
int sum;
IntegerMatrix * result = new IntegerMatrix(SIZE);
for (i = 0; i < SIZE; i++) {
for (j = 0; j < SIZE; j++) {
sum = 0;
for (k = 0; k < SIZE; k++) {
sum += this->table[i][k] * table2.table[k][j];
}
result->table[i][j] = sum;
}
}
return *result;
}
I have a struct like this:
struct db {
string name,sur;
int num;
};
And declared an array of db structs:
struct db a[10];
and every member of a[] is filled with a name, surname and a number but there can be the same number appearing multiple times.
I need to sort the numbers, and print the results, i.e. sort by the num of each struct and the print the name, sur and the num in each line starting from the smallest num going down to the largest. I don't know how to do this, please help me.
First, in C++ you don't need to repeat "struct" every time.
You can use the std::sort() function and give it a custom predicate.
bool db_cmp(const db &left, const db &right)
{
return left.num < right.num;
}
//...
db a[10];
std::sort(a, a + 10, db_cmp);
// then, display the contents of a..
You can use qsort.
int db_comparator ( const void * elem1, const void * elem2 )
{
struct db *first = (struct db *) elem1, *second = (struct db *) elem2;
return first->num - second->num;
}
qsort(a, sizeof(a)/sizeof(a[0]), sizeof(a[0]), db_comparator);
Do you have to implement your own sorting algorithm?
If so I strongly suggest typing "Sorting Algorithms" into google and/or checking out the wikipedia page.
Bubble sort is REALLY easy to implement (But is a poor sorting algorithm). It will come down to checking each number against each other and then swapping them is one is less than the other. String sorting is easy too as strcmp returns you a value less than 0 for a string "less" than the one being compared to and greater than zero for one "greater" than.
If you don't need to implement your own algorithm then use std::sort.
You could add a comparison method to your structure:
struct db
{
string name;
string sur;
int num;
bool operator <(const db& other)
{
if (name == other.name)
{
return sur < other.sur;
}
return name < other.name;
};
Now you can use the std::sort algorithm because your object has the '<' operator defined.
This question already has answers here:
How do I sort a std::vector by the values of a different std::vector? [duplicate]
(13 answers)
Closed 9 years ago.
This is probably best stated as an example. I have two vectors/lists:
People = {Anne, Bob, Charlie, Douglas}
Ages = {23, 28, 25, 21}
I want to sort the People based on their ages using something like sort(People.begin(), People.end(), CustomComparator), but I don't know how to write the CustomComparator to look at Ages rather than People.
Obvious Approach
Instead of creating two separate vectors/lists, the usual way to handle this is to create a single vector/list of objects that include both names and ages:
struct person {
std::string name;
int age;
};
To get a sort based on age, pass a comparator that looks at the ages:
std::sort(people.begin(), people.end(),
[](auto const &a, auto const &b) { return a.age < b.age; });
In older C++ (pre C++11, so no lambda expressions) you can define the comparison as a member overload of operator< or else as a function-object (an object that overloads operator()) to do the comparison:
struct by_age {
bool operator()(person const &a, person const &b) const noexcept {
return a.age < b.age;
}
};
Then your sort would look something like:
std::vector<person> people;
// code to put data into people goes here.
std::sort(people.begin(), people.end(), by_age());
As for choosing between defining operator< for the class, or using a separate comparator object as I show above, it's mostly a question of whether there's a single ordering that's "obvious" for this class.
In my opinion, it's not necessarily obvious that sorting people would always happen by age. If, however, in the context of your program it would be obvious that sorting people would be done by age unless you explicitly specified otherwise, then it would make sense to implement the comparison
as person::operator< instead of in a separate comparison class the way I've done it above.
Other Approaches
All that having been said, there are a few cases where it really is impractical or undesirable to combine the data into a struct before sorting.
If this is the case, you have a few options to consider. If a normal sort is impractical because the key you're using is too expensive to swap (or can't be swapped at all, though that's pretty rare), you might be able to use a type where you store the data to be sorted along with just an index into the collection of keys associated with each:
using Person = std::pair<int, std::string>;
std::vector<Person> people = {
{ "Anne", 0},
{ "Bob", 1},
{ "Charlie", 2},
{ "Douglas", 3}
};
std::vector<int> ages = {23, 28, 25, 21};
std::sort(people.begin(), people.end(),
[](Person const &a, person const &b) {
return Ages[a.second] < Ages[b.second];
});
You can also pretty easily create a separate index that you sort in the order of the keys, and just use that index to read through the associated values:
std::vector<std::string> people = { "Anne", "Bob", "Charlie", "Douglas" };
std::vector<int> ages = {23, 28, 25, 21};
std::vector<std::size_t> index (people.size());
std::iota(index.begin(), index.end(), 0);
std::sort(index.begin(), index.end(), [&](size_t a, size_t b) { return ages[a] < ages[b]; });
for (auto i : index) {
std::cout << people[i] << "\n";
}
Note, however, that in this case, we haven't really sorted the items themselves at all. We've just sorted the index based on the ages, then used the index to index into the array of data we wanted sorted--but both the ages and names remain in their original order.
Of course, it's theoretically possible that you have such a bizarre situation that none of the above will work at all, and you'll need to re-implement sorting to do what you really want. While I suppose the possibility could exist, I've yet to see it in practice (nor do I even recall seeing a close call where I almost decided that was the right thing to do).
As others have noted, you should consider grouping People and Ages.
If you can't/don't want to, you could create an "index" to them, and sort that index instead. For example:
// Warning: Not tested
struct CompareAge : std::binary_function<size_t, size_t, bool>
{
CompareAge(const std::vector<unsigned int>& Ages)
: m_Ages(Ages)
{}
bool operator()(size_t Lhs, size_t Rhs)const
{
return m_Ages[Lhs] < m_Ages[Rhs];
}
const std::vector<unsigned int>& m_Ages;
};
std::vector<std::string> people = ...;
std::vector<unsigned int> ages = ...;
// Initialize a vector of indices
assert(people.size() == ages.size());
std::vector<size_t> pos(people.size());
for (size_t i = 0; i != pos.size(); ++i){
pos[i] = i;
}
// Sort the indices
std::sort(pos.begin(), pos.end(), CompareAge(ages));
Now, the name of the nth person is people[pos[n]] and its age is ages[pos[n]]
Generally you wouldn't put data that you want to keep together in different containers. Make a struct/class for Person and overload operator<.
struct Person
{
std::string name;
int age;
}
bool operator< (const Person& a, const Person& b);
Or if this is some throw-away thing:
typedef std::pair<int, std::string> Person;
std::vector<Person> persons;
std::sort(persons.begin(), persons.end());
std::pair already implement comparison operators.
It doesn't make sense to keep them in two separate data structures: if you reorder People, you no longer have a sensible mapping to Ages.
template<class A, class B, class CA = std::less<A>, class CB = std::less<B> >
struct lessByPairSecond
: std::binary_function<std::pair<A, B>, std::pair<A, B>, bool>
{
bool operator()(const std::pair<A, B> &left, const std::pair<A, B> &right) {
if (CB()(left.second, right.second)) return true;
if (CB()(right.second, left.second)) return false;
return CA()(left.first, right.first);
}
};
std::vector<std::pair<std::string, int> > peopleAndAges;
peopleAndAges.push_back(std::pair<std::string, int>("Anne", 23));
peopleAndAges.push_back(std::pair<std::string, int>("Bob", 23));
peopleAndAges.push_back(std::pair<std::string, int>("Charlie", 23));
peopleAndAges.push_back(std::pair<std::string, int>("Douglas", 23));
std::sort(peopleAndAges.begin(), peopleAndAges.end(),
lessByPairSecond<std::string, int>());
I would suggest merging these two lists into a single list of structures. That way you can simply define operator < like dirkgently said.
Jerry Coffin answer was fully clear and correct.
A just have a related issue that may grant a good discussion to the topic... :)
I had to reorder the columns of a matrix object (lets say TMatrix< T >) based on the sorting of a vector (lets say sequence)... The TMatrix< T > class do not provide reference access to it's rows (thus I can not create a structure to reorder it...) but conveniently provides a method TMatrix< T >::swap(row1, row2)...
So that's the code:
TMatrix<double> matrix;
vector<double> sequence;
//
// 1st step: gets indexes of the matrix rows changes in order to sort by time
//
// note: sorter vector will have 'sorted vector elements' on 'first' and
// 'original indexes of vector elements' on 'second'...
//
const int n = int(sequence.size());
std::vector<std::pair<T, int>> sorter(n);
for(int i = 0; i < n; i++) {
std::pair<T, int> ae;
ae.first = sequence[i];
ae.second = i;
sorter[i] = ae;
}
std::sort(sorter.begin(), sorter.end());
//
// 2nd step: swap matrix rows based on sorter information
//
for(int i = 0; i < n; i++) {
// updates the the time vector
sequence[i] = sorter[i].first;
// check if the any row should swap
const int pivot = sorter[i].second;
if (i != pivot) {
//
// store the required swaps on stack
//
stack<std::pair<int, int>> swaps;
int source = pivot;
int destination = i;
while(destination != pivot) {
// store required swaps until final destination
// is equals to first source (pivot)
std::pair<int, int> ae;
ae.first = source;
ae.second = destination;
swaps.push(ae);
// retrieves the next requiret swap
source = destination;
for(int j = 0; j < n; j++) {
if (sorter[j].second == source)
destination = j;
break;
}
}
}
//
// final step: execute required swaps
//
while(!swaps.empty()) {
// pop the swap entry from the stack
std::pair<int, int> swap = swaps.top();
destination = swap.second;
swaps.pop();
// swap matrix coluns
matrix.swap(swap.first, destination);
// updates the sorter
sorter[destination].second = destination;
}
// updates sorter on pivot
sorter[pivot].second = pivot;
}
}
I belive that's still O(n log n) since every row that is not in place will swap just one time...
Have fun! :)