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.
Related
I am required to implement a dynamic array that adjusts, dynamically, in accordance with the number of value (temperatures) that are input into the code. I have written the majority of the code for this to be possible, however I have run into a bug and for the life of me, have been unable to locate the issue.
The program is supposed to output the values of temp_a, make temp_b = temp_a, output the value of temp_b, and then clear the value of temp_a, and finally output the values of temp_b once more.
However, when I compile the program, it outputs that the list is full and cannot add any more values, meaning there is a logic error somewhere in the code.
Please forgive me for the lengthy code, as soon as I can locate the error, the code shall be separated into multiple compilations.
#include <iostream>
using namespace std;
class TemperatureList {
private:
int* temp; // pointer to dynamic array
short current_size; // current number of elements
short max_size; // max number of elements allowed in this list
public:
// Overloading assignment operator
void operator =(const TemperatureList& another_list);
// === Constructors ===
// Default constructor
TemperatureList();
// Constructor that accepts an integer parameter that specifies the max length of the list
TemperatureList(int max);
// Copy constructor that accepts another List as parameter
TemperatureList(const TemperatureList& another_list);
// Destructor
~TemperatureList();
// === Modifier functions ===
// add new_value to end of list if there is still space
void add_temperature(int new_value);
// === Accessor functions ===
// return current current_size of the list
short get_current_size();
// === Other functions ===
// return the last element, or 0 if the list is empty, with a warning output
int get_last();
// return element at the position-th position, or 0 if the list is empty, with a warning output
int get_temp(short position);
// returns if current_size == 0
bool set_temp(short position, int value);
// returns if current_size == 0
bool empty();
// returns if current_size == max_size
bool full();
// Output list separated by commas
friend ostream& operator <<(ostream& outs, const TemperatureList& list);
};
int main() {
TemperatureList temp_a;
temp_a.add_temperature(23.5);
temp_a.add_temperature(24.6);
cout << temp_a;
TemperatureList temp_b = temp_a;
cout << temp_b;
temp_a = TemperatureList();
cout << "Now there's no temperatures in a.\n";
cout << temp_a;
cout << "How about temperatures in b?\n";
cout << temp_b;
return 0;
}
void TemperatureList::operator =(const TemperatureList& another_list) {
delete[] temp;
current_size = another_list.current_size;
max_size = another_list.max_size;
if (current_size > 0) {
temp = new int[max_size];
for (int i = 0; i < max_size; i++) {
temp[i] = another_list.temp[i];
}
}
else {
temp = NULL;
}
}
TemperatureList::TemperatureList() {
current_size = 0;
max_size = 0;
temp = NULL;
}
TemperatureList::TemperatureList(int max) : max_size(max) {
current_size = 0;
temp = new int[max];
}
TemperatureList::TemperatureList(const TemperatureList& another_list) {
current_size = another_list.current_size;
max_size = another_list.max_size;
if (current_size > 0) {
temp = new int[max_size];
for (int i = 0; i < max_size; i++) {
temp[i] = another_list.temp[i];
}
}
else {
temp = NULL;
}
}
TemperatureList::~TemperatureList() {
//cout << "== I am in destructor ==\n";
delete[] temp;
}
void TemperatureList::add_temperature(int new_value) {
if (current_size < max_size) {
temp[current_size] = new_value;
current_size++;
}
else {
cout << "Cannot add value to the list. It is full.\n";
}
}
int TemperatureList::get_last() {
if (empty()) {
cout << "The list is empty\n";
return 0;
}
else {
return temp[current_size - 1];
}
}
int TemperatureList::get_temp(short position) {
if (current_size >= position) {
return temp[position - 1];
}
else {
cout << "There is no temperature\n";
return 0;
}
}
bool TemperatureList::set_temp(short position, int value) {
if (current_size >= position) {
temp[position - 1] = value;
return true;
}
else {
return false;
}
}
short TemperatureList::get_current_size() {
return current_size;
}
bool TemperatureList::empty() {
return (current_size == 0);
}
bool TemperatureList::full() {
return (current_size == max_size);
}
ostream& operator <<(ostream& outs, const TemperatureList& list) {
int i;
for (i = 0; i < (list.current_size - 1); i++) {
outs << list.temp[i] << ",";
}
outs << list.temp[i];
return outs;
}
The logic error seems to stem from the fact that you initialize your current_size and max_size to zero. So, unless your run the overloaded constructor (wherein you’re set the max_size), every call to addTemperature() is going to fail the (current_size < max_size) check because they are both equal to zero.
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++)
My assignment is to make a binary expression tree to convert postfix expressions to infix expressions in C++. I originally coded all my work in my Xcode IDE and would periodically ssh to linprog4 in terminal to make sure it works there because it has to before I turn it in. I don't understand the errors that are popping up when I compile it using g++ -o proj4.x -std=c++11 proj4_driver.cpp BET.cpp
This assignment was due 2 weeks ago and unfortunately when I was turning in the tar file with all my files, I forgot to include the .tar extension. I don't think that would affect my files but now they aren't compiling and I don't understand the errors I am getting. Could someone skim through my code and see if I am missing anything? I've looked over my code and it doesn't look like I accidentally typed something randomly somewhere.
Here is a screenshot of the errors I am getting
BET.h
#ifndef BET_H
#define BET_H
using namespace std;
class BET {
private:
struct BinaryNode {
string data;
BinaryNode * parent;
BinaryNode * childLeft;
BinaryNode * childRight;
bool visited; // to tell if node has been visited to or not
// Construct a blank copy version BinaryNode when an
// object of BET is created
BinaryNode( const char & d = char{}, BinaryNode * p = NULL,
BinaryNode * l = NULL,
BinaryNode * r = NULL, bool v = false )
: data { d },
parent { p },
childLeft { l },
childRight { r },
visited { v } {}
// Construct a blank move version of BinaryNode when an
// an object of BET is created
BinaryNode( char && d, BinaryNode * p = NULL, BinaryNode * l = NULL,
BinaryNode * r = NULL, bool v = false )
: data { std::move(d) },
parent { p },
childLeft { l },
childRight { r },
visited { v } {}
}; // end of BinaryNode struct
public:
// constructors and destructor
BET();
BET( const string postfix );
BET( const BET & rhs );
~BET();
// help copy constructor
bool buildFromPostfix( const string postfix );
// copy assignment operator
const BET & operator=( const BET & rhs );
void printInfixExpression();
void printPostfixExpression();
size_t size();
size_t leaf_nodes();
bool empty();
bool isOperand(BinaryNode * n);
private:
BinaryNode *root;
size_t leaves, nodes;
bool useP;
void printInfixExpression( BinaryNode * n );
void makeEmpty( BinaryNode* & t );
BinaryNode * clone( BinaryNode * t ) const;
void printPostfixExpression( BinaryNode * n );
size_t size( BinaryNode * t );
size_t leaf_nodes( BinaryNode * t );
}; // end of BET class
#endif
BET.cpp
#include <iostream>
#include <stack>
#include <sstream>
#include <string>
#include "BET.h"
//using namespace std;
// default zero-param constructor
BET::BET() {
root = new BinaryNode;
leaves = 0;
nodes = 0;
}
// one-param constructor, where parameter "postfix" is a
// string containing a postfix expression. The tree should
// be built based on the postfix expression. Tokens in the
// postfix expression are separated by space
BET::BET(const string postfix) {
root = new BinaryNode;
buildFromPostfix(postfix);
}
// copy constructor
BET::BET(const BET & rhs) {
leaves = rhs.leaves;
nodes = rhs.nodes;
root = rhs.root;
}
// destructor
BET::~BET() {
makeEmpty(root);
leaves = nodes = 0;
}
bool BET::buildFromPostfix(const string postfix) {
// Create stack to hold variables
stack<BinaryNode *> s;
stack<BinaryNode> bet;
char token;
string temp;
int index = 1;
bool doubleDigit = false;
int opCount = 0, digitCount = 0;
//stringstream hexToInt;
// iterator through postfix
for (int i = 0; i < postfix.size(); ++i) {
// grab token at iterations index
token = postfix[i];
if ( (token > '0' && token < '9') || (token > 62 && token < 80)) {
// check to see if token is an operand
// create a dynamic object of BinaryNode
BinaryNode *operand = new BinaryNode;
// check to see if next index of postfix is digit
// if its not, then we know its a double digit
// this while loop should only continue as long as the
// next index is between 0 and 9
temp = postfix[i];
while (postfix[i + index] >= '0' && postfix[i + index] <= '9') {
temp += postfix[i + index];
index++;
doubleDigit = true;
}
if (doubleDigit == true) {
i += index;
doubleDigit = false;
index = 1;
operand->data = temp;
} else {
operand->data = postfix[i];
}
s.push(operand);
digitCount++;
} else if (token == '+' || token == '-' || token == '*' || token == '/'){
// check to see if token is operator
BinaryNode *operand = new BinaryNode;
operand->data = postfix[i];
operand->childLeft = s.top();
s.top()->parent = operand;
s.pop();
operand->childRight = s.top();
s.top()->parent = operand;
s.pop();
s.push(operand);
opCount++;
} else {
// if neither, must be space or other character
if (token == ' ') {
} else
return false;
}
}
if (digitCount <= opCount) {
return false;
}
root = s.top();
nodes = size();
//leaves = leaf_nodes();
// THINGS TO DO:
// Make error cases with if statements to return false at some point
return true;
}
// assignment operator
const BET & BET::operator=(const BET & rhs) {
root = clone(rhs.root);
return *this;
}
// public version of printInfixExpression()
// calls the private version of the printInfixExpression fuction
// to print out the infix expression
void BET::printInfixExpression() {
printInfixExpression(root);
}
// public version of printPostfixExpression()
// calls the private version of the printPostfixExpression function
// to print out the postfix expression
void BET::printPostfixExpression() {
printPostfixExpression(root);
}
// public version of size()
// calls the private version of the size function to return
// the number of nodes in the tree
size_t BET::size() {
return size(root);
}
// public version of leaf_nodes()
// calls the private version of leaf_nodes function to return
// the number of leaf nodes in the tree
size_t BET::leaf_nodes() {
return leaf_nodes(root);
}
// public version of empty()
// return true if the tree is empty. return false otherwise
bool BET::empty() {
if (nodes == 0) {
return true;
} else
return false;
}
// checks whether node is operand or not
bool BET::isOperand(BinaryNode * n) {
if (n->data != "+" && n->data != "-" && n->data != "*" && n->data != "/") {
return true;
} else
return false;
}
// private version of printInfixExpression
// print to the standard output the corresponding infix expression
void BET::printInfixExpression(BinaryNode * n) {
//BinaryNode * temp = NULL;
if (n != NULL ) {
printInfixExpression(n->childRight);
cout << n->data << " ";
printInfixExpression(n->childLeft);
}
/*
if (n != NULL && useP == true) {
printInfixExpression(n->childRight);
if (isOperand(n->parent) && n->parent != NULL && !n->childLeft) {
cout << "(";
}
cout << n->data << " ";
if (isOperand(n->parent) && n->parent != NULL && !n->childRight) {
cout << ")";
}
printInfixExpression(n->childLeft);
}
*/
}
// private method makeEmpty()
// delete all nodes in the subtree pointed to by n.
// Called by functions such as the destructor
void BET::makeEmpty(BinaryNode * & n) {
if (n != NULL) {
makeEmpty(n->childLeft);
makeEmpty(n->childRight);
delete n;
}
}
// private method clone()
// clone all nodes in the subtree pointed by n. Called by
// functions such as the assignment operator=
BET::BinaryNode * BET::clone(BinaryNode * n) const {
if (n != NULL) {
root->childRight = clone(n->childRight);
root->childLeft = clone(n->childLeft);
root->data = n->data;
}
return root;
}
// private method printPostfixExpression()
// print to the standard output the corresponding postfix expression
void BET::printPostfixExpression(BinaryNode * n) {
if (n != NULL) {
printPostfixExpression(n->childRight);
printPostfixExpression(n->childLeft);
cout << n->data << " ";
}
}
// private version of size()
// return the number of nodes in the subtree pointed by n
size_t BET::size(BinaryNode * n) {
if (n != NULL) {
size(n->childLeft);
size(n->childRight);
nodes++;
}
return nodes;
}
// return the number of leaf nodes in the subtree pointed by n
size_t BET::leaf_nodes(BinaryNode * n) {
if (n != NULL) {
leaf_nodes(n->childLeft);
leaf_nodes(n->childRight);
if (n->childLeft == NULL && n->childRight == NULL) {
leaves += 1;
}
}
return leaves;
}
Driver.cpp
#include "BET.cpp"
//using namespace std;
int main() {
string postfix;
// get a postfix expression
cout << "Enter the first postfix expression: ";
getline(cin, postfix);
// create a binary expression tree
BET bet1(postfix);
if (!bet1.empty()) {
cout << "Infix expression: ";
bet1.printInfixExpression();
cout << "\n";
cout << "Postfix expression: ";
bet1.printPostfixExpression();
cout << "\nNumber of nodes: ";
cout << bet1.size() << endl;
cout << "Number of leaf nodes: ";
cout << bet1.leaf_nodes() << endl;
// test copy constructor
BET bet2(bet1);
cout << "Testing copy constructor: ";
//bet2.printInfixExpression();
// test assignment operator
BET bet3;
bet3 = bet1;
cout << "Testing assignment operator: ";
//bet3.printInfixExpression();
}
cout << "Enter a postfix expression (or \"quit\" to quit): ";
while (getline(cin, postfix)) {
if (postfix == "quit") {
break;
}
if (bet1.buildFromPostfix(postfix)) {
cout << "Infix expression: ";
bet1.printInfixExpression();
cout << "Postfix expression: ";
bet1.printPostfixExpression();
cout << "Number of nodes: ";
cout << bet1.size() << endl;
cout << "Number of leaf nodes: ";
cout << bet1.leaf_nodes() << endl;
}
cout << "Enter a postfix expression (or \"quit\" to quit): ";
}
return 0;
}
Driver.cpp #include "BET.cpp" should be #include "BET.h"
Or (and this is just for completeness, not recommended), leave the include of the .cpp, but then only try to compile the one .cpp (as in g++ Driver.cpp) - since driver will include BET and so all your code is there and will build.
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);
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.)