Generic Segment Tree implementation using C++ Templates - c++

I am trying to make a generic Segment Tree Class for updates and range queries.
Instead of assuming that the elements would just be integers and the operation to be done over a range of elements would be their sum or product, i would want the user to provide the type T of the element and a function, which i named compose.
This function takes in two parameters of type T and returns a value of the same type T. This return value is the result when that desired operation is performed over range of 2 elements which i can use to perform that same operation on a range of any number of elements.
The class is as follows:
#include <functional>
template<class T>
class SegmentTree {
public:
class binary_function_unitype: public std::binary_function<T,T,T> {
public:
virtual T operator() (T arg1, T arg2) {};
};
private:
class Node {
public:
T value;
int seg_start, seg_end;
Node* left;
Node* right;
Node (T value, int seg_start, int seg_end, Node* left=0, Node* right=0) {
this->value = value;
this->seg_start = seg_start;
this->seg_end = seg_end;
this->left = left;
this->right = right;
}
};
// Not expecting the compose function to be robust enough.
T composeUtil (T arg1, T arg2) {
if (arg1!=0 && arg2!=0)
return compose(arg1,arg2);
else if (arg1!=0)
return arg1;
else if (arg2!=0)
return arg2;
}
// Creating the Segment Tree.
Node* createTree (T leaves[], int start, int end) {
// base case - leaf of tree.
if (start==end)
return new Node(leaves[start],start,start,0,0);
// general case.
int mid = start + (end-start)/2;
Node* left = createTree(leaves,start,mid);
Node* right = createTree(leaves,mid+1,end);
T retValue = composeUtil(left->value,right->value);
return new Node(retValue,start,end,left,right);
}
// Range Query helper.
T queryUtil (Node* root, int start, int end) {
int seg_start = root->seg_start, seg_end = root->seg_end;
if (seg_start>end || seg_end<start)
return 0;
else if (seg_start>=start && seg_end<=end)
return root->value;
else
return compose( queryUtil(root->left,start,end), queryUtil(root->right,start,end));
}
// Helper function for Updating the Segment Tree.
void updateUtil (Node* root, int position, T updatedValue) {
int seg_start = root->seg_start, seg_end = root->seg_end;
if(seg_start>position || seg_end<position)
return;
else if(seg_start==seg_end)
root->value = updatedValue;
else
root->value = composeUtil(root->left->value,root->right->value);
}
// Freeing the memory allocated to the Segment Tree.
void destroyTree(Node* root) {
if (root->left!=0)
destroyTree(root->left);
if (root->right!=0)
destroyTree(root->right);
delete root;
}
Node* root;
binary_function_unitype compose;
public:
SegmentTree (T leaves[], binary_function_unitype compose, int start, int end) {
this->compose = compose;
this->root = createTree(leaves, start, end);
}
T query (int start, int end) {
return queryUtil(root, start, end);
}
void update (int position, T updatedValue) {
updateUtil(root, position, updatedValue);
}
~SegmentTree () {
destroyTree(root);
}
};
When I tried to use this class, it turns out that the compose function, which I took in as a paramater is not being used, on the contrary the one from the class binary_function_unitype is being used.
I expected that the function definition from the user would override the one in class binary_function_unitype and my work would be done. But that did not happen. The program using this class is as follows:
#include <iostream>
#include "SegmentTree.h"
using namespace std;
class Compose: public SegmentTree<int>::binary_function_unitype {
public:
int operator() (int arg1, int arg2) {
return arg1+arg2;
}
};
int main()
{
int num;
cin>>num;
int arr[num];
for(int i=0;i<num;i++)
cin>>arr[i];
Compose compose;
SegmentTree<int> segTree(arr, compose, 0, num-1);
int s,e;
cin>>s>>e;
cout<<segTree.query(s-1,e-1);
return 0;
}
Can somebody tell me whats the flaw in my approach or if I misunderstood some basic concept about using inheritance or templates in C++ ?
Thanks.

