Disjoint set data structure : track size of each tree - c++

Below is my implementation to keep track of the size of each tree in the disjoint set forest.
Can you please tell me what is wrong with it ? I am trying to solve UVa problem https://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=3638
#include <iostream>
#include <cstdio>
#include <unordered_map>
using namespace std;
class Node {
public :
int id;
Node *parent;
unsigned long long rank;
Node(int id) {
this->id = id;
// this->data = data;
this->rank =1; //size here
this->parent = this;
}
friend class DisjointSet;
};
class DisjointSet {
unordered_map<int,Node*> nodesMap;
Node *find_set_helper(Node *aNode) {
if (aNode == aNode->parent) {
return aNode->parent;
}
return find_set_helper(aNode->parent);
}
void link(Node *xNode,Node *yNode) {
if( xNode->rank > yNode->rank) {
yNode->parent = xNode;
xNode->rank += yNode->rank;
}
// else if(xNode-> rank < yNode->rank){
// xNode->parent = yNode;
// yNode->rank += xNode->rank;
// }
else {
xNode->parent = yNode;
yNode->rank += xNode->rank;
}
}
public:
DisjointSet() {
}
void AddElements(int sz) {
for(int i=0;i<sz;i++)
this->make_set(i);
}
void make_set(int id) {
Node *aNode = new Node(id);
this->nodesMap.insert(make_pair(id,aNode));
}
void Union(int xId, int yId) {
Node *xNode = find_set(xId);
Node *yNode = find_set(yId);
if(xNode && yNode)
link(xNode,yNode);
}
Node* find_set(int id) {
unordered_map<int,Node*> :: iterator itr = this->nodesMap.find(id);
if(itr == this->nodesMap.end())
return NULL;
return this->find_set_helper(itr->second);
}
~DisjointSet(){
unordered_map<int,Node*>::iterator itr;
for(itr = nodesMap.begin(); itr != nodesMap.end(); itr++) {
delete (itr->second);
}
}
};
int main() {
int n,m,k,first,cur;
//freopen("in.in","r",stdin);
scanf("%d %d",&n,&m);
while(n != 0 || m != 0) {
DisjointSet *ds = new DisjointSet();
ds->AddElements(n); // 0 to n-1
//printf("\n n = %d m = %d",n,m);
for(int i=1;i<=m;i++) {
scanf("%d",&k);
//printf("\nk=%d",k);
if ( k > 0 ) {
scanf("%d",&first);
for(int j=2;j<=k;j++) {
scanf("%d",&cur);
ds->Union(first,cur);
}
}
}
Node *zeroSet = ds->find_set(0);
// unsigned long long count = ds->getCount(zeroSet->id);
printf("%llu\n",zeroSet->rank);
delete ds;
scanf("%d %d",&n,&m);
}
return 0;
}
The link function in the above code does the job of updating the tree size.
The solution to the problem is to find the set which elements 0 belongs to and get the size of the representative element of the set.
But I am getting wrong answer with this code.
Can you please help me

In your Union function, check if both nodes are already in the same set.
if(xNode && yNode && xNode != yNode)
link(xNode,yNode);

Related

Syntax error for the code found in a tutorial?

