Invalid memory access when using binary research tree - c++

Here is my codes.
#include<iostream>
template<class Elem>
class BinNode
{
public:
virtual Elem& getVal() = 0;
virtual void setVal(const Elem&) = 0;
virtual BinNode* left() = 0;
virtual BinNode* right() = 0;
virtual void setLeft(BinNode*) = 0;
virtual void setRight(BinNode*) = 0;
virtual bool isLeaf() = 0;
};//abstract class
template<class Elem>
class BinNodePtr:public BinNode<Elem>
{
public:
Elem val;
BinNodePtr* lc;
BinNodePtr* rc;
BinNodePtr()
{
lc = rc = NULL;
}
~BinNodePtr()
{
delete lc;
delete rc;
}
void setVal(const Elem& e)
{
val = e;
}
Elem& getVal()
{
return this->val;
}
void setLeft(BinNode<Elem>* e)
{
lc = (BinNodePtr<Elem>*)e;
}
void setRight(BinNode<Elem>* e)
{
rc = (BinNodePtr<Elem>*)e;
}
bool isLeaf()
{
if(this->lc == NULL && this->rc == NULL)
return true;
return false;
}
BinNodePtr<Elem>* left()
{
return lc;
}
BinNodePtr<Elem>* right()
{
return rc;
}
};
template<class Elem>
class BST
{
public:
BinNodePtr<Elem> *root;
int nodenum;
void deleteElem(BinNodePtr<Elem>* start);
void midorder(BinNodePtr<Elem>* start);
public:
BST()
{
root = NULL;
nodenum = 0;
}
~BST()
{
deleteElem(root);
}
bool insert(BinNodePtr<Elem>* ptr,const Elem &e);
BinNodePtr<Elem>* getRoot(){return root;}
};
template<class Elem>
void BST<Elem>::deleteElem(BinNodePtr<Elem>* start)
{
BinNodePtr<Elem>* temp =(BinNodePtr<Elem>*) start;
if(temp == NULL) return;
deleteElem((BinNodePtr<Elem>*)temp->left());
deleteElem((BinNodePtr<Elem>*)temp->right());
delete temp;
}
template<class Elem>
void BST<Elem>::midorder(BinNodePtr<Elem> *start)
{
if(start == NULL) return;
midorder(start->lc);
printf("%d ",start->getVal());
midorder(start->rc);
}
template<class Elem>
bool BST<Elem>::insert(BinNodePtr<Elem>*ptr,const Elem &e)
{
if(ptr == NULL)
{
ptr = new BinNodePtr<Elem>;
ptr->lc = NULL;
ptr->rc = NULL;
ptr->val = e;
return true;
}
else
{
if(ptr->val < e || ptr->val == e)
{
ptr = ptr->right();
insert(ptr->rc,e);
}
else
{
ptr = ptr->left();
insert(ptr->lc,e);
}
}
return false;
}
int main()
{
BST<int> myBST;
myBST.insert(myBST.root,10);
myBST.insert(myBST.root,20);
myBST.insert(myBST.root,5);
myBST.insert(myBST.root,30);
printf("%d",myBST.getRoot()->getVal());
system("pause");
return 0;
}
There are some functions which are not used in my program.I focus on the "insert" function.When I debug this ,the program breaks down at printf("%d",myBST.getRoot()->getVal());saying "invalid memory access",Why and how to solve it?

You have to remember that in C++ arguments are by default passed by value, that means their value is copied to the argument in the called function. When you change an argument in the function, you only change its local copy, no changes to the copy will be propagated to the caller.
To change an argument in the caller, you have to pass it by reference, like
bool insert(BinNodePtr<Elem>*& ptr,const Elem& e);
This will make the ptr argument a reference to the pointer, so changes to it will propagate to the caller.

If you want to change the ptr argument in the insert function, you should pass the address of it, like so:
template<class Elem>
bool BST<Elem>::insert(BinNodePtr<Elem>**ptr,const Elem &e)
or pass a reference to it.

Related

Visual Studio 2019 Edits My C++ Code And Ruins My Iterator

