I'm trying to refactor part of a pathfinding algorithm I had that used pointers to not use pointers. Unfortunately I'm not that knowledgable about references. I get the error: Invalid operands to binary expression ('std::__1::reference_wrapper<Tile>' and 'const std::__1::reference_wrapper<Tile>')
I also have no idea what that means. My code is below, and I can gather that it comes from the line: openList.erase(std::find(openList.begin(), openList.end(), current)); but I'm not sure how to fix this.
bool TileMap::tilesBetween(Tile& p_start, Tile& p_end)
{
std::vector<std::reference_wrapper<Tile>> openList;
std::vector<std::reference_wrapper<Tile>> closedList;
openList.push_back(p_start);
do
{
std::sort(openList.begin(), openList.end(), sortF());
Tile& current = openList[0];
closedList.push_back(current);
openList.erase(std::find(openList.begin(), openList.end(), current));
if(std::find(closedList.begin(), closedList.end(), p_end) != closedList.end())
{
return true;
}
std::vector<std::reference_wrapper<Tile>> adjacentTiles;
if (current.m_coordinates.x > 0)
{
adjacentTiles.push_back(m_tiles[current.m_coordinates.y * m_width + (current.m_coordinates.x - 1)]);
}
if (current.m_coordinates.x < m_width)
{
adjacentTiles.push_back(m_tiles[current.m_coordinates.y * m_width + (current.m_coordinates.x + 1)]);
}
if (current.m_coordinates.y > 0)
{
adjacentTiles.push_back(m_tiles[(current.m_coordinates.y - 1) * m_width + current.m_coordinates.x]);
}
if (current.m_coordinates.y < m_height)
{
adjacentTiles.push_back(m_tiles[(current.m_coordinates.y + 1) * m_width + current.m_coordinates.x]);
}
for(auto t : adjacentTiles)
{
if(std::find(closedList.begin(), closedList.end(), t) != closedList.end())
{
continue;
}
if(std::find(openList.begin(), openList.end(), t) == closedList.end())
{
openList.push_back(t);
}
}
}
while(!openList.empty());
return false;
}
EDIT: posted sortF
struct sortF
{
bool operator()(const Tile* p_a, const Tile* p_b) const
{
return p_a->f < p_b->f;
}
};
UPDATE: As per the suggestion, I've changed the function to use pointers instead of references. It SEEMS to be working, but I have more to implement before it's finished.
bool TileMap::tilesBetween(Tile* p_start, Tile* p_end)
{
std::vector<Tile*> openList;
std::vector<Tile*> closedList;
std::cout << p_start << ", ";
openList.push_back(p_start);
do
{
std::sort(openList.begin(), openList.end(), sortF());
Tile* current = openList[0];
closedList.push_back(current);
openList.erase(std::find(openList.begin(), openList.end(), current));
if(std::find(closedList.begin(), closedList.end(), p_end) != closedList.end())
{
return true;
}
std::vector<Tile*> adjacentTiles;
if (current->m_coordinates.x > 0)
{
adjacentTiles.push_back(&m_tiles[current->m_coordinates.y * m_width + (current->m_coordinates.x - 1)]);
}
if (current->m_coordinates.x < m_width)
{
std::cout << &m_tiles[current->m_coordinates.y * m_width + (current->m_coordinates.x + 1)] << std::endl;
adjacentTiles.push_back(&m_tiles[current->m_coordinates.y * m_width + (current->m_coordinates.x + 1)]);
}
if (current->m_coordinates.y > 0)
{
adjacentTiles.push_back(&m_tiles[(current->m_coordinates.y - 1) * m_width + current->m_coordinates.x]);
}
if (current->m_coordinates.y < m_height)
{
adjacentTiles.push_back(&m_tiles[(current->m_coordinates.y + 1) * m_width + current->m_coordinates.x]);
}
for(auto t : adjacentTiles)
{
if(std::find(closedList.begin(), closedList.end(), t) != closedList.end())
{
continue;
}
if(std::find(openList.begin(), openList.end(), t) == openList.end())
{
openList.push_back(t);
}
}
}
while(!openList.empty());
return false;
}
I can gather that it comes from the line: openList.erase(std::find(openList.begin(), openList.end(), current)); but I'm not sure how to fix this.
std::find iterates over std::reference_wrapper<Tile> and not Tile& itself. Hence
Tile& current = openList[0];
openList.erase(std::find(openList.begin(), openList.end(), current));
is incorrect. Change this to
openList.erase(std::find_if(openList.begin(), openList.end(), [&](const std::reference_wrapper<Tile> &i)
{
return i.get() == current;
}));
std::reference_wrapper::get returns the underlying reference.
A simple, working example to demonstrate this
#include <algorithm>
#include <list>
#include <vector>
#include <iostream>
#include <functional>
struct S
{
int val;
S(int i) : val(i) {}
};
int main()
{
std::list<S> l = {-4, -3, -2, -1, 0, 1, 2, 3, 4};
std::vector<std::reference_wrapper<S>> v(l.begin(), l.end());
auto& x = l.front();
v.erase(std::find_if(v.cbegin(), v.cend(), [&](const std::reference_wrapper<S> &i)
{
return i.get().val == x.val;
}));
std::cout << v[0].get().val;
}
Your problem is here:
std::sort(openList.begin(), openList.end(), sortF());
Your sortF is an invalid comparison object. The operator() must look like this:
bool operator()(const Tile& lhs, const Tile& rhs) const
// ^^^ ref ^^^ ^^^ ref ^^^
{
return lhs.f < rhs.f;
}
Instead of:
bool operator()(const Tile* p_a, const Tile* p_b) const
// ^^^ ptr ^^^ ^^^ ptr ^^^
You have a vector of reference_wrapper<Tile>, not a vector of Tile*.
Related
I'm very very new to vectors and templates. Can't seem to wrap my head around them just yet.
The code is as follows:
template <class T>
class m_vector
{
int m_iNextIndex;
int m_iMaxSize;
T* m_pArray;
public:
m_vector()
{
m_pArray = 0;
init();
}
m_vector(const m_vector<T>& other)
{
m_pArray = 0;
m_iNextIndex = 0;
m_iMaxSize = 0;
*this = other;
}
~m_vector()
{
if (m_pArray != 0)
delete [] m_pArray;
}
void init()
{
m_iMaxSize = VECT_INC_SIZE;
m_pArray = new T[m_iMaxSize];
m_iNextIndex = 0;
}
inline void push_back(const T& item)
{
if (m_iNextIndex >= m_iMaxSize)
{
resize(m_iNextIndex + VECT_INC_SIZE);
m_iNextIndex -= VECT_INC_SIZE;
}
m_pArray[m_iNextIndex] = item;
++m_iNextIndex;
}
void resize(int iNewSize)
{
if (iNewSize >= m_iMaxSize)
{
T* temp = new T[iNewSize];
for (int i = 0; i < m_iNextIndex; ++i)
{
temp[i] = m_pArray[i];
}
delete [] m_pArray;
m_pArray = temp;
m_iMaxSize = iNewSize;
}
m_iNextIndex = iNewSize;
}
};
The push_back is called with Vectors that are (x, y) and rectangles that are (x, y, width, height).
I thought that since the code had "m_pArray[m_iNextIndex] = item" that I could simply add a new function to check that the item is unique before adding it to the vector list. So I coded a routine as follows:
int inline exists(const &item)
{
for(int i = 0; i < m_iMaxSize; i++)
{
if(m_pArray[i] == item)
return 1;
}
return 0;
}
The compiler was non to happy. It reported the following error on the if statement:
“left operand must be a pointer or pointer to class member, or arithmetic”
I'm thinking that I probably need something like:
if (type == vector)
if( (m_pArray[i].x == item.x) ....)
else
if( (m_pArray[i].x == item.x) && (m_pArray[i].width == item.width) )
Am I on the right track?
If so, how do I check the type of item.
Thx, Bill.
The problem is that your Vector or Rectangle are missing a comparison operator e.g.
friend bool operator== (Vector const& lhs, Vector const& rhs){
return lhs.x == rhs.x && lhs.y == rhs.y;
}
But the rest of you code is not good and needs a rewrite. I've rewritten my code to old-old style:
NOTE: DON'T BLINDLY COPY THIS CODE. ITS JUST FOR REFERENCE. TEST BEFORE YOU USE
#define VECT_INC_SIZE 10
// replaced by iterator version
//template< class InputIt, class Size, class OutputIt>
//OutputIt copy_n(InputIt first, Size count, OutputIt result) {
// while (count-- > 0) {
// *result++ = *first++;
// }
// return result;
//}
template<class InputIt, class OutputIt>
OutputIt copy(InputIt first, InputIt last, OutputIt d_first) {
while (first != last) {
*d_first++ = *first++;
}
return d_first;
}
template<class T>
T exchange(T& obj, T new_value)
{
T old_value = obj;
obj = new_value;
return old_value;
}
template <class T>
class m_vector
{
private:
unsigned int size;
unsigned int capacity;
T* array;
public:
m_vector()
: size(0)
, capacity(VECT_INC_SIZE)
, array(new T[VECT_INC_SIZE])
{}
m_vector(m_vector<T> const& other)
: size(other.size)
, capacity(other.capacity)
, array(new T[other.capacity]) {
//copy_n(other.array, size, array);
copy(other.cbegin(), other.cend(), begin());
}
// rule of 3
m_vector& operator=(m_vector<T> const& other) {
if (&other != this) {
if (other.capacity != capacity){
delete [] exchange(array, new T[other.capacity]);
capacity = other.capacity;
}
size = other.size;
//copy_n(other.array, size, array);
copy(other.cbegin(), other.cend(), begin());
}
return *this;
}
~m_vector() {
if (array != 0) delete [] array;
}
void push_back(T const& item) {
if (size >= capacity) {
reserve(capacity + VECT_INC_SIZE);
}
array[size] = item;
++size;
}
void reserve(unsigned int newCapacity) {
if (size > capacity) {
T* const temp = new T[newCapacity];
//copy_n(array, size, temp);
copy(cbegin(), cend(), temp);
delete [] exchange(array, temp);
capacity = newCapacity;
}
}
bool exists(T const& item) const {
//for(unsigned int i = 0; i < size; ++i) {
// if(array[i] == item) return true;
//}
for(T const* it = cbegin(); it != cend(); ++it) {
if(*it == item) return true;
}
return false;
}
void erase(T const& item) {
T* it = begin();
T* const endIt = end();
while(it != endIt && *it != item) ++it;
if (it == endIt) return;
copy(it + 1, endIt, it);
--size;
}
// iterators
T* begin() { return array; }
T* end() { return array + size; }
T const* cbegin() const { return array; }
T const* cend() const { return array + size; }
};
class Vector {
private:
int x,y;
public:
Vector() : x(0), y(0) {}
Vector(int x, int y) : x(x), y(y) {}
friend bool operator== (Vector const& lhs, Vector const& rhs){
return lhs.x == rhs.x && lhs.y == rhs.y;
}
friend bool operator!= (Vector const& lhs, Vector const& rhs){
return !(lhs==rhs);
}
};
#include <cstdio>
void VectorInM_Vector(m_vector<Vector> const& vec, Vector const& item) {
if (vec.exists(item)) printf("Vector found in vector\n");
else printf("Vector not found in vector\n");
}
int main(){
m_vector<Vector> vec;
vec.push_back(Vector(1,1));
VectorInM_Vector(vec, Vector(1,1));
m_vector<Vector> vec2(vec);
vec.erase(Vector(1,1));
VectorInM_Vector(vec, Vector(1,1));
VectorInM_Vector(vec2, Vector(1,1));
vec2 = vec;
VectorInM_Vector(vec2, Vector(1,1));
}
on compiler explorer/godbolt
I have the following Edgeclass:
class Edge {
public:
int src, dest;
bool operator== (const Edge &edge) const {
return ((src == edge.src) && (dest == edge.dest)) || ((src == edge.dest) && (dest == edge.src));
}
bool operator<(const Edge& edge) const {
return !(((src == edge.src) && (dest == edge.dest)) || ((src == edge.dest) && (dest == edge.src)));
}
Edge(int src, int dest) {
this->src = src;
this->dest = dest;
}
};
The point of overriding the < operator is when I try to find an edge in a set Edge(0, 1) should be equal to Edge(1, 0). However, the following test code fails to do so and std::find returns an edge that doesn't even exist:
Edge edge(0, 3);
set<Edge> test;
test.insert(Edge(3, 1));
test.insert(Edge(3, 0));
auto a = test.find(edge);
cout << a->src << " " << a->dest << endl;
This will strangely print out 2 0. I can't figure out why and I'm new to C++ any help is appreciated.
You currently don't have a valid Compare for std::set, so your program has undefined behaviour.
Here is one that is compatible with your ==
bool operator<(const Edge& edge) const {
return std::minmax(src, dest) < std::minmax(edge.src, edge.dest);
}
This can also be used to simplify your ==
bool operator==(const Edge& edge) const {
return std::minmax(src, dest) == std::minmax(edge.src, edge.dest);
}
There are two issues in your code.
First, you do not check whether test.find() returns a valid edge; note that find returns end() if no element was found.
Second, your <-operator does not implement a strict ordering, it actually just defines a !=. To overcome this, I'd normalize each edge such that the lower node is always treated as the start; then decide based on the starting nodes, and only if they are equal, consider the destination nodes:
class Edge {
public:
int src, dest;
bool operator== (const Edge &edge) const {
return ((src == edge.src) && (dest == edge.dest)) || ((src == edge.dest) && (dest == edge.src));
}
bool operator<(const Edge& edge) const {
// return !(((src == edge.src) && (dest == edge.dest)) || ((src == edge.dest) && (dest == edge.src)));
int thisSrc = std::min(src,dest);
int thisDest = std::max(src,dest);
int eSrc = std::min(edge.src,edge.dest);
int eDest = std::max(edge.src,edge.dest);
if (thisSrc < eSrc) {
return true;
} else if (thisSrc > eSrc) {
return false;
} else {
return thisDest < eDest;
}
}
Edge(int src, int dest) {
this->src = src;
this->dest = dest;
}
};
#include <set>
int main() {
Edge edge(0, 3);
std::set<Edge> test;
test.insert(Edge(3, 1));
test.insert(Edge(3, 0));
auto a = test.find(edge);
if (a == test.end()) {
std::cout << "edge not found." << std::endl;
} else {
std::cout << a->src << " " << a->dest << std::endl;
}
}
Output:
3 0
I implemented an A* algorithm in C++ but the vector doesn't always have the target node in it resulting in an endless loop. The library I'm using is: https://nullptr.club/libkmint/index.html. The function shortestPathToDist() should do the following: find the shortest path from the source node to the target node using A* ad return that path. Is this a correct implementation of A* or did I do something wrong and what?
Helper.hpp:
#ifndef UFO_HELPER_HPP
#define UFO_HELPER_HPP
#include <map>
#include <iostream>
#include "kmint/map/map.hpp"
namespace kmint {
namespace ufo {
class helper {
public:
helper();
std::vector<const map::map_node*> shortestPathToDist(const kmint::map::map_node& source_node, const kmint::map::map_node& target_node);
private:
const map::map_node* helper::smallestDistance(std::map<const map::map_node*, float>& actualCost, std::map<const map::map_node*, float>& heuristicCost, std::vector<const kmint::map::map_node*>& queue);
float heuristic(const map::map_node& source_node, const map::map_node& target_node);
};
}
}
#endif
Helper.cpp:
#include "kmint/ufo/helper.hpp"
namespace kmint {
namespace ufo {
helper::helper() {
}
std::vector<const map::map_node*> helper::shortestPathToDist(const map::map_node& source_node, const map::map_node& target_node)
{
std::vector<const map::map_node*> path;
std::vector<const map::map_node*> visited;
std::vector<const map::map_node*> queue;
std::map<const map::map_node*, const map::map_node*> previous;
std::map<const map::map_node*, float> cost;
std::map<const map::map_node*, float> heuristic_cost;
queue.push_back(&source_node);
cost[&source_node] = 0;
heuristic_cost[&source_node] = heuristic(source_node, target_node);
while (queue.size() > 0) {
const map::map_node* shortest_path_node = smallestDistance(cost, heuristic_cost, queue);
for (int i = 0; i < shortest_path_node->num_edges(); i++) {
map::map_edge edge = (*shortest_path_node)[i];
const map::map_node *node_to = &edge.to();
if (std::find(visited.begin(), visited.end(), node_to) == visited.end()
&& std::find(queue.begin(), queue.end(), node_to) == queue.end()) {
queue.push_back(node_to);
}
if (cost.find(node_to) == cost.end() || cost[node_to] > cost[shortest_path_node] + edge.weight())
{
cost[node_to] = cost[shortest_path_node] + edge.weight();
heuristic_cost[node_to] = heuristic(*shortest_path_node, target_node);
previous[node_to] = shortest_path_node;
}
if (node_to->node_id() == target_node.node_id())
{
cost[node_to] = cost[shortest_path_node] + edge.weight();
heuristic_cost[node_to] = heuristic(*shortest_path_node, target_node);
previous[node_to] = shortest_path_node;
break;
}
}
queue.erase(queue.begin());
visited.push_back(shortest_path_node);
}
// shortest path to target_node
const map::map_node* current_node = nullptr;
for (auto const&[key, val] : previous) {
if (key != nullptr && key != NULL) {
if (key->node_id() == target_node.node_id()) {
current_node = val;
break;
}
}
}
path.clear();
if (current_node == nullptr || current_node == NULL) {
std::cout << "could not find target node\n";
//this->shortest_path_to_target(source_node, target_node);
return path;
}
while (current_node != &source_node) {
if (current_node != nullptr && current_node != NULL) {
if (path.size() > 0) {
bool found = false;
for (auto &p : path) {
if (p != NULL && p != nullptr && p->node_id() == current_node->node_id()) {
found = true;
break;
}
}
if (!found) {
path.insert(path.begin(), current_node);
}
}
else {
path.insert(path.begin(), current_node);
}
}
for (auto const&[key, val] : previous) {
if (key != nullptr && key != NULL && current_node != nullptr && current_node != NULL) {
if (key->node_id() == current_node->node_id()) {
current_node = val;
break;
}
}
}
}
return path;
}
// manhatan heuristic
float helper::heuristic(const map::map_node& fNode, const map::map_node& sNode)
{
return std::abs(fNode.location().x() - sNode.location().x()) + std::abs(fNode.location().y() - sNode.location().y());
}
const map::map_node* helper::smallestDistance(std::map<const map::map_node*, float>& actualCost, std::map<const map::map_node*, float>& heuristicCost, std::vector<const map::map_node*>& queue)
{
const map::map_node* sDN = nullptr;
for (int i = 0; i < queue.size(); i++)
{
if (sDN == nullptr || actualCost[queue[i]] + heuristicCost[queue[i]] < actualCost[sDN] + heuristicCost[sDN]) {
sDN = queue[i];
}
}
return sDN;
}
}
}
queue.erase(queue.begin());. This is a bug. You are erasing the oldest added object, while you should pop the current shortest path node.
You should also remove the shortest path node from the visited set!
The real issue is that you are not using the correct data structures.
std::vector<const map::map_node*> queue;
should become
using scored_node = std::pair<double, const map::map_node*>
std::priority_queue<scored_node, std::vector<scored_node>, std::greater<scored_node>> queue;
With this change, you don't need smallestDistance anymore, and you should use
const auto shortest_path_scored_node = queue.top();
const auto shortest_path_node = shortest_path_scored_node.second;
queue.pop();
visited.erase(shortest_path_node);
Rather than use a vector
std::vector<const map::map_node*> visited;
you should use an unordered set, given you just care whether the element was visited. You are guaranteed uniqueness and fast retrieval without effort.
std::unodered_set<const map::map_node*> visited;
I have a custom bitset class implementation in C++. I often iterate over the indexes of bits that are set in the bitset (i.e. for bitset '10011' I want to iterate over numbers 0, 3, 4.) This iteration can be implemented as follows:
struct Bitset {
uint64_t* data_;
size_t chunks_;
std::vector<int> Elements() const {
std::vector<int> ret;
for (size_t i=0;i<chunks_;i++){
uint64_t td = data_[i];
while (td) {
ret.push_back(i*BITS + __builtin_ctzll(td));
td &= ~-td;
}
}
return ret;
}
};
void Iterate(Bitset bitset) {
for (int b : bitset.Elements()) {
std::cout << "bit: " << b << std::endl;
}
}
The above implementation provides clean code for the iteration, but it involves an unnecessary heap allocation with the vector. The following version which essentially inlines the Elements() function is often faster:
void Iterate(Bitset bitset) {
int chunks = bitset.chunks_;
for (int i = 0; i < chunks; i++) {
uint64_t td = bitset.data_[i];
while (td) {
std::cout << "bit: " << i*BITS + __builtin_ctzll(td) << std::endl;
td &= ~-td;
}
}
}
What would be a good way to implement an abstraction for the iteration so that it would be as clean as the above version, but also with no performance cost.
Just iterate over your class. Provide your own implementation of an iterator class for your Bitset and provide begin() and end() methods. A simplest (untested!) implementation could look something like this:
#include <vector>
#include <cstdint>
#include <iostream>
struct Bitset {
uint64_t* data_;
size_t chunks_;
struct iterator {
uint64_t *pnt;
uint_fast8_t pos;
iterator(uint64_t *pnt, size_t pos) :
pnt(pnt), pos(pos) {}
bool operator !=(const iterator& o) {
return o.pnt != pnt || o.pos != pos;
}
void operator ++() {
pos++;
if (pos == 64) {
pnt++;
pos = 0;
}
}
bool operator *() {
return *pnt & (1 << pos);
}
};
iterator begin() { return iterator(data_, 0); }
iterator end() { return iterator(data_ + chunks_, 64); }
};
void Iterate(Bitset bitset) {
for (auto&& b : bitset) {
std::cout << "bit: " << b << std::endl;
}
}
I believe for your strange while (td) { ... i*BITS + __builtin_ctzll(td) ... loop that I don't understand that could be something along (untested!):
constexpr int BITS = 100000;
struct Bitset {
uint64_t* data_;
size_t chunks_;
struct iterator {
uint64_t *data_;
int i = 0;
uint64_t td = 0;
iterator(uint64_t *data_, int i, uint64_t td) :
data_(data_), i(i), td(td) {}
bool operator !=(const iterator& o) {
return o.data_ != data_ || o.i != i || o.td != td;
}
void operator ++() {
if (td == 0) {
td = *data_;
data_++;
} else {
td &= ~-td;
}
}
bool operator *() {
return i * BITS + __builtin_ctzll(td);
}
};
iterator begin() { return iterator(data_, 0, *data_); }
iterator end() { return iterator(data_ + chunks_, 0, 0); }
};
As KamilCuk suggested, I used an iterator to solve this problem. Now the implementation looks like:
struct Bitset {
uint64_t* data_;
size_t chunks_;
class BitsetIterator {
private:
const Bitset* const bitset_;
size_t pos_;
uint64_t tb_;
public:
BitsetIterator(const Bitset* const bitset, size_t pos, uint64_t tb) :
bitset_(bitset), pos_(pos), tb_(tb) { }
bool operator!=(const BitsetIterator& other) const {
return pos_ != other.pos_ || tb_ != other.tb_;
}
const BitsetIterator& operator++() {
tb_ &= ~-tb_;
while (tb_ == 0 && pos_ < bitset_->chunks_) {
pos_++;
if (pos_ < bitset_->chunks_) {
tb_ = bitset_->data_[pos_];
}
}
return *this;
}
int operator*() const {
return pos_*BITS + __builtin_ctzll(tb_);
}
};
BitsetIterator begin() const {
size_t pos = 0;
while (pos < chunks_ && data_[pos] == 0) {
pos++;
}
if (pos < chunks_) {
return BitsetIterator(this, pos, data_[pos]);
} else {
return BitsetIterator(this, pos, 0);
}
}
BitsetIterator end() const {
return BitsetIterator(this, chunks_, 0);
}
};
void Iterate(Bitset bitset) {
for (int b : bitset) {
std::cout << "bit: " << b << std::endl;
}
}
This avoids heap allocation and is much faster than the version that uses vector. I'm not sure if this provides exactly same performance as the version without any abstractions, but it should be very close.
I would like to dump the content inside the object tmp_np which is a UllmanSet which if you know a key then you know the position and if you know the position , you know the key. Is there a standard C++ container that's similar to the Ullmanset. Ullmanset 's index starts at 0 and Ullmanset1's index start at 1.
and also dump the content of frontierq which is a PriorityQ class.
UllmanSet tmp_np;
template<unsigned B>
class BasedUllmanSet
{
size_t n;
std::vector<int> key;
BasedVector<unsigned, B> pos;
public:
BasedUllmanSet()
: n(0)
{}
BasedUllmanSet(size_t cap)
: n(0), key(cap), pos(cap)
{}
size_t capacity() const { return key.size(); }
size_t size() const { return n; }
bool empty() const { return n == 0; }
void clear() { n = 0; }
void resize(size_t cap)
{
key.resize(cap);
pos.resize(cap);
n = 0;
}
bool contains(int k) const
{
unsigned p = pos[k];
return (p < n
&& key[p] == k);
}
void insert(int k)
{
if (contains(k))
return;
unsigned p = n++;
key[p] = k;
pos[k] = p;
}
void extend(int k)
{
assert(!contains(k));
unsigned p = n++;
key[p] = k;
pos[k] = p;
}
void erase(int k)
{
if (!contains(k))
return;
unsigned p = pos[k];
--n;
if (p != n)
{
int ell = key[n];
pos[ell] = p;
key[p] = ell;
}
}
int ith(int i)
{
assert(i >= 0 && i < (int)n);
return key[i];
}
};
using UllmanSet = BasedUllmanSet<0>;
using UllmanSet1 = BasedUllmanSet<1>;
The priority queue is implemented as followed. I like to print out the values inside the queue using std::cout.
PriorityQ<std::pair<int, int>, Comp> frontierq;
class Comp
{
public:
Comp() {}
bool operator()(const std::pair<int, int> &lhs,
const std::pair<int, int> &rhs) const
{
return (lhs.second > rhs.second
|| (lhs.second == rhs.second
&& lhs.first > rhs.first));
}
};
class PriorityQ
{
public:
Comp comp;
std::vector<T> v;
unsigned n;
public:
PriorityQ() : n(0) {}
PriorityQ(Comp comp_) : comp(comp_), n(0) {}
size_t size() const { return n; }
void clear() { n = 0; }
bool empty() { return n == 0; }
void push(const T &x)
{
assert(v.size() >= n);
if (v.size() == n)
v.push_back(x);
else
v[n] = x;
++n;
std::push_heap(&v[0], &v[n], comp);
}
const T &pop()
{
assert(n > 0);
std::pop_heap(&v[0], &v[n], comp);
--n;
return v[n];
}
const T &top()
{
assert(n > 0);
return v[0];
}
};
C++ standard containers do get this esoteric. If you have another question about the priority queue you should make another post.