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++)
Related
I'm trying to do the Maximum Sort of a Simple One-way List. However my program has some bugs in it, which I can't figure out what it is.
It behaves strange because sometimes it works well to a point where it just stop working but i see return 0 (for example: I give the list of 1234 and I get back 3412), sometimes it working to a point, then goes to an infinte loop. (for example: case of 12345 it put 5, 4 and 3 the the 1st place and then infinite loop).
The problem is probably in the list::remMax() or in the maxRend().
My code:
struct chain
{
char key;
chain *next;
};
/////////////////////////////////////////////
class list
{
private:
chain *L, **act;
public:
list() {
L=NULL;
act=&L;
}
~list() {
chain *p;
while(L) {
p=L;
L=L->next;
delete []p;
}
}
enum ERROR {endErr, memErr};
void first() {act=&L;};
void next() {
if(*act!=NULL) {
act=&(*act)->next;
} else throw endErr;
}
bool end() {return *act==NULL;}
bool oneEIn() {return L->next==NULL;} //list contains only 1 element
bool twoEIn() {return L->next->next==NULL;} //list contains 2 elements
void addE(char x) {
chain *p=new(nothrow) chain;
if(p == NULL) throw memErr;
p->key=x;
p->next=*act;
*act=p;
}
chain* remMax(chain *H) {
if(!oneEIn()) {
chain *qe, *q, *Mpe, *Mp;
if(twoEIn()) {
Mp = H;
q = Mp->next;
if(q->key > Mp->key) {
Mp->next=q->next;
return q;
} else {
H=q;
Mp->next=NULL;
return Mp;
}
} else {
Mp=H;
q=Mp->next;
Mpe = H;
qe = Mp;
while(q != NULL) {
if(Mpe->key > Mp->key) Mp = Mpe;
if(q->key > Mp->key) {
Mp=q;
Mpe=qe;
}
qe=q;
q=q->next;
}
if(Mpe == Mp) H=Mp->next;
else {
Mpe->next = Mp->next;
}
Mp->next=NULL;
return Mp;
}
} else {
chain *Mp;
Mp = H;
H = NULL;
return Mp;
}
}
void inE(chain *Mp) {
first();
Mp->next = *act;
addE(Mp->key);
}
chain* getFirst() {return L;}
void printList() {
chain *p=L;
while(p != NULL) {
putchar(p->key);
p=p->next;
}
}
};
///////////////////////////////////
void makeList(list& L) {
char c;
while((c=getchar())!='\n') {
L.addE(c);
L.next();
}
}
void maxRend(list& L) {
if(!L.oneEIn()) {
chain *H, *Mp;
H=L.getFirst();
while(H != NULL) {
cout<<"1.while\n";
Mp = L.remMax(H);
L.inE(Mp);
cout<<"putIn: "<<Mp->key<<endl;
H=H->next;
L.printList();
cout<<endl;
}
cout<<"\nSorted list: ";
L.printList();
} else L.printList();
}
//////////////////////////////////////////////
int main()
{
list L;
makeList(L);
maxRend(L);
return 0;
}
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++)
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);
when I insert a new struct A with the '1' command (so I already have one or more struct A linked to one or more struct S), i lose the link of the previous struct A to their struct S.
For exaple:
command 1 and then command 3 : 2014 and command 4
Output:
year:2014
matricola:1
now command 1 and then command 3 : 2015 and command 4
Output:
year:2015
matricola:2
year:2014
no S struct
I hope that the example will be helpful
Here is the code:
#include <stdio.h>
#include <stdlib.h>
struct S
{
int matr;
struct S* next;
};
struct A
{
int year;
struct A *nextA;
struct S *nextS;
};
int years = 2013;
int matricola=0;
void insA(struct A**T);
void printA(struct A*T);
void insS(struct A **T);
void printS(struct A *T);
int main()
{
struct A *T=NULL;
int cmd,sc=0;
while(1)
{
printf("\n command:");
sc=scanf("%d",&cmd);
while(sc==0)
{
printf("\nerror:");
fflush(stdin);
sc=scanf("%d",&cmd);
}
if(cmd==1)
{
insA(&T);
}
if(cmd==2)
{
printA(T);
}
if(cmd==3)
{
insS(&T);
}
if(cmd==4)
{
printS(T);
}
}
return 0;
}
void insA(struct A**T)
{
struct A *new_p=(struct A*)malloc(sizeof(struct A));
if(new_p==NULL)
{
printf("Errore");
exit(0);
}
years++;
new_p->nextA=NULL;
new_p->nextS=NULL;
if((*T)==NULL)
{
(*T)=new_p;
}
else
{
new_p->nextA=(*T);
(*T)=new_p;
}
new_p->year=years;
}
void printA(struct A *T)
{
struct A *tmp=T;
while(tmp!=NULL)
{
printf("\n%d",tmp->year);
tmp=tmp->nextA;
}
return;
}
void insS(struct A **T)
{
int search,sc=0;
struct S* new_p=(struct S*)malloc(sizeof(struct S));
if(new_p==NULL)
{
printf("error");
exit(0);
}
new_p->next=NULL;
printf("\nyear in which to insert:");
sc=scanf("%4d",&search);
while(sc==0 || search > years || search <= 2013)
{
printf("\nerror:");
fflush(stdin);
sc=scanf("%4d",&search);
}
struct A*tmp=*T;
while(tmp!=NULL)
{
if(tmp->year==search)
{
matricola++;
if(tmp->nextS==NULL)
{
tmp->nextS=new_p;
}
else
{
new_p->next=tmp->nextS;
tmp->nextS=new_p;
}
}
tmp=tmp->nextA;
}
new_p->matr=matricola;
return;
}
void printS(struct A *T)
{
struct A *tmp=T;
struct S *s=tmp->nextS;
while(tmp!=NULL)
{
printf("\nyear:%d",tmp->year);
if(s==NULL)
{
printf("\nno S struct");
return;
}
else
{
while(s!=NULL)
{
printf("\nmatricola:%d",s->matr);
s=s->next;
}
}
tmp=tmp->nextA;
}
}
And this is my first post so I apologize for any errors .
After struggling to understand what you want to do I figured out your problem, you have to change your printS function.
void printS(struct A *T) {
struct A *tmp=T;
truct S *s = tmp->nextS;
while(tmp != NULL) {
printf("\nyear:%d", tmp->year);
if(s == NULL) {
printf("\nno S struct");
return ;
} else {
while(s != NULL) {
printf("\nmatricola:%d",s->matr);
s = s->next;
}
}
tmp = tmp->nextA;
}
}
Like this.
void printS(struct A *T) {
struct A *tmp=T;
while(tmp != NULL) {
struct S *s = tmp->nextS;
printf("\nyear:%d", tmp->year);
if(s == NULL) {
printf("\nno S struct");
return ;
} else {
while(s != NULL) {
printf("\nmatricola:%d",s->matr);
s = s->next;
}
}
tmp = tmp->nextA;
}
}
Because the struct S *s = tmp->nextS; have to be updated to the actual struct A in which you are, so it have to be inside the while loop, if you leave struct S *s = tmp->nextS; outside the while loop you will try to print the list of structs S that starts from your first struct A, and not the entire list of structs S starts from each struct A.
Note: As I said, try to avoid fflush(stdin); because if the argument don't point to an output stream the behavior is undefined.