I have spent some time recently designing an iterator for the AVL Tree (right now it just has the inserting mechanics though; haven't implemented tree balancing).
I wanted to test out the iterator, so I checked how to make it online and settled on making it by having a stack holding the tree nodes (e.g. in normal iteration stack would contain all nodes left of this->top node).
This is how the iteration is supposed to work:
for (auto it = tree.iterator(); it.hasNext(); it.next())
{
// process
}
However, VS changes (disables) my Iterator(const Iterator& it) and Iterator(Iterator&& it) constructors and then the iteration fails because the stack is always empty.
After setting Iterator() = delete;, I run into the issue of stack having an unusually large size with invisible parameters.
If extra information is needed, feel free to ask. I think that it's best if I just paste the relevant code because I do not understand this behaviour and do not know what details I should say:
avlTree<Key, Info>::iterator:
class Iterator
{
private:
std::vector<Node*> stack;
bool reverse;
Node* ptr;
std::vector<Node*> makeStack(Node* start, long height)
{
std::vector<Node*> newStack;
newStack.reserve(height);
while (start != nullptr)
{
newStack.push_back(start);
if (reverse)
start = start->right;
else
start = start->left;
}
return newStack;
}
Iterator(Node* start, long height, bool reverse = false) : reverse(reverse), ptr(nullptr)
{
stack = makeStack(start, height);
}
friend class avlTree;
public:
Iterator(Iterator&& iterator)
{
stack = move(iterator.stack);
ptr = nullptr;
}
Iterator(const Iterator& iterator)
{
stack = iterator.stack;
ptr = nullptr;
}
//Iterator() = delete;
bool hasNext()
{
return stack.size() > 0;
}
void next()
{
if (!stack.size()) throw "Empty iterator stack";
if (ptr == stack[stack.size() - 1])
{
stack.pop_back();
if (reverse) // fill the stack with the subsequent nodes (reverse or normal direction)
{
Node* start = ptr->left;
while (start != nullptr)
{
stack.push_back(start);
start = start->right;
}
}
else
{
Node* start = ptr->right;
while (start != nullptr)
{
stack.push_back(start);
start = start->left;
}
}
}
if (stack.size() > 0)
ptr = stack[stack.size() - 1];
}
const Key& getKey()
{
if (!ptr) throw "ptr is nullptr";
else return ptr->key;
}
Info& getInfo()
{
if (!ptr) throw "ptr is nullptr";
else return ptr->info;
}
};
main:
avlTree<char, int> tester;
for (char i = 'g'; i <= 'z'; ++i)
tester.insert(i);
for (char i = 'a'; i < 'g'; ++i)
tester.insert(i);
for (auto it = tester.iterator(); it.hasNext(); it.next())
{
std::cout << it.getKey() << " ";
}
Screenshot of the code & message I get while debugging: http://prntscr.com/qi79zd
How do I fix the issue and make the iteration work?
EDIT:
Complete code:
#include <iostream>
#include <string>
#include <vector>
#include <map>
#include <fstream>
#include <chrono>
#include <iterator>
#include <functional>
//#include <ctime>
template<typename T>
void swap(T& a, T& b)
{
T temp = a;
a = b;
b = temp;
}
template<typename Key, typename Info>
class avlTree
{
private:
struct Node
{
const Key key;
Info info;
Node* left;
Node* right;
long leftHeight, rightHeight;
Node(const Key& key, Info&& info = Info(), Node* left = nullptr, Node* right = nullptr)
: key(key), info(info), left(left), right(right), leftHeight(1), rightHeight(1) {}
Node& operator()(Node* nleft, Node* nright)
{
left = nleft;
right = nright;
return *this;
}
Node& operator()(long left, long right)
{
leftHeight = left;
rightHeight = right;
}
};
Node* top;
long length;
public:
class Iterator
{
private:
std::vector<Node*> stack;
bool reverse;
Node* ptr;
std::vector<Node*> makeStack(Node* start, long height)
{
std::vector<Node*> newStack;
newStack.reserve(height);
while (start != nullptr)
{
newStack.push_back(start);
if (reverse)
start = start->right;
else
start = start->left;
}
return newStack;
}
Iterator(Node* start, long height, bool reverse = false) : reverse(reverse), ptr(nullptr)
{
stack = makeStack(start, height);
}
friend class avlTree;
public:
Iterator(Iterator&& iterator)
{
stack = move(iterator.stack);
ptr = nullptr;
}
Iterator(const Iterator& iterator)
{
stack = iterator.stack;
ptr = nullptr;
}
bool hasNext()
{
return stack.size() > 0;
}
void next()
{
if (!stack.size()) throw "Empty iterator stack";
//stack.insert(stack.end(), vector.begin(), vector.end());
if (ptr == stack[stack.size() - 1])
{
stack.pop_back();
if (reverse)
{
Node* start = ptr->left;
while (start != nullptr)
{
stack.push_back(start);
start = start->right;
}
}
else
{
Node* start = ptr->right;
while (start != nullptr)
{
stack.push_back(start);
start = start->left;
}
}
}
if (stack.size() > 0)
ptr = stack[stack.size() - 1];
}
const Key& getKey()
{
if (!ptr) throw "ptr is nullptr";
else return ptr->key;
}
Info& getInfo()
{
if (!ptr) throw "ptr is nullptr";
else return ptr->info;
}
};
avlTree()
{
this->top = nullptr;
this->length = 0;
}
~avlTree()
{
recursiveDelete(top);
length = 0;
}
void printAsc()
{
for (auto it = iterator(); it.hasNext(); it.next())
{
std::cout << it.getKey() << " " << it.getInfo() << "\n";
}
}
void printDesc()
{
recDesc(top);
}
void printTop()
{
if (top) // != nullptr
{
std::cout << ".." << top->key << std::endl;
if (top->left)
std::cout << "." << top->left->key << "..";
else std::cout << ".0..";
if (top->right)
std::cout << top->right->key << std::endl;
else std::cout << "0" << std::endl;
}
}
void insert(const Key& key);
long height()
{
return !top ? 0 : top->leftHeight > top->rightHeight ? top->leftHeight : top->rightHeight;
}
private:
void recDesc(Node* parent);
void recursiveDelete(Node* parent);
void insertRecursive(Node* parent, const Key& key, int& depth);
// void rightRotation(Node* top, Node* parent = nullptr);
public:
Iterator iterator()
{
return Iterator(top, height());
}
};
std::vector<std::string> readFile(bool toDarwin = true);
/****************************************************************************/
int main()
{
// auto start = std::chrono::system_clock::now();
avlTree<std::string, int> counter;
avlTree<char, int> tester;
for (char i = 'g'; i <= 'z'; ++i)
tester.insert(i);
for (char i = 'a'; i < 'g'; ++i)
tester.insert(i);
for (auto it = tester.iterator(); it.hasNext(); it.next())
{
std::cout << it.getKey() << " ";
}
return 0;
}
/****************************************************************************/
template<typename Key, typename Info>
void avlTree<Key, Info>::recDesc(Node* parent)
{
if (parent->left != nullptr)
recAsc(parent->left);
std::cout << parent->key;
if (parent->right != nullptr)
recAsc(parent->left);
}
template<typename Key, typename Info>
void avlTree<Key, Info>::recursiveDelete(Node* parent)
{
if (!parent) return;
if (parent->left != nullptr)
recursiveDelete(parent->left);
if (parent->right != nullptr)
recursiveDelete(parent->right);
delete parent;
}
template<typename Key, typename Info>
void avlTree<Key, Info>::insertRecursive(Node* parent, const Key& key, int& depth)
{
if (parent->key == key)
++(parent->info);
else if (parent->key > key)
{
if (parent->left == nullptr)
{
parent->left = new Node(key);
++(parent->left->info);
++length;
depth = 1;
// (* parent->left)(depth, depth)
}
else
{
insertRecursive(parent->left, key, depth);
++depth;
parent->leftHeight = depth;
}
}
else if (parent->key < key)
{
if (parent->right == nullptr)
{
parent->right = new Node(key);
++(parent->right->info);
++length;
depth = 1;
// (* parent->right)(depth, depth)
}
else
{
insertRecursive(parent->right, key, depth);
++depth;
parent->rightHeight = depth;
}
}
}
template<typename Key, typename Info>
void avlTree<Key, Info>::insert(const Key& key)
{
int depth = 0;
if (!top)
{
top = new Node(key);
// (*top)(1, 1)
++length;
++(top->info);
}
else
{
insertRecursive(top, key, depth);
++depth;
top->key > key ? ++(top->leftHeight) : top->key < key ? ++(top->rightHeight) : NULL;
}
}
/* Irrelevant to the problem
std::vector<std::string> readFile(bool toDarwin)
{
// shrink_to_fit()
std::ifstream file;
std::string word;
std::vector<std::string> words;
words.reserve(1000000);
if (toDarwin == 1)
file.open("OnTheOriginOfSpecies.txt");
else
file.open("The_bible.txt");
while (file >> word)
{
words.push_back(word);
}
words.shrink_to_fit();
return words;
}
*/
I believe the problem is that you are not aware of RVO - return value optimization. Most compilers do so and in fact it is mandatory in C++17. What's RVO?
class A;
A func()
{
A a_infunc = {};
return a_infunc;
}
//use
A a_outsidefunc = func();
In this simple example at no point A::A(const A&) or A::A(A&&) is called. a_infunc is exactly the same variable as a_outsidefunc.
So in the for-loop:
for (auto it = tree.iterator(); it.hasNext(); it.next())
{
// process
}
There will be no calls to Iterator(const Iterator& it) or Iterator(Iterator&& it) due to RVO.

Need help, AVL Tree of objects

Our teacher provided us with the AVL_Tree.h and AVL_Node.h
I am trying to declare a new AVL_Tree of Folder (class that I created). However I keep getting the same error
error C2784: 'bool std::operator <(const std::vector<_Ty,_Ax> &,const
std::vector<_Ty,_Ax> &)' : could not deduce template argument for 'const
std::vector<_Ty,_Ax> &' from 'const AVLNode<Item_Type>'
Here is the AVL_Tree class
#ifndef AVL_TREE_H
#define AVL_TREE_H
#include "AVL_Node.h"
template<typename Item_Type>
class AVL_Tree{
public:
AVL_Tree() : root(NULL){
}
AVL_Tree(const Item_Type& the_data, const AVL_Tree<Item_Type>& left_child = AVL_Tree(),
const AVL_Tree<Item_Type>& right_child = AVL_Tree()) :
root(new AVLNode<Item_Type>(the_data, left_child.root,
right_child.root)) {}
/** Return the left-subtree */
AVL_Tree<Item_Type> get_left_subtree() const {
if (root == NULL) {
throw std::invalid_argument("get_left_subtree on empty tree");
}
return AVL_Tree<Item_Type>(root->left);
}
/** Return the right-subtree */
AVL_Tree<Item_Type> get_right_subtree() const {
if (root == NULL) {
throw std::invalid_argument("get_right_subtree on null tree");
}
return AVL_Tree<Item_Type>(root->right);
}
/** Return the data field of the root
#throws std::invalid_argument if null tree
*/
const Item_Type& AVL_Tree<Item_Type>::get_data() const {
if (root == NULL) {
throw std::invalid_argument("get_data on null tree");
}
return root->data;
}
bool is_null() const {
return root == NULL;
}
/** Indicate that this tree is a leaf. */
bool is_leaf() const {
if (root != NULL) {
return root->left == NULL && root->right == NULL;
}
else
return true;
}
virtual bool insert(const Item_Type& item) {
return insert(this->root, item);
}
bool erase(const Item_Type& item) {
return erase(this->root, item);
}
const Item_Type* find(const Item_Type& item) const {
return find(this->root, item);
}
protected:
AVLNode<Item_Type>* root;
AVL_Tree(AVLNode<Item_Type>* new_root) : root(new_root) {}
const Item_Type* find(AVLNode<Item_Type>* local_root, const Item_Type& target) const {
if (local_root == NULL)
return NULL;
if (target < local_root->data)
return find(local_root->left, target);
else if (local_root->data < target)
return find(local_root->right, target);
else
return &(local_root->data);
}
bool erase(AVLNode<Item_Type>*& local_root, const Item_Type& item) {
if (local_root == NULL) {
return false;
}
else {
if (item < local_root->data){
bool return_value = erase(local_root->left, item);
if (return_value){
adjust_balance(local_root);
rebalance(local_root);
}
return return_value;
}
else if (local_root->data < item){
bool return_value = erase(local_root->right, item);
if (return_value){
adjust_balance(local_root);
rebalance(local_root);
}
return return_value;
}
else {
AVLNode<Item_Type>* old_root = local_root;
if (local_root->left == NULL)
local_root = local_root->right;
else if (local_root->right == NULL)
local_root = local_root->left;
else
replace_parent(old_root, old_root->left);
if (local_root != NULL){
adjust_balance(local_root);
rebalance(local_root);
}
delete old_root;
return true;
}
}
}
void rebalance(AVLNode<Item_Type>*& local_root){
if (local_root->balance() <= -2)
rebalance_left(local_root);
else if (local_root->balance() >= 2)
rebalance_right(local_root);
}
void adjust_balance(AVLNode<Item_Type>*& node){
node->update_left_height();
node->update_right_height();
}
void replace_parent(AVLNode<Item_Type>*& old_root, AVLNode<Item_Type>*& local_root) {
if (local_root->right != NULL) {
replace_parent(old_root, local_root->right);
adjust_balance(local_root);
rebalance(local_root);
}
else {
old_root->data = local_root->data;
old_root = local_root;
if (local_root->left != NULL){
local_root = local_root->left;
adjust_balance(local_root);
}
else
local_root = NULL;
}
}
bool insert(AVLNode<Item_Type>*& local_root, const Item_Type& item) {
if (local_root == NULL) {
local_root = new AVLNode<Item_Type>(item);
return true;
}
else {
if (item < local_root->data) {
bool return_value = insert(local_root->left, item);
if (return_value){ //we have inserted the item
local_root->update_left_height(); //left height might increase by 1
if (local_root->balance() <= -2) // local root is now critically unbalanced
rebalance_left(local_root);
}
return return_value;
}
else if (local_root->data < item) {
bool return_value = insert(local_root->right, item);
if (return_value){
local_root->update_right_height(); //right height might increase by 1
if (local_root->balance() >= 2) // local root is now critically unbalanced
rebalance_right(local_root);
}
return return_value;
}
else
return false; //item already exists
}
}
void rebalance_left(AVLNode<Item_Type>*& local_root) {
if (local_root->left->balance() > 0) // See whether left-right-heavy
rotate_left(local_root->left); // Perform left rotation
// Finally rotate right
rotate_right(local_root);
}
void rebalance_right(AVLNode<Item_Type>*& local_root) {
if (local_root->right->balance() < 0) // See whether right-left-heavy
rotate_right(local_root->right); // Perform left rotation
// Finally rotate right
rotate_left(local_root);
}
void rotate_right(AVLNode<Item_Type>*& local_root) {
AVLNode<Item_Type>* temp = local_root->left;
local_root->left = temp->right;
//adjust the balances
local_root->update_left_height();
temp->right = local_root;
temp->update_right_height();
local_root = temp;
}
void rotate_left(AVLNode<Item_Type>*& local_root) {
AVLNode<Item_Type>* temp = local_root->right;
local_root->right = temp->left;
//adjust the balances
local_root->update_right_height();
temp->left = local_root;
temp->update_left_height();
local_root = temp;
}
};
#endif
This is the AVL_Node class
#ifndef AVLNODE_H_
#define AVLNODE_H_
#include <sstream>
template<typename Item_Type>
struct AVLNode {
// Additional data field
int right_height;
int left_height;
AVLNode<Item_Type>* left;
AVLNode<Item_Type>* right;
Item_Type data;
// Constructor
AVLNode(const Item_Type& the_data, AVLNode<Item_Type>* left = NULL, AVLNode<Item_Type>* right = NULL) : data(the_data), left(left), right(right), right_height(0), left_height(0) {}
// Destructor (to avoid warning message)
virtual ~AVLNode() {}
int balance(){ return right_height - left_height; }
int height(){
return right_height > left_height ? right_height : left_height; }
void update_right_height(){
if (right != NULL)
right_height = 1 + right->height();
else
right_height = 0;
}
void update_left_height(){
if (left != NULL)
left_height = 1 + left->height();
else
left_height = 0;
}
// to_string
virtual std::string to_string() const {
std::ostringstream os;
os << "data : " << this->data;
return os.str();
}
}; // End AVLNode
#endif
Finally, the class I created, the Folder class:
#pragma once
#include <string>
#include "AVL_Tree.h"
using namespace std;
class Folder
{
private:
string name;
int size;
public:
Folder()
{
name = "";
size = 0;
}
Folder(string Name, int Size)
{
name = Name;
size = Size;
}
int getSize()
{
return size;
}
string getName()
{
return name;
}
void setSize(int Size)
{
size = Size;
}
void setName(string Name)
{
name = Name;
}
};
The error only occurs when I try to do
AVL_Tree<Folder> folderTree;
it works for other types, such as string, int, char, etc. Any help would be greatly appreciated. As far as I know, we are not supposed to modify the instructor's code.
Your class Folder should be "comparable", it means the following code should compile Folder a,b; bool result = (a<b);
To achieve this, you can define the comparison operator withing your class
bool operator< (const Folder & other) const
{
return size < other.size || (size == other.size && name < other.name);
}
Alternatively you can define a global comparison operator bool operator< (const Folder & lhs, const Folder & rhs).

