I have been staring at this all day and have gotten slightly somewhere, but it's still not working correctly! Just trying to 'put' (really insert, or find if it's there) an element k into a LL red black tree. Here's my method:
Node * RPut(Node* p, const K& k, Node*& location)
{
// if you are at the bottom of the tree,
// add new node at bottom of the tree
if (p == 0)
{
// new red note with new data
location = NewNode(k, Data(), RED);
return location;
}
if(greater_(k,p->key_))
{
// if it's greater than the root, move down to the left child
p->left_ = Rput(p->left_, k, location);
}
// right subtree
else if (greater_(p->key_,k))
{
// but if the key is less than root, move down to right child
p->right_ = Rput(p->right_, k, location);
}
// if they are equal
else
{
location = p;
}
// code for rotating
// this sort of worked.
if(p->right_ && p->right_->IsRed())
{
p = RotateLeft(p);
if (p->left_->IsBlack())
{
p->SetBlack();
p->left_->SetRed();
}
}
if (p->left_ && p->left_->IsRed())
{ if (p->left_->left_ && p->left_->left_->IsRed())
{
p = RotateRight(p);
p->left_->SetBlack();
p->right_->SetBlack();
}
}
return p;
}
I know my rotate methods work perfectly. This inserts correctly until the fifth element (I haven't tried every combination, but usually.) For instance, abcde inserted correctly would be
d
b e
a c --
[with b as red node]
mine works but stops here, giving me:
b
a d
- - c e
with NO red nodes.
Anyone see anything obvious I am overlooking or why it isn't working properly? Any help at all much appreciated.
Thanks!
This does not directly answer the question, but have you read Sedgewick's paper on left-leaning red black trees? The code in it is exceptionally clear, there are beautiful diagrams explaining how things work, and, I imagine, it would be straight-forward to reimplement everything into C++.
Edit
I tried, for fun to implement Sedgewick's code. It turns out the paper had a few methods/subroutines left out that would have been pretty helpful to include. Anyway, my C++11 implementation, along with some tests, follows.
Since Java does automagic memory management, Sedgewick doesn't explicitly note where memory should be freed in his code. Rather than try to figure this out for a quick project and possibly leave memory leaks, I've opted to use std::shared_ptr, which provides a similar worry-free behaviour.
#include <iostream>
#include <vector>
#include <cstdlib>
#include <memory>
template<class keyt, class valuet>
class LLRB {
private:
static const bool COLOR_RED = true;
static const bool COLOR_BLACK = false;
class Node {
public:
keyt key;
valuet val;
std::shared_ptr<Node> right;
std::shared_ptr<Node> left;
bool color;
Node(keyt key, valuet val){
this->key = key;
this->val = val;
this->color = COLOR_RED;
this->right = nullptr;
this->left = nullptr;
}
};
typedef std::shared_ptr<Node> nptr;
nptr root;
nptr rotateLeft(nptr h){
nptr x = h->right;
h->right = x->left;
x->left = h;
x->color = h->color;
h->color = COLOR_RED;
return x;
}
nptr rotateRight(nptr h){
nptr x = h->left;
h->left = x->right;
x->right = h;
x->color = h->color;
h->color = COLOR_RED;
return x;
}
nptr moveRedLeft(nptr h){
flipColors(h);
if(isRed(h->right->left)){
h->right = rotateRight(h->right);
h = rotateLeft(h);
flipColors(h);
}
return h;
}
nptr moveRedRight(nptr h){
flipColors(h);
if(isRed(h->left->left)){
h = rotateRight(h);
flipColors(h);
}
return h;
}
void flipColors(nptr h){
h->color = !h->color;
h->left->color = !h->left->color;
h->right->color = !h->right->color;
}
bool isRed(const nptr h) const {
if(h==nullptr) return false;
return h->color == COLOR_RED;
}
nptr fixUp(nptr h){
if(isRed(h->right) && !isRed(h->left)) h = rotateLeft (h);
if(isRed(h->left) && isRed(h->left->left)) h = rotateRight(h);
if(isRed(h->left) && isRed(h->right)) flipColors (h);
return h;
}
nptr insert(nptr h, keyt key, valuet val){
if(h==nullptr)
return std::make_shared<Node>(key,val);
if (key == h->key) h->val = val;
else if(key < h->key) h->left = insert(h->left, key,val);
else h->right = insert(h->right,key,val);
h = fixUp(h);
return h;
}
//This routine probably likes memory
nptr deleteMin(nptr h){
if(h->left==nullptr) return nullptr;
if(!isRed(h->left) && !isRed(h->left->left))
h = moveRedLeft(h);
h->left = deleteMin(h->left);
return fixUp(h);
}
nptr minNode(nptr h){
return (h->left == nullptr) ? h : minNode(h->left);
}
//This routine leaks memory like no other!! I've added a few cleanups
nptr remove(nptr h, keyt key){
if(key<h->key){
if(!isRed(h->left) && !isRed(h->left->left))
h = moveRedLeft(h);
h->left = remove(h->left, key);
} else {
if(isRed(h->left))
h = rotateRight(h);
if(key==h->key && h->right==nullptr)
return nullptr;
if(!isRed(h->right) && !isRed(h->right->left))
h = moveRedRight(h);
if(key==h->key){
std::shared_ptr<Node> mn = minNode(h->right);
h->val = mn->val;
h->key = mn->key;
h->right = deleteMin(h->right);
} else {
h->right = remove(h->right, key);
}
}
return fixUp(h);
}
void traverse(const nptr h) const {
if(h==nullptr)
return;
traverse(h->left);
std::cout<< h->key << "=" << h->val <<std::endl;
traverse(h->right);
}
public:
LLRB(){
root = nullptr;
}
void traverse() const {
traverse(root);
}
valuet search(keyt key){
nptr x = root;
while(x!=nullptr){
if (key == x->key) return x->val;
else if (key < x->key) x=x->left;
else x=x->right;
}
return keyt();
}
void insert(keyt key, valuet val){
root = insert(root,key,val);
root->color = COLOR_BLACK;
}
void remove(keyt key){
root = remove(root,key);
root->color = COLOR_BLACK;
}
};
int main(){
for(int test=0;test<500;test++){
LLRB<int,int> llrb;
std::vector<int> keys;
std::vector<int> vals;
for(int i=0;i<1000;i++){
//Ensure each key is unique
int newkey = rand();
while(llrb.search(newkey)!=int())
newkey = rand();
keys.push_back(newkey);
vals.push_back(rand()+1);
llrb.insert(keys.back(),vals.back());
}
//llrb.traverse();
for(int i=0;i<1000;i++){
if(llrb.search(keys[i])!=vals[i]){
return -1;
}
}
for(int i=0;i<500;i++)
llrb.remove(keys[i]);
for(int i=500;i<1000;i++){
if(llrb.search(keys[i])!=vals[i]){
return -1;
}
}
}
std::cout<<"Good"<<std::endl;
}
Related
I got an assignment but I'm stuck in the titled problem. It will be very glad that you will help me to solve this. The quick over review I have provided the classes and main file for which I have to implemented the function and run the code. There are two files named fheap.hpp and djstra.hpp and the main file.
int main(){
// Fibonacci Heap
FibonacciHeap<int> heap(3);
std::cout<<(heap.get_min()==std::nullopt)<<std::endl;
std::vector<int> inserted;
for(int i = 0 ; i < 15 ; ++i) {
int temp = rand() % 100+1;
heap.insert(temp);
cout << temp;
cout << "inserted & min :";
cout << heap.get_min().value() << endl;
}
std::cout<<heap.get_min().value()<<std::endl;
for (int j = 0; j < 15; ++j) {
int min_value = heap.extract_min().value();
cout << "min_value: ";
std::cout << min_value;
cout << " size: ";
cout << heap.size()<<endl;
}
// Dijkstra's Algorithm
edges_t edges1 = {{0, 1, 3.0f},
{0, 2, 1.0f},
{1, 2, 7.0f},
{1, 3, 5.0f},
{1, 4, 1.0f},
{2, 3, 2.0f},
{3, 4, 7.0f}};
Graph g1(5, edges1, GraphType::UNDIRECTED);
std::unordered_map<vertex_t, std::optional<std::tuple<vertex_t, edge_weight_t>>> result
= dijkstra_shortest_path(g1, 2);
// Previous vertex of src are not checked.
std::vector<vertex_t> previous = {2, 0, (vertex_t)-1, 2, 1};
std::vector<edge_weight_t> dist = {1.0f, 4.0f, 0.0f, 2.0f, 5.0f};
// The printed result should be same as above.
for(size_t i = 0 ; i < 5 && i!=2 ; ++i) {
std::cout<<"[vertex i] ";
std::cout<<"previous: "<<std::get<0>(result[i].value())<<", ";
std::cout<<"distance: "<<std::get<1>(result[i].value())<<std::endl;
}
return 0;
}
Suprisingly the djstra part is giving me the required output. second file loop in the main section throws memory error Edit: ( meaning it exits the program with some memory address and sometimes show what() std:: optional error). The fheap class is below that are responsible for it are below:
#ifndef __FHEAP_H_
#define __FHEAP_H_
#include <iostream>
#include <initializer_list>
#include <optional>
#include <vector>
#include <cmath>
#include <memory>
#include <queue>
#include <list>
template <typename T>
class PriorityQueue {
public:
virtual void insert(const T& item) = 0;
virtual std::optional<T> extract_min() = 0;
virtual bool is_empty() const = 0;
};
template <typename T>
class FibonacciNode {
public:
// Constructors
FibonacciNode()
:key(), degree(0), marked(false), child(nullptr), right(nullptr) {}
FibonacciNode(const T& item)
:key(item), degree(0), marked(false), child(nullptr), right(nullptr) {}
// Destructor
~FibonacciNode() = default;
T key;
size_t degree;
bool marked;
std::shared_ptr<FibonacciNode<T>> right;
std::shared_ptr<FibonacciNode<T>> child;
// NOTE: To prevent circular reference, left/parent pointer should be set to weak_ptr.
std::shared_ptr<FibonacciNode<T>> left;
std::shared_ptr<FibonacciNode<T>> parent;
};
template <typename T>
class FibonacciHeap : public PriorityQueue<T> {
public:
// Constructors
FibonacciHeap()
: min_node(nullptr), size_(0) {}
FibonacciHeap(const T& item)
: min_node(nullptr), size_(0) { insert(item); }
// Disable copy constructor.
FibonacciHeap(const FibonacciHeap<T> &);
// Destructor
//~FibonacciHeap();
void insert(const T& item) override;
void insert(std::shared_ptr<FibonacciNode<T>>& node);
// Return raw pointer of the min_node.
FibonacciNode<T>* get_min_node() { return min_node.get(); }
std::optional<T> get_min() const;
std::optional<T> extract_min() override;
std::optional<T> extract_min1();
void decrease_key(std::shared_ptr<FibonacciNode<T>>& x, T new_key);
void remove(std::shared_ptr<FibonacciNode<T>>& node);
bool is_empty() const override { return !size_; }
size_t size() const { return size_; }
private:
std::shared_ptr<FibonacciNode<T>> min_node;
std::shared_ptr<FibonacciNode<T>> min;
size_t size_;
void consolidate();
void merge(std::shared_ptr<FibonacciNode<T>>& x, std::shared_ptr<FibonacciNode<T>>& y);
void cut(std::shared_ptr<FibonacciNode<T>>& x);
void recursive_cut(std::shared_ptr<FibonacciNode<T>>& x);
};
template <typename T>
void FibonacciHeap<T>::insert(const T& item) {
std::shared_ptr<FibonacciNode<T>> node = std::make_shared<FibonacciNode<T>>(item);
insert(node);
}
template <typename T>
std::optional<T> FibonacciHeap<T>::get_min() const {
if (min_node) {
return min_node->key;
} else {
return std::nullopt;
}
}
template <typename T>
void FibonacciHeap<T>::insert(std::shared_ptr<FibonacciNode<T>>& node) {
// Make the new node the right sibling of the min_node, if it exists
if (min_node) {
node->right = min_node->right;
min_node->right = node;
node->left = min_node;
node->right->left = node;
}
// Otherwise, make the new node the min_node and its own right sibling
else {
min_node = node;
node->right = node;
node->left = node;
}
// If the new node has a smaller key than the current min_node, update min_node
if (node->key < min_node->key) {
min_node = node;
}
// Increase the size of the heap
++size_;
}
template <typename T>
std::optional<T> FibonacciHeap<T>::extract_min() {
// Return nullopt if the heap is empty
if (!min_node) {
return std::nullopt;
}
// Store the min_node in a temporary variable
std::shared_ptr<FibonacciNode<T>> z = min_node;
// If the min_node has children, add them to the root list
if (z->child) {
std::shared_ptr<FibonacciNode<T>> child = z->child;
do {
child->parent.reset();
child = child->right;
} while (child != z->child);
merge(min_node, z->child);
}
// Remove the min_node from the root list
std::shared_ptr<FibonacciNode<T>> left = z->left;
std::shared_ptr<FibonacciNode<T>> right = z->right;
left->right = right;
right->left = left;
// If the min_node was the only node in the heap, set min_node to nullptr
if (z == right) {
min_node.reset();
}
// Otherwise, set the new min_node to be the node that was previously to the right of z
else {
min_node = right;
consolidate();
}
// Decrease the size of the heap
--size_;
// Return the key of the extracted min_node
return z->key;
}
template <typename T>
void FibonacciHeap<T>::decrease_key(std::shared_ptr<FibonacciNode<T>>& x, T new_key) {
// If the new key is greater than the current key, throw an exception
if (new_key > x->key) {
throw std::invalid_argument("New key is greater than current key.");
}
// Update the key of the node
x->key = new_key;
// If the node has a parent and its new key is smaller than its parent's key, cut it from its parent and add it to the root list
auto parent = x->parent.lock();
if (parent && x->key < parent->key) {
cut(x);
}
// If the node's new key is smaller than the current min_node's key, update min_node
if (x->key < min_node->key) {
min_node = x;
}
}
template <typename T>
void FibonacciHeap<T>::remove(std::shared_ptr<FibonacciNode<T>>& x) {
// Set the key of the node to be removed to the minimum value
x->key = std::numeric_limits<T>::min();
// Perform a decrease key operation on the node to be removed
decrease_key(x, std::numeric_limits<T>::min());
// Extract the minimum value, which should be the node to be removed
extract_min();
}
template <typename T>
void FibonacciHeap<T>::consolidate() {
float phi = (1 + sqrt(5)) / 2.0;
int len = int(log(size_) / log(phi)) + 10;
std::vector<std::shared_ptr<FibonacciNode<T>>> A(len, nullptr);
std::shared_ptr<FibonacciNode<T>> w = min_node;
std::shared_ptr<FibonacciNode<T>> x = w;
do {
x = x->right;
std::shared_ptr<FibonacciNode<T>> y = x;
int d = y->degree;
while (A[d]) {
std::shared_ptr<FibonacciNode<T>> z = A[d];
if (y->key > z->key) {
std::swap(y, z);
}
merge(y, z);
A[d] = nullptr;
++d;
}
A[d] = y;
} while (w != x);
min_node.reset();
for (int i = 0; i < len; ++i) {
if (A[i]) {
if (min_node) {
A[i]->right = min_node->right;
min_node->right = A[i];
A[i]->left = min_node;
A[i]->right->left = A[i];
if (A[i]->key < min_node->key) {
min_node = A[i];
}
}
else {
min_node = A[i];
min_node->right = min_node;
min_node->left = min_node;
}
}
}
}
template <typename T>
void FibonacciHeap<T>::merge(std::shared_ptr<FibonacciNode<T>>& x, std::shared_ptr<FibonacciNode<T>>& y) {
// Make x the right sibling of y
x->right = y->right;
y->right->left = x;
y->right = x;
x->left = y;
// If x has a smaller key than y, make x the new min_node
if (x->key < y->key) {
min_node = x;
}
// Otherwise, make y the new min_node
else {
min_node = y;
}
// Increase the size of the heap
size_ += 2;
}
template <typename T>
void FibonacciHeap<T>::cut(std::shared_ptr<FibonacciNode<T>>& x) {
// Get a pointer to the parent of x
auto parent = x->parent;
// If x has no parent, we do not need to cut it
if (!parent) return;
// Remove x from the child list of parent
if (x->right == x) {
parent->child = nullptr;
}
else {
x->right->left = x->left;
x->left->right = x->right;
if (parent->child == x) {
parent->child = x->right;
}
}
// Decrease the degree of parent
--parent->degree;
// Add x to the root list of the heap
x->right = min_node->right;
min_node->right = x;
x->left = min_node;
x->right->left = x;
// Clear the parent and marked fields of x
x->parent.reset();
x->marked = false;
}
template <typename T>
void FibonacciHeap<T>::recursive_cut(std::shared_ptr<FibonacciNode<T>>& x) {
// Get the parent of the node
auto parent = x->parent.lock();
// If the node has a parent, cut it from the parent and perform a recursive cut on the parent
if (parent) {
if (x->marked) {
// Cut the node from the parent
cut(x);
// Perform a recursive cut on the parent
recursive_cut(parent);
}
// If the node is not marked, mark it
else {
x->marked = true;
}
}
}
#endif // __FHEAP_H_
I know, I'm asking a very long question. I've tried every approach but it's not solving.
I Tried debugging the code and introducing cout operations where I think is error after debugging is in the line
`
std::shared_ptr<FibonacciNode<T>> z = A[d];
I tried ArrayList but still no change.
Edit: Second for loop means the 2nd loop in int main ()
I am trying to make the Dijkstra algorithm to take input from the text file. I found this example (https://www.programiz.com/dsa/dijkstra-algorithm) for Dijkstra, which does exactly what I need - finds the shortest path between two nodes and prints it together with a cost.
How can I fill the graph from the given text file? Thanks in advance for any replies.
Code example, updated to use decimal weights:
// Dijkstra's Algorithm in C++
#include <iostream>
#include <vector>
#include <limits.h>
using namespace std;
void DijkstrasTest();
int main() {
DijkstrasTest();
return 0;
}
class Node;
class Edge;
void Dijkstras();
vector<Node*>* AdjacentRemainingNodes(Node* node);
Node* ExtractSmallest(vector<Node*>& nodes);
double Distance(Node* node1, Node* node2);
bool Contains(vector<Node*>& nodes, Node* node);
void PrintShortestRouteTo(Node* destination);
vector<Node*> nodes;
vector<Edge*> edges;
class Node {
public:
Node(char id)
: id(id), previous(NULL), distanceFromStart(INT_MAX) {
nodes.push_back(this);
}
public:
char id;
Node* previous;
double distanceFromStart;
};
class Edge {
public:
Edge(Node* node1, Node* node2, double distance)
: node1(node1), node2(node2), distance(distance) {
edges.push_back(this);
}
bool Connects(Node* node1, Node* node2) {
return (
(node1 == this->node1 &&
node2 == this->node2) ||
(node1 == this->node2 &&
node2 == this->node1));
}
public:
Node* node1;
Node* node2;
double distance;
};
///////////////////
void DijkstrasTest() {
Node* a = new Node('a');
Node* b = new Node('b');
Node* c = new Node('c');
Node* d = new Node('d');
Node* e = new Node('e');
Node* f = new Node('f');
Node* g = new Node('g');
Edge* e1 = new Edge(a, c, 1.74);
Edge* e2 = new Edge(a, d, 2.156);
Edge* e3 = new Edge(b, c, 2.516);
Edge* e4 = new Edge(c, d, 1.321);
Edge* e5 = new Edge(b, f, 3.51);
Edge* e6 = new Edge(c, e, 3.11);
Edge* e7 = new Edge(e, f, 2.2);
Edge* e8 = new Edge(d, g, 1.1);
Edge* e9 = new Edge(g, f, 1.5);
a->distanceFromStart = 0; // set start node
Dijkstras();
PrintShortestRouteTo(f);
}
///////////////////
void Dijkstras() {
while (nodes.size() > 0) {
Node* smallest = ExtractSmallest(nodes);
vector<Node*>* adjacentNodes =
AdjacentRemainingNodes(smallest);
const int size = adjacentNodes->size();
for (int i = 0; i < size; ++i) {
Node* adjacent = adjacentNodes->at(i);
double distance = Distance(smallest, adjacent) +
smallest->distanceFromStart;
if (distance < adjacent->distanceFromStart) {
adjacent->distanceFromStart = distance;
adjacent->previous = smallest;
}
}
delete adjacentNodes;
}
}
// Find the node with the smallest distance,
// remove it, and return it.
Node* ExtractSmallest(vector<Node*>& nodes) {
int size = nodes.size();
if (size == 0) return NULL;
int smallestPosition = 0;
Node* smallest = nodes.at(0);
for (int i = 1; i < size; ++i) {
Node* current = nodes.at(i);
if (current->distanceFromStart <
smallest->distanceFromStart) {
smallest = current;
smallestPosition = i;
}
}
nodes.erase(nodes.begin() + smallestPosition);
return smallest;
}
// Return all nodes adjacent to 'node' which are still
// in the 'nodes' collection.
vector<Node*>* AdjacentRemainingNodes(Node* node) {
vector<Node*>* adjacentNodes = new vector<Node*>();
const int size = edges.size();
for (int i = 0; i < size; ++i) {
Edge* edge = edges.at(i);
Node* adjacent = NULL;
if (edge->node1 == node) {
adjacent = edge->node2;
} else if (edge->node2 == node) {
adjacent = edge->node1;
}
if (adjacent && Contains(nodes, adjacent)) {
adjacentNodes->push_back(adjacent);
}
}
return adjacentNodes;
}
// Return distance between two connected nodes
double Distance(Node* node1, Node* node2) {
const int size = edges.size();
for (int i = 0; i < size; ++i) {
Edge* edge = edges.at(i);
if (edge->Connects(node1, node2)) {
return edge->distance;
}
}
return -1; // should never happen
}
// Does the 'nodes' vector contain 'node'
bool Contains(vector<Node*>& nodes, Node* node) {
const int size = nodes.size();
for (int i = 0; i < size; ++i) {
if (node == nodes.at(i)) {
return true;
}
}
return false;
}
///////////////////
void PrintShortestRouteTo(Node* destination) {
Node* previous = destination;
cout << "Distance from start: "
<< destination->distanceFromStart << endl;
while (previous) {
cout << previous->id << " ";
previous = previous->previous;
}
cout << endl;
}
// these two not needed
vector<Edge*>* AdjacentEdges(vector<Edge*>& Edges, Node* node);
void RemoveEdge(vector<Edge*>& Edges, Edge* edge);
vector<Edge*>* AdjacentEdges(vector<Edge*>& edges, Node* node) {
vector<Edge*>* adjacentEdges = new vector<Edge*>();
const int size = edges.size();
for (int i = 0; i < size; ++i) {
Edge* edge = edges.at(i);
if (edge->node1 == node) {
cout << "adjacent: " << edge->node2->id << endl;
adjacentEdges->push_back(edge);
} else if (edge->node2 == node) {
cout << "adjacent: " << edge->node1->id << endl;
adjacentEdges->push_back(edge);
}
}
return adjacentEdges;
}
void RemoveEdge(vector<Edge*>& edges, Edge* edge) {
vector<Edge*>::iterator it;
for (it = edges.begin(); it < edges.end(); ++it) {
if (*it == edge) {
edges.erase(it);
return;
}
}
}
Fragment of the input file, number of lines is unknown:
source_id,target_id,weight
1,2,0.17
2,3,0.13
3,4,0.15
3,5,0.02
4,5,0.09
5,2,0.01
Your input is a list of node links.
Your algorithm requires an adjacency matrix, which is a vector containing vectors of the nodes adjacent to each node.
To convert from a list of links to an adjacency matrix, you need a graph class that among other things will populate the adjacency martrix using a function such as AddLink( int src, int dst, double cost )
There are many such classes available for you to copy or modify to your particular situation. I'll mention just one: PathFinder
Below is the PathFinder code to do the conversion. You will need something slightly different to handle the format of your file. Here is the format that PathFinder is reading
while (std::getline(myFile, line))
{
std::cout << line << "\n";
auto token = ParseSpaceDelimited(line);
if (!token.size())
continue;
switch (token[0][0])
{
case 'g':
if (myFinder.linkCount())
throw std::runtime_error("cPathFinderReader:: g ( directed ) must occurr before any links");
myFinder.directed();
break;
case 'l':
if (weights && (token.size() != 4))
throw std::runtime_error("cPathFinder::read bad link line");
else if (3 > token.size() || token.size() > 4)
throw std::runtime_error("cPathFinder::read bad link line");
if (weights)
cost = atof(token[3].c_str());
else
cost = 1;
if (cost < maxNegCost)
maxNegCost = cost;
myFinder.addLink(
token[1],
token[2],
cost);
break;
case 's':
if (token.size() != 2)
throw std::runtime_error("cPathFinder::read bad start line");
myFinder.start(token[1]);
break;
case 'e':
if (token.size() != 2)
throw std::runtime_error("cPathFinder::read bad end line");
myFinder.end(token[1]);
break;
}
}
I have a breadth first search to find the best solution to an 8 puzzle. In order to make sure I don't execute the same function call on the same puzzle move I have created a tree structure. It doesn't store the puzzle, just creates a pathway in the tree for the 9 values for the 9 slots in the puzzle. Here is the code:
static const int NUM_NODES = 9;
class TreeNode
{
public:
TreeNode *mylist[NUM_NODES];
TreeNode()
{
for (int x = 0; x < NUM_NODES; ++x)
mylist[x] = nullptr;
}
};
class Tree
{
private:
TreeNode *mynode;
public:
Tree()
{
mynode = new Node();
}
bool checkOrCreate(const Puzzle &p1)
{
Node *current_node = mynode;
bool found = true;
for (int x = 0; x < PUZZLE_SIZE; ++x)
{
for (int y = 0; y < PUZZLE_SIZE; ++y)
{
int index_value = p1.grid[x][y];
if (current_node->mylist[index_value] == nullptr)
{
found = false;
current_node->mylist[index_value] = new Node();
current_node = current_node->mylist[index_value];
}
else
current_node = current_node->mylist[index_value];
}
}
return found;
}
};
static Node* depth_Limited_Search(Problem &problem, int limit)
{
mylist.reset();
return recursive_Depth_Search(&Node(problem.initial_state, nullptr, START), problem, limit);
}
static Node *recursive_Depth_Search(Node *node, Problem &problem, int limit)
{
if (problem.goal_state == node->state)
return node;
else if (limit == 0)
return nullptr;
if (mylist.checkOrCreate(node->state)) //if state already exists, delete the node and return nullptr
return nullptr;
std::unique_ptr<int> xy(node->state.getCoordinates());
int xOfSpace = xy.get()[0];
int yOfSpace = xy.get()[1];
set <Action> actions = problem.actions(node->state); //gets actions
for (auto it = begin(actions); it != end(actions); ++it)
{
Action action = *it;
Node &child = child_node(problem, *node, action);
Node *answer = recursive_Depth_Search(&child, problem, limit - 1);
if (answer != nullptr)
return answer;
}
return nullptr;
}
static Node& child_node(Problem problem, Node &parent, Action action)
{
Node &child = *(new Node());
child.state = problem.result(parent.state, action);
child.parent = &parent;
child.action = action;
child.path_cost = parent.path_cost + problem.step_cost(parent.state, action);
return child;
}
Puzzle& result(const Puzzle &state, Action action)
{
// return a puzzle in the new state after perfroming action
Puzzle &new_state = *(new Puzzle(state));
int r = state.getCoordinates()[0], c = state.getCoordinates()[1];
if (action == UP)
new_state.swap(r, c, r - 1, c);
else if (action == RIGHT)
new_state.swap(r, c, r, c + 1);
else if (action == DOWN)
new_state.swap(r, c, r + 1, c);
else if (action == LEFT)
new_state.swap(r, c, r, c - 1);
return new_state;
}
I've used this on breadth and also on depth limited search using recursion to solve. Using this structure to store all the possible solutions for these algorithms takes a long time. I believe it has something to do with the allocation taking time. Is that the reason? I was thinking of trying to just create a lump of memory, and then assigning a node that address of memory instead of letting the program do it. Would that be the best solution, and how would I do that? (Since I've used this on multiple searches and they all take a long time to perform I haven't included that code.)
I'm coding the Red-Black-Tree by following Introduction to Algorithms. And when it comes to the right-rotate function, one of my pointer was modified unexpectedly.
void RBTree::RightRotate(pNode &z)
{
pNode l=z->lChild;
z->lChild = l->rChild; //link z->l-r to z as a lChild
if(l->rChild != nil)
l->rChild->p = z;
l->p = z->p; //when pass the tree's root as parameter
//z,after executing this line, z was
//modified to pointing to nil
//(known from debug window), why?
if(z->p == nil)
root = l;
else if (z == z->p->lChild)
z->p->lChild = l;
else
z->p->rChild = l;
l->rChild=z;
z->p=l;
}
And just as Introduction to Algorithms goes, I set nil pointer in my class.
Since only when root was passed as parameter z can cause this problem, I defer it's something wrong with nil and root.The following is the whole code.
:
#include
#include
#include
#define RED 1
#define BLACK 0
using namespace std;
typedef struct Node
{
int color, val;
struct Node* lChild, *rChild, *p;
Node(int val_, struct Node* tmp)
{color=RED, val=val_,lChild=rChild=p=tmp;}
Node(){color=BLACK, val=0,lChild=rChild=p=NULL;}
}Node,*pNode;
class RBTree
{
public:
RBTree()
{
root=NULL;
}
~RBTree()
{
Free_(root);
}
void Free_(pNode p)
{
if(p!=NULL)
{
Free_(p->lChild);
Free_(p->rChild);
delete(p);
p=NULL;
}
}
pNode FindMin() const
{
pNode p=root;
if (p)
while(p->lChild)
p=p->lChild;
return p;
}
pNode FindMax() const
{
pNode p=root;
if (p)
while(p->rChild)
p=p->rChild;
return p;
}
void Print(pNode p, int n) const
{
if(!p)
return;
Print(p->rChild,n+2);
for(int i=0;ivalcolor==1)?"R":"B")lChild,n+2);
}
pNode Root() {return root;}
void Insert(int const& val_);
void InsertFixup(pNode &z);
void LeftRotate(pNode &p);
void RightRotate(pNode &p);
pNode Search(pNode const &p, int x) const;
void Delete(pNode &p, int x);
private:
pNode root;
static pNode nil;
};
pNode RBTree::nil = new Node();
/*
Inserting pipiline:
Insert node into RBTree, then fixup.
In the fixup procedure , rotate may be called
*/
void RBTree::InsertFixup(pNode &z)
{
while (z->p->color == RED)
{
pNode y;
if (z->p == z->p->p->lChild)
{
y=z->p->p->rChild;
if(y->color == RED)
{
z->p->color = BLACK;
y->color = BLACK;
z->p->p->color = RED;
z = z->p->p;
}
else
{
if(z==z->p->rChild)
{
z = z->p;
LeftRotate(z);
}
z->p->color = BLACK;
z->p->p->color = RED;
RightRotate(z->p->p);
}
}
else
{
y=z->p->p->lChild;
if(y->color == RED)
{
z->p->color = BLACK;
y->color = BLACK;
z->p->p->color = RED;
z=z->p->p;
}
else
{
if(z==z->p->lChild)
{
z = z->p;
RightRotate(z);
}
z->p->color = BLACK;
z->p->p->color = RED;
LeftRotate(z->p->p);
}
}
}
root->color = BLACK;
}
void RBTree::Insert(int const &val_)
{
pNode z=new Node(val_, nil); //set val, lChild, rChild, p to NULL, color to RED
pNode x = root;
pNode pre = nil;
if(NULL == root)
root = z;
else
{
while (x!=nil)
{
pre=x;
x=(x->valrChild:x->lChild;
}
z->p = pre;
if (z->val val)
pre->lChild = z;
else
pre->rChild = z;
}
InsertFixup(z);
}
//left-rotate
//denote z, z's rChild == r
//parent changed: z, r, r's lChild
//child chagend: z->rChild, r->lChild, z->p->lChild/rChild
void RBTree::LeftRotate(pNode &z)
{
pNode r=z->rChild;
z->rChild = r->lChild; //link p->r-l to p as a r
if(r->lChild != nil)
r->lChild->p = z;
r->p = z->p;
if(z->p == nil)
root = r;
else if (z == z->p->lChild)
z->p->lChild = r;
else
z->p->rChild = r;
r->lChild=z;
z->p=r;
}
// right-rotate
void RBTree::RightRotate(pNode &z)
{
pNode l=z->lChild;
z->lChild = l->rChild; //link p->l-r to p as a l
if(l->rChild != nil)
l->rChild->p = z;
l->p = z->p;
if(z->p == nil) //link parent from top to bottom
root = l;
else if (z == z->p->lChild)
z->p->lChild = l;
else
z->p->rChild = l;
l->rChild=z;
z->p=l;
}
int main()
{
int a[9] = {11, 2, 14, 1, 7, 15, 5, 8, 4};
RBTree tr;
for(int i=0;i
Am I using nil in a wrong way?
Thanks.
Nill is not a C++ expression. However some environments might include it, just using it as an alias for NULL or 0. If you use C++11, I would recommend nullptr
Try to have a look whether
l->p < z && z< l->p + sizeof(z)
If that is the case, you are assigning to z.
I have searched through the other questions and none of them seem to apply
exactly.
I am writing a program that finds a route through a maze,
the only real thing im having a problem with is this one compiler error.
It has to do with the one function I have the returns a Node ( struct).
Header file: (I cut the define stuff off)
#include <iostream>
#include <string>
using namespace std;
class Graph {
private:
struct Node {
int id; //int id
Node * north; //north path node
Node * south; //south path node
Node * east; //east path node
Node * west; //went path node
bool visited; // visited bool
};
//this struct holds the path that is found.
struct Elem {
int id; //The id of the node
string last; //the door that it passed through
Elem * back; //back one path
Elem * next; //forward one path
};
//This is a graph with a very smart struct
//This is the main node that makes up the graph.
Node * start;
Node ** initArr;
int arrLen;
Elem * head;
Elem * tail;
int path;
public:
Graph();
//Constructs empty graph
Graph(const Graph &v);
//copy constructor
~Graph();
//destructor
Graph & operator = (const Graph &v);
//assignment operator
void output(ostream & s) const;
//Prints the graph
void input(istream & s);
//input and creates the graph
Node * find(int id);
//finds the node in the graph
void makePath();
//makes a path through the maze
bool findPath(Node* cur, string room);
//worker function for recursion
void pathOut(ostream & s) const;
//Outputs the found path
void removeTail();
//Removes the last element
void addTail(Node* n, string door);
//Adds the element to the tail
//Mutators
void setId(Node* n ,int x);
void setVisited(Node* n, bool v);
//Elem Mutator
void seteId(Elem* e, int x);
//Elem Accessor
int geteId(Elem* e);
//Accessors
int getId(Node* n);
bool getVisited(Node* n);
};
And my actual code file.
#include <iostream>
#include "graph.h"
using namespace std;
//Constructs empty graph
Graph::Graph()
{
start = 0;
head = tail = 0;
path = 0;
}
//copy constructor
Graph::Graph(const Graph &v)
{
//not implemented
}
//destructor
Graph::~Graph()
{
for(int i = 0; i < arrLen + 1; i++)
{
delete initArr[i];
}
while(head != 0)
{
Elem* p = head;
head = head->next;
delete p;
}
delete[] initArr;
}
//assignment operator
Graph & Graph::operator = (const Graph &v)
{
//not implemented
}
//Prints the graph
void Graph::output(ostream & s) const
{
s<<"Node"<<'\t'<<"North"<<'\t'<<"East"<<'\t'<<"South"<<'\t'<<"West"<<'\n';
for(int i = 1; i < arrLen + 1; i++)
{
Node* temp = initArr[i];
s<<temp->id<<'\t';
if(temp->north != 0)
s<<temp->north->id<<'\t';
else
s<<"--"<<'\n';
if(temp->east != 0)
s<<temp->east->id<<'\t';
else
s<<"--"<<'\n';
if(temp->south != 0)
s<<temp->south->id<<'\t';
else
s<<"--"<<'\n';
if(temp->west != 0)
s<<temp->west->id<<'\t';
else
s<<"--"<<'\n';
s<<'\n';
}
}
//input and creates the graph
void Graph::input(istream & s)
{
int length = 0;
s>>length;
arrLen = length;
if(s)
{
//define array
initArr = new Node*[length + 1];
int temp = 0;
for(int i = 1; i < length + 1; i++)
{
//Create node
s>>temp;
Node* n = new Node;
n->id = temp;
n->visited = false;
//Add to array
initArr[i] = n;
}
//Make Exit Node
Node *x = new Node;
x->id = 0;
x->visited = false;
initArr[0] = x;
//Loop through all of the node input
int tn = 0;
for(int f = 0; f < length; f++)
{
//Set Pointers
s>>tn;
Node* curNode = find(tn);
int n = 0;
int e = 0;
int st = 0;
int w = 0;
s>>n>>e>>st>>w;
curNode->north = find( n );
curNode->east = find( e );
curNode->south = find( st );
curNode->west = find( w );
}
//set Entry point to graph
int last = 0;
s>>last;
start = find(last);
}
}
//finds the node in the array
Node* Graph::find(int id)
{
if( id == 0)
{
return initArr[0];
}
if(id == -1)
{
return 0;
}
else
{
for(int i = 1; i < arrLen + 1; i++)
{
if(initArr[i]->id == id)
{
return initArr[i];
}
}
cerr<<"NOT FOUND IN GRAPH";
return 0;
}
}
//makes a path through the maze
void Graph::makePath()
{
if(findPath(start->north, "north") == true)
{
path = 1;
return;
}
else if( findPath(start->east, "east") == true)
{
path = 1;
return;
}
else if( findPath(start->south, "south") == true)
{
path = 1;
return;
}
else if( findPath(start->west, "west") == true)
{
path = 1;
return;
}
return;
}
//finds a path to the outside
bool Graph::findPath(Node* cur, string room)
{
addTail(cur, room);
if(cur = initArr[0])
{
return true;
}
if(cur->north != 0 && cur->north->visited == false)
{
cur->visited = true;
findPath(cur->north, "north");
}
else if(cur->east != 0 && cur->east->visited == false)
{
cur->visited = true;
findPath(cur->north, "east");
}
else if(cur->south !=0 && cur->south->visited == false)
{
cur->visited = true;
findPath(cur->north, "south");
}
else if(cur->west != 0 && cur->west->visited == false)
{
cur->visited = true;
findPath(cur->north, "west");
}
else
{
cur->visited = false;
removeTail();
}
}
//Outputs the found path
void Graph::pathOut(ostream & s) const
{
if(path == 1)
{
Elem *p;
p = head->next;
while(p != 0)
{
s<<p->id<<"--> "<<p->last;
p= p->next;
}
}
else if(path == 0)
{
}
}
//Removes the last element in the chain
void Graph::removeTail()
{
Elem* temp = 0;
temp = tail;
tail = tail->back;
delete temp;
}
//Adds the element to the tail
void Graph::addTail(Node* n, string door)
{
if(head != 0)
{
Elem* temp = new Elem;
temp->id = n->id;
tail->next = temp;
tail->last = door;
temp->back = tail;
temp->next = 0;
tail = 0;
}
else
{
Elem *p = new Elem;
p->last = "";
p->back = 0;
p->next = 0;
head = p;
tail = p;
}
}
//Mutators
void Graph::setId(Node *n ,int x)
{
n->id = x;
}
void Graph::setVisited(Node *n, bool v)
{
n->visited = v;
}
//Elem Mutator
void Graph::seteId(Elem *e, int x)
{
e->id = x;
}
//Elem Accessor
int Graph::geteId(Elem *e)
{
return e->id;
}
//Accessors
int Graph::getId(Node *n)
{
return n-> id;
}
bool Graph::getVisited(Node *n)
{
return n->visited;
}
/*
//This is a graph with a very smart struct
//This is the main node that makes up the graph.
struct Node {
int id; //int id
Node *north; //north path node
Node *south; //south path node
Node *east; //east path node
Node *west; //went path node
bool visited; // visited bool
};
//this struct holds the path that is found.
struct Elem {
int id; //The id of the node
string last; //the door that it passed through
Elem* back; //back one path
Elem* next; //forward one path
};
Node* Start;
Node ** initArr;
Elem* head;
Elem* tail;
*/
//outputs using named operation
ostream & operator << (ostream &s, const Graph & v)
{
v.output(s);
return s;
}
The error is occurring on the find function.
In the cpp file, Node is not in global scope. It's nested inside Graph as such, you need to qualify it in a return type:
Graph::Node* Graph::find(int id){
// ...
}
Inside the function, you're in the scope of Graph again, as such you do not need to qualify it.
You have both Node and Element defined as structs inside the class Graph. It would be better to define them outside the class Graph. You can define a separate Node class and store the element struct as its private members. The error happens because Node is a private member of Graph, which can be accessed as Graph::Node. E.g. Graph::Node* find(...).