I was learning to do a program online and found this solution and I wanted to execute and learn from it.
I am keep getting syntax error, can someone help with formatting it? I tried but couldn't understand the code that much to see where we need to provide indentation etc.,
I couldn't find a python example online for that question, I could only find c++ answer.
class Node {
public:
virtual int Compute() = 0;
inline void SetLeft(Node* left) {
left_ = left;
}
inline void SetRight(Node* right) {
right_ = right;
}
protected:
Node* left_ = nullptr;
Node* right_ = nullptr;
};
class SumNode : public Node {
public:
inline int Compute() override {
return left_->Compute() + right_->Compute();
}
};
class SubNode : public Node {
public:
inline int Compute() override {
return left_->Compute() - right_->Compute();
}
};
class MulNode : public Node {
public:
inline int Compute() override {
return left_->Compute() * right_->Compute();
}
};
class NumNode : public Node {
public:
NumNode(int num) : num_(num) {}
inline int Compute() override {
return num_;
}
private:
int num_;
};
class Solution {
public:
vector<int> diffWaysToCompute(string expression) {
vector<Node*> nodes;
// parse the expression
for(int i = 0; i < expression.size(); ++i) {
switch(expression[i]) {
case '+':
nodes.emplace_back(new SumNode());
break;
case '-':
nodes.emplace_back(new SubNode());
break;
case '*':
nodes.emplace_back(new MulNode());
break;
default:
int num = 0;
while(expression[i] >= '0' && expression[i] <= '9') {
num = num * 10 + expression[i] - '0';
++i;
}
--i;
nodes.emplace_back(new NumNode(num));
break;
}
}
vector<Node*> trees = GenerateAllTrees(nodes, 0, nodes.size() - 1);
for(Node* node : nodes) {
delete node;
}
vector<int> results;
for(Node* tree : trees) {
results.emplace_back(tree->Compute());
delete tree;
}
return results;
}
vector<Node*> GenerateAllTrees(const vector<Node*> nodes, int beg, int end) {
if(beg == end) {
return {new NumNode(nodes[beg]->Compute())};
}
vector<Node*> results;
for(int i = beg; i <= end; i++) {
// assuming the expression is well formed, operators will be in odd positions
if((i & 1) == 0) continue;
vector<Node*> left_trees = GenerateAllTrees(nodes, beg, i - 1);
vector<Node*> right_trees = GenerateAllTrees(nodes, i + 1, end);
for(Node* left : left_trees) {
for(Node* right : right_trees) {
nodes[i]->SetLeft(left);
nodes[i]->SetRight(right);
Node* result = new NumNode(nodes[i]->Compute());
results.emplace_back(result);
}
}
for(Node* t : left_trees) {
delete t;
}
for(Node* t : right_trees) {
delete t;
}
}
return results;
}
};
You just need to import the modules you are using, exactly like Python, except the syntax is different:
#include <vector>
#include <string>
using namespace std;
class Node {
public:
...
And because it is using emplace_back, if you are using g++, you'll need to specify -std=c++11 on the command line.
Also, you need to understand this is not a runnable example. These are just classes you could use in your own code. To run this, you'll need to supply a main() function. Maybe:
#include <iostream>
int main()
{
Solution s;
vector<int> result = s.diffWaysToCompute( "3+9*7-16" );
for( auto i : result )
cout << i << "\n";
}

shared_ptrs and memory leaks

I had a project to do in C++ (moreover, I had to use some stuff from C++11, specifically: custom iterators, smart pointers and chrono) which constructs suffix tree for specific string. When it comes down to constructing a tree, I think I did a good job - I have a proper tree, construction times and search times are looking rather good and there's not a single problem with this. However, I know I messed up with my TNode struct - I didn't use weak_ptrs, therefore in my tree class I had to build up hugeass destructor walking on every node and forcibly erasing any connections.
Anyway, I used Deleaker to check for possible memory leaks. There were none for "abracadabra" word. Unfortunately, it found some leaks for "lorem ipsum (...)". Most of them are linked with creating new nodes and I fail to understand where my problem is. I simply don't get it - it appears that every node is destructed when program is ending. Where did I make mistake?
Node.h:
#pragma once
#include <algorithm>
#include <vector>
#include <memory>
#include <Windows.h>
#define INF 1<<30
struct TNode : public std::enable_shared_from_this<TNode>{
long int indexStart;
long int indexEnd;
std::vector<std::shared_ptr<TNode>> children;
std::shared_ptr<TNode> suffixLink;
int count;
TNode(long int pIndexStart, int pCount) {
indexStart = pIndexStart;
indexEnd = INF;
children.clear();
suffixLink = nullptr;
count = pCount;
}
~TNode() {
//OutputDebugString(L"node dies\n");
}
int EdgeLength(long int pos) {
return min(indexEnd, pos+1) - indexStart;
}
};
tree.h
#pragma once
#include <memory>
#include <vector>
#include "IChildIterator.h"
#include "Node.h"
class CTree
{
public:
CTree();
~CTree();
void LoadString(std::string* newString);
void CreateTree();
bool FindPhrase(std::string* toFind);
void PrintSuffix(std::vector<long> indexes);
std::shared_ptr<TNode> GetRoot();
private:
std::shared_ptr<TNode> root;
std::shared_ptr<TNode> activeNode;
long int activeEdge;
long int activeLength;
std::string* string;
std::shared_ptr<TNode> lastAddedNode;
long int position;
long int remainder;
int count;
void AddSuffixLink(std::shared_ptr<TNode> node);
bool WalkDown(std::shared_ptr<TNode> node);
void ExtendTree();
char GetActiveEdge();
};
tree.cpp
#include "stdafx.h"
#include "Tree.h"
CTree::CTree()
{
std::shared_ptr<TNode> nowy(new TNode(-1, -1));
root = activeNode = nowy;
activeEdge = activeLength = 0;
lastAddedNode = nowy;
position = -1;
remainder = 0;
count = 0;
string = nullptr;
}
CTree::~CTree()
{
if (string) {
delete string;
}
std::vector<IChildIterator> iterstack;
iterstack.resize(0);
IChildIterator child(root, true);
while (true) {
if (0 == (*child)->children.size()) {
if (iterstack.size() == 0)
break;
child = iterstack.back();
iterstack.pop_back();
(*child)->children.erase((*child)->children.begin());
child++;
continue;
}
if ((*child)->children.front()->indexEnd != INF) {
iterstack.push_back(child);
child = IChildIterator(*child);
continue;
}
std::shared_ptr<TNode> temp = (*child)->children.front();
if (temp->suffixLink) temp->suffixLink = nullptr;
(*child)->children.erase((*child)->children.begin());
}
OutputDebugString(L"tree dies\n");
}
void CTree::LoadString(std::string* newString)
{
string = new std::string(*newString);
}
void CTree::CreateTree()
{
for (int i = 0; i < string->size(); i++) {
ExtendTree();
}
}
std::shared_ptr<TNode> CTree::GetRoot()
{
return root;
}
void CTree::AddSuffixLink(std::shared_ptr<TNode> node)
{
if (lastAddedNode) lastAddedNode->suffixLink = node;
lastAddedNode = node->shared_from_this();
}
bool CTree::WalkDown(std::shared_ptr<TNode> node)
{
if (activeLength >= node->EdgeLength(position)) {
activeEdge += node->EdgeLength(position);
activeLength -= node->EdgeLength(position);
activeNode = node;
return true;
}
return false;
}
void CTree::ExtendTree()
{
++position;
lastAddedNode = nullptr;
remainder++;
while (remainder > 0) {
if (activeLength == 0) activeEdge = position;
std::shared_ptr<TNode> selected = nullptr;
for each (std::shared_ptr<TNode> child in activeNode->children) {
if (string->at(child->indexStart) == GetActiveEdge()) {
selected = child;
break;
}
}
if (!selected) {
std::shared_ptr<TNode> newLeaf(new TNode(position, count++));
activeNode->children.push_back(newLeaf);
AddSuffixLink(activeNode);
}
else {
if (WalkDown(selected)) continue;
if (string->at(selected->indexStart + activeLength) == string->at(position)) {
activeLength++;
AddSuffixLink(activeNode);
break;
}
//split
if (selected->children.size() > 0) {
long lastStart = selected->indexStart;
selected->indexStart = selected->indexStart + activeLength;
std::shared_ptr<TNode> newNode(new TNode(lastStart, count++));
newNode->indexEnd = selected->indexStart;
newNode->children.push_back(selected);
std::shared_ptr<TNode> yetAnotherNewLeaf(new TNode(position, count++));
newNode->children.push_back(yetAnotherNewLeaf);
std::vector<std::shared_ptr<TNode>>::iterator iter;
iter = activeNode->children.begin();
while (true) {
if (*iter == selected) {
activeNode->children.insert(iter, newNode);
iter = activeNode->children.begin();
while (true) {
if (*iter == selected) {
activeNode->children.erase(iter);
break;
}
iter++;
}
break;
}
iter++;
}
AddSuffixLink(newNode);
}
else {
selected->indexEnd = selected->indexStart + activeLength;
std::shared_ptr<TNode> newLeaf(new TNode(selected->indexEnd, count++));
selected->children.push_back(newLeaf);
std::shared_ptr<TNode> yetAnotherNewLeaf(new TNode(position, count++));
selected->children.push_back(yetAnotherNewLeaf);
AddSuffixLink(selected);
}
}
remainder--;
if (activeNode == root && activeLength > 0) {
activeLength--;
activeEdge = position - remainder + 1;
}
else {
if (activeNode->suffixLink) {
activeNode = activeNode->suffixLink;
}
else {
activeNode = root;
}
}
}
}
char CTree::GetActiveEdge()
{
return string->at(activeEdge);
}
Memory leaks:
during creation of every new node in ExtendTree() method
tree constructor
on line
iter = activeNode->children.begin();
I'd be grateful for any kind of tip how to fix this.
There's a potential leak when calling LoadString:
void CTree::LoadString(std::string* newString)
{
string = new std::string(*newString);
}
This function does not delete previously allocated string.
Your method for creating shared_ptr objects is also odd. This shouldn't necessarily cause memory leaks but it's very strange to behold. You are, for example, doing this:
std::shared_ptr<TNode> newLeaf(new TNode(position, count++));
When you should be doing this:
std::shared_ptr<TNode> newLeaf = std::make_shared<TNode>(position, count++)

AVL Tree Memory issues with destructor

I'm trying to implement AVL Tree in C++, but I'm stuck with the insertion, I have changed some things but nothing seemed to effectively solve the problem. I used Xcode's Address Sanitizer and I'm getting that error after inserting a second element into the tree:
Thread 1: Use of deallocated memory detected.
==3822==ERROR: AddressSanitizer: heap-use-after-free on address.....
This is the implementation of the tree so far:
RoadTree.hpp
#ifndef RoadTree_hpp
#define RoadTree_hpp
#include "Road.hpp"
class RoadTree {
private:
struct TreeNode {
Road *key;
TreeNode *rightChild;
TreeNode *leftChild;
int height;
TreeNode() : key(NULL), rightChild(NULL), leftChild(NULL), height(0) { }
TreeNode(Road *r) : key(r), rightChild(NULL), leftChild(NULL), height(0) { }
};
TreeNode *root;
int numberOfRoads;
int GetHeight(TreeNode *n) const;
void SimpleRightRotation(TreeNode *&n);
void DoubleRightRotation(TreeNode *&n);
void SimpleLeftRotation(TreeNode *&n);
void DoubleLeftRotation(TreeNode *&n);
void Insert(TreeNode *&n, Road *r);
void ClearTree(TreeNode *&n);
void PreOrder(TreeNode *n) const;
public:
RoadTree();
~RoadTree();
void Insert(Road *r);
Road *FindRoad(string destination);
void ListRoads();
void ClearTree();
void PreOrder();
inline int RoadCount() {
return numberOfRoads;
}
};
#endif /* RoadTree_hpp */
RoadTree.cpp
#include "RoadTree.hpp"
RoadTree::RoadTree() : root(NULL), numberOfRoads(0) { }
RoadTree::~RoadTree() {
ClearTree(root);
}
void RoadTree::Insert(Road *r) {
Insert(root, r);
}
int RoadTree::GetHeight(TreeNode *n) const {
if (n == NULL)
return -1;
else
return n->height;
}
void RoadTree::SimpleRightRotation(TreeNode *&n) {
TreeNode *tempNode = n->rightChild;
n->rightChild = tempNode->leftChild;
tempNode->leftChild = n;
n->height = 1 + max(GetHeight(n->leftChild), GetHeight(n->rightChild));
n = tempNode;
tempNode->height = 1 + max(n->height, GetHeight(tempNode->rightChild));
}
void RoadTree::DoubleRightRotation(TreeNode *&n) {
SimpleLeftRotation(n->rightChild);
SimpleRightRotation(n);
}
void RoadTree::SimpleLeftRotation(TreeNode *&n) {
TreeNode *tempNode = n->leftChild;
n->leftChild = tempNode->rightChild;
tempNode->rightChild = n;
n->height = 1 + max(GetHeight(n->leftChild), GetHeight(n->rightChild));
n = tempNode;
tempNode->height = 1 + max(n->height, GetHeight(n->leftChild));
}
void RoadTree::DoubleLeftRotation(TreeNode *&n) {
SimpleRightRotation(n->leftChild);
SimpleLeftRotation(n);
}
void RoadTree::ClearTree(TreeNode *&n) {
if (n != NULL) {
ClearTree(n->rightChild);
ClearTree(n->leftChild);
delete n;
}
n = NULL;
}
void RoadTree::Insert(TreeNode *&n, Road *r) {
if (n == NULL) {
n = new TreeNode(r);
numberOfRoads++;
} else {
if (r->GetDestination() < n->key->GetDestination()) {
Insert(n->leftChild, r);
if ((GetHeight(n->leftChild) - GetHeight(n->rightChild)) == 2) {
if (r->GetDestination() < n->leftChild->key->GetDestination())
SimpleLeftRotation(n);
else
DoubleLeftRotation(n);
}
} else if (r->GetDestination() > n->key->GetDestination()) {
Insert(n->rightChild, r);
if ((GetHeight(n->rightChild) - GetHeight(n->leftChild)) == 2) {
if (r->GetDestination() > n->rightChild->key->GetDestination())
SimpleRightRotation(n);
else
DoubleRightRotation(n);
}
} else if (r->GetDestination() == n->key->GetDestination())
n->key->SetRoad(r->GetDestination(), r->GetCost(), r->GetInfo());
}
n->height = 1 + max(GetHeight(n->leftChild), GetHeight(n->rightChild));
}
Road *RoadTree::FindRoad(string destination) {
TreeNode *n = root;
while (n != NULL) {
string current = n->key->GetDestination();
if (destination < current)
n = n->leftChild;
else if (destination > current)
n = n->rightChild;
else if (destination == current)
return n->key;
}
return NULL;
}
void RoadTree::PreOrder(TreeNode *n) const {
if (n != NULL) {
cout << " " << n->key->GetDestination() << " ";
PreOrder(n->leftChild);
PreOrder(n->rightChild);
}
}
void RoadTree::PreOrder() {
PreOrder(root);
}
void RoadTree::ListRoads() {
}
void RoadTree::ClearTree() {
ClearTree(root);
}
And this is the implementation of Road:
Road.hpp
#ifndef Road_hpp
#define Road_hpp
#include <iostream>
using namespace std;
class Road {
private:
string destination;
int cost;
string info;
public:
Road();
Road(string destination, int cost, string info);
inline string GetDestination() {
return destination;
}
inline int GetCost() {
return cost;
}
inline string GetInfo() {
return info;
}
};
#endif /* Road_hpp */
Road.cpp
#include "Road.hpp"
Road::Road() {
destination = "";
cost = 0;
info = "";
}
Road::Road(string destination, int cost, string info) {
this->destination = destination;
this->cost = cost;
this->info = info;
}
The only way I can insert more than 1 element is leaving the destructor blank, then no error shows, so I don't know what's causing it to fail. The error is showing up at the Insertion method, in the line that compares the elements in order to advance in the tree.
Update: Since this is part of a bigger project, I'm almost 100% sure that the problem isn't from the tree's implementation (I put the tree and Road class in a separate project and everything worked as intended). The full project has a class called Place, it has a name and info, as well as an AVL Tree for each place (where I store the place's roads). Those places are stored in a Hash Table (that I have implemented myself).
This is the implementation of the Place class:
Place.hpp
#ifndef Place_hpp
#define Place_hpp
#include <iostream>
#include "Road.hpp"
#include "RoadTree.hpp"
using namespace std;
class Place {
private:
string name;
string info;
RoadTree adjacentRoads;
public:
Place();
Place(string name, string info);
void InsertRoad(Road *r);
Road *FindRoad(string destination);
void ListRoads();
inline string GetName() {
return name;
}
inline string GetInfo() {
return info;
}
inline void SetPlace(string newName, string newInfo) {
name = newName;
info = newInfo;
}
inline void Write() {
cout << name << endl;
cout << "Info: " << info << endl;
}
};
Place.cpp
#include "Place.hpp"
Place::Place() {
name = "";
info = "";
}
Place::Place(string name, string info) {
this->name = name;
this->info = info;
}
void Place::InsertRoad(Road *r) {
adjacentRoads.Insert(r);
}
Road *Place::FindRoad(string destination) {
return adjacentRoads.FindRoad(destination);
}
void Place::ListRoads() {
adjacentRoads.ListRoads();
}
This is how I get a pointer from the Hash Table (if the full code is needed tell me):
Place *HashTable::Find(string key) {
unsigned long hashedKey = HashFunction(key);
list<Place>::iterator current;
for (current = table[hashedKey].begin(); current != table[hashedKey].end(); current++) {
Place currentPlace = *current;
if (currentPlace.GetName() == key)
return &*current;
}
return NULL;
}
And this is an example of a main that gives me the Thread 1: Use of deallocated memory detected. error
int main(int argc, const char * argv[]) {
//Declare a HashTable to store Places
HashTable map;
//Declare some places
Place p1("Murcia", "10");
Place p2("Lorca", "11");
Place p3("Cartagena", "12");
Place p4("Zaragoza", "13");
Place p5("Madrid", "14");
Place p6("Galicia", "15");
//Insert those places into the HashTable
map.Insert(p1);
map.Insert(p2);
map.Insert(p3);
map.Insert(p4);
map.Insert(p5);
map.Insert(p6);
//Declare some roads
Road *r1 = new Road(p2.GetName(), 20, "asdgasdg");
Road *r2 = new Road(p3.GetName(), 61, "asdgsw2");
//Get a pointer of a place from the HashTable to insert roads in it
Place *p1f = map.Find(p1.GetName());
//Check if it's not null, if it's not then insert the first road,
//get a pointer of it and print the name
if (p1f != NULL) {
p1f->InsertRoad(r1);
Road *r1f = p1f->FindRoad(p2.GetName());
cout << r1f->GetDestination() << endl;
}
//Get pointer of a place again (each time you want to insert a road
//in a place you must get it's pointer from the HashTable
Place *p2f = map.Find(p1.GetName());
//Checks again and insert second road, then throws error after that
if (p2f != NULL) {
p2f->InsertRoad(r2);
Road *r2f = p1f->FindRoad(p3.GetName());
cout << r2f->GetDestination() << endl;
}
return 0;
Update 2: Added HashTable implementation
HashTable.hpp
#ifndef HashTable_hpp
#define HashTable_hpp
#include "Place.hpp"
#include <list>
class HashTable {
private:
list<Place> *table;
int numberOfEntries;
int currentTableSize;
float maxLoadFactor;
unsigned int HashFunction(string key);
bool LoadFactorExceeded();
void ResizeTable();
bool IsPrime(int number);
int NextPrime(int number);
public:
HashTable();
~HashTable();
void Insert(Place p);
Place *Find(string key);
void EmptyTable();
void ListPlaces();
inline int Count() {
return numberOfEntries;
}
};
#endif /* HashTable_hpp */
HashTable.cpp
#include "HashTable.hpp"
#include <algorithm>
const int START_SIZE = 101;
HashTable::HashTable() {
table = new list<Place>[START_SIZE];
numberOfEntries = 0;
maxLoadFactor = 2.0f;
currentTableSize = START_SIZE;
for (int i = 0; i < START_SIZE; i++) {
table[i].clear();
}
}
HashTable::~HashTable() {
delete [] table;
}
unsigned int HashTable::HashFunction(string key) {
unsigned long hashValue = 0;
for (int i = 0; i < key.length(); i++)
hashValue = 47 * hashValue + key[i];
return (hashValue % currentTableSize);
}
bool HashTable::LoadFactorExceeded() {
float currentLoadFactor = numberOfEntries / currentTableSize;
if (currentLoadFactor > maxLoadFactor)
return true;
else
return false;
}
void HashTable::ResizeTable() {
list<Place> *oldTable = table;
int oldTableSize = currentTableSize;
currentTableSize *= 2;
currentTableSize = NextPrime(currentTableSize);
table = new list<Place>[currentTableSize];
for (int i = 0; i < currentTableSize; i++)
table[i].clear();
numberOfEntries = 0;
for (int i = 0; i < oldTableSize; i++) {
list<Place>::iterator current;
for (current = oldTable[i].begin(); current != oldTable[i].end(); current++)
Insert(*current);
}
delete [] oldTable;
}
bool HashTable::IsPrime(int number) {
if (number % 2 == 0 || number % 3 == 0)
return false;
int divisor = 6;
while (divisor * divisor - 2 * divisor + 1 <= number) {
if (number % (divisor - 1) == 0)
return false;
if (number % (divisor + 1) == 0)
return false;
divisor += 6;
}
return true;
}
int HashTable::NextPrime(int number) {
while (!IsPrime(++number)) {}
return number;
}
void HashTable::Insert(Place p) {
unsigned long hashedKey = HashFunction(p.GetName());
list<Place>::iterator current = table[hashedKey].begin();
if (!table[hashedKey].empty()) {
for (current = table[hashedKey].begin(); current != table[hashedKey].end(); current++) {
Place &currentPlace = *current;
if (currentPlace.GetName() == p.GetName()) {
currentPlace.SetPlace(p.GetName(), p.GetInfo());
break;
} else if (current == --table[hashedKey].end()) {
table[hashedKey].push_back(p);
numberOfEntries++;
}
}
} else {
table[hashedKey].push_back(p);
numberOfEntries++;
}
if (LoadFactorExceeded())
ResizeTable();
}
Place *HashTable::Find(string key) {
unsigned long hashedKey = HashFunction(key);
list<Place>::iterator current;
for (current = table[hashedKey].begin(); current != table[hashedKey].end(); current++) {
Place currentPlace = *current;
if (currentPlace.GetName() == key)
return &*current;
}
return NULL;
}
void HashTable::EmptyTable() {
for (int i = 0; i < currentTableSize; i++) {
table[i].clear();
}
table = new list<Place>[START_SIZE];
numberOfEntries = 0;
currentTableSize = START_SIZE;
}
void HashTable::ListPlaces() {
list<string> places;
for (int i = 0; i < currentTableSize; i++) {
list<Place>::iterator current;
for (current = table[i].begin(); current != table[i].end(); current++)
places.push_back(current->GetName());
}
places.sort();
for (list<string>::iterator current = places.begin(); current != places.end(); current++)
cout << *current << endl;
cout << "Total: " << numberOfEntries << " lugares" << endl;
}
What could be causing the problem?
I'm not sure if this is it, but I noticed something: it looks like a linked list, and your recursive ClearTree function will attempt to free items repeatedly:
void RoadTree::ClearTree(TreeNode *&n) {
if (n != NULL) {
ClearTree(n->rightChild);
ClearTree(n->leftChild);
delete n;
}
n = NULL;
}
Assuming there are 2 elements in the list, and we call it with the first element:
ClearTree( firstElement );
It will then first
ClearTree(n->rightChild); // 2nd element
which in turn will first call
ClearTree(n->rightChild); // non-existing 3rd element: NOP
and proceed with
ClearTree(n->leftChild); // first element again
Maybe if you didn't get the error, this would recurse until you get a stack overflow?
You could simply remove the call to ClearTree(n->leftChild) to fix it; the function will recurse across the rightChild until it reaches the end, then delete the nodes from last to first when it backtracks.
Perhaps it's better to just iterate over the list: (untested, hope this works)
TreeNode * cur = n;
while ( cur != NULL )
TreeNode * next = n->rightChild;
delete cur;
cur = next;
}
n = NULL;
UPDATE
I've found the problem. Here's my debug output:
> g++ -O0 -g *cpp && gdb ./a.out
(gdb) r
Starting program: /home/kenney/roadtree/a.out
= INITIALIZING PLACES =
--> RoadTree[0x7fffffffe1a0] CONSTRUCTOR root: 0
--> RoadTree[0x7fffffffe1c0] CONSTRUCTOR root: 0
--> RoadTree[0x7fffffffe1e0] CONSTRUCTOR root: 0
--> RoadTree[0x7fffffffe200] CONSTRUCTOR root: 0
--> RoadTree[0x7fffffffe220] CONSTRUCTOR root: 0
--> RoadTree[0x7fffffffe240] CONSTRUCTOR root: 0
= INSERTING PLACES =
<-- RoadTree[0x7fffffffe340] DESTRUCTOR! root: 0
<-- RoadTree[0x7fffffffe360] DESTRUCTOR! root: 0
<-- RoadTree[0x7fffffffe380] DESTRUCTOR! root: 0
<-- RoadTree[0x7fffffffe3a0] DESTRUCTOR! root: 0
<-- RoadTree[0x7fffffffe3c0] DESTRUCTOR! root: 0
<-- RoadTree[0x7fffffffe3e0] DESTRUCTOR! root: 0
= CREATING ROADS =
These are the p1..p6 and the map.Insert(p1..p6). There's already a hint that something is wrong. Next this code is run:
cout << "= p1 =\n";
Place *p1f = map.Find(p1.GetName());
cout << "found " << p1f << " for " << p1.GetName() << "\n";
Producing this debug output:
= p1 =
<-- RoadTree[0x7fffffffe110] DESTRUCTOR! root: 0
found 0x6098f0 for Murcia
Then,
if (p1f != NULL) {
p1f->InsertRoad(r1);
Road *r1f = p1f->FindRoad(p2.GetName());
cout << r1f->GetDestination() << endl;
}
outputting this debug from RoadTree::Insert, indicating that the first if statement's 'then' is executed, assigning a new TreeNode to n:
n null, allocating.
--> TreeNode[0x609ad0] CONSTRUCTOR
allocated TreeNode 0x609ad0 key: 0x609a60 dest: Lorca
Lorca
So far so good, now the same again for p2. First the output of map.Find:
= p2 =
FINDING Murcia
<-- RoadTree[0x7fffffffe110] DESTRUCTOR! root: 0x609ad0
!!! RoadTree::ClearTree:: delete 0x609a60
<-- TreeNode[0x609ad0] DESTRUCTOR
found 0x6098f0 for Murcia
Next we continue to p2f->InsertRoad(r2); which is basically Place.adjacentroads.Insert aka RoadTree.insert:
n not null: 0x609ad0 key: 0x609af0
Note the address of n: this is the deleted TreeNode.
Here, the 'else' of the 'if' in RoadTree::Insert is taken since n != NULL:
if (r->GetDestination() < n->key->GetDestination()) {
is executed, causing:
Program received signal SIGSEGV, Segmentation fault.
0x00007ffff7b9126b in std::basic_string<char, std::char_traits<char>, std::allocator<char> >::basic_string(std::string const&) ()
from /usr/lib/x86_64-linux-gnu/libstdc++.so.6
(gdb) bt
#0 0x00007ffff7b9126b in std::basic_string<char, std::char_traits<char>, std::allocator<char> >::basic_string(std::string const&) ()
from /usr/lib/x86_64-linux-gnu/libstdc++.so.6
#1 0x00000000004046b3 in Road::GetDestination (this=0x609af0) at Road.hpp:20
#2 0x0000000000405121 in RoadTree::Insert (this=0x609900, n=#0x609900: 0x609ad0, r=0x609ab0) at RoadTree.cpp:75
#3 0x0000000000404c0d in RoadTree::Insert (this=0x609900, r=0x609ab0) at RoadTree.cpp:15
#4 0x0000000000404845 in Place::InsertRoad (this=0x6098f0, r=0x609ab0) at Place.cpp:14
#5 0x000000000040401d in main (argc=1, argv=0x7fffffffe5f8) at main.cpp:63
(gdb)
The fault is apparent in the n->key->GetDestination() which attempts to return a copy of a string that is already deleted, causing a segfault because some pointers are already overwritten.
The problem is in HashTable::Find, which does this:
Place currentPlace = *current;
if (currentPlace.GetName() == key)
return &*current;
which constructs a Place copy on the stack that gets destroyed when the method returns. The private fields of Place also get destroyed, including the string name, which was attempted to be returned by Road::GetDestination().
Replacing it with this with this solves it:
if (current->GetName() == key)
return &*current;
I'm not sure this is the only fix needed, but it's a step.

Endless loop recording string

The code should create a doubly linked list. THen a list of IP adresses should be added to this list with the number of times the unique IP is met. Then the list should be sorted. TO my sorry, the code is cycled somewhere when it's recorded. Highlighted the place in bold (tried to do that:)).
P.S. I would be pleased if you'll help me with sort method selection. I've already made one, but what would be better to use quicksort or something else?
#include <stdlib.h>
#include <iostream>
#include <stdio.h>
using namespace std;
struct IP
{
char b[20];
int count;
};
struct Node
{
IP a;
Node *Next,*Prev;
};
struct List
{
Node *Head,*Tail;
int length;
List():Head(NULL),Tail(NULL){};
};
List* list_new()
{
return (List *)calloc(1, sizeof(List));
}
void list_delete(List* l)
{
while (l->Head)
{
l->Tail=l->Head->Next;
free (l->Head);
l->Head=l->Tail;
}
l->length=0;
}
bool push(List* l, IP a)
{
Node *temp=(Node* ) calloc (1, sizeof(Node));
temp->Next=NULL;
temp->a=a;
if (l->Head!=NULL)
{
temp->Prev=l->Tail;
l->Tail->Next=temp;
l->Tail=temp;
}
else
{
temp->Prev=NULL;
l->Head=l->Tail=temp;
}
return 1;
}
bool pop(List*l, IP* x)
{
(*x)=l->Tail->a;
l->Tail->Prev->Next=NULL;
l->Tail=l->Tail->Prev;
l->length++;
return 1;
}
bool unshift(List*l, IP a)
{
Node *temp=(Node* ) calloc (1, sizeof(Node));
temp->Next=NULL;
temp->a=a;
if (l->Head!=NULL)
{
temp->Next=l->Head;
l->Head->Prev=temp;
l->Head=temp;
}
else
{
temp->Prev=NULL;
l->Head=l->Tail=temp;
}
return 1;
}
bool shift(List* l, IP* x)
{
(*x)=l->Head->a;
l->Head->Next->Prev=NULL;
l->Head=l->Head->Next;
return 1;
}
bool reverse (List* l)
{
Node* temp=l->Head;
Node* swaps=NULL;
l->Tail=l->Head;
while (temp!=NULL)
{
swaps=temp->Prev;
temp->Prev=temp->Next;
temp->Next=swaps;
temp=temp->Prev;
}
if (swaps != NULL) l->Head = swaps->Prev;
return 1;
}
void sort (List* l)
{
int i;
for (i=0; i<l->length; ++i) {
Node* compared = l->Head;
while (compared->Next != NULL) {
if (compared->Next->a.count > compared->a.count) {
IP t = compared->Next->a;
compared->Next->a = compared->a;
compared->a = t;
}
compared = compared->Next;
}
}
}
void Show(List* l)
{
int i;
Node* temp=l->Head;
while (temp!=NULL)
{
cout<<temp->a.b<<" "<<temp->a.count<<"\n";
temp=temp->Next;
}
cout<<"\n";
}
int main ()
{
int i;
char strbuf[1000],chTemp;
IP ipTemp;
bool met;
system("CLS");
List* l = list_new();
FILE* foo;
errno_t err;
err=fopen_s(&foo,"input.txt","r");
if( err == 0 )
{
printf( "The file 'input.txt' was opened\n" );
}
else
{
printf( "The file 'input.txt' was not opened\n" );
}
while (!feof(foo))
{
fgets(strbuf,1000,foo);
fclose(foo);
for (i=0;i++;i<20)
if (strbuf[i]==' ') {strncpy_s( ipTemp.b,strbuf, i);break;}
Node* cur = l->Head;
met=0;
while (cur!=NULL)
{
if (cur->a.b == ipTemp.b)
{
met=1;
cur->a.count++;
break;
}
cur=cur->Next;
}
if (met==0)
{
push(l,ipTemp);
l->Tail->a.count++;
}
}
sort(l);
Show(l);
system("PAUSE");
}
If the code had a cleaner indentation, you would maybe realize that the logic is wrong:
while (!feof(foo))
{
fgets(strbuf,1000,foo); // <-- what if fgets hits EOF or error occurs?
fclose(foo); // <-- why?
for (i = 0; i++; i < 20) // <-- i++ is always true ~> infinite loop
....
...
}
should be (assuming you want to write code in C):
while (fgets(strbuf, 1000, foo))
{
for (i = 0; i < 20; i++)
....
...
}
for (i=0;i++;i<20) should be for (i=0;i<20;i++)

Dijkstra's Algorithm issue [repost]

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.)