c++ how implement iterator for a doubly linked list

I am using this text book
http://cpp.datastructures.net
chapter 5 iterator usage:
http://cpp.datastructures.net/source/ch05/CPP/IteratorPrint.cpp-DSACiterator.html
here is how i implement it (the ObjectIterator class)
#include <iostream>
using namespace std;
class PositionException {
protected:
string message;
public:
PositionException(const string &m) {
message = m;
}
void print() {
cout << message << endl;
}
};
template <typename T>
class NodeList {
protected:
struct Node {
Node *prev;
Node *next;
T item;
Node(T i = T(), Node *p = NULL, Node *n = NULL) : item(i), prev(p), next(n) {}
};
typedef Node * NodePtr;
public:
class Position {
protected:
NodePtr node;
public:
bool isNull() {
return node == NULL;
}
Position(NodePtr n = NULL) : node(n) {}
T& element() {
return node->item;
}
friend class NodeList;
};
class ObjectIterator {
protected:
NodePtr node;
public:
ObjectIterator(NodePtr n = NULL) : node(n) {}
bool hasNext() {
if (node->next == NULL) {
return false;
}
if (node->next->next == NULL) {
return false;
}
return true;
}
ObjectIterator next() {
return ObjectIterator(node->next);
}
T& element() {
return node->item;
}
friend class NodeList;
};
protected:
int sz;
NodePtr header;
NodePtr trailer;
public:
NodeList() {
header = new Node();
trailer = new Node();
header->next = trailer;
trailer->prev = header;
sz = 0;
}
bool isEmpty() const {
return size() == 0;
}
int size() const {
return sz;
}
bool isFirst(const Position& p) const {
return p.node->prev == header;
}
bool isLast(const Position& p) const {
return p.node->next = trailer;
}
Position first() const {
if (isEmpty()) {
throw PositionException("no first for empty list");
}
return Position(header->next);
}
Position last() const {
if (isEmpty()) {
throw PositionException("no last for emtpy list");
}
return Position(trailer->prev);
}
Position before(const Position& p) const{
if (p.node->prev == header) {
throw PositionException("already the first element, nothing before it");
}
return Position(p.node->prev);
}
Position after(const Position& p) const{
if (p.node->next == trailer) {
throw PositionException("already the last element, nothing after it");
}
return Position(p.node->next);
}
Position insertAfter(const Position& p, const T& o) {
NodePtr node = new Node(o, p.node, p.node->next);
p.node->next->prev = node;
p.node->next = node;
sz++;
return Position(node);
}
Position insertBefore(const Position& p, const T& o) {
NodePtr node = new Node(o, p.node->prev, p.node);
p.node->prev->next = node;
p.node->prev = node;
sz++;
return Position(node);
}
void remove(const Position& p) {
p.node->prev->next = p.node->next;
p.node->next->prev = p.node->prev;
sz--;
delete p.node;
}
void removeFirst() {
remove(first());
}
void removeLast() {
remove(last());
}
void replaceElement(const Position& p, const T& element) {
if (p.isNull()) {
throw PositionException("p is null");
}
p.node->item = element;
}
Position insertFirst(const T& o) {
NodePtr node = new Node(o, header, header->next);
header->next->prev = node;
header->next = node;
sz++;
return Position(node);
}
Position insertLast(const T& o) {
NodePtr node = new Node(o, trailer->prev, trailer);
trailer->prev->next = node;
trailer->prev = node;
sz++;
return Position(node);
}
void copyFrom(const NodeList<T>& nl) {
sz = nl.sz;
if (nl.sz > 0) {
Position p0 = nl.first();
Position p = insertFirst(p0.node->item);
while (!nl.isLast(p0)) {
p0 = nl.after(p0);
insertAfter(p, p0.node->item);
}
}
}
void emptyList() {
while (!isEmpty()) {
removeFirst();
}
}
~NodeList() {
emptyList();
delete header;
delete trailer;
}
NodeList<T>& operator=(const NodeList<T>& nl) {
emptyList();
copyFrom(nl);
}
NodeList(const NodeList<T>& nl) {
emptyList();
copyFrom(nl);
}
void print() {
cout << "size is: " << size() << endl;
if (size() > 0) {
ObjectIterator i = elements();
while (i.hasNext()) {
cout << i.element() << "\t";
i = i.next();
}
cout << endl;
}
}
ObjectIterator elements() {
if (isEmpty()) {
throw PositionException("iterator error: empty");
}
return ObjectIterator(header->next);
}
void swapItems(const Position& p1, const Position& p2) {
T temp = p1.node->item;
p1.node->item = p2.node->item;
p2.node->item = temp;
}
};
If i don't use the iterator, the following code for printing is correct
void print() {
if (size() > 0) {
NodePtr n = header->next;
while (n != trailer) {
cout << n->item << "\t";
n = n->next;
}
cout << endl;
}
}
If I use the iterator for the print function
void print() {
cout << "size is: " << size() << endl;
if (size() > 0) {
ObjectIterator i = elements();
while (i.hasNext()) {
cout << i.element() << "\t";
i = i.next();
}
cout << endl;
}
}
one of the node is missing.
The book does not provide the correct way to implement the iterator

