I wrote a program in C++ for hashing using linear probing. The code is showing no error at the time of compilation but when I run it, computer shows the notification that the program has stopped working. I am giving the entire code below. Please help me out.
#include<iostream>
#include<vector>
using namespace std;
class Acc
{
public:
int iData;
double dData;
Acc(int id,double dd)
{
iData = id;
dData = dd;
}
void displayAcc()
{
cout<<"iData = "<<iData<<"\n";
cout<<"dData = "<<dData<<"\n";
}
};
class Linear_Hash
{
private:
vector<Acc*> hashArray;
int nElem;
Acc* noElem;
public:
Linear_Hash(int max)
{
nElem = max;
hashArray.resize(nElem);
noElem = new Acc(-1,1.1);
for(int i = 0;i<max;i++)
{
hashArray[i] = NULL;
}
}
int hashfunc(int key)
{
return key%nElem;
}
void insertAcc(int id,double dd)
{
Acc* newacc = new Acc(id,dd);
int hashVal = hashfunc(id);
while(hashArray[hashVal]->iData!=-1&&hashArray[hashVal]!=NULL)
{
hashVal++;
hashVal = hashVal%nElem;
}
hashArray[hashVal] = newacc;
}
Acc* search(int key)
{
int hashVal = key%nElem;
while(hashArray[hashVal]->iData!=key&&hashArray[hashVal]!=NULL)
{
hashVal++;
hashVal = hashVal%nElem;
}
if(hashArray[hashVal]->iData==key)
{
return hashArray[hashVal];
}
else
return NULL;
}
bool deleteAcc(int key)
{
int hashVal = hashfunc(key);
while(hashArray[hashVal]->iData!=key&&hashArray[hashVal]!=NULL)
{
hashVal++;
hashVal = hashVal%nElem;
}
if(hashArray[hashVal]==NULL)
return false;
else
{
Acc* pTemp = hashArray[hashVal];
hashArray[hashVal] = noElem;
delete pTemp;
return true;
}
}
};
int main(void)
{
int key;
char val;
Linear_Hash lh(20);
lh.insertAcc(100,100.1);
lh.insertAcc(204,204.204);
lh.insertAcc(105,105.10);
lh.insertAcc(237,348.23);
lh.insertAcc(209,923.23);
lh.insertAcc(230,230.23);
lh.insertAcc(403,348.34);
lh.insertAcc(405,938.50);
lh.insertAcc(450,348.23);
lh.insertAcc(945,495.409);
while(val!='x')
{
cout<<"Enter the key to be searched\n";
cin>>key;
if(lh.search(key)==NULL)
cout<<key<<" could not be found\n";
else
lh.search(key)->displayAcc();
cout<<"Enter the key to be deleted\n";
cin>>key;
if(lh.deleteAcc(key))
cout<<key<<" has been deleted\n";
else
cout<<"Invalid request\n";
cout<<"Do you want to continue\n";
cin>>val;
}
return 0;
}
I am unable to use the debugger in this case as I don't know where the error is. I have also tried dry-running it on paper but wasn't able to pin point the bug.
Near the top of main you do this:
Linear_Hash lh(20);
lh.insertAcc(100,100.1);
The first line sets up the vector:
for(int i = 0;i<max;i++)
{
hashArray[i] = NULL;
}
So, before the second line you have a vector of NULLs.
The second line then does this:
Acc* newacc = new Acc(id,dd);
int hashVal = hashfunc(id);
while(hashArray[hashVal]->iData ...
So, hashArray contains NULLS, then you try to look at hashArray[hashVal]->iData i.e.
NULL->iData
You should check hashArray[hashVal]!=NULL before you try to do anything with it.
Related
I need some help, I'm learing data structers and I got a task to write a programm based on array of pointers to structres which can add elements and do other task with array.I have next model of levels:
first level --> net of shops
second level --> shop
third level --> goods
I've written types for this
typedef struct
{
QString date;
QString prod_code;
QString name;
}goods;
typedef struct
{
QString address;
QString number;
void **sublevel;
}shop;
typedef struct
{
QString website;
QString name;
QString owner;
QString address;
void **sublevel;
}net;
Then I've created global variable void **Start which points to array of pointers:
// init list
void ** init_list()
{
void** p = new void*[SIZE_AR];
p = p+2;
((int*)p)[COUNT_POS] = 0;
((int*)p)[SIZE_POS] = SIZE_AR;
return p;
}
void ** Start = init_list();
COUNT_POS - index of elements where I store count of currently used elemnets
SIZE_POS - size of array allocated in dynamic memory
SIZE_AR - default size for array
But I get segmentation fault when I try to add to element to the last level
(for previous two ones works fine):
// expand array if it overfilled
void ExpandArrPtr (void **&ar, int &SizeAr, int Cnt)
{
void **arW;
arW = new void*[SizeAr+DELTA+2];
for (int K = SizeAr-1; K >= 0; K--) {
arW[K+2] = ar[K];
}
SizeAr = SizeAr + DELTA;
ar=ar-2;
delete []ar;
ar=arW+2;
((int*)ar)[COUNT_POS] = Cnt;
((int*)ar)[SIZE_POS] = SizeAr;
}
// binary search
void bin_search(void **start, QString key, int &pos, bool &find, Cmpmethod func)
{
int mid;
int high, low;
find = false;
if((int*)start[COUNT_POS] == 0)
{
pos = 0;
qDebug()<<"zero elem\n";
return;
}
low = 0;
high = ((int*)start)[COUNT_POS] - 1;
do
{
mid = (high + low) / 2;
int result = func(start[mid], key);
if(result == 0)
{
pos = mid;
find = true;
return;
}
else if(result == 1)
{
high = mid - 1;
}
else
{
low = mid + 1;
}
}while(low <= high);
pos = low;
}
// function for adding in any level
void addtosort(void **&start, void *pnew, int pos)
{
int count = ((int*)start)[COUNT_POS];
int size = ((int*)start)[SIZE_POS];
if(count == size)
{
ExpandArrPtr(start, size, count);
}
if(pos == count)
{
start[pos] = pnew;
}
else
{
for(int i = count;i >= pos;i--)
{
start[i+1] = start[i];
}
start[pos] = pnew;
}
count++;
((int*)start)[COUNT_POS] = count;
}
void add_goods(void **&Start, goods * Pnew)
{
int pos;
bool find;
bin_search((((shop*)(Start))->sublevel), Pnew->name, pos, find, compare_goods);
addtosort((((shop*)(Start))->sublevel), Pnew, pos);
}
// finding the item in second level to add
void find_place(QString key)
{
int pos;
bool find;
int count = ((int*)Start)[COUNT_POS];
for(int i = 0;i < count;i++)
{
bin_search(((net*)(Start)[i])->sublevel, key, pos, find, compare_shop);
if(find)
{
goods * Pnew = new goods;
Pnew->date = "foo"
Pnew->name = "bar"
add_goods(((net*)(Start)[pos])->sublevel, Pnew);
break;
}
}
}
What can cause such problem?
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 ¤tPlace = *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.
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);
about data structures,why i can't output paths of the maze? I use the stack to storage the information of the current position.Read map of maze through a text file,if the position cant't pass
will be marker by "#",it is a wall.the way marker by "+". written in C++.
PS:My English is very poor.
//stack.h
#ifndef _STACK_H_
#define _STACK_H_
#include<iostream>
#include<stdlib.h>
const int SIZE = 81;
using namespace std;
typedef struct
{
int x;
int y;
}PosType;
typedef struct SElemType{
int ord;//steps
PosType seat;//coordinate
int di;//direction
}SElemType;
typedef struct SqStack{
SElemType *base;
SElemType *top;
int StackSize;
}SqStack;
void Init_S(SqStack &S)
{
S.base = new SElemType[SIZE];
if(!S.base)
exit(EXIT_FAILURE);
S.top = S.base;
S.StackSize = SIZE;
}
bool StackEmpty(SqStack S)
{
if(S.top = S.base)
return true;
return false;
}
void Push(SqStack &S,SElemType e)
{
SElemType *newbase;
if(S.top-S.base>=S.StackSize)
{
newbase = new SElemType[S.StackSize*2];
if(!S.base)
exit(EXIT_FAILURE);
for(int i(0);i<S.top-S.base;i++)
*(newbase+i) = *(S.base+i);
delete[]S.base;
S.base = newbase;
S.top = S.base+S.StackSize;
S.StackSize *= 2;
}
*(S.top)++ = e;
}
void Pop(SqStack &S,SElemType e)
{
if(StackEmpty(S))
cout<<"empty stack!\n";
else
e = *(--S.top);
}
#endif
//maze.cpp
#include<iostream>
#include<cstdlib>
#include<fstream>
#include"stack.h"
using namespace std;
const int m = 10;
const int n = 10;
typedef char MazeG[m][n];
void Show_MG(MazeG MG)
{
for(int i(0);i<m;i++)
{
for(int j(0);j<n;j++)
{
cout<<MG[i][j];
}
cout<<"\t\n";
}
}
PosType Next(PosType &pos,int di)
{
PosType repos;
switch(di)
{
case 0://north
repos.x = pos.x-1;
repos.y = pos.y;
break;
case 1://east
repos.x = pos.x;
repos.y = pos.y+1;
break;
case 2://south
repos.x = pos.x+1;
repos.y = pos.y;
break;
case 3://west
repos.x = pos.x;
repos.y = pos.y-1;
break;
default:
break;
}
return repos;
}
int MazePath(MazeG &MG,PosType begin,PosType end)
{
PosType curpos = begin;
SqStack S;
Init_S(S);
SElemType e;
e.ord = 0;
do{
if(MG[curpos.x][curpos.y]=='*')
{
MG[curpos.x][curpos.y] = '+';
e.seat = curpos;
e.di = 0;
e.ord++;
Push(S,e);
if(curpos.x==end.x&&curpos.y==end.y)
{
cout<<"此迷宫的一条路径如下:(+标记为路径)\n";//the path of maze:
cout<<"走了"<<e.di<<"步到达出口\n";//The number of steps walked
Show_MG(MG);
return 0;
}
else
curpos = Next(curpos,e.di);
}
else
if(!StackEmpty(S))
{
Pop(S,e);
e.ord--;
while(e.di==3&&!StackEmpty(S))
{
MG[curpos.x][curpos.y] = '#';
Pop(S,e);
e.ord--;
}
if(e.di<3)
{
e.di++;
Push(S,e);
e.ord++;
curpos = Next(curpos,e.di);
}
}
}while(!StackEmpty(S));
cout<<"此迷宫没有入口到出口的路径!\n";//no path of the maze
//return -1;
}
int main()
{
MazeG MG;
PosType begin,end;
begin.x = 1; begin.y = 1;
end.x = 8; end.y = 8;
ifstream fin;
fin.open("file.txt");
if(!fin.is_open())
{
cout<<"erorr file!!\n";
exit(EXIT_FAILURE);
}
if(fin.good())
{
for(int i(0);i<m;i++)
for(int j(0);j<n;j++)
fin>>MG[i][j];
}
cout<<"迷宫图为:(*代表能通过)\n";//map of maze:('*' is means through)
Show_MG(MG);
cout<<begin.x<<begin.y<<end.x<<end.y<<endl;
fin.close();
MazePath(MG,begin,end);
return 0;
}
This is wrong
bool StackEmpty(SqStack S)
{
if(S.top = S.base)
return true;
return false;
}
It should be this
bool StackEmpty(SqStack S)
{
if(S.top == S.base) // == not =
return true;
return false;
}
Use == for equality not =.
Now,I understand my the error of code is that I mismatch the data will be stored by stack.
I have changed my code,that's right.
//stack.h
SElemType Gettop(SqStack S)
{
if(!Empty_S(S))
return *(S.top-1);
}
//maze_path.cpp
do{
if(MG[curpos.x][curpos.y]=='*')
{
MG[curpos.x][curpos.y] = '+';
e.seat = curpos;
e.di = 0;
e.ord++;
Push(S,e);
if(curpos.x==end.x&&curpos.y==end.y)
{
cout<<"此迷宫的一条路径如下:(+标记为路径)\n";//the path of maze:
cout<<"走了"<<e.di<<"步到达出口\n";//The number of steps walked
Show_MG(MG);
return 0;
}
else
curpos = Next(curpos,e.di);
}
else
if(!StackEmpty(S))
{
if(e.di<3)
{
e.ord++;
curpos = Next(curpos,e.di);
}
else
{
MG[curpos.x][curpos.y] = '#';
Pop(S,e);
e = Gettop(S);
}
}
}while(!StackEmpty(S));
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.)