I'm creating a function that creates a map from an image with a maze in it.
It takes the image, goes to every pixel and decides if it has to create a node there. One rule is, that when it finds a white pixel at one of the borders it will either be the start or the end node. To tell my pathfinding function where to start, I push the node into a vector(like all other nodes, too) and save the address of that node in a (double)pointer. My problem is, at the end of the loop, the variables in this node change their values(a bool variable might get the value 133) I actually never modify most of the members in this loop. I really have no idea why this is the case...
For examle:
After assigning the node to the pointer:
Completed: false
DistanceTo: 4294967295
PreviousNode: 0x0
XPos: 3
YPos: 0
m_vConnections: <0 Elements>
After function finished:
Completed: 8
DistanceTo: 32674
PreviousNode: SomeAddress
XPos: 3
YPos: 0
m_vConnections: <0 Elements>
The node at SomeAddress actually has completely screwed values, too, but I suspect that the address just changed and it now interprets the data found there as a node.
Sometimes m_vConnections becomes "inaccesseble" which results in sigsegvs when I try to connect something to it.
My function:
bool CreateGraph(const sf::Image &mMaze, std::vector<dijkstra::CNode> *vGraph, dijkstra::CNode **mStart, dijkstra::CNode **mEnd, SMazeCol mColors)
{
*mStart = 0;
unsigned short nExits = 0;
//Get Maze Colours
sf::Color mWallColor = mColors.Wall;
sf::Color mPathColor = mColors.Path;
//Create nodes
for(unsigned int y = 0; y < mMaze.getSize().y; ++y)
{
for(unsigned int x = 0; x < mMaze.getSize().x; ++x)
{
if(mMaze.getPixel(x, y) == mPathColor) //Current pixel is a path
{
bool bTop = false;
bool bBottom = false;
unsigned short nNeighbours = 0;
//Check surroundings of pixel
if(y != 0 && mMaze.getPixel(x, y - 1) == mPathColor)
{
bTop = true;
++nNeighbours;
}
if(y != mMaze.getSize().y - 1 && mMaze.getPixel(x, y + 1) == mPathColor)
{
bBottom = true;
++nNeighbours;
}
if(x != 0 && mMaze.getPixel(x - 1, y) == mPathColor)
{
++nNeighbours;
}
if(x != mMaze.getSize().x - 1 && mMaze.getPixel(x + 1, y) == mPathColor)
{
++nNeighbours;
}
//Decide if a node has to be created at that pixel
if(x == 0 || y == 0 || x == mMaze.getSize().x - 1 || y == mMaze.getSize().y - 1)
{
dijkstra::CNode mNode;
mNode.XPos = x;
mNode.YPos = y;
vGraph->push_back(mNode);
if(*mStart == 0)
{
*mStart = &vGraph->back();
++nExits;
}
else
{
*mEnd = &vGraph->back();
++nExits;
}
}
else if(nNeighbours == 2 && bTop != bBottom)
{
dijkstra::CNode mNode;
mNode.XPos = x;
mNode.YPos = y;
vGraph->push_back(mNode);
}
else if(nNeighbours > 2)
{
dijkstra::CNode mNode;
mNode.XPos = x;
mNode.YPos = y;
vGraph->push_back(mNode);
}
}
}
}
if(nExits != 2)
return false;
The CNode class:
struct SConnection
{
SConnection(CNode *To, unsigned int Distance);
CNode *To;
unsigned int Distance;
};
class CNode
{
public:
CNode();
std::vector<SConnection> Connections()const;
bool AddConnection(CNode *mTo, unsigned int nDistance);
bool AddConnection(const SConnection &mConnection);
bool RemoveConnection(CNode *mTo);
bool operator > (const CNode &rhs)const;
bool operator < (const CNode &rhs)const;
bool operator == (const CNode &rhs)const;
CNode* Addr();
bool Completed;
unsigned int DistanceTo;
CNode *PreviousNode;
unsigned int XPos, YPos;
private:
std::vector<SConnection> m_vConnections;
};
Implementation:
SConnection::SConnection(CNode *To, unsigned int Distance)
{
this->Distance = Distance;
this->To = To;
}
CNode::CNode()
:Completed(false), DistanceTo(std::numeric_limits<unsigned int>::max()), PreviousNode(0)
{
}
std::vector<SConnection> CNode::Connections() const
{
return m_vConnections;
}
bool CNode::AddConnection(CNode *mTo, unsigned int nDistance)
{
if(mTo == 0)
return false;
if(mTo == this)
return false;
for(auto &it : m_vConnections)
{
if(it.To == mTo)
return false;
}
m_vConnections.push_back({mTo, nDistance});
mTo->m_vConnections.push_back({this, nDistance});
return true;
}
bool CNode::AddConnection(const SConnection &mConnection)
{
return (AddConnection(mConnection.To, mConnection.Distance));
}
bool CNode::RemoveConnection(CNode *mTo)
{
for(auto it = m_vConnections.begin(); it != m_vConnections.end(); ++it)
{
if(it->To == mTo)
{
m_vConnections.erase(it);
for(auto it2 = mTo->m_vConnections.begin(); it2 != m_vConnections.end(); ++it2)
{
if(it2->To == this)
mTo->m_vConnections.erase(it2);
}
}
}
return false;
}
bool CNode::operator >(const CNode &rhs)const
{
return DistanceTo > rhs.DistanceTo;
}
bool CNode::operator <(const CNode &rhs) const
{
return DistanceTo < rhs.DistanceTo;
}
bool CNode::operator ==(const CNode &rhs)const
{
return DistanceTo == rhs.DistanceTo;
}
CNode *CNode::Addr()
{
return this;
}
Your main problem is here:
dijkstra::CNode mNode;
//...
vGraph->push_back(mNode);
if(*mStart == 0)
{
*mStart = &vGraph->back();
++nExits;
}
else
{
*mEnd = &vGraph->back();
++nExits;
}
}
else if(nNeighbours == 2 && bTop != bBottom)
{
dijkstra::CNode mNode;
//...
vGraph->push_back(mNode);
}
else if(nNeighbours > 2)
{
dijkstra::CNode mNode;
//...
vGraph->push_back(mNode);
}
Local variables are not placed in global heap, and can be forgotten by programm soon after the code block where they were created is finished.
The better way to improve your code is to rewrite function declaration as
bool CreateGraph(const sf::Image &mMaze, std::vector<dijkstra::CNode*> *vGraph, dijkstra::CNode **mStart, dijkstra::CNode **mEnd, SMazeCol mColors)
And inside function change all:
dijkstra::CNode mNode
vGraph->push_back(mNode);
to
std::shared_ptr<dijkstra::CNode> mNode =
std::shared_ptr<dijkstra::CNode>(new dijkstra::CNode(X, Y));
vGraph->push_back(mNode.get());
Related
i try to sort a vector which element-type is a class like following:
void sort_test() {
class A{
public:
A(float x, float y, float z):score_(x),rerank_score_(y),ranking_score_(z) {};
float score_;
float rerank_score_;
float ranking_score_;
};
using A_ptr = std::shared_ptr<A>;
auto CompareA_ptr = [](A_ptr x, A_ptr y) {
if (x == nullptr && y != nullptr) {
return false;
} else if (x == nullptr && y == nullptr) {
return false;
} else if (x != nullptr && y == nullptr) {
return true;
} else {
if (x->rerank_score_ > y->rerank_score_) {
return true;
} else if (x->rerank_score_ < y->rerank_score_) {
return false;
} else {
if (x->score_ > y->score_) {
return true;
} else if (x->score_ < y->score_) {
return false;
} else {
return x->ranking_score_ >= y->ranking_score_;
}
}
}
};
std::vector<A_ptr> X;
for (int i = 0; i < 7; ++i) {
X.push_back(std::make_shared<A>(A(0.1, 0.1, 0.1)));
}
std::sort(X.begin(), X.end(), CompareA_ptr);
}
int main(){
sort_test();
return 0;
}
I run the code in Xcode and get the Xcode error "Thread 1: EXC_BAD_ACCESS (code=EXC_I386_GPFLT)"in memory.cpp:
I found that the code runs correctly when the vector size is less than 7, and an error is reported when the vector size is greater than 7. It bothers me a lot.
Appreciate for any reply.
Testing your code in Visual Studio revelas that CompareA_ptr doesn't define a strict weak ordering as required for a comparator. This causes undefined behaviour.
The culprit seems to be
return x->ranking_score_ >= y->ranking_score_;
where >= should be changed to >
return x->ranking_score_ > y->ranking_score_;
I've been trying to understand what havn't I initialized in this code and I completely(?) understand what is uninitialized but I don't know how to initialize it.
I am getting the error:
==11931== Conditional jump or move depends on uninitialised value(s)
==11931== at 0x804ABA6: Hashtable<int>::put(int, int) (hash_table.h:169)
==11931== by 0x8048F80: test_put() (hash_table_test.cpp:27)
==11931== by 0x804A551: main (hash_table_test.cpp:52)
==11931== Uninitialised value was created by a heap allocation
==11931== at 0x402ADFC: operator new[](unsigned int) (in /usr/lib/valgrind/vgpreload_memcheck-x86-linux.so)
==11931== by 0x804A9AE: Hashtable<int>::Hashtable() (hash_table.h:64)
==11931== by 0x8048F62: test_put() (hash_table_test.cpp:26)
==11931== by 0x804A551: main (hash_table_test.cpp:52)
from the valgrind so apparantly I havn't been initializing correctly the c'tor for Hashtable class:
Hashtable() :
ht_keys(2), ht_size(0), dynamicArray(NULL) {
dynamicArray = new Node[ht_keys];
for (int i = 0; i < ht_keys; i++) {
dynamicArray[i].delete_val = false;
dynamicArray[i].key=0;
dynamicArray[i].default_node = false;
}
}
the dynamic array is of type Node* which it's private fields are:
bool delete_val;
T element;
int key;
bool default_node;
the class Node is inside the class Hashtable.
how can I initialize dynamicArray?
here's the full code:
#include <string>
#include <iostream>
#include "library2.h"
#include <iterator>
using namespace std;
#ifndef HASH_TABLE_HPP_
#define HASH_TABLE_HPP_
#define DIV 2
//type T must have c'tor, operator !=
template<class T>
class Hashtable {
public:
class Node {
public:
Node(const T t) :
delete_val(false), element(t), key(0), default_node(true) {
}
Node(bool v, const Node& n) :
delete_val(v), element(n.element), key(0), default_node(
n.default_node) {
}
Node(const Node& n) :
delete_val(false), element(n.element), key(n.key), default_node(
n.default_node) {
}
Node() :
delete_val(false), key(0), default_node(true) {
}
bool operator==(const Node* n) {
if (n) {
if (element != n->element || default_node != n->default_node) {
return false;
}
return true;
}
return false;
}
bool operator!=(const Node n) {
if (!(*this == n)) {
return false;
}
return true;
}
bool delete_val;
T element;
int key;
bool default_node;
};
Hashtable() :
ht_keys(2), ht_size(0), dynamicArray(NULL) {
dynamicArray = new Node[ht_keys];
for (int i = 0; i < ht_keys; i++) {
dynamicArray[i].delete_val = false;
dynamicArray[i].key=0;
dynamicArray[i].default_node = false;
}
}
//seriously damaged programming...
Hashtable(Node* array, int HT_keys, int HT_size) :
ht_keys(HT_keys), ht_size(HT_size) {
dynamicArray = new Node[ht_keys];
if (array != NULL) {
for (int i = 0; i < ht_keys; i++) {
dynamicArray[i] = array[i];
}
}
}
Hashtable(const Hashtable& ht) {
if (&ht == this) {
return;
}
ht_keys = ht.ht_keys;
ht_size = ht.ht_size;
dynamicArray = new Node[ht_keys];
for (int i = 0; i < ht.ht_keys; i++) {
this->dynamicArray[i] = ht.dynamicArray[i];
}
}
~Hashtable() {
delete[] this->dynamicArray;
}
Hashtable operator=(const Hashtable& ht) {
Hashtable<T> newHT = ht;
return newHT;
}
//Returns true if some value equal to value exists within the hash table.
bool contains(Node n, int i) {
if (i < 0 || i > ht_keys || !n) {
return false;
}
if (i == ht_keys) {
return false;
}
//make sure that n.delete_val is not set as true.
if (dynamicArray[i]->element == n.element
&& !dynamicArray[i]->delete_val) {
return true;
}
if (dynamicArray[i]->delete_val) {
return contains(n, i + 1);
}
return false;
return true;
}
//Returns true if some key equal to key exists within the hash table.
bool containsKey(int i) {
if (i < 0 || i > ht_keys) {
return false;
}
if (dynamicArray[i]->element && !dynamicArray[i]->delete_val) {
return true;
}
return false;
}
//Returns true if some value equal to value exists within the hash table.
bool containsValue(T e) {
return true;
}
//Returns an enumeration of the values contained in the hash table.
int enumeration() {
return ht_size;
}
//Returns the object that contains the value associated with key.
//If key is not in the hash table, a null object is returned.
Node get(int i) {
if (i >= 0) {
return dynamicArray[i % ht_keys];
}
Node n;
return n;
}
//Returns true if the hash table is empty;
//returns false if it contains at least one key.
bool isEmpty() {
if (ht_size) {
return false;
}
return true;
}
//Returns an enumeration of the keys contained in the hash table.
int keys();
//Inserts a key and a value into the hash table.
//Returns false if key isn't already in the hash table;
//returns true if key is already in the hash table.
bool put(T e, int i) {
if (e && i > 0) {
Node n;
n.default_node = false;
n.delete_val = false;
n.key = i;
n.element = e;
//line 168
for (int j = (i % ht_keys); j < ht_keys; j = ((j + 1) % ht_keys)) { //line 169
if (!dynamicArray[j % ht_keys].element
|| dynamicArray[j % ht_keys].delete_val) {
dynamicArray[j % ht_keys] = n;
ht_size++;
return true;
}else if (i == (j + 1) % ht_keys) {
rehash();
return put(e, i);
}
}
return false;
}
return false;
}
bool put_aux(Node n, int i, Node* Array, int HT_keys) {
for (int j = (i % HT_keys); j < HT_keys; j = ((j + 1) % HT_keys)) {
if (!Array[j % HT_keys].element || Array[j % HT_keys].delete_val) {
Array[j % HT_keys] = n;
return true;
} else if (Array[j % HT_keys].element == n.element) {
return true;
}
}
return false;
}
//Increases the size of the hash table and rehashes all of its keys.
void rehash() {
int old_ht_keys = ht_keys;
ht_keys = DIV * ht_keys;
Node* newArray = new Node[ht_keys];
if (ht_keys > DIV) {
for (int j = 0; j < old_ht_keys; j++) {
put_aux(dynamicArray[j],dynamicArray[j].key,newArray,ht_keys);
}
}
delete[] dynamicArray;
dynamicArray = newArray;
}
//Removes key and its value.
//Returns the value associated with key.
//If key is not in the hash table, a null objecht_sizet is returned.
T remove(int i) {
if (i >= 0 && i < ht_keys) {
Node deleted_node(true, dynamicArray[i % ht_keys]);
dynamicArray[i % ht_keys] = deleted_node;
ht_size--;
return deleted_node.element;
}
return NULL;
}
//Returns the number of entries in the hash table.
int size() {
return this->ht_size;
}
private:
int ht_keys;
int ht_size;
Node* dynamicArray;
};
#endif /* HASH_TABLE_HPP_ */
It seems to be complaining about the line !dynamicArray[j % ht_keys].element (on line 163 of the code you posted; this would be a lot easier if the code you posted matched the code valgrind was using; right now the code you posted is several lines shorter than the code valgrind is using).
You never initialize the element member when you allocate the memory in the constructor. You then attempt to use it here in a conditional statement. valgrind correctly warns you of the problem.
Here's the code :
The place where it crashed is marked with a comment(//////crash).
I don't know what results in the problem.
After I print the size of data got from file,It shows '1' means that the array should only contains 1 element. So it seems that there's no 'bad_allocate error' ...
Could you guys help me ? I would appreciate your kindly help very much. :)
#include<stdio.h>
#include<iostream>
#include<string>
#include<map>
#include<vector>
#include<algorithm>
#include<string.h>
#include<type_traits>
using namespace std;
bool read_int(int& val,FILE*& fp)
{
if(fp == nullptr)
return false;
fread(&val,sizeof(int),1,fp);
return true;
}
bool write_int(int val,FILE*& fp)
{
if(fp == nullptr)
{
return false;
}
fwrite(&val,sizeof(int),1,fp);
return true;
}
struct SANOBJ
{
char path[128];
char nickname[40];
SANOBJ(const char* _p = nullptr,const char* _n = nullptr)
{
if(_p == nullptr || _n == nullptr)
*this = {};
int m = strlen(_p),n = strlen(_n);
if(m < 128) strcpy(path,_p);
if(n < 40) strcpy(nickname,_n);
}
~SANOBJ(){}
SANOBJ(const SANOBJ& other)
{
memcpy(path,other.path,sizeof(char) * 128);
memcpy(nickname,other.nickname,sizeof(char) * 40);
}
bool operator < (const SANOBJ& other) const
{
return string(path) < string(other.path);
}
bool operator == (const SANOBJ& other) const
{
return (strcmp(other.path,path) == 0);
}
};
template <typename source_type> //the 'source_type' type need to have the member 'int m_index'
class FrameQueue
{
public:
FrameQueue() //fill the 1st frame automatically
{
source_type new_node;
new_node.m_index = 0;
m_data.push_back(new_node);
}
FrameQueue(const FrameQueue& other)
{
m_data = other.m_data;
}
bool AddFrame(const source_type& other) // keeps an ascending order
{
int index = _binary_search(other);
if(index != -1)
{
return false;
}
m_data.insert(std::upper_bound(m_data.begin(),m_data.end(),other,
[](const source_type& a,const source_type& b)->bool const{return a.m_index < b.m_index;}
),other);
return true;
}
bool DeleteFrameByElemIndex(int elemIndex) //delete frame according to the index of frame in the queue
{
if(elemIndex < 0)
return false;
if(elemIndex >= m_data.size())
return false;
typename std::vector<source_type>::iterator it ;
it = m_data.begin() + elemIndex;
it = m_data.erase(it);
return true;
}
bool DeleteFrameByFrameIndex(int frameIndex)
{
source_type node = {};
node.m_index = frameIndex;
int index = _binary_search(node);
if(index == -1)
{
return false;
}
typename std::vector<source_type>::iterator it;
it = m_data.begin() + index;
it = m_data.erase(it);
return true;
}
bool Clear() // There would always be a single frame
{
source_type new_node = {};
new_node.m_index = 0;
m_data.clear();
m_data.push_back(new_node);
return true;
}
bool WriteFile(FILE*& fp)
{
if(fp == nullptr)
return false;
bool result = write_int(m_data.size(),fp);
if(result == false)
return false;
fwrite(&(m_data[0]),sizeof(source_type),m_data.size(),fp);
return true;
}
bool ReadFile(FILE*& fp)
{
if(fp == nullptr)
return false;
int data_size;
bool result = read_int(data_size,fp);
if(result == false)
return false;
if(data_size > 0)
{
m_data.resize(data_size);
fread(&(m_data[0]),sizeof(source_type),data_size,fp);
}
return true;
}
private:
int _binary_search(source_type target)
{
int l = 0,r = (int)m_data.size() - 1,mid;
while(l<=r)
{
mid = (l + r) / 2;
if(m_data[l].m_index == target.m_index)
{
return l;
}
if(m_data[r].m_index == target.m_index)
{
return r;
}
if(m_data[mid].m_index == target.m_index)
{
return mid;
}
if(m_data[mid].m_index > target.m_index)
{
r = mid - 1;
}
else
{
l = mid + 1;
}
}
return -1;
}
public:
vector<source_type> m_data;
};
template<typename source_type>
class UniqueSource
{
public:
UniqueSource(){}
~UniqueSource(){}
bool Add(const source_type& other)//return false when insert failed,otherwise return true
{
if(m_map_source_to_index.find(other) == m_map_source_to_index.end())
{
int map_size = m_map_source_to_index.size();
m_data.push_back(other);
m_map_source_to_index.insert(pair<source_type,int>(other,map_size));
m_result.push_back(map_size);
return true;
}
else
{
m_result.push_back(m_map_source_to_index[other]);
return true;
}
return false;
}
bool Delete(int elemIndex) // delete the elem by elem Index,If succeed ,return true,otherwise return false
{
if(elemIndex < 0)
return false;
if(elemIndex >= m_data.size())
return false;
typename std::map<source_type,int>::iterator mit;
typename std::vector<source_type>::iterator vit;
for(mit = m_map_source_to_index.begin();mit!=m_map_source_to_index.end();++mit)
{
m_map_source_to_index.erase(mit);
}
vit = m_data.begin() + elemIndex;
m_data.erase(vit);
return true;
}
bool Clear()
{
m_map_source_to_index.clear();
m_data.clear();
m_result.clear();
return true;
}
bool WriteFile(FILE*& fp)
{
if(fp == nullptr)
return false;
bool result = write_int(m_data.size(),fp);
if(result == false)
return false;
if(m_data.size() > 0)
fwrite(&(m_data[0]),sizeof(source_type),m_data.size(),fp);
result = write_int(m_result.size(),fp);
if(result == false)
return false;
if(m_result.size() > 0)
fwrite(&(m_result[0]),sizeof(int),m_result.size(),fp);
return true;
}
bool ReadFile(FILE*& fp)
{
if(fp == nullptr)
return false;
Clear();
int data_size;
read_int(data_size,fp);
if(data_size > 0)
{
printf("[%d]",data_size);
m_data.resize(data_size); /////////////////Crash!!!!!!!!!!!!
printf("Resize Ok\r\n");
fread(&(m_data[0]),sizeof(source_type),data_size,fp);
}
read_int(data_size,fp);
printf("[%d]",data_size);
if(data_size > 0)
{
m_result.resize(data_size);
fread(&(m_result[0]),sizeof(int),data_size,fp);
}
return true;
}
//private:
map<source_type,int> m_map_source_to_index;
vector<source_type> m_data;
vector<int> m_result; //the index I want
};
int main()
{
UniqueSource<SANOBJ> m;
SANOBJ t = {"123","456"};
m.Add(t);
printf("Added\r\n");
FILE* fp = nullptr;
fp = fopen("test.b","wb");
if(fp == nullptr)
{
printf("Failed...\r\n");
}
bool ret = false;
ret = m.WriteFile(fp);
if(ret)
{
printf("Writed!\r\n");
fclose(fp);
}
fp = fopen("test.b","rb");
if(fp == nullptr)
{
printf("Failed...\r\n");
}
ret = m.ReadFile(fp);
fclose(fp);
printf("Readed\r\n");
for(int i=0;i<m.m_data.size();i++)
printf("%s %s\r\n",m.m_data[i].path,m.m_data[i].nickname);
return 0;
}
*this = {} default-constructs a new SANOBJ instance and then assigns it to *this. This would normally be OK, but here you are calling it from the SANOBJ default constructor (making the logic being something like "to default-construct a SANOBJ, default-construct a SANOBJ and then assign its value to myself"), leading to infinite recursion and eventually a stack overflow.
Sidenote: The copy constructor is not needed.
Yes. The problem is is with *this = {}
If I were you, I'd rewrite SANOBJ constructor like this (this is a rough code and you may need to slightly modify it if you wish)
SANOBJ(const char* _p = nullptr,const char* _n = nullptr)
{
if (( _p != nullptr ) && ((strlen(_p) < 128)))
strcpy(path,_p);
if (( _n != nullptr ) && ((strlen(_n) < 40)))
strcpy(nickname,_n);
}
It'll resolve the problem.
Naturally, I don't play with *this (not this).
If you want to be sure that the member variables are empty (char path[128] and char nickname[40])
set at the beginning of the constructor something like:
path[0] = '\0';
nickname[0] = '\0';
Or use something like on constructor:
SANOBJ(const char* _p = nullptr,const char* _n = nullptr)
: path(), nickname()
{
}
But don't use *this= {}
I have sevral questions about maze - solver algorithms:C
What is the time complexity of recursive (backtracking) maze-solver?(As an amount of paths in the matrix? - I can`t figure this number..)
What is the time complexity of BFS based maze-solver?(O(n^2)?) n is a dimension of the squared maze matrix?
What is the best algoritm to count the number of all possible paths from the source to the destination in the maze?
Can you propose the idea if and how an it be implemented using parallel computing (opecl/cuda)
Here is the class for my maze solver ,which has brute (recursive) and bfs based version.I implemented it and the questions are based on this maze-solver implementation
//MazeSolver.h
//#define N 5
typedef enum {BLACK,WHITE,GRAY,VISITED} color;
class MazeSolver
{
public:
MazeSolver(){}
struct Cell
{
unsigned int _x;
unsigned int _y;
Cell* _p;
Cell(unsigned int x = 0,unsigned int y = 0, Cell* p = NULL) : _x(x),_y(y),_p(p) {}
bool operator == (const Cell& c)
{
return _x == c._x && _y == c._y;
}
};
bool solveMazeBrute(color maze[][N],unsigned int n,int xS,int yS,int xD,int yD,std::list<Cell>& path);
bool solveMazeBFS(color maze[][N],unsigned int n,int xS,int yS,int xD,int yD,std::list<Cell>& path);
private:
std::queue<Cell* > _bfs;
std::vector<Cell* > _cells;
Cell* addCellBFS(color maze[][N],unsigned int n,int x,int y,Cell* p = NULL);
};
//MazeSolver.cpp
MazeSolver::Cell* MazeSolver::addCellBFS(color maze[][N],unsigned int n,int x,int y,Cell* p)
{
if (x >= 0 && x < n && y >= 0 && y < n && maze[x][y] == WHITE)
{
Cell* c = new Cell(x,y,p);
maze [x][y] = VISITED;
_bfs.push(c);
_cells.push_back(c);
return c;
}
return NULL;
}
bool MazeSolver::solveMazeBrute(color maze[][N],unsigned int n,int xS,int yS,int xD,int yD,std::list<MazeSolver::Cell>& path)
{
bool solved = false;
if (xS < 0 || xS >= n || yS < 0 || yS >= n || maze[xS][yS] == VISITED || maze[xS][yS] == BLACK)
{
return false;
}
Cell s(xS,yS);
Cell d(xD,yD);
if (s == d)
{
path.push_front(s);
return true;
}
maze[xS][yS] = VISITED;
if (solveMazeBrute(maze,n,xS + 1,yS,xD,yD,path) ||
solveMazeBrute(maze,n,xS - 1,yS,xD,yD,path) ||
solveMazeBrute(maze,n,xS,yS + 1,xD,yD,path) ||
solveMazeBrute(maze,n,xS,yS - 1,xD,yD,path))
{
path.push_front(s);
solved = true;
}
maze[xS][yS] = WHITE;
return solved;
}
bool MazeSolver::solveMazeBFS(color maze[][N],unsigned int n,int xS,int yS,int xD,int yD,std::list<Cell>& path)
{
Cell d(xD,yD);
addCellBFS(maze,n,xS,yS);
while(!_bfs.empty())
{
Cell* cur = _bfs.front();
if (*cur == d)
{
while (cur != NULL)
{
path.push_front(*cur);
cur = cur->_p;
}
return true;
}
_bfs.pop();
addCellBFS(maze,n,cur->_x - 1,cur->_y,cur);
addCellBFS(maze,n,cur->_x + 1,cur->_y,cur);
addCellBFS(maze,n,cur->_x,cur->_y - 1,cur);
addCellBFS(maze,n,cur->_x,cur->_y + 1,cur);
}
for(std::vector<Cell*>::iterator itC= _cells.begin();itC != _cells.end();++itC)
{
maze[(*itC)->_x][(*itC)->_y] = WHITE;
delete *itC;
}
return false;
}
Maybe we can find the target in O(n).
Let's imagine 5X5 matrix.
In each iteration we'll step single step ahead, we'll check the cell is valid and is not the end of maze, and mark it as "visited".
So, we'll start at the first cell (0,0). in next iteration we'll check the next layer, mean (0,1),(1,0), in next iteration we'll continue check the next layer (0,2),(1,1),(2,0). and so on.
So, we'll check each cell once only! and we'll find the end (the target) in n complexity.
Am i wrong?
I realized I can't post answers to my own questions because of my low rep or whatever so i deleted my old question and am reasking it. i changed some things and still can't get what i'm looking for.
Here is most of the code
I left out some of the simpler implementations such as parts of the pathFinder class because I know for sure they work, which is why you'll see playerVertex and time just randomly there.
In the example they used a decreaseKey function, I'm not sure if THAT'S what I'm missing? I'm a beginner here, so constructive criticism is welcome. (hopefully as polite as possible) lol. My problem is printing the path, I get a looop of the same two values over and over again.
class Heap
{
public: Heap();
~Heap();
void insert(double element);
double deletemin();
void print();
int size(){return heap.size();}
private:
int currentIndex;
int left(int parent);
int right(int parent);
int parent(int child);
void heapifyup(int index);
void heapifydown(int index);
private:
vector<double> heap;
};
Heap::Heap()
{
currentIndex = 0;
}
Heap::~Heap()
{}
void Heap::insert(double element)
{
heap.push_back(element);
currentIndex++;
heapifyup(heap.size() - 1);
}
double Heap::deletemin()
{
double min = heap.front();
heap[0] = heap.at(heap.size()-1);
heap.pop_back();
heapifydown(0);
currentIndex--;
return min;
}
void Heap::print()
{
vector<double>::iterator pos = heap.begin();
cout << "Heap = ";
while ( pos != heap.end() )
{
cout << *pos;
++pos;
cout << endl;
}
}
void Heap::heapifyup(int index)
{
while((index>0) && (parent(index) >=0) && (heap[parent(index)] > heap[index]))
{
double tmp = heap[parent(index)];
heap[parent(index)] = heap[index];
heap[index] = tmp;
index = parent(index);
}
}
void Heap::heapifydown(int index)
{
int child = left(index);
if((child > 0) && (right(index) > 0) && (heap[child]>heap[right(index)]))
{
child = right(index);
}
if(child > 0)
{
double tmp = heap[index];
heap[index] = heap[child];
heap[child] = tmp;
heapifydown(child);
}
}
int Heap::left(int parent)
{
int i = ( parent <<1) + 1;
return(i<heap.size()) ? i : - 1;
}
int Heap::right(int parent)
{
int i = ( parent <<1) + 2;
return(i<heap.size()) ? i : - 1;
}
int Heap::parent(int child)
{
if(child != 0)
{
int i = (child - 1) >>1;
return i;
}
return -1;
}
class pathFinder : public weightedGraph
{
private:
vertex* playerVertex;
double time;
public:
string source;
pathFinder()
{
playerVertex = NULL;
time = 0;
}
void Dijkstra(int s,int t)
{
vertex *verts = findVertex(grid[s][t]);
Heap H;
for each(vertex *v in vertexList)
{
if(v->data == verts->data)
{
verts->distance = 0;
verts->pred = NULL;
}
v->distance = INFINITY;
v->pred = NULL;
H.insert(v->data);
}
while(H.size() != 0)
{
vertex *x = findVertex(H.deletemin());
for each(edge *v in x->adjacencyList)
{
if(v->end->visited != true)
{
relax(x,v->end);
v->end->visited = true;
}
else
break;
}
}
}
void relax(vertex *a, vertex *b)
{
if(a->distance + weightFrom(a,b) > b->distance)
{
b->distance = a->distance + weightFrom(a,b);
b->pred = a;
}
}
void printPath(double dest,double dest1)
{
vertex *verta = findVertex(dest);
while(verta->pred->data != dest1)
{
cout<<verta->data<<endl;
verta = verta->pred;
}
}
and i'm not sure about the print path being that. i just used the print path from the BFS algorithm i've implemented before.
Where in your printPath function are you looking for the end of the list?
You keep going verta = verta->pred until the data is not equal to some value.
By the way, don't compare doubles for equality, as it ain't going to happen. See What Every Computer Scientist Should Know About Floating Point.
What happens when you single step with your debugger?
(Try drawing the links and how you traverse them.)