error picture
The compiler says there is something wrong with the conversion of iterators in my for loops. Can someone tell me what's wrong exactly?
For this project, I have supposed to store values into keys. I am storing the keys and values in each node and each time theres a new key, there will be a new node with its vectors of values.
struct node{
int key;
vector<int> values;
};
class key_value_sequences {
public:
key_value_sequences() { }
~key_value_sequences() { }
key_value_sequences(const key_value_sequences& A) {
myList = A.myList;
v = A.v;
}
key_value_sequences& operator=(const key_value_sequences& A) {
if (this == &A) return *this;
myList = A.myList;
v = A.v;
return *this;
}
// YOU SHOULD USE C++ CONTAINERS TO AVOID RAW POINTERS
// IF YOU DECIDE TO USE POINTERS, MAKE SURE THAT YOU MANAGE MEMORY PROPERLY
// IMPLEMENT ME: SHOULD RETURN SIZE OF A SEQUENCE FOR GIVEN KEY
// IF NO SEQUENCE EXISTS FOR A GIVEN KEY RETURN -1
int size(int key) const {
if (find(v.begin(), v.end(), key)!=v.end()) {
for(list<node>::iterator it = myList.begin(); it != myList.end(); it++) {
if (it->key == key) {
return it->values.size();
}
}
}
else return -1;
}
// IMPLEMENT ME: SHOULD RETURN POINTER TO A SEQUENCE FOR GIVEN KEY
// IF NO SEQUENCE EXISTS FOR A GIVEN KEY RETURN nullptr
const int* data(int key) const {
if (find(v.begin(), v.end(), key)!=v.end()) {
for(list<node>::iterator it = myList.begin(); it != myList.end(); it++) {
if (it->key == key) {
return it->values.data();
break;
}
}
}
else return nullptr;
}
// IMPLEMENT ME: INSERT VALUE INTO A SEQUENCE IDENTIFIED BY GIVEN KEY
void insert(int key, int value) {
if(v.size() == 0) { //empty list
v.push_back(key);
node n;
n.key = key;
n.values.push_back(value);
myList.push_back(n);
}
else if((find(v.begin(), v.end(), key)!=v.end())) { //if key exists already
for(list<node>::iterator it = myList.begin(); it != myList.end(); it++) {
if (it->key == key) {
it->values.push_back(value);
break;
}
}
}
else { //if theres no existing key
v.push_back(key);
node n;
n.key = key;
n.values.push_back(value);
myList.push_back(n);
}
}
private:
vector<int> v;
list<node> myList;
}; // class key_value_sequences
Your size and data methods are declared const. Therefore myList is const and its begin method returns const_iterators. Change list::iterator into list::const_iterator and it should work fine.
Related
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'm trying to understand how the iterator works.
I have build the following code:
list<Bucket<Key,Val>> *array;
template<typename Key, typename Val>
class Bucket
{
public:
Bucket(Key key, Val value)
{
this->key = key;
this->value = value;
}
~Bucket(){}
const Key getKey() const
{
return key;
}
const Val getValue() const
{
return value;
}
private:
Key key;
Val value;
};
After inserting a bucket in one of the lists, I would like to do 2 actions at least:
Find and Remove.
I can look for a given value with this code:
int entryNum = HashFunc()(key);
for(auto i: array[entryNum % capacity])
{
if(MatchFunc(i.getKey(),key)())
{
value = i.getValue();
}
}
But I can't seem to delete an item by adding something like
i = array[entryNum % capacity].erase(i);
or with remove.
But if i do this, it works:
int entryNum = HashFunc()(key);
typename list<Bucket<Key,Val>>::iterator it;
for(auto i: array[entryNum % capacity])
{
++testcounter;
if(MatchFunc(i.getKey(),key)())
{
value = i.getValue();
}
}
for (it=array[entryNum % capacity].begin(); it!= array[entryNum % capacity].end(); ++it)
{
if(testcounter!=0) --testcounter;
else
{
array[entryNum % capacity].erase(it);
return htKeyFound;
}
}
This is obviously not ideal, I would like to NOT go twice over the same list + keeping a counter for it. But I can't seem to join them into one.
When I try to access the it.getKey() it obviously doesn't work and crests a compilation error.
Any advice about what I'm doing wrong?
Range for loops iterates over the values inside the container.
The std::list::erase function expects an iterator and not a value.
And you don't need two loops, you can dereference an iterator to get the value it "points" to:
int entryNum = HashFunc()(key);
auto& list_ref = array[entryNum % capacity];
for(auto it = list_ref.begin(); it != list_ref.end(); ++it)
{
if(MatchFunc(it->getKey(),key)())
{
value = it->getValue();
list_ref.erase(it);
return htKeyFound;
}
}
Why doesn't it accept hash1.find(p) but hash1[p] works find if i use that?
class LRUCACHE {
list<int> list1; // store keys of Cache.
unordered_map<int, list<int>::const_iterator> hash1; // Store reference of Keys in Cache.
int maxsize;
public:
LRUCACHE(int);
void set(int);
void get(int);
};
LRUCACHE::LRUCACHE(int n) {
maxsize = n;
}
void LRUCACHE::get(int x) {
// Not Found in Cache.
if (hash1.find(x) == hash1.end() ) {
// if Max size.
if (list1.size() == maxsize ) {
// returns the last element of LIST.
int last = list1.back();
// Remove last element of LIST and reduce size by 1.
list1.pop_back();
hash1.erase(last);
}
}
else {
list1.erase(hash1[x]);
}
list1.push_front(x);
hash1[x] = list1.begin(); // points and updates.
}
void LRUCACHE::get(int p) {
if (hash1.find(p) == hash1.end() ){
cout << "not found " << endl;
}
else {
list1.erase(hash1.find(p)); // Error Here member function not found
}
}
I think im using const_iterator for unordermap? so it should accept it list function call of iterator erase( const_iterator position ); ?
i think hash1.find should return const_iterator?
std::unordered_map::find() returns an iterator, not the value in the map. So what you get is std::unordered_map<int, std::list<int>::const_iterator>>::iterator (or std::unordered_map<int, std::list<int>::const_iterator>>::const_iterator)
You can retrieve the value in map under iterator by using hash1.find(x)->second:
void LRUCACHE::get(int p) {
const auto iter = hash1.find(p);
if (iter == hash1.end() ){
cout << "not found " << endl;
} else {
list1.erase(iter->second);
}
}
std::unordered_map::operator[] on the other hand doesn't return an iterator, but a reference to the value in map under the key. Which means no further extraction is needed to directly access the value.
I want to implement a custom iterator class that has some differences with typical iterators. The container in this example is a vector and the idea is to walk throw it but using a specific syntax, like this:
int main()
{
VectorElement E;
for (size_t i = 0; i < 5; i++)
{
Element e;
e.id = i;
E.push_back(e);
}
for (ElementIterator e(E); e.end(); ++e)
cout << "Element " << e.id << endl;
}
I tried with the following definitions, but it gives me a Segmentation Fault at the static_cast line after two iterations. Does someone know how to improve this? Thanks
class Element
{
public:
Element() {};
size_t id;
};
typedef vector<Element> VectorElement;
class ElementIterator: public Element
{
typedef vector<Element>::iterator iter;
public:
ElementIterator(const Element& e) : Element(e) { }
ElementIterator(VectorElement& ve_)
{
ve = &ve_;
it = ve->begin();
}
ElementIterator operator++()
{
++it;
*this = static_cast<ElementIterator>(*it);
return *this;
}
bool end()
{
if (it != ve->end() )
return true;
return false;
}
vector<Element>* ve;
iter it;
};
Here is alternate implementation that does not rely on global variables or deriving from 'Element':
class Element
{
public:
Element() {};
size_t id;
};
class ElementIterator
{
std::vector<Element>& ve;
std::vector<Element>::iterator it;
public:
ElementIterator(std::vector<Element>& ve_) : ve(ve_)
{
it = ve.begin();
}
ElementIterator(const ElementIterator &rhs) : ve(rhs.ve)
{
it = rhs.it;
}
ElementIterator operator++()
{
++it;
return *this;
}
const Element *operator ->() const
{
assert(!this->end());
return &(*it);
}
bool end() const
{
if (it == ve.end())
return true;
return false;
}
};
Main:
int main()
{
std::vector<Element> E;
for (size_t i = 0; i < 5; i++)
{
Element e;
e.id = i;
E.push_back(e);
}
for (ElementIterator e(E); !e.end(); ++e)
std::cout << "Element " << e->id << std::endl;
}
NOTE: I changed the behaviour of 'ElementIterator::end' so that it returns 'true' when it is at the end which seemed more logical.
Try it here:
http://coliru.stacked-crooked.com/a/8bf8b1025d87a882
I suspect that the segfault occurs because the 'ElementIterator::operator++()' increments the internal 'it' attribute and then deferences it without verifying that its valid first. It could be implemented as follows:
ElementIterator::operator ++()
{
++it;
if (!this->end())
*this = static_cast<ElementIterator>(*it);
return *this;
}
I finally use this workaround, that it is not elegant but works. The main problem was that the iterator "it" was overwritten so I put it in the global scope.
class Element
{
public:
Element() {};
size_t id;
};
typedef vector<Element> VectorElement;
typedef vector<Element>::iterator iter;
iter it;
class ElementIterator: public Element
{
public:
ElementIterator(const Element& e) : Element(e) { }
ElementIterator(VectorElement& ve_)
{
ve = &ve_;
it = ve->begin();
}
ElementIterator operator++()
{
++it;
*this = static_cast<ElementIterator>(*it);
return *this;
}
bool end()
{
if (it != ve->end() )
return true;
return false;
}
vector<Element>* ve;
};
I need help to design the best data structure for a GRAPH. The following is my implementation.
Please give your thoughts on this design.
#ifndef _GRAPH_H_
#define _GRAPH_H_
#include <map>
#include <vector>
#include <iostream>
#include <list>
template <typename T>
class Vertex {
public:
Vertex(){};
Vertex(T inVertex): m_vertex(inVertex), m_visited(false){}
~Vertex(){}
bool operator<(const Vertex<T>& right) const { return m_vertex < right.m_vertex;}
T getVertex () { return m_vertex;}
T getVisited () { return m_visited;}
T getParent () { return m_vertexParentVisited;}
void setVisited(bool inVisited) { m_visited = inVisited;}
void setParent(T inParentVertex) { m_vertexParentVisited = inParentVertex;}
private:
T m_vertex;
T m_vertexParentVisited;
bool m_visited;
};
template <typename T>
class Edge
{
public:
enum EDGE_TYPE
{
TREE_EDGE,
PARENT_EDGE,
BACK_EDGE,
DOWN_EDGE
};
Edge(Vertex<T>* inSrc, Vertex<T>* inDst)
{
m_SourceVertex = inSrc;
m_DestVertex = inDst;
}
void SetEdgeType( EDGE_TYPE t)
{
m_EdgeType = t;
}
private:
Vertex<T>* m_SourceVertex;
Vertex<T>* m_DestVertex;
EDGE_TYPE m_EdgeType;
protected:
};
template <typename T>
class Graph
{
public:
typedef Vertex<T> GraphVertex;
// Adjancency List Datastructure and Iterator declaration.
// Use STL List here
typedef std::list<GraphVertex*> AdjList;
typedef typename AdjList::iterator AdjListIterator;
// Graph Data structure declaration and Iterator declaration
// Graph is map of GraphVertex* and List of adjacency list.
typedef std::map<GraphVertex*, AdjList> GraphMap;
typedef typename GraphMap::iterator GraphIterator;
// Graph Memory pool is map where actual memory allocation
// will happen.
// Make sure you have some way to identify each vertex.
// Map key is the identification method of the vertex.
// Map value is the pointer to actual object.
typedef std::map<T,GraphVertex*> GraphMemoryPool;
typedef typename GraphMemoryPool::iterator GraphInMemoryIterator;
// Edge Class Declaration.
typedef std::vector<Edge<T> > GraphEdge;
private:
bool m_isDirected;
GraphMap m_graph;
GraphMemoryPool m_graphMemoryPool;
std::vector<T> m_SearchOrderVector;
GraphEdge m_GraphEdge;
public:
Graph(bool inIsDirected):m_isDirected(inIsDirected) {}
~Graph()
{
for ( GraphInMemoryIterator itr = m_graphMemoryPool.begin(); itr != m_graphMemoryPool.end(); ++itr)
{
if ( itr->second) delete itr->second;
}
m_graphMemoryPool.clear();
m_graph.clear();
}
void insert(T inSRC, T inDST)
{
if ( m_isDirected)
{
__insert(inSRC,inDST);
}
else
{
__insert(inSRC,inDST);
__insert(inDST,inSRC);
}
}
void printGraph()
{
for ( GraphIterator itr = m_graph.begin(); itr != m_graph.end(); ++itr)
{
std::cout << static_cast<GraphVertex*>(itr->first)->getVertex() << " : ";
AdjList tmp = static_cast<AdjList>(itr->second);
for ( AdjListIterator itr1 = tmp.begin(); itr1 != tmp.end(); ++itr1)
{
std::cout << (*itr1)->getVertex() << " ";
}
std::cout << std::endl;
}
}
void printSearchOrder()
{
std::vector<T> tmp = getSearchOrderVector();
for ( vector<T>::iterator itr = tmp.begin(); itr != tmp.end(); ++itr)
{
std::cout << *itr << " ";
}
std::cout << std::endl;
}
void printParentLinkMap()
{
std::vector<T> tmp = getSearchOrderVector();
for ( vector<T>::iterator itr = tmp.begin(); itr != tmp.end(); ++itr)
{
GraphVertex *tmp = __VertexInstance(*itr);
std::cout << "[" << tmp->getParent() << "] Parent Of [" << tmp->getVertex() << "]" << std::endl;
}
}
void DFS()
{
for ( GraphInMemoryIterator itr = m_graphMemoryPool.begin(); itr != m_graphMemoryPool.end(); ++itr)
{
(*itr).second->setVisited(false);
}
m_SearchOrderVector.clear();
// This loop handles the case when the grpah is not
// Connected.
for ( GraphIterator itr = m_graph.begin(); itr != m_graph.end(); ++itr)
{
GraphVertex *currentVertex = static_cast<GraphVertex*>(itr->first);
if ( currentVertex->getVisited() == false)
{
T curVertex = currentVertex->getVertex();
// Insert new element in Search Order Vector.
m_SearchOrderVector.push_back(curVertex);
// Set the parent of this root node in the DFS search tree
currentVertex->setParent(curVertex);
// Create Edge with itself here.
__setTypeAndInsertNewEdge( curVertex,
curVertex,
Edge<T>::TREE_EDGE);
// Mark the vertex as visited.
currentVertex->setVisited(true);
__rundfs(itr);
}
}
}
std::vector<T> getSearchOrderVector() { return m_SearchOrderVector;}
int getNumberOfVertex(){ return (int)m_graph.size();}
private:
void __setTypeAndInsertNewEdge( T inSRC, T inDST, typename Edge<T>::EDGE_TYPE t )
{
Edge<T> tmp(__VertexInstance(inSRC),
__VertexInstance(inDST));
tmp.SetEdgeType(t);
m_GraphEdge.push_back(tmp);
}
// Recursive DFS function.
// Apart from visiting vertices
// this implementatioin will be doing following.
// 1. Maintain the order in which vertices are visited.
// 2. Update Parent link map
// 3. Create Edge and update the type of the edge.
void __rundfs( typename GraphMap::iterator &itr)
{
for (AdjListIterator itr1 = itr->second.begin(); itr1 != itr->second.end(); ++itr1)
{
GraphVertex *childVertex = (*itr1);
GraphVertex *parentVertex = itr->first;
if ( childVertex->getVisited() == false)
{
m_SearchOrderVector.push_back(childVertex->getVertex()); // Update the search order Vector.
childVertex->setParent(parentVertex->getVertex()); // Update the parent-link map.
childVertex->setVisited(true); // Mark the vertex as visited.
__setTypeAndInsertNewEdge(parentVertex->getVertex(),
childVertex->getVertex(),
Edge<T>::TREE_EDGE); // setup the edge type
__rundfs(m_graph.find(
__VertexInstance(childVertex->getVertex())));
}
else
{
if ( childVertex->getVertex() == parentVertex->getVertex())
{
}
}
}
}
void __insert(T inSRC, T inDST)
{
GraphIterator itr = m_graph.find(__VertexInstance(inSRC));
if ( itr != m_graph.end())
{
// Update the Adjancency list
itr->second.push_back(__VertexInstance(inDST));
}
else
{
// Create new Adjancy list
m_graph.insert(std::make_pair(__VertexInstance(inSRC),AdjList() ));
GraphIterator itr = m_graph.find(__VertexInstance(inSRC));
// Update the Adjacency List
itr->second.push_back(__VertexInstance(inDST));
}
}
// Searches if the Vertex is already allocated in the pool map
// If ye return the pointer from the map.
// Else Create new Vertex instance
// Insert into the memory pool map
// Return the pointer.
GraphVertex *__VertexInstance(T inVertex)
{
GraphVertex *newVertex = (GraphVertex *)0;
GraphInMemoryIterator itr = m_graphMemoryPool.find(inVertex);
if ( itr == m_graphMemoryPool.end())
{
newVertex = new GraphVertex(inVertex);
m_graphMemoryPool.insert(std::make_pair(inVertex,newVertex));
}
else
{
newVertex = ( GraphVertex *)itr->second;
}
return newVertex;
}
};
#endif
It seems you know this, but I'm reviewing for all to benefit:
There are two typical ways to implement a graph: a matrix of edges, and a sparse matrix (represented as a vector of edges for each vertex).
The matrix is an NxN structure where N is the number of vertices. Each datum is the edge length between the two vertices, so G[1][2] is the distance from 1 to 2. This also allow for directed graphs.
The other method, better for sparse graphs, is to have a vector of edges for each vertex. So you'd have vector> g where g[1] is the vector of edges for vertex 1. Each item in that vector would be and edge holding the vertex it goes to and the distance.
For more details go here: http://en.wikipedia.org/wiki/Graph_(data_structure)#Representations
Given all that, one of these implementations is likely to be quite useful to you.
EDIT1
For storing weights in a graph, on might use a structure such as vector> (as noted above). In such a case, the edge class may be like this:
class edge {
int weight;
int destination_vertex;
};
In this way, the edge from 1 to 2 would be g[1][2].