I'm writing a search algorithm in C++, and one of the things I need to do is have a few if statements that check cells above, below, left of, and right of.
Each time a cell is found to be open and added to the stack, I want it added to a list of cells already checked.
I want to be able to say in the if statement if(thisCell is not in checkedCells).
Any simple ideas?
For this purpose it's better to use the std::set container, because it provides you with the ability to search for items faster than a list. Then you can write:
std::set<itemType> myset;
...
if (myset.find(item) != myset.end()) {
// item is found
}
A larger example can be found by googling. For example, here.
If the number of items are in the hundreds, you can use simple, sequential search. This algorithm is built-into C++ as the find() function:
#include <algorithm> // for find()
typedef std::vector<Cell> CellList;
CellList checked_cells;
// .....
Cell cellToSearch;
if (is_in_checked_cells (cellToSearch, cells))
{
// .....
}
// Makes a sequential search using find().
static bool
is_in_checked_cells (const Cell &cell, const CellList &cells)
{
CellList::const_iterator end = cells.end ();
CellList::const_iterator item = std::find (cells.begin (), end, cell);
return (item != end);
}
Make sure Cell has operator< overridden.
If the list is very large, you may want to use binary search, which also comes bundled with C++:
#include <algorithm> // for sort() and binary_search()
CellList checked_cells;
// Make sure the cells are sorted.
checked_cells.sort (checked_cells.begin (), checked_cells.end ());
Cell cellToSearch;
if (is_in_checked_cells (cellToSearch, cells))
{
// .....
}
// Searches using binary_search().
static bool
is_in_checked_cells (const Cell &cell, const CellList &cells)
{
return std::binary_search (cells.begin (), cells.end (), cell);
}
Related
CppCheck suggest me to replace one of my code by a STL algorithm, I'm not against it, but I don't know how to replace it. I'm pretty sure this is a bad suggestion (There is warning about experimental functionalities in CppCheck).
Here is the code :
/* Cutted beginning of the function ... */
for ( const auto & program : m_programs )
{
if ( program->compare(vertexShader, tesselationControlShader, tesselationEvaluationShader, geometryShader, fragmentShader) )
{
TraceInfo(Classname, "A program has been found matching every shaders.");
return program;
}
}
return nullptr;
} /* End of the function */
And near the if condition I got : "Consider using std::find_if algorithm instead of a raw loop."
I tried to use it, but I can't get the return working anymore... Should I ignore this suggestion ?
I suppose you may need to use that finding function not once. So, according to DRY, you need to separate the block where you invoke an std::find_if algorithm to a distinct wrapper function.
{
// ... function beginning
auto found = std::find_if(m_programs.cbegin(), m_programs.cend(),
[&](const auto& prog)
{
bool b = prog->compare(...);
if (b)
TraceInfo(...);
return b;
});
if (found == m_programs.cend())
return nullptr;
return *found;
}
The suggestion is good. An STL algorithm migth be able to choose an appropriate
approach based on your container type.
Furthermore, I suggest you to use a self-balancing container like an std::set.
// I don't know what kind of a pointer you use.
using pProgType = std::shared_pointer<ProgType>;
bool compare_progs(const pProgType &a, const pProgType &b)
{
return std::less(*a, *b);
}
std::set<std::shared_pointer<prog_type>,
std::integral_constant<decltype(&compare_progs), &compare_progs>> progs.
This is a sorted container, so you will spend less time for searching a program by a value, given you implement a compare operator (which is invoked by std::less).
If you can use an stl function, use it. This way you will not have to remember what you invented, because stl is properly documented and safe to use.
I want to sort my objects according to some criteria (according to how big the items are)
My funcSort in multiset slows down calculations and makes the solution does not scale. How can I make it faster?
To avoid it I tried to use vector, sort it (should go quicker?) and change it into multiset. My solution however does not work, I am not sure what I do wrong?
Function arguments:
void deliver(const std::set<MyItem::Ptr> items, MyItem::Ptr item)
(Typedef of shared_ptr):
typedef boost::shared_ptr<MyItem> Ptr;
sort function:
auto funcSort = [item](MyItem::Ptr lhs, MyItem::Ptr rhs){
return lhs->howFar(item->howBig()) < rhs->howFar(item->howBig());
};
Original with multiset (SLOW when using funcSort):
std::multiset<MyItem::Ptr, decltype(funcSort)> sortedItems(funcSort);
for (MyItem::Ptr item : items){
sortedItems.insert(item);
}
My vector attempt (Error message):
std::vector<MyItem::Ptr> sortedItems;
for (MyItem::Ptr item : items)
{
sortedItems.push_back(item);
}
std::sort(sortedItems.begin(), sortedItems.end(), funcSort());
std::multiset<MyItem::Ptr> ms(sortedItems.begin(), sortedItems.end());
Error message:
__lambda1
auto funcSort = [item](MyItem::Ptr lhs, MyItem::Ptr rhs)
candidate expects 2 arguments, 0 provided
You got the sort call wrong. You just want to pass the funcSort, not call it.
Try it like this:
std::sort(sortedItems.begin(), sortedItems.end(), funcSort);
I've implemented a wxListCtrl and would like to sort the list alphabetically. Although this sounds similar as the question here, it is different with one major difference: I'm using SetItemData() and GetItemData() to store the index of a vector.
The code supplied here works nicely, but requires GetItemData(). Even though the comparison function does not refer to any of the item data, if I omit it, the sorting is not complete.
static int wxCALLBACK MyCompareFunction(long item1, long item2, long sortData) {
wxSortedListCtrl *ctrl = (wxSortedListCtrl*) sortData;
wxString a, b;
a = ctrl->GetItemText(item1, ctrl->GetSortedColumn());
b = ctrl->GetItemText(item2, ctrl->GetSortedColumn());
if( ctrl->IsSortedAscending() )
return a.CmpNoCase(b);
return b.CmpNoCase(a);
}
bool wxSortedListCtrl::SortItems(void) {
long item = -1;
for ( ;; ) {
item = GetNextItem(item);
if ( item == -1 )
break;
SetItemData(item, item);
//this is needed even though MyCompareFunction doesn't use it AT ALL.
//however it overwrites the data that I use myself...
}
return wxListCtrl::SortItems(MyCompareFunction, (long)this);
}
How would I use this sort function while maintaining the item data I've set myself with SetItemData()?
If you want to rely on the control to do the sorting (as opposed to resorting the items internally and just reinserting them into it in the correct order), you must be able to access the sort key (i.e. text in your case) via the item data. So, instead of just associating your own data with each item, associate some struct containing both the item text and your custom data with it.
Alternatively, use wxLC_VIRTUAL and just override OnGetItemXXX() to return the items in the correct order. This may sometimes be simpler than dealing with sorting the items manually and is definitely much more efficient for any non-trivial number of items.
Let Action be a class with a is_finished method and a numeric tag property.
Let this->vactions be a std::vector<Action>
The intent is to iterate the vector and identify those Actions who are finished,
store their tags in a std::vector<unsigned int> and delete the actions.
I tried to play with lambdas and a little and came up with a little
code that read nicely but caused memory corruptions. The "extended" version,
on the other hand, works as expected.
I suspect foul play in the remove_if part, but for the life of me I can't figure
out what's wrong.
Here's the example code.
This causes memory corruptions
std::vector<unsigned int> tags;
auto is_finished=[p_delta](Action& action) -> bool {return action.is_finished();};
//This is supposed to put the finished actions at the end of the vector and return
//a iterator to the first element that is finished.
std::vector<Action>::iterator nend=remove_if(this->vactions.begin(), this->vactions.end(), is_finished);
auto store_tag=[&tags](Action& action)
{
if(action->has_tag())
{
tags.push_back(action->get_tag());
}
};
//Store the tags...
for_each(nend, this->vactions.end(), store_tag);
//Erase the finished ones, they're supposed to be at the end.
this->vaction.erase(nend, this->vaction.end());
if(tags.size())
{
auto do_something=[this](unsigned int tag){this->do_something_with_tag(tag);};
for_each(tags.begin(), tags.end(), do_something);
}
This, on the other side, works as expected
std::vector<Action>::iterator ini=this->vactions.begin(),
end=this->vactions.end();
std::vector<unsigned int> tags;
while(ini < end)
{
if( (*ini).is_finished())
{
if((*ini).has_tag())
{
tags.push_back((*ini).get_tag());
}
ini=this->vaction.erase(ini);
end=this->vaction.end();
}
else
{
++ini;
}
}
if(tags.size())
{
auto do_something=[this](unsigned int tag){this->do_something_with_tag(tag);};
for_each(tags.begin(), tags.end(), do_something);
}
I am sure there's some rookie mistake here. Can you help me spot it?.
I thought that the for_each could be updating my nend iterator but found
no information about it. What if it did? Could the vector try to erase beyond the "end" point?.
std::remove_if does not preserve the values of the elements that are to be removed (See cppreference). Either get the tag values before calling remove_if - as you do in the second case - or use std::partition instead.
I have been looking for an effective solution to remove duplicates from a C++ list.
The list consists of pointers to a class object which has an attribute ID. I want to remove duplicates based on that ID.
for my purpose, the unique method of the STL list will work in which we can pass a BinaryPredicate. i.e.
void unique( BinPred pr );
I searched on the internet about how to use this method, n got an example in which we can declare a function returning boolean and use the "name" of that function as Binary Predicate.
But it's not working.
What actually is this binary predicate and how do i use it ? ...
Any help will be appreciated.
Here is the code snippet:
class SP_MDI_View {
..
..
bool removeDupli(SP_DS_Node*, SP_DS_Node*);
bool DoReductionGSPN(SP_DS_Node*, SP_ListNode*, SP_DS_Node*);
..
..
}
SP_MDI_View::DoReduction( ... ) {
SP_ListNode setZ; // typedef list<SP_DS_Node*> SP_ListNode, where SP_DS_Node is some other class
setZ.clear();
setZ.merge(tempsubset);
setZ.merge(setX);
setZ.push_back(*cs_iter);
setZ.unique(removeDupli); //Error here
}
bool SP_MDI_View::removeDupli(SP_DS_Node* first, SP_DS_Node* second) {
return ( (first->GetId())==(second->GetId()) );
}
You could write a function like:
bool foo (int first, int second)
{ return (first)==(second) ); }
Also, you might need to declare the function as static if your using it in class.
You have to use unique on an ordered list. So the first thing that you must do is sort the list.