The constructor takes a binary_function_unitype by value, so it will slice.

Related

C++ Using proper child-class pointer

basically, I want to implement document type converter. I've designed pretty straight-forward solution:
DocTypeParser : Parser will converts file into tree structure of nodes, representing different elements (headers, lists, bold texts, ...)
DocTypePrinter : Printer will deconstruct that tree back into text file
So far so good, but I came across nasty problem - The connection between tree nodes is estabilished through std::vector<Node *> and I am not sure how to determine what child class is being processed.
My demo code:
class Node
{
public:
Node()
{
}
~Node()
{
for (auto it : Leaf)
delete it;
}
Node &Add(Node *leaf)
{
Leaf.push_back(leaf);
return *this;
}
std::vector<Node *> Leaf;
};
class NodeA : public Node
{
public:
NodeA() : Node()
{
}
};
class Printer
{
public:
Printer() = default;
std::string Print(Node &n)
{
int i = 0, k = n.Leaf.size();
std::string res = "<n>";
for (; i < k; ++i)
res += Print(*(n.Leaf[i]));
res += "</n>";
return res;
}
std::string Print(NodeA &n)
{
int i = 0, k = n.Leaf.size();
std::string res = "<A>";
for (; i < k; ++i)
res += Print(*(n.Leaf[i]));
res += "</A>";
return res;
}
};
int main(int argc, const char *argv[])
{
NodeA tree;
tree.Add(new NodeA).Add(new NodeA);
Printer p;
std::cout << p.Print(tree) << std::endl;
return 0;
}
Desired result: <A><A></A><A></A></A>
Actual result: <A><n></n><n></n></A>
I pretty much understand what is the problem (vector stores Node pointers, not NodeChild pointers), but not that sure how to overcome that. dynamic_cast seems to be not-the-solution-at-all.
So finally question - is there cure for me or am I longing for the wrong design altogether?
You used type erasure wrongly. Your nodes accessed by Node* , so *(n.Leaf[i]) expression returns type Node, not NodeA.
What you do resembles visitor pattern, to recognize which class is which you have to use a virtual method in Node class and override it in NodeA, calling it with dispatcher as argument (classic visitor) or calling it from dispatcher you can recognize which instance is which.
In first case node would call the Print method and pass it *this.
This is minimal rework of your code, but I think, it needs honing\optimizing. Depends on what your actual task is, vistor might be a little too excessive.
#include <string>
#include <iostream>
#include <vector>
class Node;
class NodeA;
class AbstractPrinter
{
public:
virtual std::string Print(Node &n) =0;
virtual std::string Print(NodeA &n) =0;
};
class Node
{
public:
Node()
{
}
virtual ~Node()
{
for (auto it : Leaf)
delete it;
}
Node &Add(Node *leaf)
{
Leaf.push_back(leaf);
return *this;
}
virtual std::string Print(AbstractPrinter& p)
{
return p.Print(*this);
}
std::vector<Node *> Leaf;
};
class NodeA : public Node
{
public:
NodeA() : Node()
{
}
// if not override this, it would use Node
virtual std::string Print(AbstractPrinter& p) override
{
return p.Print(*this);
}
};
class Printer : public AbstractPrinter
{
public:
Printer() = default;
std::string Print(Node &n)
{
int i = 0, k = n.Leaf.size();
std::string res = "<n>";
for (; i < k; ++i)
res += n.Leaf[i]->Print(*this);
res += "</n>";
return res;
}
std::string Print(NodeA &n)
{
int i = 0, k = n.Leaf.size();
std::string res = "<A>";
for (; i < k; ++i)
res += n.Leaf[i]->Print(*this);
res += "</A>";
return res;
}
};
int main(int argc, const char *argv[])
{
NodeA tree;
tree.Add(new NodeA).Add(new NodeA);
Printer p;
std::cout << tree.Print(p) << std::endl;
return 0;
}

