Related
I am currently struggling coming up with an optimized method for dynamic ordering. I currently have a vector that looks like this in some place of my code
std::vector<std::string> vec {
"optionB",
"optionA",
"optionC"
};
The items in the above vector can be shuffled.The items in this vector are inserted in a specific order so the above order can be different. For simplicity sakes I added the items during declaration.There are about 9 items in the actual case for simplicity I am using only 3 string items.
Now somewhere else in my code I have something like this.
void filter()
{
bool _optionA,_optionB,_optionC
...
//These boolean variables get assigned values
...
...
/*
Todo : I would like to change the ordering of the
following code based on the ordering of items in the
vector. Currently its in the order _optionA _optionB,
_optionC. I would like this ordering to be based
on the order of the strings as in the above vector.
so it should be _optionB,_optionA,_optionC ,
I understand the items in the vector are string
and the following are boolean types
*/
if(_optionA){
}
if(_optionB) {
}
if(_optionC){
}
}
The simplest approach that comes to my mind is
for(auto str : vec)
{
if( (str=="optionA" && _optionA))
{
//This was optionA
}
else if( (str=="optionB" && _optionB)) {
}
else if( (str=="optionC" && _optionC)) {
}
}
I want to know what would be the most optimized way to accomplish the above task ? I am looking for a solution that would avoid iterating through a vector since its in a performance centric piece of code. Is there a way for me to use integrate bitwise operations or something like array indexing to accomplish this task ? Please let me know if something is unclear
It sounds like you want map a string to an actual process. Could you create an interface option class and have instances of options mapped to the string that should cause them to occur? That way you could use the string as a key to get back an Option object and call something like myOption.execute().
The downside to this method is that you need to create a new option class and have it inherit from the interface each time you need a new option.
#Edit: Sorry I think I may have misunderstood the question. But I think the premise still applies you could have a map of string to boolean and just use the string as a key to get back whether the option is toggled on or off.
Assuming you load the vector in on start up, you can sort it at that point to your liking. For example, in alphabetical order. This will mean that you know the order of the vector therefore you can simply reference the vector by index when checking in the your filter function.
Load in data into vector std::vector<string> data = {"optionA", "optionB"};.
Sort using std::sort(data.begin, data.end); or any other sort method of your choice.
Then in you filter function check the vector based on index. if (data.at(1) == "optionA") { }
If I understand your problem correctly, you need to imply order_by on the boolean variables/predicates.
In the below program I will refer your (_optionA, _optionB, _optionC) as predicates even though they are bool, since we can upgrade this problem to work with predicates as well.
Based on the above assumption, I am going ahead with an implementation.
You should pass an ordered_predicates to your filter function.
ordered_predicates is sorted according to your desired criteria.
filter()'s job is just to execute them in the order defined.
auto filter(std::vector<bool> const & ordered_predicates)
-> void
{
for (auto const & condition : ordered_predicates) {
if (condition) {
// ... do your usual stuff here
}
}
}
So how should we go ahead to achieve this ordered_predicates?
We will create a function called order_by that will take an order_by_criteria and a mapping, which will help it in creating ordered_predicates.
With this function, creating ordered_predicates is just a one time cost.
auto order_by(std::vector<std::string> const & order_by_criteria,
std::map<std::string, bool> const & mapping)
-> std::vector<bool>
{
std::vector<bool> ordered_predicates;
for (auto const & item : order_by_criteria)
ordered_predicates.push_back(mapping.at(item));
return ordered_predicates;
}
Where order_by_criteria is your std::vector<std::string> and mapping is just a map which tells which string and predicates are associated.
std::vector<std::string> order_by_criteria { "optionB", "optionA", "optionC" };
std::map<std::string, bool> mapping = { {"optionA", _optionA },
{"optionB", _optionB },
{"optionC", _optionC } };
Here is a complete working program for your reference.
#include <iostream>
#include <map>
#include <vector>
auto order_by(std::vector<std::string> const & order_by_criteria,
std::map<std::string, bool> const & mapping)
-> std::vector<bool>
{
std::vector<bool> ordered_predicates;
for (auto const & item : order_by_criteria)
ordered_predicates.push_back(mapping.at(item));
return ordered_predicates;
}
auto filter(std::vector<bool> const & ordered_predicates)
-> void
{
for (auto const & condition : ordered_predicates) {
if (condition) {
// ... do your usual stuff here
}
}
}
int main()
{
bool _optionA = true, _optionB = false, _optionC = true;
std::vector<std::string> order_by_criteria { "optionB", "optionA", "optionC" };
std::map<std::string, bool> mapping = { {"optionA", _optionA },
{"optionB", _optionB },
{"optionC", _optionC } };
auto ordered_predicates = order_by(order_by_criteria, mapping);
filter(ordered_predicates);
filter(ordered_predicates); // call as many times as you want, with pre-decided order
return 0;
}
If I got the problem correctly, sorting is a way to go. Just sort the vector together with bool flags, using std::vector values as keys, and then simply check bool flags in fixed, lexicographic, order.
Suppose we have a vector {"optB", "optC", "optA"}. After sorting, the indices {0, 1, 2} will rearrange: std::size_t perm[] = {2, 0, 1}. Using this information, that can be precomputed (outside filter(...)), we can rearrange the bool flags:
bool options[N];
// populate options...
bool new_options[N];
for (std::size_t i = 0; i < N; ++i)
new_options[perm[i]] = options[i];
Now we simply check new_options successively:
if (new_options[0]) {
...
}
if (new_options[1]) {
...
}
To precompute perm array use std::map:
std::map<std::string, std::size_t> map;
for (std::size_t i = 0; i < N; ++i)
map.emplace(vec[i], i);
std::size_t perm[N];
auto m = map.begin();
for (std::size_t i = 0; i < N; ++i, ++m)
perm[i] = m->second;
I'm trying to understand how I should implement an associative array which gives constant time for search operations, right now my implementation looks like this:
#include <iostream>
#include <vector>
#include <string>
using namespace std;
template <class Key, class Value> class Dict {
private:
typedef struct Item {
Value value;
Key key;
} Item;
vector<Item> _data;
public:
void clear() {
_data.clear();
}
long size() {
return _data.size();
}
bool is_item(Key key) {
for (int i = 0; i < size(); i++) {
if (_data[i].key == key) return true;
}
return false;
}
bool add_item(Key key, Value value) {
if (is_item(key)) return false;
Item new_item;
new_item.key = key;
new_item.value = value;
_data.push_back(new_item);
return true;
}
Value &operator[](Key key) {
for (int i = 0; i < size(); i++) {
if (_data[i].key == key) return _data[i].value;
}
long idx = size();
Item new_item;
new_item.key = key;
_data.push_back(new_item);
return _data[idx].value;
}
Key get_key(long index) {
if (index < 0) index = 0;
for (int i = 0; i < size(); i++)
if (i == index) return _data[i].key;
return NULL;
}
Value &operator[](long index) {
if (index < 0) index = 0;
for (int i = 0; i < size(); i++) {
if (i == index) return _data[i].value;
}
return _data[0].value;
}
};
A simple test for this:
class Foo {
public:
Foo(int value) {
_value = value;
}
int get_value() {
return _value;
}
void set_value(int value) {
_value = value;
}
private:
int _value;
};
template <class Key, class Value> void print_dict(Dict<Key, Value> &dct) {
if (!dct.size()) {
printf("Empty Dict");
}
for (int i = 0; i < dct.size(); i++) {
printf("%d%s", dct[dct.get_key(i)], i == dct.size() - 1 ? "" : ", ");
}
printf("\n");
}
int main(int argc, char *argv[]) {
printf("\nDict tests\n------------\n");
Dict<string, int> dct;
string key1("key1");
string key2("key2");
string key3("key3");
dct["key1"] = 100;
dct["key2"] = 200;
dct["key3"] = 300;
printf("%d %d %d\n", dct["key1"], dct["key2"], dct["key3"]);
printf("%d %d %d\n", dct[key1], dct[key2], dct[key3]);
print_dict(dct);
dct.clear();
print_dict(dct);
Dict<Foo *, int> dct2;
Foo *f1 = new Foo(100);
Foo *f2 = new Foo(200);
dct2[f1] = 101;
dct2[f2] = 202;
print_dict(dct2);
}
Here's the thing, right now the search operation is linear time and I'd like it to become constant time and I'm wondering about a simple/lightweight way to achieve this.
I've seen hashtables are a possible option but I'd prefer not having to implement a hash function per object. Maybe something similar to an unordered_map... dunno.
Could anyone give some ideas or maybe providing a simple lightweight implementation of what I'm trying to achieve here?
In this fictional example I'm using std::vector to avoid making the question bigger and more complex than what it is but my the real use-case won't be using the STL at all (ie: i'll be coding my own custom implementation of std::vector)
CONSTRAINTS
The reason of not using the STL at all is not because that implementation is not good (fast,generic,full-featured) enough but more because is quite heavy for my size-constrained projects (final exe <=65536bytes). Even this small implementation of the STL is actually quite big to be used as it is
I don't need a full implementation of an associative array but just providing the interface i've already implemented above (main problem being the linear-time search)
I don't care about inserting/deleting methods being slow but definitely I'd like the search/lookup being near to constant time
I guess I'd need to convert the above implementation in an associative array using a hash table but I'm unsure about the relevant implementation details (which hash functions per object, which table size, ...)
Let me address some issues you've raised in your question.
Here's the thing, right now the search operation is linear time and I'd like it to become constant time and I'm wondering about a simple/lightweight way to achieve this.
A simple lightweight way to achieve this, i.e., to have an associative array (a.k.a. key-value-store), is to use one provided by the standard library.
You are coding in a recent version of C++, you are in the lucky position that the standard library actually provides one that satisfies your constant-time requirements:
http://en.cppreference.com/w/cpp/container/unordered_map
The implementation of the data structures shipped as part of a standard library of any decent compiler these days, are probably better than anything you could come up with. (Or why did you ask for give me the code?).
I've seen hashtables are a possible option but I'd prefer not having to implement a hash function per object. Maybe something similar to an unordered_map... dunno.
A std::unordered_map actually is a hash table, and as you can see in the docs, it takes a hash function. As you can see written in the docs there are lots of specializations for lots of types already available, that can help you derive a custom hash function for your custom object types:
http://en.cppreference.com/w/cpp/utility/hash
Could anyone give some ideas or maybe providing a simple lightweight implementation of what I'm trying to achieve here?
Just have a look at the example code to std::unordered_map to see how it's used. If you worry about performance, don't forget to measure. If you really want to consume some input on implementation of hash tables, I liked these talks on the Python dictionary:
https://www.youtube.com/watch?v=C4Kc8xzcA68
https://www.youtube.com/watch?v=p33CVV29OG8
Also have a look at the wikipedia page (if you haven't already):
https://en.wikipedia.org/wiki/Associative_array
In this fictional example I'm using std::vector to avoid making the question bigger and more complex than what it is but my the real use-case won't be using the STL at all (ie: i'll be coding my own custom implementation of std::vector)
Unless you are doing this for educational/recreational purposes, don't do it. Don't be ashamed to base your endeavours on the shoulders of giants. That the standard library wasn't invented in your project is not a problem.
If you want to keep code size small, you should avoid templates as much as possible. At least templates that create non-trivial amounts of code.
For your hash map, that means: stick to one key type and only store void pointers to the values. If you don't want to deal with void* and the casts that go along with it all over in your code, implement one non-template hash map that stores void* as value, with all "no inline" functions. Then create an "all inline" (maybe even all "force inline") wrapper class that uses the void* map internally and just converts T* <-> void*.
If you really really really need different key types, see if you can stick to PODs without padding (memcpy copyable and memcmp comparable). That way you can still use the same hash map class for everything: you just have to tell the map (at runtime) what the key-size is. Then you can copy the keys into the map using memcpy, compare using memcmp and hash them using any hash algorithm that can hash byte sequences (=almost every hash algorithm).
Of course you'll also want to do a lot of other stuff, e.g. avoid inlining any non-trivial functions, avoid C-Runtime library functions, disable exception handling and RTTI etc., but that's a different topic.
Or, maybe just stick to plain C :)
I found that when writing animations I sometimes run into having to go through a for loop once, then iterate the value down afterwards. This was generally used for jump animations, or disappear then appear again animations.
Here's an example of what I had done -
// Make the sprite slowly disappear
for (int i = 256; i > 0; --i)
{
sprite.opacity(i);
draw();
}
// Make the sprite slowly appear again
for (int i = 0; i < 256; ++i)
{
sprite.opacity(i);
draw();
}
Every time I did this I had a deep feeling that it was too much. What would be a nicer way of going about this? I'm not entirely sure what would be best practice. I imagine I could use reverse_iterator, but I'm also not sure how I would implement it.
Consider the use of <cmath> abs() function:
for( int i = -255; i <= 255; i++)
use( abs( i ) );
You can use the absolute value function abs() defined in <cmath>. It will halve the code written in your case.
for(int i=0; i<512; ++i)
{
sprite.opacity( abs(256-i) );
draw();
}
I believe in the situation you are describing, you have to iterate through the sprites to set the opacity of each sprite. Whether you use a for loop, or a reverse_iterator, the time spent is going to be the same. Any implementation of the reverse_iterator will still have to iterate through each sprite. There might be ways to make it easier to read, but in the end the algorithm will come down to the same. For example, you could take advantage of the stack and call the sprites recursively to increase the opacity and then decrease on the way back out; however, I see no gain in doing so the algorithm time would still end up being the same.
In some cases, you just need to bite the bullet and spend the time doing things in a way that may seem like (or even be) brute force.
That's a great way to iterate through a loop both forward and "in reverse" - one commonly used by C++ programmers.
For your sprite, it appears that the 256 range (you might consider setting a const int RGB_RANGE equal to 256 - or a more appropriate identifier) is all that is needed; however, were the size of your object dynamic, you could also consider using the .size() function (something like an ArrayList or a vector - here is where something like an iterator would be useful):
for (i = 9; i < RGB_RANGE; i++)
{
// CODE
}
The above code being an example of the first const suggestion. Remember, simple code is never a bad thing - it means you are doing something right.
If you don't want to use abs, I'd go with something like :
template<typename Func>
void animate (size_t step_count, Func && f)
{
size_t step;
for (step = step_count ; step > 0 ; --step)
f(step - 1);
for (step = 1 ; step < step_count ; ++step)
f(step);
}
Use case :
animate(256, [](size_t step)
{
sprite.opacity(step);
draw();
});
If you wish to just iterate a range up and down again, you can go the very crazy route and just define a "container" (or range, in boost lingo) that provides iterators (well, technically they are more almost-iterators) which allow you to express exactly what you intend to do:
for(auto i : down_and_up(3)) ::std::cout << i << "\n";
For example should print
3
2
1
0
1
2
Sadly, there is not much support in the standard library for types like this, although boost provides boost::iterator_range, boost::counting_iterator, and boost::join that, in concert with std::reverse_iterator, can provide down_and_up. Writing one yourself if fairly simple (although verbose), as long as you do not completely abuse it:
struct down_and_up
{
size_t from;
down_and_up(size_t const from) : from(from) { }
struct iterator : public ::std::iterator<::std::forward_iterator_tag, size_t> {
size_t cur;
bool down;
iterator(size_t cur, bool down) : cur(cur), down(down) { }
size_t operator*() const { return cur; }
iterator& operator++()
{
if(down)
{
--cur;
if(0 == cur) down = false;
}
else ++cur;
return *this;
}
friend bool operator==(iterator const& lhs, iterator const& rhs) { return lhs.down == rhs.down && lhs.cur == rhs.cur; }
friend bool operator!=(iterator const& lhs, iterator const& rhs) { return lhs.down != rhs.down || lhs.cur != rhs.cur; }
};
iterator begin() const { return iterator{ from, true }; }
iterator end() const { return iterator{ from, false }; }
};
Note: If you wish, you can easily extend it with more container capabilities, like a value_type member typedef, but this definition is enough for the above example.
P.S.: The boost way, for your entertainment:
boost::iterator_range<boost::counting_iterator<size_t>> up(boost::counting_iterator<size_t>(0), boost::counting_iterator<size_t>(3));
boost::iterator_range<std::reverse_iterator<boost::counting_iterator<size_t>>> down(
std::reverse_iterator<boost::counting_iterator<size_t>>(boost::counting_iterator<size_t>(4)),
std::reverse_iterator<boost::counting_iterator<size_t>>(boost::counting_iterator<size_t>(1)));
for(auto i : boost::join(down, up)) ::std::cout << i << "\n";
This is my first question here, so hopefully it's a good one (I have searched for an answer, but not found it yet).
I have an event based disease model written in C++, and I'm trying to convert it to OOP (partly for my own learning experience). The basic class (Herd) stores numbers of susceptible, infective, and resistant animals, and the rates at which possible events occur.
class Herd {
private:
int S,I,R,N;
float birth, death, infection, recovery, movement;
public:
void calc_birth(void) { birth = r*N*(1.0-N/c); }
void calc_infection(void) { infection = N>0 ? beta*S*I/N : 0.0; }
// etc.
};
I then have a vector of herds to keep track of. Throughout this model I will need to calculate the sum of each member across all herd, after an event changes the number or category of individuals in a herd (this happens a lot). I already have 4 categories and 5 events, and this model could easily be expanded and require considerably more.
In my old, procedural code, I simply had a separate vector for each member, and it was easy to create a sum() function to calculate the results, but I can't see how to do this with a class without writing a separate sum function for each member (which is possible, but I doubt it's a particularly good way of doing it). I could make a static member (e.g. sum_S) to track the total, and update it every time an event occurs but this might not be appropriate for all members, and I'm not sure if the total might not slowly wander away from the true value when it comes to the rates.
Is there a way to write a single sum() function, which takes the member I want as a parameter, and returns the sum of that particular member across all the herds?
Thank you!
The standard library header numeric contains the function accumulate. It does not do exactly what you want, but is easily adaptable:
#include <numeric>
#include <vector>
#include <iostream>
struct Foo {
int member;
};
int main()
{
std::vector<Foo> v = { {1}, {2}, {3} };
int sum
= std::accumulate(begin(v), end(v), 0,
// lambda that sums up
[](const int& x, const Foo& y)
{return x + y.member;});
std::cout << sum << std::endl;
return 0;
}
The code uses initializer_lists and lambdas. If those aren't supported by your compiler, use the corresponding C++03 code (push_back and functors).
Sure, using pointer-to-members.
float sum_for_member( std::vector< Herd > const &herds, float Herd::*member ) {
float acc = 0;
for ( std:vector< Herd >::const_iterator it = herds.begin();
it != herds.end(); ++ it ) {
acc += (*it).*member;
}
return acc;
}
to call it:
float total_recovery = sum_for_member( my_herds, & Herd::recovery );
If you want to use a member function getRecovery instead, the parameter declaration becomes float (Herd::*member)() and the summation becomes acc += ((*it).*member)().
If you're not afraid to get further from OO and into generic C++ style, you can use a function template and let the Standard Library take care of the loop:
template< float Herd::*member >
float plus( float lhs, Herd const &rhs )
{ return lhs + rhs.*member; }
vector< Herd > h;
std::accumulate( h.begin(), h.end(), 0., plus< & Herd::recovery > );
So this is what I ended up with (inside a class called State, which holds the simulation state including a vector<Herd>):
Class State {
...
template <typename T>
T sum(T (Herd::*getter)()) {
T acc = (T) 0.0;
for (int i=0; i<size; ++i) {
acc += (herds[i].*getter)();
}
return acc;
...
}
This works for both the numbers of individuals (ints) and the event rates (floats), and uses pointers to member functions to keep those values private. An example of how this is called in the code is:
cout << "total # of S = " << state.sum(&Herd::getS)
"total # of I = " << state.sum(&Herd::getI)
"total birth rate = " << state.sum(&Herd::get_birth)
"total infection rate = " << state.sum(&Herd::get_infection)
etc.
Thanks very much for your help, especially to Potatoswatter. This is much better than the tedious boilerplate code I had before!
This is my first time using this site so sorry for any bad formatting or weird formulations, I'll try my best to conform to the rules on this site but I might do some misstakes in the beginning.
I'm right now working on an implementation of some different bin packing algorithms in C++ using the STL containers. In the current code I still have some logical faults that needs to be fixed but this question is more about the structure of the program. I would wan't some second opinion on how you should structure the program to minimize the number of logical faults and make it as easy to read as possible. In it's current state I just feel that this isn't the best way to do it but I don't really see any other way to write my code right now.
The problem is a dynamic online bin packing problem. It is dynamic in the sense that items have an arbitrary time before they will leave the bin they've been assigned to.
In short my questions are:
How would the structure of a Bin packing algorithm look in C++?
Is STL containers a good tool to make the implementation be able to handle inputs of arbitrary lenght?
How should I handle the containers in a good, easy to read and implement way?
Some thoughts about my own code:
Using classes to make a good distinction between handling the list of the different bins and the list of items in those bins.
Getting the implementation as effective as possible.
Being easy to run with a lot of different data lengths and files for benchmarking.
#include <iostream>
#include <fstream>
#include <list>
#include <queue>
#include <string>
#include <vector>
using namespace std;
struct type_item {
int size;
int life;
bool operator < (const type_item& input)
{
return size < input.size;
}
};
class Class_bin {
double load;
list<type_item> contents;
list<type_item>::iterator i;
public:
Class_bin ();
bool operator < (Class_bin);
bool full (type_item);
void push_bin (type_item);
double check_load ();
void check_dead ();
void print_bin ();
};
Class_bin::Class_bin () {
load=0.0;
}
bool Class_bin::operator < (Class_bin input){
return load < input.load;
}
bool Class_bin::full (type_item input) {
if (load+(1.0/(double) input.size)>1) {
return false;
}
else {
return true;
}
}
void Class_bin::push_bin (type_item input) {
int sum=0;
contents.push_back(input);
for (i=contents.begin(); i!=contents.end(); ++i) {
sum+=i->size;
}
load+=1.0/(double) sum;
}
double Class_bin::check_load () {
return load;
}
void Class_bin::check_dead () {
for (i=contents.begin(); i!=contents.end(); ++i) {
i->life--;
if (i->life==0) {
contents.erase(i);
}
}
}
void Class_bin::print_bin () {
for (i=contents.begin (); i!=contents.end (); ++i) {
cout << i->size << " ";
}
}
class Class_list_of_bins {
list<Class_bin> list_of_bins;
list<Class_bin>::iterator i;
public:
void push_list (type_item);
void sort_list ();
void check_dead ();
void print_list ();
private:
Class_bin new_bin (type_item);
bool comparator (type_item, type_item);
};
Class_bin Class_list_of_bins::new_bin (type_item input) {
Class_bin temp;
temp.push_bin (input);
return temp;
}
void Class_list_of_bins::push_list (type_item input) {
if (list_of_bins.empty ()) {
list_of_bins.push_front (new_bin(input));
return;
}
for (i=list_of_bins.begin (); i!=list_of_bins.end (); ++i) {
if (!i->full (input)) {
i->push_bin (input);
return;
}
}
list_of_bins.push_front (new_bin(input));
}
void Class_list_of_bins::sort_list () {
list_of_bins.sort();
}
void Class_list_of_bins::check_dead () {
for (i=list_of_bins.begin (); i !=list_of_bins.end (); ++i) {
i->check_dead ();
}
}
void Class_list_of_bins::print_list () {
for (i=list_of_bins.begin (); i!=list_of_bins.end (); ++i) {
i->print_bin ();
cout << "\n";
}
}
int main () {
int i, number_of_items;
type_item buffer;
Class_list_of_bins bins;
queue<type_item> input;
string filename;
fstream file;
cout << "Input file name: ";
cin >> filename;
cout << endl;
file.open (filename.c_str(), ios::in);
file >> number_of_items;
for (i=0; i<number_of_items; ++i) {
file >> buffer.size;
file >> buffer.life;
input.push (buffer);
}
file.close ();
while (!input.empty ()) {
buffer=input.front ();
input.pop ();
bins.push_list (buffer);
}
bins.print_list ();
return 0;
}
Note that this is just a snapshot of my code and is not yet running properly
Don't wan't to clutter this with unrelated chatter just want to thank the people who contributed, I will review my code and hopefully be able to structure my programming a bit better
How would the structure of a Bin packing algorithm look in C++?
Well, ideally you would have several bin-packing algorithms, separated into different functions, which differ only by the logic of the algorithm. That algorithm should be largely independent from the representation of your data, so you can change your algorithm with only a single function call.
You can look at what the STL Algorithms have in common. Mainly, they operate on iterators instead of containers, but as I detail below, I wouldn't suggest this for you initially. You should get a feel for what algorithms are available and leverage them in your implementation.
Is STL containers a good tool to make the implementation be able to handle inputs of arbitrary length?
It usually works like this: create a container, fill the container, apply an algorithm to the container.
Judging from the description of your requirements, that is how you'll use this, so I think it'll be fine. There's one important difference between your bin packing algorithm and most STL algorithms.
The STL algorithms are either non-modifying or are inserting elements to a destination. bin-packing, on the other hand, is "here's a list of bins, use them or add a new bin". It's not impossible to do this with iterators, but probably not worth the effort. I'd start by operating on the container, get a working program, back it up, then see if you can make it work for only iterators.
How should I handle the containers in a good, easy to read and implement way?
I'd take this approach, characterize your inputs and outputs:
Input: Collection of items, arbitrary length, arbitrary order.
Output: Collection of bins determined by algorithm. Each bin contains a collection of items.
Then I'd worry about "what does my algorithm need to do?"
Constantly check bins for "does this item fit?"
Your Class_bin is a good encapsulation of what is needed.
Avoid cluttering your code with unrelated stuff like "print()" - use non-member help functions.
type_item
struct type_item {
int size;
int life;
bool operator < (const type_item& input)
{
return size < input.size;
}
};
It's unclear what life (or death) is used for. I can't imagine that concept being relevant to implementing a bin-packing algorithm. Maybe it should be left out?
This is personal preference, but I don't like giving operator< to my objects. Objects are usually non-trivial and have many meanings of less-than. For example, one algorithm might want all the alive items sorted before the dead items. I typically wrap that in another struct for clarity:
struct type_item {
int size;
int life;
struct SizeIsLess {
// Note this becomes a function object, which makes it easy to use with
// STL algorithms.
bool operator() (const type_item& lhs, const type_item& rhs)
{
return lhs.size < rhs.size;
}
}
};
vector<type_item> items;
std::sort(items.begin, items.end(), type_item::SizeIsLess);
Class_bin
class Class_bin {
double load;
list<type_item> contents;
list<type_item>::iterator i;
public:
Class_bin ();
bool operator < (Class_bin);
bool full (type_item);
void push_bin (type_item);
double check_load ();
void check_dead ();
void print_bin ();
};
I would skip the Class_ prefix on all your types - it's just a bit excessive, and it should be clear from the code. (This is a variant of hungarian notation. Programmers tend to be hostile towards it.)
You should not have a class member i (the iterator). It's not part of class state. If you need it in all the members, that's ok, just redeclare it there. If it's too long to type, use a typedef.
It's difficult to quantify "bin1 is less than bin2", so I'd suggest removing the operator<.
bool full(type_item) is a little misleading. I'd probably use bool can_hold(type_item). To me, bool full() would return true if there is zero space remaining.
check_load() would seem more clearly named load().
Again, it's unclear what check_dead() is supposed to accomplish.
I think you can remove print_bin and write that as a non-member function, to keep your objects cleaner.
Some people on StackOverflow would shoot me, but I'd consider just making this a struct, and leaving load and item list public. It doesn't seem like you care much about encapsulation here (you're only need to create this object so you don't need do recalculate load each time).
Class_list_of_bins
class Class_list_of_bins {
list<Class_bin> list_of_bins;
list<Class_bin>::iterator i;
public:
void push_list (type_item);
void sort_list ();
void check_dead ();
void print_list ();
private:
Class_bin new_bin (type_item);
bool comparator (type_item, type_item);
};
I think you can do without this class entirely.
Conceptually, it represents a container, so just use an STL container. You can implement the methods as non-member functions. Note that sort_list can be replaced with std::sort.
comparator is too generic a name, it gives no indication of what it compares or why, so consider being more clear.
Overall Comments
Overall, I think the classes you've picked adequately model the space you're trying to represent, so you'll be fine.
I might structure my project like this:
struct bin {
double load; // sum of item sizes.
std::list<type_item> items;
bin() : load(0) { }
};
// Returns true if the bin can fit the item passed to the constructor.
struct bin_can_fit {
bin_can_fit(type_item &item) : item_(item) { }
bool operator()(const bin &b) {
return item_.size < b.free_space;
}
private:
type_item item_;
};
// ItemIter is an iterator over the items.
// BinOutputIter is an output iterator we can use to put bins.
template <ItemIter, BinOutputIter>
void bin_pack_first_fit(ItemIter curr, ItemIter end, BinOutputIter output_bins) {
std::vector<bin> bins; // Create a local bin container, to simplify life.
for (; curr != end; ++curr) {
// Use a helper predicate to check whether the bin can fit this item.
// This is untested, but just for an idea.
std::vector<bin>::iterator bin_it =
std::find_if(bins.begin(), bins.end(), bin_can_fit(*curr));
if (bin_it == bins.end()) {
// Did not find a bin with enough space, add a new bin.
bins.push_back(bin);
// push_back invalidates iterators, so reassign bin_it to the last item.
bin_it = std::advance(bins.begin(), bins.size() - 1);
}
// bin_it now points to the bin to put the item in.
bin_it->items.push_back(*curr);
bin_it->load += curr.size();
}
std::copy(bins.begin(), bins.end(), output_bins); // Apply our bins to the destination.
}
void main(int argc, char** argv) {
std::vector<type_item> items;
// ... fill items
std::vector<bin> bins;
bin_pack_first_fit(items.begin(), items.end(), std::back_inserter(bins));
}
Some thoughts:
Your names are kinda messed up in places.
You have a lot of parameters named input, thats just meaningless
I'd expect full() to check whether it is full, not whether it can fit something else
I don't think push_bin pushes a bin
check_dead modifies the object (I'd expect something named check_*, to just tell me something about the object)
Don't put things like Class and type in the names of classes and types.
class_list_of_bins seems to describe what's inside rather then what the object is.
push_list doesn't push a list
Don't append stuff like _list to every method in a list class, if its a list object, we already know its a list method
I'm confused given the parameters of life and load as to what you are doing. The bin packing problem I'm familiar with just has sizes. I'm guessing that overtime some of the objects are taken out of bins and thus go away?
Some further thoughts on your classes
Class_list_of_bins is exposing too much of itself to the outside world. Why would the outside world want to check_dead or sort_list? That's nobodies business but the object itself. The public method you should have on that class really should be something like
* Add an item to the collection of bins
* Print solution
* Step one timestep into the future
list<Class_bin>::iterator i;
Bad, bad, bad! Don't put member variables on your unless they are actually member states. You should define that iterator where it is used. If you want to save some typing add this: typedef list::iterator bin_iterator and then you use bin_iterator as the type instead.
EXPANDED ANSWER
Here is my psuedocode:
class Item
{
Item(Istream & input)
{
read input description of item
}
double size_needed() { return actual size required (out of 1) for this item)
bool alive() { return true if object is still alive}
void do_timestep() { decrement life }
void print() { print something }
}
class Bin
{
vector of Items
double remaining_space
bool can_add(Item item) { return true if we have enough space}
void add(Item item) {add item to vector of items, update remaining space}
void do_timestep() {call do_timestep() and all Items, remove all items which indicate they are dead, updating remaining_space as you go}
void print { print all the contents }
}
class BinCollection
{
void do_timestep { call do_timestep on all of the bins }
void add(item item) { find first bin for which can_add return true, then add it, create a new bin if neccessary }
void print() { print all the bins }
}
Some quick notes:
In your code, you converted the int size to a float repeatedly, that's not a good idea. In my design that is localized to one place
You'll note that the logic relating to a single item is now contained inside the item itself. Other objects only can see whats important to them, size_required and whether the object is still alive
I've not included anything about sorting stuff because I'm not clear what that is for in a first-fit algorithm.
This interview gives some great insight into the rationale behind the STL. This may give you some inspiration on how to implement your algorithms the STL-way.