Something wrong when deleting an element in a Binary search tree

I only use function insert, remove and midorder.
#include<iostream>
template<class Elem>
class BinNode
{
public:
virtual Elem& getVal() = 0;
};
template<class Elem>
class BinNodePtr:public BinNode<Elem>
{
public:
Elem val;
BinNodePtr* lc;
BinNodePtr* rc;
BinNodePtr()
{
lc = rc = NULL;
}
~BinNodePtr()
{
delete lc;
delete rc;
}
Elem& getVal()
{
return this->val;
}
};
template<class Elem>
class BST
{
public:
BinNodePtr<Elem> *root;
int nodenum;
void midorder(BinNodePtr<Elem>* start);
public:
BST()
{
root = NULL;
nodenum = 0;
}
bool insert(BinNodePtr<Elem>*&ptr,const Elem &e);//
void remove(BinNodePtr<Elem>*&start,const Elem &e);//
BinNodePtr<Elem>* getRoot(){return root;}
};
template<class Elem>
void BST<Elem>::midorder(BinNodePtr<Elem> *start)
{
if(start == NULL) return;
midorder(start->lc);
printf("%d ",start->getVal());
midorder(start->rc);
}
template<class Elem>
bool BST<Elem>::insert(BinNodePtr<Elem>*&ptr,const Elem &e)
{
if(ptr == NULL)
{
ptr = new BinNodePtr<Elem>;
ptr->lc = NULL;
ptr->rc = NULL;
ptr->val = e;
return true;
}
else
{
if(ptr->val < e || ptr->val == e)
{
insert(ptr->rc,e);
}
else
{
insert(ptr->lc,e);
}
}
return false;
}
template<class Elem>
void BST<Elem>::remove(BinNodePtr<Elem>*&start,const Elem &e)
{
if(start == NULL)
return ;
if(start->val < e)
remove(start->rc,e);
else if(start->val > e)
remove(start->lc,e);
else
{
if(start->lc == NULL && start->rc == NULL)
{
delete start;
}
else if(start->lc == NULL)
{
BinNodePtr<Elem> *temp = start;
start = start->rc;
delete (temp);
}
else if(start->rc == NULL)
{
BinNodePtr<Elem> *temp = start;
start = start->lc;
delete temp;
}
else
{
BinNodePtr<Elem>* temp = start->rc;
while(temp->lc!= NULL)
{
temp = temp->lc;
}
start->val = temp->val;
remove(start->rc,temp->val);
}
}
}
int main()
{
BST<int> myBST;
(myBST.insert(myBST.root,10));
(myBST.insert(myBST.root,20));
(myBST.insert(myBST.root,5));
(myBST.insert(myBST.root,30));
myBST.midorder(myBST.getRoot());
myBST.remove(myBST.root,10);
myBST.midorder(myBST.getRoot());
system("pause");
return 0;
}
I have successfully inserted 10, 20, 5, 30 because I can "printf" them out, but the program breaks down when I use function remove. I debugged this and found that there is something wrong in function remove but I don't know how to fix it.