Efficient generic buffer queue for sequential processing

I have a producer-consumer queue which is being updated by parallel programs. The queue is queried for various statistics like mean or standard deviation or variance or something else on the current queue contents. For mean, this is the code, I use
class BufferQueue {
const int nMaxQueueSize_;
int* values;
int head, tail;
double sum;
::utils::FastMutex queue_mutex;
public:
BufferQueue(const int nMaxQueueSize) :
nMaxQueueSize_(nMaxQueueSize) {
head = tail = 0;
sum = 0;
values = new int[nMaxQueueSize_];
}
void enqueue(int val) {
values[head] = val;
if ((head + 1) % nMaxQueueSize_ == tail) {
queue_mutex.lock();
sum = val.value_point - values[tail].value_point;
utils::memory_barrier();
head = (1 + head) % nMaxQueueSize_;
tail = (1 + tail) % nMaxQueueSize_;
queue_mutex.unlock();
} else {
queue_mutex.lock();
sum += val.value_point;
utils::memory_barrier();
head = (1 + head) % nMaxQueueSize_;
queue_mutex.unlock();
}
}
bool dequeue() {
if (head != tail) {
queue_mutex.lock();
sum -= values[tail].value_point;
utils::memory_barrier();
tail = (1 + tail) % nMaxQueueSize_;
queue_mutex.unlock();
return true;
} else {
sum = 0;
return false;
}
}
MarketSpreadPoint& operator[](int i) {
return values[ (tail + i) % nMaxQueueSize_ ];
}
inline int getSize() {
return (head - tail + nMaxQueueSize_) % nMaxQueueSize_;
}
inline double average() {
queue_mutex.lock();
double result = sum / getSize();
queue_mutex.unlock();
return result;
}
~BufferQueue() {
delete values;
}
};
NOTE: One important thing to remember is that only one operation is being performed. Neither do I want to repeat code by writing separate implementations like BufferQueueAverage, BufferQueueVariance etc. I want very limit code redundancy(compiler optimizations). Even conditioning on type of queue for every update seems sub-optimal.
inline double average() {
queue_mutex.lock();
if(type_is_average){
double result = sum / getSize();
}else if(type_is_variance){
/// update accordingly.
}
double result = sum / getSize();
queue_mutex.unlock();
return result;
}
What can be a good alternative to this idea ?
Note: In this implementation, if queue is full, head automatically make the tail to move forward. In other words, the oldest element is deleted automatically.
Thanks
So you want to separate the queue from the statistics. I see two possible solutions:
Use a pattern like Template Method or Strategy to factor out the dependency.
Use a template that does this.
Assuming that all statistics you gather can gathered incrementally, the latter could look similar to the following (just meant as pseudo code):
class StatisticsMean
{
private:
int n = 0;
double mean = 0.0;
public:
void addSample(int s) { ++n; mean += (s - mean) / n; }
void removeSample(int s) { ... }
double getStatistic() const { return mean; }
}
template <typename TStatistics>
class BufferQueue
{
TStatistics statistics;
...
void enqueue(int val)
{
...
statistics.addSample(val);
}
...
double getStatistic() const { return statistics.getStatistic(); }
}
The template approach gives you full compile-time optimization. You can achieve the same with the Template Method pattern. This would also allow you to have distinct names for the getters (getStatistic() in the above example).
This could look similar to this:
class AbstractBufferQueue
{
virtual void addSample(int s) = 0;
virtual void removeSample(int s) = 0;
void enqueue(int val)
{
...
addSample(val);
}
}
class BufferQueueAverage : public AbstractBufferQueue
{
int n;
double mean;
void addSample(int s) { ++n; mean += (s - mean) / n; }
void removeSample(int s) { ... }
double getAverage() const { return mean; }
}
One way to do what you're asking is by using template classes.
First, decide on a common interface that an accumulator will have. It might be something like:
class accumulator
{
public:
typedef double value_type;
public:
void push(int v); // Called when pushing a new value.
void pop(int v); // Called when popping a new value;
value_type result(size_t n) const; // Returns the current accumulation.
};
As a special case, mean_accumulator could be this:
class mean_accumulator
{
public:
typedef double value_type;
public:
mean_accumulator() : m_sum{0} {}
void push(int v) { m_sum += v; }
void pop(int v); { m_sum -= v; }
double result(size_t n) const { return m_sum / n; };
private:
int m_sum;
};
Now, parameterize your queue by Accumulator, and call it when necessary (while you're at it, note that boost::circular_buffer has much of what you need for the implementation:
template<class Accumulator>
class queue
{
private:
boost::circular_buffer<int> m_buf;
std::mutex m_m;
public:
void push(int v)
{
// Lock the mutex, push to the circular buffer, and the accumulator
}
bool pop()
{
// Lock the mutex; if relevant, update the accumulator and pop the circular buffer
}
typename Accumulator::value_type result() const
{
// Lock the mutex and return the accumulator's result.
}
};

Segfault Error in Custom Dictionary Class C++

So, as part of my assignment in Computer Science, which was to read tweets and put them into a custom Dictionary, I had to, you guessed it, create a dictionary. However, during testing with the dictionary, I encountered an error which I have been unable to fix, despite hours of attempted troubleshooting. I have narrowed it down, and determined that the error lies on line 144, somewhere in the statement cout<<j.get("name").getFront()->getText();, but I have been unable to determine which part of this causes issues, even when breaking it down by parts, except that it begins when I add in the ->getText(), however I heavily suspect that the problem starts earlier on.
I am sorry if I am not too specific, or if I ramble too much, I have just been having trouble with this for a while, and am beginning to get frustrated.
I understand not all the execution or style is the best, so I may ask you to refrain from leaving comments on the way things are done, unless it may directly relate to the problem at hand.
Thank you for any and all help.
/*********************************************************************************************************************
* [REDACTED] *
* CS 101-- Project 4 (Hashing Twitter) *
* This program stores Twitter posts in a hash table * *
*********************************************************************************************************************/
#include <iostream>
#include <stdlib.h>
#include <vector>
using namespace std;
class tweet {
private:
string create_at;
string text;
string screen_name;
public:
string getCreate_at() {
return create_at;
};
string getText() {
return text;
};
string getScreen_name() {
return screen_name;
};
void setCreate_at(string c) {
create_at=c;
};
void setText(string c) {
text=c;
};
void setScreen_name(string c) {
screen_name=c;
};
};
class LinkedList {
public:
tweet* getFront() {
return top;
};
LinkedList* getNext() {
return next;
};
void setNext(LinkedList* c) {
next = c;
};
void setTweet(tweet c) {
top = &c;
};
void setTweet(tweet* c) {
top = c;
};
void insertFront(tweet c) {
LinkedList temp;
temp.setTweet(top);
temp.setNext(next);
this->setTweet(c);
this->setNext(&temp);
};
tweet* removeFront() {
tweet* temp;
temp = top;
if(next != NULL){
top = next->getFront();
if(next->getNext() != NULL)
next = next->getNext();
}
return temp;
};
private:
tweet* top;
LinkedList* next;
};
class HashTable {
private:
vector<LinkedList> store [256];//access by firstcharacter of name as index of array then search through vector linearly until find key
LinkedList getLinkedList(string c) {
vector<LinkedList> temp=store[(int)c.c_str()[0]];
for(int i =0;i<temp.size();i++) {
if(temp.at(i).getFront()->getScreen_name()==c) {
return temp.at(i); //gets list of tweets
}
};
};
bool keyExists(string c) {
vector<LinkedList> temp = store[(int)c.c_str()[0]];
for(int i =0;i<temp.size();i++) {
if(temp.at(i).getFront()->getScreen_name()==c) {
return true; //gets list of tweets
}
};
return false;
};
void insertTweet(tweet c){
if(keyExists(c.getScreen_name())){
getLinkedList(c.getScreen_name()).insertFront(c);
} else {
LinkedList temp;
temp.setTweet(c);
store[c.getScreen_name().c_str()[0]].push_back(temp);
}
};
public:
void put(tweet c) {
insertTweet(c);
};
LinkedList get(string key) {
return getLinkedList(key);
};
bool contains(string key) {
return keyExists(key);
};
void remove(string key) {
vector<LinkedList> temp=store[key.c_str()[0]];
for(int i =0;i<temp.size();i++) {
if(temp.at(i).getFront()->getScreen_name()==key) {
temp.erase(temp.begin()+i); //gets list of tweets
}
};
};
};
HashTable parser(string filename) {
//backslashes
};
int main(int argc, char *argv[])
{
tweet hello;
hello.setText("hello");
hello.setScreen_name("user");
hello.setCreate_at("10211997");
tweet heyo;
heyo.setText("heyo");
heyo.setScreen_name("name");
heyo.setCreate_at("79912101");
LinkedList jerome;
jerome.insertFront(hello);
cout<<jerome.getFront()->getText()<<endl;
jerome.insertFront(heyo);
cout<<jerome.removeFront()->getText()<<endl;
HashTable j;
j.put(heyo);
cout<<j.get("name").getFront()->getText();
}
You are getting the addresses of temporaries:
void insertFront(tweet c) {
LinkedList temp;
temp.setTweet(top);
temp.setNext(next);
this->setTweet(c); //should be &c, but c is a temporary!
this->setNext(&temp); //temp is a temporary!
};
Also, in HashTable, you need put and insertTweet to have a tweet& parameter.
Finally, still in insertTweet, you should pass the address of c to setTweet.
Note that this code is very fragile, as you will have dangling pointers as soon as the tweet objects go out of scope.

How to get the min value of an object in a list (C++)

I've a question to ask.
So, I have a structure call Node as shown below:
struct Node
{
int xKoor, yKoor;
Node *parent;
char nodeId;
float G;
float H;
float F;
Node(int x, int y, int id, Node * par)
{
xKoor = x;
yKoor = y;
nodeId = id;
parent = 0;
}
Node(int x, int y, char id)
{
xKoor = x;
yKoor = y;
nodeId = id;
}
};
And I have list that contains elements of this structure:
list<Node*> OPEN;
This list's size varies in time.
What I need to do is to find the Node object which has the minimum F value, then pop out that object from the list.
So, I tried to write a function as shown below:
void enKucukFliNodeBul(list<Node*> OPEN)
{
list<Node*>::iterator it = OPEN.begin();
for(it = OPEN.begin(); it != OPEN.end(); it++)
{
if(it._Ptr->_Myval->F < it._Ptr->_Next->_Myval->F)
{
}
}
}
But I'm stuck. I'm new to STL. How can I solve this?
My best regards...
You can use std::min_element with a suitable comparison function for this.
bool nodeComp(const Node* lhs, const Node* rhs) {
return lhs->F < rhs->F;
}
#include <algorithm> // for std::min_element
list<Node*>::iterator it = std::min_element(OPEN.begin(), OPEN.end(), nodeComp);
This assumes that list<Node*> is std::list<Node*>, in which case you should be aware that std::list itself is a linked list.
Other useful operations, based on your comments:
Remove a minimum value node from the list and delete it:
OPEN.erase(it);
delete *it; //
You may need to perform other operations, if your nodes depend on each other.
Sort the list:
OPEN.sort(nodeComp);
use std::min_element algirithm and overload Compare function
bool compareF(Node *lhs, Node *rhs)
{
return lhs->F < rhs->F;
}
if you are using C++03:
std::<Node*>::itertor ter = std::min_element(OPEN.begin(),OPEN.end(), compareF);
if you are using C++11:
auto iter = std::min_element(OPEN.begin(),OPEN.end(), compareF);
To sort the list, you can call OPEN.sort(compareF); to sort your list with compareF function
Try adding this:
bool compare_node_F(Node* n1, Node* n2)
{
return n1-> F< n2-> F;
}
#include <list>
#include <algorithm>
#include <cstdlib>
#include <iostream>
int main()
{
std::list<Node*> nodes;
for(int i= 100; i--;)
{
Node* n= new Node(42, 42, 42);
n-> F= i;
nodes.push_back(n);
}
std::list<Node*>::iterator min_element_iter= std::min_element(nodes.begin(), nodes.end(), compare_node_F);
std::cout<< "Min F: "<< (*min_element_iter)-> F<< '\n';
for(std::list<Node*>::iterator d= nodes.begin(); d!= nodes.end(); ++ d)
delete *d;
}

how to convert this code from Dijkstra to Astar?

So I have a project of which I want to switch to Astar due to speed reasons.
But C++ is not my strongest point. Could anyone help me (or tell me how to do the..) converting the algorythm from Dijkstra to Astar?
I found this Astar implementation:
http://code.google.com/p/a-star-algorithm-implementation/
But I don't know how to use it with my existing code.
Here is the graph file which got the algorithm:
#include "Graph.h"
#include <iostream>
#include <algorithm>
#include <stack>
Graph::Graph(void)
{
}
Graph::~Graph(void)
{
while(!mNodes.empty())
{
delete mNodes.back();
mNodes.pop_back();
}
}
void Graph::addNode(int name, bool exists, Node** NodeID )
{
Node* pStart = NULL;
mNodes.push_back(new Node(name,exists));
std::vector<Node*>::iterator itr;
itr = mNodes.begin()+mNodes.size()-1;
pStart = (*itr);
if(exists == true)pStart->DoesExist_yes();
*NodeID = pStart;
}
void Graph::connect_oneway(Node* pFirst, Node* pSecond, int moveCost)
{
if(pFirst != NULL && pSecond != NULL)
{
pFirst->createEdge(pSecond, moveCost);
}
}
#define MAX_NODES (32768)
#define MAX_CONNECTIONS (5)
#include <time.h>
int * Graph::findPath_r(Node* pStart, Node* pEnd)
{
int *arr = new int[MAX_NODES+2];
for (int i=0; i<MAX_NODES; i++)
arr[i] = -1;
arr[0] = 0;
if(pStart == pEnd)
{
return arr;
}
std::vector<Node*> openList;
openList.push_back(pStart);
Node* pCurrNode = NULL;
while(!openList.empty())
{
//Get best node from open list (lowest F value).
//Since we sort the list at the end of the previous loop we know
//the front node is the best
pCurrNode = openList.front();
//Exit if we're are the goal
if(pCurrNode == pEnd)
break;
//Remove the node from the open list and place it in the closed
openList.erase(openList.begin());
pCurrNode->setClosed(true); //We use a flag instead of a list for speed
//Test all of the edge nodes from the current node
std::vector<Edge*>* pEdges = pCurrNode->getEdges();
Node* pEdgeNode = NULL;
for(std::vector<Edge*>::iterator i = pEdges->begin(); i != pEdges->end(); ++i)
{
pEdgeNode = (*i)->pNode;
//If it's closed we've already analysed it
if(!pEdgeNode->getClosed() && pCurrNode->DoesExist() == true)
{
if(!inList(pEdgeNode,&openList))
{
openList.push_back(pEdgeNode);
pEdgeNode->setGCost(pCurrNode->getGCost()+(*i)->moveCost);
pEdgeNode->calcFCost();
pEdgeNode->setParent(pCurrNode);
}
else
{
//If this is a better node (lower G cost)
if(pEdgeNode->getGCost() > pCurrNode->getGCost()+(*i)->moveCost)
{
pEdgeNode->setGCost(pCurrNode->getGCost()+(*i)->moveCost);
pEdgeNode->calcFCost();
pEdgeNode->setParent(pCurrNode);
}
}
}
}
//Place the lowest F cost item in the open list at the top, so we can
//access it easily next iteration
std::sort(openList.begin(), openList.end(), Graph::compareNodes);
}
//Make sure we actually found a path
if(pEnd->getParent() != NULL)
{
//Output the path
//Use a stack because it is LIFO
std::stack<Node*> path;
while(pCurrNode != NULL)
{
path.push(pCurrNode);
pCurrNode = pCurrNode->getParent();
}
int counter = 0;
arr[1] = 0;
while(!path.empty())
{
arr[counter+2] = path.top()->getName();
counter++;
arr[1] += path.top()->getGCost();
path.pop();
}
arr[0] = counter;
return arr;
}
return arr;
}
bool Graph::inList(Node* pNode, std::vector<Node*>* pList)
{
for(std::vector<Node*>::iterator i = pList->begin(); i != pList->end(); ++i)
{
if((*i) == pNode)
{
return true;
}
}
return false;
}
bool Graph::compareNodes(Node* pFirst, Node* pSecond)
{
return pFirst->getFCost() < pSecond->getFCost();
}
void Graph::reset(void)
{
for(std::vector<Node*>::iterator i = mNodes.begin(); i != mNodes.end(); ++i)
{
(*i)->reset();
}
}
The function for finding the path is this one:
Graph::findPath_r
What I really want to do is preserve the edges (because they decide if the road is both or one-way).
Here are the other files:
Graph.h
#ifndef _GRAPH_H_
#define _GRAPH_H
#include "Node.h"
class Graph
{
public:
Graph(void);
~Graph(void);
//void addNode(int name, bool exists);
void addNode(int name, bool exists, Node** NodeID );
void connect_oneway(int ppFirst, int ppSecond, int moveCost);
void connect_oneway(Node* pFirst, Node* pSecond, int moveCost);
//int * findPath_r(int start, int end);
int * findPath_r(Node* pStart, Node* pEnd);
void reset(void);
private:
void findNodesx(int firstName, Node** ppFirstNode);
bool inList(Node* pNode, std::vector<Node*>* pList);
static bool compareNodes(Node* pFirst, Node* pSecond);
std::vector<Node*> mNodes;
};
#endif
Node.h
#ifndef _NODE_H_
#define _NODE_H_
#include <string>
#include <vector>
//Forward declare Node so Edge can see it
class Node;
struct Edge
{
Edge(Node* node, int cost) : pNode(node), moveCost(cost){}
Node* pNode;
int moveCost;
};
class Node
{
public:
Node(void);
Node(int name, bool exists);
~Node(void);
void createEdge(Node* pTarget, int moveCost);
void setGCost(int cost);
void setClosed(bool closed);
void setParent(Node* pParent);
int getGCost(void);
int getFCost(void);
bool getClosed(void);
Node* getParent(void);
int getName(void);
bool DoesExist(void);
bool DoesExist_yes(void);
std::vector<Edge*>* getEdges(void);
void calcFCost(void);
void reset(void);
private:
int mGCost;
int mTotal;
bool mClosed;
Node* mpParent;
int mName;
bool mHeur;
std::vector<Edge*> mEdges;
};
#endif
Node.cpp
#include "Node.h"
Node::Node(void)
{
}
Node::Node(/*const std::string&*/int name, bool exists) : mGCost(0), mTotal(0), mClosed(false), mpParent(NULL), mName(name), mHeur(exists)
{
}
Node::~Node(void)
{
while(!mEdges.empty())
{
delete mEdges.back();
mEdges.pop_back();
}
}
int Node::getName(void)
{
return mName;
}
void Node::createEdge(Node* pTarget, int moveCost)
{
mEdges.push_back(new Edge(pTarget, moveCost));
}
void Node::setClosed(bool closed)
{
mClosed = closed;
}
bool Node::getClosed(void)
{
return mClosed;
}
std::vector<Edge*>* Node::getEdges(void)
{
return &mEdges;
}
int Node::getGCost(void)
{
return mGCost;
}
void Node::setGCost(int cost)
{
mGCost = cost;
}
void Node::calcFCost(void)
{
mTotal = mGCost;
}
void Node::setParent(Node* pParent)
{
mpParent = pParent;
}
int Node::getFCost(void)
{
return mTotal;
}
bool Node::DoesExist(void)
{
return mHeur;
}
bool Node::DoesExist_yes(void)
{
mHeur = true;
return true;
}
Node* Node::getParent(void)
{
return mpParent;
}
void Node::reset(void)
{
mGCost = 0;
mTotal = 0;
mClosed = false;
mpParent = NULL;
}
You mentioned a library on GoogleCode. It is node clear what you want to do with, and I think the best is to write your implementation yourself.
First, you should know that Dijsktra is a special case of A*. In A*, you have an heuristic, named h; A* = possible implementation of Dijsktra when h is the null function.
Then, about your implementation, let's start with Node. It will need the following functions:
constructor, destructor
create/get edge
set/get parent
set/is closed (for speed)
set/get GCost
set/get FCost
set/is obstacle (name way more descriptive than 'DoesExist')
set/get position
reset
// optional method:
get name
Hopefully, this part of your code won't change a lot. The heuristic code will be placed in the pathfinder. The Edge class is left untouched.
Now the big one: Graph. You won't need to delete any of your public methods.
You will need a heuristic method. For the implementation which will be described, you will need an admissible consistent heuristic:
it must not over-estimate the distance to the goal (admissible)
it must be monotone (consistent)
The general case signature is int getHCost(Node* node);. If you always return 0, you will have a Dijsktra algorithm, which is not what you want. Here we will take the euclidiean distance between the node and the goal. Slower to compute than manhattan distance, but better results. You can change this afterwards.
int getHCost(Node* node, Note* goal);
This implies you must place your nodes in the 3d space. Note that the heuristic is a heuristic, ie, an estimation of the distance.
I won't write the code. I will write some pseudo-code adapted to your situation. The original pseudocode is located on the Wikipedia A* page. This pseudo-code is your findPath_r function:
function A*(start,goal)
set all nodes to not closed // The set of nodes already evaluated.
openset = {start} // The set of tentative nodes to be evaluated, initially containing the start node
start.gcost = 0 // Cost from start along best known path.
// Estimated total cost from start to goal through y.
start.fcost = start.gcost + getHCost(start, goal)
while openset is not empty
current = the node in openset having the lowest f_cost (usually the first if you use a sorted list)
if current == goal
return construct_path(goal)
remove current from openset
current.closed = true
for each neighbor in (node connected by edge in current.edges) // Here is the condition for one-way edges
if neighbor.closed or neighbor.obstacle
continue
gcost = current.gcost + dist_between(current,neighbor) // via edge distance
if neighbor not in openset
add neighbor to openset
neighbor.parent = current
neighbor.gcost = gcost
neighbor.fcost = neighbor.gcost + getHCost(neighbor, goal)
else if gcost < neighbor.gcost
neighbor.parent = current
neighbor.gcost = gcost
neighbor.fcost = neighbor.gcost + getHCost(neighbor, goal)
update neighbor position in openset
return failure
function construct_path(current_node)
std::vector<Node*> path
while current_node != 0
path.push_front(current_node)
current_node = current_node.parent
return path
The implementation above use one-way edges.
You were able to write Dijsktra algorithm in C++, so writing this pseudocode in C++ shouldn't be a problem.
Second part, performances. First, measure ;).
I have some hints that can improve performances:
use a memory pool for allocation deallocation
use an intrusive list for the open list (you can also make it auto-sorted with this technique)
I advise you to read A* for beginners, which is a useful reading, even if you don't use tilemap.