I have been programming for a little while, but I am relativly new to c++. I am trying to implement the A* algorithm and have managed to produce the code below. The implementation producces the expected result, the shortest path from point A to B in a 2D grid, but I suspect i leave behind some memory leaks.
I tested this by overloading the new and delete operators to keep track of the amount of bytes allocated on the heap and it showed that a lot of memeory never got released. However I also tested the number of nodes that never got deleted but it showed that there were that all allocated nodes also got their destructor called. Note in the code that i only call new on Node, hence my confunsion. I have much confusion about this and would be happy for an explenation.
I have tried using smart pointers, but enden up with circular refrences which were difficult to resolve.
This is also my first post on Stack Overflow so please feel free to point how I can improve my questions. Thanks in advance.
#include<vector>
#include<array>
#include<cmath>
int mynodes = 0;
int memory_left = 0;
void* operator new(size_t size)
{
memory_left += size;
return malloc(size);
}
void operator delete(void* memory, size_t size)
{
memory_left -= size;
free(memory);
}
struct Node{
std::array<int, 2> position;
Node* parent = nullptr;
double h, g, f;
Node(const std::array<int, 2>& pos)
:position(pos){mynodes++;}
~Node(){ mynodes--; }
};
std::vector<std::array<int, 2>> find_children(const std::vector<std::vector<int>>& grid, const std::array<int, 2>& pos){
std::vector<std::array<int, 2>> children;
children.reserve(8);
for(int t = -1; t < 2; t++){
for(int q = -1; q < 2; q++){
if(t != 0 || q != 0){
if(abs(t) == abs(q)) continue;
std::array<int, 2> cur_pos = {pos[0]+q, pos[1]+t};
if(cur_pos[0] >= 0 && cur_pos[0] < grid[0].size() && cur_pos[1] >= 0 && cur_pos[1] < grid.size())
{
if(grid[cur_pos[1]][cur_pos[0]] == 0)
{
children.push_back(cur_pos);
}
}
}
}
}
return children;
}
bool search_vect(const std::vector<Node*>& set, const std::array<int, 2>& pos)
{
for(Node* node : set)
{
if(node->position[0] == pos[0] && node->position[1] == pos[1]) return true;
}
return false;
}
void releaseNodes(std::vector<Node*>& set)
{
for(auto& node : set)
{
delete node;
}
set.clear();
}
std::vector<std::array<int, 2>> find_path(const std::vector<std::vector<int>>& grid, std::array<int, 2> start, std::array<int, 2> end){
Node* cur_node = new Node(start);
std::vector<Node*> open_vect;
std::vector<Node*> closed_vect;
open_vect.push_back(cur_node);
while(cur_node->position != end){
double lowest_f = INFINITY;
size_t idx = 0;
for(size_t i = 0; i < open_vect.size(); i++)
{
if(open_vect[i]->f < lowest_f)
{
cur_node = open_vect[i];
lowest_f = cur_node->f;
idx = i;
}
}
open_vect.erase(open_vect.begin() + idx);
std::vector<std::array<int, 2>> children = find_children(grid, cur_node->position);
closed_vect.push_back(cur_node);
for(const auto& child_pos : children){
// if(closed_vect.find(child_pos) != closed_vect.end() || open_vect.find(child_pos) != open_vect.end()) continue;
if(search_vect(closed_vect, child_pos) || search_vect(open_vect, child_pos))
{
continue;
}
Node* new_node = new Node(child_pos);
new_node->g = cur_node->g + 1;
new_node->h = abs(end[0] - child_pos[0]) + abs(end[1] - child_pos[1]);
new_node->f = new_node->g + new_node->h;
new_node->parent = cur_node;
// double h = sqrt(pow(end[0] - child_pos[0], 2) + pow(end[1] - child_pos[1], 2));
open_vect.push_back(new_node);
}
}
std::vector<std::array<int, 2>> path;
while(cur_node != nullptr){
path.push_back(cur_node->position);
cur_node = cur_node->parent;
}
releaseNodes(open_vect);
releaseNodes(closed_vect);
return path;
}
int main()
{
std::vector<std::vector<int>> grid( 100 , std::vector<int> (100, 0));
{
auto path = find_path(grid, {1, 1}, {98, 98});
}
}
Here the minimal/easy way of getting rid of any explicit new/delete:
#include<vector>
#include<array>
#include<cmath>
struct Node{
std::array<int, 2> position;
Node* parent = nullptr;
double h{0.};
double g{0.};
double f{0.};
Node(const std::array<int, 2>& pos)
: position(pos) {}
};
std::vector<std::array<int, 2>> find_children(const std::vector<std::vector<int>>& grid, const std::array<int, 2>& pos){
std::vector<std::array<int, 2>> children;
children.reserve(8);
for(int t = -1; t < 2; t++){
for(int q = -1; q < 2; q++){
if(t != 0 || q != 0){
if(abs(t) == abs(q)) continue;
std::array<int, 2> cur_pos = {pos[0]+q, pos[1]+t};
if(cur_pos[0] >= 0 && cur_pos[0] < grid[0].size() && cur_pos[1] >= 0 && cur_pos[1] < grid.size())
{
if(grid[cur_pos[1]][cur_pos[0]] == 0)
{
children.push_back(cur_pos);
}
}
}
}
}
return children;
}
bool search_vect(const std::vector<Node*>& set, const std::array<int, 2>& pos)
{
for(Node* node : set)
{
if(node->position[0] == pos[0] && node->position[1] == pos[1]) return true;
}
return false;
}
std::vector<std::array<int, 2>> find_path(const std::vector<std::vector<int>>& grid, std::array<int, 2> start, std::array<int, 2> end){
std::vector<Node> nodes{};
nodes.emplace_back(start);
Node* cur_node = &nodes.back();
std::vector<Node*> open_vect;
std::vector<Node*> closed_vect;
open_vect.push_back(cur_node);
while(cur_node->position != end){
double lowest_f = INFINITY;
size_t idx = 0;
for(size_t i = 0; i < open_vect.size(); i++)
{
if(open_vect[i]->f < lowest_f)
{
cur_node = open_vect[i];
lowest_f = cur_node->f;
idx = i;
}
}
open_vect.erase(open_vect.begin() + idx);
std::vector<std::array<int, 2>> children = find_children(grid, cur_node->position);
closed_vect.push_back(cur_node);
for(const auto& child_pos : children){
// if(closed_vect.find(child_pos) != closed_vect.end() || open_vect.find(child_pos) != open_vect.end()) continue;
if(search_vect(closed_vect, child_pos) || search_vect(open_vect, child_pos))
{
continue;
}
nodes.emplace_back(child_pos);
Node* new_node = &nodes.back();
new_node->g = cur_node->g + 1;
new_node->h = abs(end[0] - child_pos[0]) + abs(end[1] - child_pos[1]);
new_node->f = new_node->g + new_node->h;
new_node->parent = cur_node;
// double h = sqrt(pow(end[0] - child_pos[0], 2) + pow(end[1] - child_pos[1], 2));
open_vect.push_back(new_node);
}
}
std::vector<std::array<int, 2>> path;
while(cur_node != nullptr){
path.push_back(cur_node->position);
cur_node = cur_node->parent;
}
return path;
}
int main()
{
std::vector<std::vector<int>> grid( 100 , std::vector<int> (100, 0));
{
auto path = find_path(grid, {1, 1}, {98, 98});
}
}
This is not perfect, but it easily demonstrates how easy it is to not cause any potential memory leaks. Instead of replacing the vectors of pointers with vectors of nodes, I just added an additional vector of nodes (the owner). Now the pointers are non-owning and nothing weird should happen anymore.
Related
Feel free to point out my mistakes, I do not claim to be a good C++ programmer or even good w/ Data structures. I'm just looking to improve and learn upon my example.
This approach is not my own but the code is. I learned a concept and attempted to code it in C++.
The point here is to learn to build this without using libraries such as std::priority_queue. Thanks again!
#include <iostream>
#include <memory>
#include <vector>
#include <unordered_map>
#include <algorithm>
// directions of each node
enum
{
IS_LEFT = 1,
IS_RIGHT = 2
};
// (ADT) Priority Queue which uses a (DS) heap
using std::vector;
// Makes removal of any node anywhere within the heap O(log(n))
using std::unordered_map;
class BinaryStack
{
private:
// tracks the last node in heap
size_t last_index { 0 };
// the heap
vector<int> heap{ };
// the hashmap to track where any given node is at (required for node removal within a heap)
unordered_map<int, vector<size_t>> hashmap{ };
// swap any two values from two given vectors
void swapVectorValue(vector<size_t> &vec1, size_t val1, vector<size_t> &vec2, size_t val2)
{
vec1.erase(std::remove(vec1.begin(), vec1.end(), val1), vec1.end());
vec2.erase(std::remove(vec2.begin(), vec2.end(), val2), vec2.end());
vec1.push_back(val2);
vec2.push_back(val1);
}
// adds a value to hashmap | the keys are the node values & the values are their respective indexes
void addToHashMap(int val, size_t last_index)
{
auto search = hashmap.find(val);
if (search != hashmap.end())
hashmap[val].push_back(last_index);
else
hashmap[val] = vector<size_t> { last_index };
}
public:
// insert a node into the heap
void insert(int val)
{
heap.push_back(val);
// point last node to end of array
size_t last_index = heap.size()-1;
addToHashMap(val, last_index);
// only one node so lets just stop here
if (heap.size() == 1) return;
// determines if node is on left or right
short node_direction = (heap.size() % 2 == 0) ? IS_LEFT : IS_RIGHT;
size_t parent_index = (last_index - node_direction) / 2;
// keep going until bubbles to top
while (heap[parent_index] > heap[last_index])
{
//swaps indexes of swapped nodes
swapVectorValue(hashmap[heap[parent_index]], parent_index, hashmap[heap[last_index]], last_index);
// update value of parent and new node
int temp { heap[parent_index] };
heap[parent_index] = heap[last_index];
heap[last_index] = temp;
// leave if at top
if (parent_index == 0) break;
// find new parent
last_index = parent_index;
node_direction = (last_index % 2 == 0) ? IS_RIGHT : IS_LEFT;
parent_index = (last_index - node_direction) / 2;
}
}
// remove any node
void remove(int val)
{
size_t parent_index{ };
auto search = hashmap.find(val);
if (search != hashmap.end())
{
parent_index = hashmap[val].back();
hashmap[val].pop_back();
if (hashmap[val].size() == 0) hashmap.erase(val);
} else return;
last_index = heap.size()-1;
heap[parent_index] = heap[last_index];
heap.pop_back();
size_t left_child = (parent_index * 2) + 1;
size_t right_child = (parent_index * 2) + 2;
size_t smallest_child{ };
if (left_child > last_index) return;
if (left_child == last_index && heap[left_child] > heap[parent_index]) return;
if (right_child > last_index)
smallest_child = left_child;
else
smallest_child = (heap[left_child] < heap[right_child]) ? left_child : right_child;
while (heap[parent_index] > heap[smallest_child])
{
swapVectorValue(hashmap[heap[parent_index]], parent_index, hashmap[heap[smallest_child]], smallest_child);
// update value of parent and new node
int temp { heap[parent_index] };
heap[parent_index] = heap[smallest_child];
heap[smallest_child] = temp;
parent_index = smallest_child;
left_child = (parent_index * 2) + 1;
right_child = (parent_index * 2) + 2;
if (left_child > last_index) return;
if (left_child == last_index && heap[left_child] > heap[parent_index]) return;
if (right_child > last_index)
smallest_child = left_child;
else
smallest_child = (heap[left_child] < heap[right_child]) ? left_child : right_child;
}
}
// removes only the top node
int poll(int val)
{
// NOT PROGRAMMED YET
return 1;
}
void display()
{
// get parent node
for (const auto &n: heap)
{
std::cout << n << ' ';
}
std::cout << std::endl;
}
void hashmapDisplay()
{
for (const auto& r: hashmap)
{
std::cout << "value: " << r.first << " at indexes: ";
for (const auto& s: r.second)
{
std::cout << s << ' ';
}
std::cout << std::endl;
}
}
};
int main()
{
std::unique_ptr<BinaryStack> bstack(new BinaryStack());
bstack->insert(95);
bstack->insert(9);
bstack->insert(9);
bstack->insert(12);
bstack->insert(14);
bstack->insert(9);
bstack->insert(93);
bstack->remove(93);
bstack->remove(9);
// proves order of heap
bstack->display();
// just to prove the indexes are being tracked correctly
bstack->hashmapDisplay();
return 0;
}
Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 2 years ago.
Improve this question
I am running into a few errors, a memory error with the back function and failing to pass many of the tests that the program checks for.
I need to get this code working, which is in Vector.cpp:
#include <stdexcept>
#include "Vector.h"
using namespace std;
void Vector::grow()
{
const int GROWER = 1.6;
capacity = capacity * GROWER;
}
Vector::Vector()
{
capacity = CHUNK;
n_elems = 0;
data_ptr = new int[capacity];
for (size_t i = 0; i < capacity; i++)
{
data_ptr[i] = 0;
}
}
Vector::Vector(const Vector& v)
{
n_elems = 0;
capacity = v.capacity;
data_ptr = new int[capacity];
for (size_t i = 0; i < capacity; i++)
{
data_ptr[i] = v.data_ptr[i];
n_elems++;
}
}
Vector& Vector::operator=(const Vector& v)
{
capacity = v.capacity;
data_ptr = new int[capacity];
for (size_t i = 0; i < capacity; i++)
{
data_ptr[i] = v.data_ptr[i];
}
return *this;
}
Vector::~Vector()
{
delete[] data_ptr;
}
int Vector::front() const
{
if (n_elems != 0)
{
return data_ptr[0];
}
else
{
return -1;
throw range_error("Range Error");
}
}
int Vector::back() const
{
if (n_elems != 0)
{
return data_ptr[n_elems - 1];
}
else
{
throw range_error("Range Error");
}
}
int Vector::at(size_t pos) const
{
if (pos >= 0 && pos < capacity)
{
return data_ptr[pos];
}
else
{
throw range_error("Range Error");
}
}
size_t Vector::size() const
{
return n_elems;
}
bool Vector::empty() const
{
if (n_elems == 0)
{
return true;
}
else
{
return false;
}
}
int& Vector::operator[](size_t pos)
{
return data_ptr[pos];
}
void Vector::push_back(int item)
{
grow();
data_ptr[n_elems - 1] = item;
}
void Vector::pop_back()
{
if (n_elems >= 0)
{
--n_elems;
}
else
{
throw range_error("Range Error");
}
}
void Vector::erase(size_t pos)
{
if (pos >= 0 && pos < capacity)
{
for (size_t i = pos; i < capacity; i++)
{
data_ptr[i] = data_ptr[i + 1];
}
n_elems--;
}
else
{
throw range_error("Range Error");
}
}
void Vector::insert(size_t pos, int item)
{
int moveCount = n_elems - pos;
grow();
if (pos >= 0 && pos < capacity)
{
for (size_t i = n_elems; i >= 0; i--)
{
data_ptr[i] = data_ptr[i - 1];
}
data_ptr[pos] = item;
n_elems++;
}
else
{
throw range_error("Range Error");
}
}
void Vector::clear()
{
n_elems = 0;
}
int* Vector::begin()
{
if (n_elems == 0)
{
return nullptr;
}
else
{
return data_ptr;
}
}
int* Vector::end()
{
if (n_elems == 0)
{
return nullptr;
}
else
{
return (data_ptr + (n_elems - 1));
}
}
bool Vector::operator==(const Vector& v) const
{
bool flag = true;
for (size_t i = 0; i < capacity; i++)
{
if (data_ptr[i] == v.data_ptr[i])
{
flag = true;
}
else
{
flag = false;
break;
}
}
return flag;
}
bool Vector::operator!=(const Vector& v) const
{
bool flag = true;
for (size_t i = 0; i < capacity; i++)
{
if (data_ptr[i] != v.data_ptr[i])
{
flag = true;
}
else
{
flag = false;
break;
}
}
return flag;
}
To pass these tests, which are located in a file called testVector.cpp:
#include "Vector.h"
#include "test.h"
#include <stdexcept>
using namespace std;
int main() {
// Test exceptions
Vector v;
throw_(v.at(0), range_error);
throw_(v.pop_back(), range_error);
throw_(v.erase(0), range_error);
throw_(v.front(), range_error);
throw_(v.back(), range_error);
// Test adding an element
v.push_back(1);
test_(v.size() == 1);
test_(v.at(0) == 1);
test_(v[0] == 1);
test_(v.front() == 1);
test_(v.back() == 1);
test_(!v.empty());
// Add another
v.push_back(2);
test_(v.size() == 2);
test_(v.at(0) == 1);
test_(v.at(1) == 2);
test_(v[0] == 1);
test_(v[1] == 2);
test_(v.front() == 1);
test_(v.back() == 2);
test_(!v.empty());
// Test iterators
auto iter = v.begin();
test_(*iter == 1);
++iter;
test_(*iter == 2);
++iter;
test_(iter == v.end());
// Test copy and ==
Vector v2 = v;
test_(v2.size() == 2);
test_(v2.at(0) == 1);
test_(v2.at(1) == 2);
test_(v2[0] == 1);
test_(v2[1] == 2);
test_(v2.front() == 1);
test_(v2.back() == 2);
test_(!v2.empty());
test_(v == v2);
iter = v2.begin();
test_(*iter == 1);
++iter;
test_(*iter == 2);
++iter;
test_(iter == v2.end());
// Test assignment
Vector v3;
v3 = v;
test_(v3.size() == 2);
test_(v3.at(0) == 1);
test_(v3.at(1) == 2);
test_(v3[0] == 1);
test_(v3[1] == 2);
test_(v3.front() == 1);
test_(v3.back() == 2);
test_(!v3.empty());
//iter = v3.begin();
//test_(*iter == 1);
//++iter;
//test_(*iter == 2);
//++iter;
//test_(iter == v3.end());
// Test assignment
v[1] = -2;
test_(v.back() == -2);
test_(v.at(1) == -2);
test_(v[1] == -2);
// Test pop_back
v.pop_back();
test_(v.size() == 1);
test_(v.front() == 1);
test_(v.back() == 1);
test_(v.at(0) == 1);
test_(v[0] == 1);
// Test clear and !=
v.clear();
test_(v.size() == 0);
test_(v.empty());
throw_(v.at(0), range_error);
throw_(v.pop_back(), range_error);
throw_(v.erase(0), range_error);
throw_(v.front(), range_error);
throw_(v.back(), range_error);
test_(v != v2);
// Test erase
v3.erase(0);
test_(v3.size() == 1);
test_(v3.at(0) == 2);
test_(v3[0] == 2);
test_(v3.front() == 2);
test_(v3.back() == 2);
// Test insert
//v3.insert(0,1);
test_(v3.size() == 2);
test_(v3.at(0) == 1);
test_(v3[0] == 1);
test_(v3[1] == 2);
test_(v3.front() == 1);
test_(v3.back() == 2);
// Test grow
Vector v4;
for (int i = 1; i <= 10; ++i)
v4.push_back(i);
test_(v4.size() == 10);
test_(v4.front() == 1);
test_(v4.back() == 10);
v4.insert(10,11);
test_(v4.size() == 11);
test_(v4.front() == 1);
test_(v4.back() == 11);
report_();
}
push_back() and insert() both call grow(), which fails to increase the capacity because GROWER is an int, so 1.6 truncates to 1, and multiplying capacity * 1 doesn't change its value. But even if capacity were increased properly, the data_ptr array is not being re-allocated at all to fit the new capacity.
But even if grow() were working properly, there is no need to call grow() on every insertion of a new element, that defeats the purpose of separating n_elems from capacity to begin with. You should grow the array only when n_elems has reached capacity.
There are many other problems with your class, as well:
operator= is not testing for self-assignment, and is leaking the allocated memory of the old array. Consider using the copy-swap idiom instead.
front() does not reach the throw statement when the array is empty.
at() and erase() are performing bounds checking using capacity instead of n_elems.
push_back() is inserting the new value at the wrong index, and not incrementing n_elems.
pop_back() does not throw an error when the array is empty, causing n_elems to decrement below 0, which wraps around to the max positive value of size_t because size_t is unsigned.
erase() and operator== go out of bounds while iterating the array.
begin() and end() should not be returning nullptr for an empty array. And end() is returning a pointer to the last element in a non-empty array rather than returning a pointer to 1 past the last element.
operator== and operator!= do not perform any bounds checking to make sure the 2 vectors have the same same n_elems before iterating their arrays. And they are comparing element values beyond n_elems. Also, operator!= is returning the wrong result.
With that said, try something more like this:
#include <stdexcept>
#include <algorithm>
#include "Vector.h"
void Vector::grow()
{
static const float GROWER = 1.6f;
size_t new_capacity = capacity * GROWER;
if (new_capacity <= capacity)
throw std::overflow_error("cant grow capacity");
int *new_data_ptr = new int[new_capacity];
std::copy(data_ptr, data_ptr + n_elems, new_data_ptr);
delete[] data_ptr;
data_ptr = new_data_ptr;
capacity = new_capacity;
}
Vector::Vector()
{
capacity = CHUNK;
n_elems = 0;
data_ptr = new int[capacity];
}
Vector::Vector(const Vector& v)
{
capacity = v.capacity;
n_elems = v.n_elems;
data_ptr = new int[capacity];
std::copy(v.begin(), v.end(), data_ptr);
}
Vector& Vector::operator=(const Vector& v)
{
if (this != &v)
{
Vector temp(v);
std::swap(capacity, temp.capacity);
std::swap(n_elems, temp.n_elems);
std::swap(data_ptr, temp.data_ptr);
}
return *this;
}
Vector::~Vector()
{
delete[] data_ptr;
}
int Vector::front() const
{
if (n_elems == 0)
throw std::range_error("Range Error");
return data_ptr[0];
}
int Vector::back() const
{
if (n_elems == 0)
throw std::range_error("Range Error");
return data_ptr[n_elems - 1];
}
int Vector::at(size_t pos) const
{
if (pos >= n_elems)
throw std::range_error("Range Error");
return data_ptr[pos];
}
size_t Vector::size() const
{
return n_elems;
}
bool Vector::empty() const
{
return (n_elems == 0);
}
int& Vector::operator[](size_t pos)
{
return data_ptr[pos];
}
void Vector::push_back(int item)
{
if (n_elems == capacity)
grow();
data_ptr[n_elems] = item;
++n_elems;
}
void Vector::pop_back()
{
if (n_elems == 0)
throw std::range_error("Range Error");
--n_elems;
}
void Vector::erase(size_t pos)
{
if (pos >= n_elems)
throw std::range_error("Range Error");
std::copy(data_ptr + pos + 1, data_ptr + n_elems, data_ptr + pos);
--n_elems;
}
void Vector::insert(size_t pos, int item)
{
if (pos > n_elems) // insert at end() is OK...
throw range_error("Range Error");
if (n_elems == capacity)
grow();
std::copy_backward(data_ptr + pos, data_ptr + n_elems, data_ptr + n_elems + 1);
data_ptr[pos] = item;
++n_elems;
}
void Vector::clear()
{
n_elems = 0;
}
int* Vector::begin()
{
return data_ptr;
}
int* Vector::end()
{
return data_ptr + n_elems;
}
bool Vector::operator==(const Vector& v) const
{
return (n_elems == v.n_elems) && std::equal(v.begin(), v.end(), data_ptr);
}
bool Vector::operator!=(const Vector& v) const
{
return !(*this == v);
}
Your'e missing declaration of vector here, but I can surmize its structure. First mistake you doing here:
const int GROWER = 1.6;
capacity = capacity * GROWER; // it will never change
Reallocation doesn't happen, where it is? You just call upon dietis of Undefined Behaviour.
You either have to make GROWER float or increment size by fixed size. Also it's very unusual for a vector to grow geometrically. And very ineffective to grow on each push_back. Instead you have to have a CAPACITY and ALLOCATED SIZE. Latter may be greater and would grow if push_back would increase capacity outside of its limits. You apparently have a number of elements n_elems there, but you ignore it?
Many of those are doing too much extra work and don't do what they should.
Like this could actually be
data_ptr = new int[capacity] {}; // value initialization
//for (size_t i = 0; i < capacity; i++)
//{
// data_ptr[i] = 0;
//}
Use initialization lists, not side effects. Or you may lose them. Copy constructor also doesn't take in account n_elems of v and may copy garbage, converting it into new elements.
Comparisons simply wrong, because vectors can have different capacity. E.g.
bool Vector::operator==(const Vector& v) const
{
// check here if either of vectors is empty,
// if both are empty, they are equal?
// if their capacities are unequal, vectors are not equal. Those are shortcuts
// capacities are same
for (size_t i = 0; i < capacity; i++ )
if (data_ptr[i] != v.data_ptr[i])
return false;
return true;
}
Can anyone solve this for me? I couldn't find why is it giving error on these specific lines. I guess the syntax is right. I have commented the error lines. It is giving error on open.push_back(p) in DFID function and mylist.push_back(p); in GenerateChildren function Please help me on this. Much Thanks
#include <iostream>
#include <algorithm>
#include <list>
#include <string>
using namespace std;
const int n = 3;
int goal[n][n] = { { 1, 2, 3 },{ 8, 0, 4 },{ 7, 6, 5 } };
static int max_depth = 0;
list <int[3][3]> open;
list <string> closed;
bool DFID(int[3][3]);
list<int[3][3]> generateChildren(int[3][3]);
bool isGoal(int [3][3]);
string convertToString(int[3][3]);
bool inClosed(string);
void main()
{
int puzzle[n][n] = { { 1, 2, 3 }, { 8, 6, 4 }, { 7, 0, 5 } };
DFID(puzzle);
}
bool DFID(int p[3][3])
{
open.push_back(p); // Error on this line
open.pop_front();
list<int[3][3]> mylist = generateChildren(p);
list<int[3][3]>::iterator it;
for (it = mylist.begin(); it != mylist.end(); ++it)
{
if (isGoal(*it))
return true;
else
{
string s =convertToString(*it);
if (inClosed(s))
{
continue;
}
else
{
//
}
}
}
}
list<int[3][3]> generateChildren(int p[3][3])
{
//finding zero element
int a = 0, b = 0;
for (int i = 0; i < n; i++)
{
for (int j = 0; i < n; j++)
{
if (p[i][j] == 0)
{
a = i;
b = j;
break;
}
}
}
list <int[3][3]> mylist;
if (p[-a][b] != -1)
{
swap(p[a][b], p[--a][b]);
mylist.push_back(p); //Error on this line
}
if (p[a][--b] != -1)
{
swap(p[a][b], p[a][--b]);
mylist.push_back(p); //Error
}
if (p[++a][b] != 3)
{
swap(p[a][b], p[++a][b]);
mylist.push_back(p); //Error
}
if (p[a][++b] != 3)
{
swap(p[a][b], p[a][++b]);
mylist.push_back(p); //Error
}
return mylist;
}
bool isGoal(int p[3][3])
{
for (int i = 0; i < n; i++)
{
for (int j = 0; i < n; j++)
{
if (p[i][j] != goal[i][j]);
return false;
}
}
return true;
}
string convertToString(int p[3][3])
{
string puzz;
for (int i = 0; i < n; i++)
{
for (int j = 0; j < n; j++)
{
puzz = puzz + to_string(p[i][j]);
}
}
return puzz;
}
bool inClosed(string s)
{
list<string>::iterator it;
for (it = closed.begin(); it != closed.end(); ++it)
{
if (*it == s);
return true;
}
return false;
}
There are multiple problems with the code as you show it.
One issue is that putting data into a container means it either needs to be move or copied. And arrays can't be neither moved nor copied.
Another issue is that e.g.
bool DFID(int[3][3]);
is equal to
bool DFID(int(*)[3]);
That is, the argument is a pointer and not an array. Pointers and arrays are different.
One possible way to solve your problems (both of them) is to use another standard container, such as std::array:
std::array<std::array<int, n>, n> goal;
std::list<std::array<std::array<int, n>, n>> open;
You can simplify the type with a type-alias:
using matrix_type = std::array<std::array<int, n>, n>;
matrix_type goal;
std::list<matrix_type> open;
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.)
I got this implementation for maximum matching off the net and is trying to give its input through main class. But I am getting zero for all the places in match. What am I doing wrong?
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <iostream>
#include <queue>
using namespace std;
void add_edge(int u, int v);
void edmonds();
struct edge {
int v, nx;
};
const int MAXN = 1000, MAXE = 2000;
edge graph[MAXE];
int last[MAXN], match[MAXN], px[MAXN], base[MAXN], N, M, edges;
bool used[MAXN], blossom[MAXN], lused[MAXN];
int main ()
{
// return 0;
add_edge(1,4);
add_edge(1,5);
add_edge(1,6);
add_edge(2,5);
add_edge(2,7);
add_edge(3,4);
add_edge(4,1);
add_edge(4,3);
add_edge(5,1);
add_edge(5,2);
add_edge(6,1);
add_edge(7,2);
edmonds();
cout << match[0];
cout << match[1];
cout << match[2];
cout << match[3];
cout << match[4];
cout << match[5];
cout << match[6];
}
inline void add_edge(int u, int v) {
graph[edges] = (edge) {v, last[u]};
last[u] = edges++;
graph[edges] = (edge) {u, last[v]};
last[v] = edges++;
}
void mark_path(int v, int b, int children) {
while (base[v] != b) {
blossom[base[v]] = blossom[base[match[v]]] = true;
px[v] = children;
children = match[v];
v = px[match[v]];
}
}
int lca(int a, int b) {
memset(lused, 0, N);
while (1) {
lused[a = base[a]] = true;
if (match[a] == -1)
break;
a = px[match[a]];
}
while (1) {
b = base[b];
if (lused[b])
return b;
b = px[match[b]];
}
}
int find_path(int root) {
memset(used, 0, N);
memset(px, -1, sizeof(int) * N);
for (int i = 0; i < N; ++i)
base[i] = i;
used[root] = true;
queue<int> q;
q.push(root);
register int v, e, to, i;
while (!q.empty()) {
v = q.front(); q.pop();
for (e = last[v]; e >= 0; e = graph[e].nx) {
to = graph[e].v;
if (base[v] == base[to] || match[v] == to)
continue;
if (to == root || (match[to] != -1 && px[match[to]] != -1)) {
int curbase = lca(v, to);
memset(blossom, 0, N);
mark_path(v, curbase, to);
mark_path(to, curbase, v);
for (i = 0; i < N; ++i)
if (blossom[base[i]]) {
base[i] = curbase;
if (!used[i]) {
used[i] = true;
q.push(i);
}
}
} else if (px[to] == -1) {
px[to] = v;
if (match[to] == -1)
return to;
to = match[to];
used[to] = true;
q.push(to);
}
}
}
return -1;
}
void build_pre_matching() {
register int u, e, v;
for (u = 0; u < N; ++u)
if (match[u] == -1)
for (e = last[u]; e >= 0; e = graph[e].nx) {
v = graph[e].v;
if (match[v] == -1) {
match[u] = v;
match[v] = u;
break;
}
}
}
void edmonds() {
memset(match, 0xff, sizeof(int) * N);
build_pre_matching();
register int i, v, pv, ppv;
for (i = 0; i < N; ++i)
if (match[i] == -1) {
v = find_path(i);
while (v != -1) {
pv = px[v], ppv = match[pv];
match[v] = pv, match[pv] = v;
v = ppv;
}
}
}
You set elements of match in two locations: In build_pre_matching() and in edmonds(). In both of these cases, no change will happen if match[x] for some index x isn't -1. The only other place elements of match get a value is during static initialization where the values get zero initialized. Since the initial value is zero and the values are only ever changed if at least one of them happens to be -1, I would expect that the values retain the value 0.
You might want to use something like
std::fill(std::begin(match), std::end(match), -1);
at a strategic location since you seem to assume that the values are initially -1. Of course, you also should consider the idea of not using global variables because this doesn't scale and works really badly in a multi-threaded program.