C++ custom template LinkedList crashes adding std::string

For academic purposes, I'm trying to develop a little "textual adventure game". I have to implement all data structures by my own. Now, I have some problems with the implementation of a generic (template) LinkedList.
In the specific, this data structure works with everything (primitive data types and custom objects) BUT strings! (standard library strings).
When I try to add strings to a list, the application crashes with the following error (in console):
"terminate called after throwing an instance of 'std::logic_error'
what(): basic_string::_S_constructor null not valid"
The list is implemented as a "double linked list" using the head-node as first-last node
Here the code ("Abstract" List interface):
#ifndef LIST_H_
#define LIST_H_
template <class T>
class List
{
public:
virtual ~List() {}
virtual T get(int position) = 0;
virtual List* add(T item) = 0;
virtual List* insert(T item, int position) = 0;
virtual List* remove(int position) = 0;
virtual int size() const = 0;
virtual bool isEmpty() const = 0;
protected:
private:
};
#endif /* LIST_H_ */
This is the LinkedList implementation (the "node" class):
#include "List.h"
#include <stdlib.h>
#ifndef LINKEDLIST_H_
#define LINKEDLIST_H_
template <class T>
class ListNode
{
public:
ListNode(T item)
{
mItem = item;
mNext = NULL;
mPrev = NULL;
}
ListNode(T item, ListNode<T>* next, ListNode<T>* prev)
{
mItem = item;
mNext = next;
mPrev = prev;
}
~ListNode()
{
delete &mItem;
}
T getItem()
{
return mItem;
}
ListNode<T>* getNext()
{
return mNext;
}
ListNode<T>* getPrev()
{
return mPrev;
}
void setItem(T item)
{
mItem = item;
}
void setNext(ListNode<T>* next)
{
mNext = next;
}
void setPrev(ListNode<T>* prev)
{
mPrev = prev;
}
protected:
private:
T mItem;
ListNode<T> *mNext, *mPrev;
};
The LinkedList class:
template <class K>
class LinkedList : public List<K>
{
public:
LinkedList()
{
mSize = 0;
mFirstNode = NULL;
}
~LinkedList()
{
// implementazione distruttore tramite ciclo sui nodi
}
K get(int position)
{
K item = NULL;
ListNode<K>* targetNode = getNodeAtPosition(position);
if (targetNode != NULL) item = targetNode->getItem();
return item;
}
List<K>* add(K item)
{
if (mFirstNode == NULL)
{
mFirstNode = new ListNode<K>(item);
mFirstNode->setNext(mFirstNode);
mFirstNode->setPrev(mFirstNode);
}
else
{
ListNode<K>* newNode = new ListNode<K>(item, mFirstNode, mFirstNode->getPrev());
mFirstNode->getPrev()->setNext(newNode);
mFirstNode->setPrev(newNode);
}
mSize++;
return this;
}
List<K>* insert(K item, int position)
{
ListNode<K>* targetNode = getNodeAtPosition(position);
if (targetNode != NULL)
{
ListNode<K>* newNode = new ListNode<K>(targetNode->getItem(), targetNode->getNext(), targetNode);
targetNode->setItem(item);
targetNode->setNext(newNode);
mSize++;
}
return this;
}
List<K>* remove(int position)
{
ListNode<K>* targetNode = getNodeAtPosition(position);
if (targetNode != NULL)
{
targetNode->setItem(targetNode->getNext()->getItem());
targetNode->setNext(targetNode->getNext()->getNext());
//delete targetNode->getNext();
mSize--;
}
return this;
}
int size() const
{
return mSize;
}
bool isEmpty() const
{
return (mFirstNode == NULL) ? true : false;
}
protected:
ListNode<K>* getNodeAtPosition(int position)
{
ListNode<K>* current = NULL;
if (mFirstNode != NULL && position < mSize)
{
current = mFirstNode;
for (int i = 0; i < position; i++)
{
current = current->getNext();
}
}
return current;
}
private:
int mSize;
ListNode<K>* mFirstNode;
};
#endif /* LINKEDLIST_H_ */
Suggestions?
Part of your problem is here:
ListNode(T item)
{
mItem = item; // for a std::string, this will be a class member, non-pointer
mNext = NULL;
mPrev = NULL;
}
ListNode(T item, ListNode<T>* next, ListNode<T>* prev)
{
mItem = item; // same here
mNext = next;
mPrev = prev;
}
~ListNode()
{
delete &mItem; // you are attempting to delete an item you never created
}
You should either change your constructors to create a T* object on the heap (which will then be deleted in your destructor), or remove the delete line from your destructor.
This problem will be evident with far more than just std::string, by the way.
Somewhere in your program you are doing this:
std::string s(nullptr);
Calling std::string's constructor with a null pointer is causing it to throw a std::logic_error exception.
From the standard:
ยง 21.4.2
basic_string(const charT* s, size_type n, const Allocator& a = Allocator());
Requires: s shall not be a null pointer and n < npos.
It seems it's not possible to pass std::string as template argument...
Strings as Template Arguments
Now I use an "old" - char const* - to achieve the expected result, even if I have to implement my personal "utils" methods to work with those pointers now...