I am attempting to create an AVL tree with unique pointers. But I am stuck on the elementary part of inserting nodes recursively. This code creates a segmentation fault at the call to the insertNode_ function. I thought that merely passing raw pointers would work, but it does not.
#ifndef AVL_H
#define AVL_H
#include <memory>
#include <iostream>
template<class T>
class AVL
{
public:
template<class K,class V>
struct nodeAVL;
typedef std::unique_ptr<nodeAVL<int,T>> node_ptr;
typedef nodeAVL<int,T> node;
/* Node struct */
template<class K,class V>
struct nodeAVL
{
nodeAVL(const K& key, const V& value):
key_ (key), value_ (value)
{ left = nullptr;right=nullptr;parent=nullptr; }
std::unique_ptr< nodeAVL<K,V> > left, right;
node* parent;
V value()
{ return value_; }
K key()
{ return key_; }
K key(const K& key)
{ key_ = key; }
private:
K key_;
V value_;
};
/* end of Node struct */
AVL()
{ head_=nullptr; };
void insert (const T& value)
{ std::cout<<value<<" inserting\n";
insertNode_ (head_, head_->parent,value); }
std::string print()
{ std::cout<<"print\n";
return print_inOrder_(head_, ""); }
private:
node_ptr head_;
template <class N, class... Args> //allows make_unique in c11
std::unique_ptr<N> make_unique(Args&&... args) {
return std::unique_ptr<N>(new N(std::forward<Args>(args)...));
}
/* recursive insertion */
void insertNode_( node_ptr& current,node* parent, const T& value)
{
std::cout<<"segmentation fault happens here, this line doesnt print\n";
if (current == nullptr){
current = std::move(make_unique<node>(-1,value));
std::cout<<current->value()<<" inserted\n";
if (parent!= nullptr)
std::cout<<"another issue happens here after root insertion\n";
}
else {
if ( current->value() > value )
insertNode_(current->left, current.get(),value);
else if ( current->value() < value )
insertNode_(current->right, current.get(),value);
}
}
/* recursive inOrder print */
std::string print_inOrder_(const node_ptr& current,std::string print)
{
if (current != nullptr) {
std::cout<<"<"<<current->value()<<">"<<std::endl;
print+= "[" + std::to_string(current->value())+"]";
print = print_inOrder_(current->left,print);
print = print_inOrder_(current->right,print);
}
return print;
}
};
#endif
Related
I'm writing codes about binary tree using smart pointer, but there is something wrong with destructor. I don't know where the momery leaks. But when I remove all components with parent pointer in BinNode, it runs with no errors.
Header file is showed as follow:
#ifndef BINARY_H
#define BINARY_H
#include <memory>
#include <iostream>
#ifndef RANK_DEFINED
#define RANK_DEFINED
typedef int64_t Rank;
#endif
template <typename T> class BinaryTree;
typedef enum {RB_RED, RB_BLACK} RBColor;
template <typename T>
class BinNode {
public:
friend class BinaryTree<T>;
BinNode() = default;
BinNode(const T& data, std::shared_ptr<BinNode> pare = nullptr, std::shared_ptr<BinNode> left = nullptr, std::shared_ptr<BinNode> right = nullptr,
int h = 1) : _data(data), left_child(left), right_child(right), parent(pare), height(h){}
~BinNode() = default;
std::shared_ptr<BinNode> insertAsLeft(const T& e) {
left_child = std::make_shared<BinNode>(e);
left_child->parent = std::shared_ptr<BinNode>(this);
return left_child;
}
std::shared_ptr<BinNode> insertAsRight(const T& e) {
right_child = std::make_shared<BinNode>(e, this);
return right_child;
}
int size() const;
std::shared_ptr<BinNode> succ();
template <typename VST> void travelLevel(VST (*f)());
template <typename VST> void travelPre(VST (*f)());
template <typename VST> void travelIn(VST&);
template <typename VST> void travelPost(VST&);
bool operator<(BinNode const& bn) { return _data < bn._data; }
bool operator==(BinNode const& bn) { return _data == bn._data; }
bool isRoot() { return !(parent); }
bool isLChild() { return !isRoot() && this == parent->left_child; }
bool isRChild() { return !isRoot() && this == parent->right_child; }
bool hasParent() { return !isRoot(); }
bool hasLChild() { return !left_child; }
bool hasRChild() { return !right_child; }
bool hasChild() { return hasLChild() || hasRChild(); }
bool hasBothChild() { return hasLChild() && hasRChild(); }
bool isLeaf() { return !hasChild(); }
std::shared_ptr<BinNode> sibling() const {
return (isLChild() ? parent->right_child : parent->left_child);
}
std::shared_ptr<BinNode> uncle() const {
return parent->sibling();
}
private:
T _data;
std::shared_ptr<BinNode<T>> left_child = nullptr;
std::shared_ptr<BinNode<T>> right_child = nullptr;
std::shared_ptr<BinNode<T>> parent = nullptr;
int height = 1;
};
// Binary Tree Defination
template <typename T>
class BinaryTree
{
using BN = BinNode<T>;
public:
BinaryTree(): _size(0), _root(nullptr) {}
~BinaryTree() = default;
int size() const { return _size; }
bool empty() const { return !_root; }
std::shared_ptr<BN> root() const { return _root; }
std::shared_ptr<BN> insertAsRoot(const T& e);
std::shared_ptr<BN> insertAsLC(std::shared_ptr<BN> pare, const T& e);
std::shared_ptr<BN> insertAsRC(std::shared_ptr<BN> pare, const T& e);
std::shared_ptr<BN> insertAsLC(std::shared_ptr<BN> pare, BinaryTree<T> bt);
std::shared_ptr<BN> insertAsRC(std::shared_ptr<BN> pare, BinaryTree<T> bt);
int remove(std::shared_ptr<BN>);
BinaryTree* secede(std::shared_ptr<BN>);
template <typename VST>
void travelLevel(VST& visit) { if (_root) _root->travelLevel(visit); }
template <typename VST>
void travelPre(VST& visit) { if (_root) _root->travelPre(visit); }
template <typename VST>
void travelIn(VST& visit) { if (_root) _root->travelIn(visit); }
template <typename VST>
void travelPost(VST& visit) { if (_root) _root->travelPost(visit); }
protected:
Rank _size;
std::shared_ptr<BN> _root;
virtual int updateHeight(std::shared_ptr<BN>);
void updateHeightAbove(std::shared_ptr<BN>);
void delTree(std::shared_ptr<BN>);
};
template <typename T>
std::shared_ptr<BinNode<T>> BinaryTree<T>::insertAsRoot(const T& e)
{
_root = std::make_shared<BN>(e);
_size = 1;
return _root;
}
template <typename T>
std::shared_ptr<BinNode<T>> BinaryTree<T>::insertAsLC(std::shared_ptr<BN> pare, const T& e)
{
auto newNode = pare->insertAsLeft(e);
_size++;
updateHeightAbove(newNode);
return pare->left_child;
}
template <typename T>
std::shared_ptr<BinNode<T>> BinaryTree<T>::insertAsRC(std::shared_ptr<BN> pare, const T& e)
{
}
template <typename T>
void BinaryTree<T>::updateHeightAbove(std::shared_ptr<BN> x)
{
while(x)
{
updateHeight(x);
x = x->parent;
}
}
template <typename T>
int BinaryTree<T>::updateHeight(std::shared_ptr<BN> x)
{
Rank lh = 1, rh = 1;
if (x->left_child)
lh = x->left_child->height;
if (x->right_child)
rh = x->right_child->height;
x->height = (lh > rh) ? lh : rh;
return x->height;
}
#endif
and main function is:
int main()
{
BinaryTree<int> bt;
bt.insertAsRoot(1);
bt.insertAsLC(bt.root(), 2);
cout << bt.size() << endl;
return 0;
}
Result is double free or corruption (out).
There are two problems with your parent links:
Both the downwards and the upwards pointers are std::shared_ptr. This is known as a reference cycle and prohibits your tree from ever being destroyed properly. A common solution is to make the parent pointer a std::weak_ptr, such that it does not count towards keeping the parent alive.
The second problem is hidden in your insertAsLeft: std::shared_ptr<BinNode>(this) will construct a new shared_ptr with refcount 1. This means that you have multiple shared_ptrs pointing to the same block of memory and the first one that drops to refcount 0 frees the block, leaving you with dangling pointers. Luckily for you, C++ has a ready-made solution. Simply inherit from std::enable_shared_from_this and use left_child->parent = shared_from_this(); instead. In a nutshell, this construction allows BinNode to keep track of which shared_ptr owns it.
The code is posted here: https://ideone.com/ul2PiS
What I'm trying to do is allow the user to specify the list nodes as member fields of the classes which will be added to the lists. Currently, this is done with a macro using offsetof() which means that the member nodes have to be public. Ideally, I'd like to be able to somehow specify, as part of each linked_list declaration, as a template parameter, which member field should be used as the node. boost::intrusive seems to manage it, but I can't quite follow how they do it.
It's a requirement that the list functions be branchless (no pointer comparisons, the platform has a very very slow branch mechanism) and that the list be intrusive and allow objects to be members of multiple lists simultaneously.
//////////////////////////////////////////////////////////////////////
// linked_list.h
#pragma once
//////////////////////////////////////////////////////////////////////
#include <cstddef>
#include <functional>
//////////////////////////////////////////////////////////////////////
struct list_node
{
list_node *next;
list_node *prev;
};
//////////////////////////////////////////////////////////////////////
template<typename T, size_t off> struct linked_list
{
//////////////////////////////////////////////////////////////////////
static list_node const *get_node(T const *o)
{
return reinterpret_cast<list_node const *>(reinterpret_cast<char const *>(o) + off);
}
//////////////////////////////////////////////////////////////////////
static list_node *get_node(T *o)
{
return reinterpret_cast<list_node *>(reinterpret_cast<char *>(o) + off);
}
//////////////////////////////////////////////////////////////////////
static T const *get_object(list_node const *node)
{
return reinterpret_cast<T const *>(reinterpret_cast<char const *>(node) - off);
}
//////////////////////////////////////////////////////////////////////
static T *get_object(list_node *node)
{
return reinterpret_cast<T *>(reinterpret_cast<char *>(node) - off);
}
//////////////////////////////////////////////////////////////////////
list_node root;
//////////////////////////////////////////////////////////////////////
linked_list()
{
root.next = &root;
root.prev = &root;
}
//////////////////////////////////////////////////////////////////////
void push_front(T *obj)
{
list_node *node = get_node(obj);
root.next->prev = node;
node->next = root.next;
node->prev = &root;
root.next = node;
}
//////////////////////////////////////////////////////////////////////
void push_front(T &obj)
{
list_node *node = get_node(&obj);
root.next->prev = node;
node->next = root.next;
node->prev = &root;
root.next = node;
}
//////////////////////////////////////////////////////////////////////
void push_back(T *obj)
{
list_node *node = get_node(obj);
node->prev = root.prev;
node->next = &root;
root.prev->next = node;
root.prev = node;
}
//////////////////////////////////////////////////////////////////////
void push_back(T &obj)
{
list_node *node = get_node(&obj);
node->prev = root.prev;
node->next = &root;
root.prev->next = node;
root.prev = node;
}
//////////////////////////////////////////////////////////////////////
void insert_before(T *pos, T *obj)
{
list_node *node = get_node(obj);
list_node *n = get_node(pos);
n->prev->next = node;
node->prev = n->prev;
n->prev = node;
node->next = n;
}
//////////////////////////////////////////////////////////////////////
void insert_before(T &pos, T &obj)
{
list_node *node = get_node(&obj);
list_node *n = get_node(&pos);
n->prev->next = node;
node->prev = n->prev;
n->prev = node;
node->next = n;
}
//////////////////////////////////////////////////////////////////////
void insert_after(T *pos, T *obj)
{
list_node *node = get_node(obj);
list_node *n = get_node(pos);
n->next->prev = node;
node->next = n->next;
n->next = node;
node->prev = n;
}
//////////////////////////////////////////////////////////////////////
void insert_after(T &pos, T &obj)
{
list_node *node = get_node(&obj);
list_node *n = get_node(&pos);
n->next->prev = node;
node->next = n->next;
n->next = node;
node->prev = n;
}
//////////////////////////////////////////////////////////////////////
void remove(T *obj)
{
list_node *node = get_node(obj);
node->prev->next = node->next;
node->next->prev = node->prev;
}
//////////////////////////////////////////////////////////////////////
void remove(T &obj)
{
list_node *node = get_node(&obj);
node->prev->next = node->next;
node->next->prev = node->prev;
}
//////////////////////////////////////////////////////////////////////
T *pop_back()
{
list_node *node = root.prev;
node->prev->next = node->next;
node->next->prev = node->prev;
return get_object(node);
}
//////////////////////////////////////////////////////////////////////
T *pop_front()
{
list_node *node = root.next;
node->next->prev = node->prev;
node->prev->next = node->next;
return get_object(node);
}
//////////////////////////////////////////////////////////////////////
bool empty() const
{
return root.next == &root;
}
//////////////////////////////////////////////////////////////////////
void clear()
{
root.next = root.prev = &root;
}
//////////////////////////////////////////////////////////////////////
T *head() const
{
return get_object(root.next);
}
//////////////////////////////////////////////////////////////////////
T *tail() const
{
return get_object(root.prev);
}
//////////////////////////////////////////////////////////////////////
T const *end()
{
return get_object(&root);
}
//////////////////////////////////////////////////////////////////////
T *next(T *i) const
{
return get_object(get_node(i)->next);
}
//////////////////////////////////////////////////////////////////////
T *prev(T *i) const
{
return get_object(get_node(i)->prev);
}
//////////////////////////////////////////////////////////////////////
bool for_each(std::function<bool (T *)> func)
{
for(T *i = head(); i != end(); i = next(i))
{
if(!func(i))
{
return false;
}
}
return true;
}
//////////////////////////////////////////////////////////////////////
T *find(std::function<bool (T *)> func)
{
for(T *i = head(); i != end(); i = next(i))
{
if(func(i))
{
return i;
}
}
return nullptr;
}
//////////////////////////////////////////////////////////////////////
};
//////////////////////////////////////////////////////////////////////
// Yuck:
#define declare_linked_list(type_name, node_name) \
linked_list<type_name, offsetof(type_name, node_name)>
#define typedef_linked_list(type_name, node_name) \
typedef declare_linked_list(type_name, node_name)
And the client code looks like:
//////////////////////////////////////////////////////////////////////
// main.cpp
#include <stdio.h>
#include <random>
#include "linked_list.h"
struct foo
{
foo() : i(rand() % 10) { }
int i;
list_node node1; // would like it if these could be made private
list_node node2; // but the nasty macros need to see inside...
list_node node3; // getting rid of the macros would be even better
};
// None of these 3 options are very nice:
// 1. declare a list with the macro
declare_linked_list(foo, node1) list1;
// 2. or via a typedef
typedef_linked_list(foo, node2) list2_t;
list2_t list2;
// 3. or very wordy non-macro declaration
linked_list<foo, offsetof(foo, node3)> list3;
int main(int, char **)
{
printf("Begin\n");
foo foos[10];
for(int i=0; i<10; ++i)
{
list1.push_back(foos[i]);
list2.push_back(foos[i]);
list3.push_back(foos[i]);
}
int sum = 0;
int n = 0;
// but this for loop is clear and readable and has very low overhead
for(foo *i = list1.head(); i != list1.end(); i = list1.next(i))
{
sum += i->i;
}
printf("Total: %d\n", sum);
list2.remove(foos[2]);
n = 0;
sum = 0;
for(foo *i = list2.head(); i != list2.end(); i = list2.next(i))
{
sum += i->i;
}
printf("Total2: %d\n", sum);
getchar();
return 0;
}
[EDIT]
OK, with pointer to member template parameter it's much nicer:
template<typename T, list_node T::* node> struct linked_list
{
//////////////////////////////////////////////////////////////////////
static list_node const *get_node(T const *o)
{
return reinterpret_cast<list_node const *>
(reinterpret_cast<char const *>(o) + offsetof(T, *node));
}
//////////////////////////////////////////////////////////////////////
static list_node *get_node(T *o)
{
return reinterpret_cast<list_node *>
(reinterpret_cast<char *>(o) + offsetof(T, *node));
}
//////////////////////////////////////////////////////////////////////
static T const *get_object(list_node const *n)
{
return reinterpret_cast<T const *>
(reinterpret_cast<char const *>(n) - offsetof(T, *node));
}
//////////////////////////////////////////////////////////////////////
static T *get_object(list_node *n)
{
return reinterpret_cast<T *>
(reinterpret_cast<char *>(n) - offsetof(T, *node));
}
so you can declare lists like:
linked_list<foo, &foo::node1> list1;
so we (mostly) get rid of the ugly declaration syntax, although I still can't find a way to allow them to be private. It looks like boost::intrusive requires them to be public as well.
Here is a bit of a hack that will allow bijective mapping between a member and the struct, doing mere pointer arithmetic on constants at run time. static_assert( std::is_pod<T>::value, "POD needed!" ); might be a good idea:
template<typename T, typename N, N T::* member>
struct member_access {
static N& ContainerToMember( T& t ) { return t.*member; }
static N const& ContainerToMember( T const& t ) { return t.*member; }
template<T* ptr=nullptr>
static constexpr std::size_t offset_of() {
return reinterpret_cast<std::size_t>(reinterpret_cast<char*>(&((ptr)->*member)));
}
static T& MemberToContainer( N& n ) {
return *reinterpret_cast<T*>(reinterpret_cast<char*>(&n)-offset_of());
}
static T const& MemberToContainer( N const& n ) {
return *reinterpret_cast<T const*>(reinterpret_cast<char const*>(&n)-offset_of());
}
};
which gets rid of your offsetof requirement.
Privacy is hard. There is the explicit specialization side effect hole in the privacy type system, but it results in runtime member pointers, and we want compile time values.
A better approach might be to stuff the linked lists into some metaprogramming:
template< typename T, unsigned index >
struct list_node:list_node<T, index-1> {
list_node* next;
list_node* prev;
T* self() { static_cast<T*>(this); }
T const* self() const { static_cast<T const*>(this); }
};
template<typename T>
struct list_node<T, 0> {
list_node* next;
list_node* prev;
T* self() { static_cast<T*>(this); }
T const* self() const { static_cast<T const*>(this); }
};
template<typename T, unsigned N>
struct listable : list_node<T, N-1> {};
template<typename T>
struct listable<T, 0> {};
then simply create your listable data like:
struct data: listable<data, 10> {
std::string s;
};
We can then do this:
template<unsigned N, typename T>
list_node<T, N>& get_node( T& t ) { return t; }
template<unsigned N, typename T>
list_node<T, N> const& get_node( T const& t ) { return t; }
template<unsigned N, typename T>
T& get_data( list_node<T, N>& n ) { return *n.self(); }
template<unsigned N, typename T>
T const& get_data( list_node<T, N> const& n ) { return *n.self(); }
which is all legal C++11.
template<typename T, unsigned index>
struct linked_list {
typedef list_node<T, index> node;
};
which is sort of nice. Downside: the list_node for each linked_list is a different type. Getting around that is a bit tricky.
We could stay in the realm of defined behavior by pushing all of the next and prev pointers to a POD array beyond the root of the topmost list_node. We then work with pointers into that. We can legally do pointer arithmetic within that array, and a pointer to the first element of the most ancestral struct can be legally reinterpreted to being a pointer to that struct.
From that, we can static_cast down to a T* directly (which is probably no binary change in the pointer value at all).
struct link { link* next; link* prev; };
template<typename T, unsigned N>
struct listable {
std::array<link, N> links;
static listable* array_to_list( std::array<link, N>* a ) { return reinterpret_cast<listable>(a); }
template<unsigned I>
static listable* link_to_list( link* l ) {
return array_to_list( reinterpret_cast<std::array<link, N>>(l - I) );
}
template<unsigned I>
link* get_link() { return &links[I]; }
T* listable_to_T() {
static_assert( std::is_base_of< listable, T >::value, "CRTP vailure" );
return static_cast<T*>(this);
}
template<unsigned I>
static T* link_to_T(link* l) {
return link_to_list<I>(l)->listable_to_T()
}
};
which at most requests that a pointer-to-first-element and a pointer-to-array be layout compatible (I hope so!)
Again, under this model, your link listable data does:
struct Bob : listable<Bob, 10> {};
to say that there are 10 embedded lists in Bob. Converting from a Bob to a link* involves invoking bob.get_link<5>(), while converting from a link* to a Bob* is listable<Bob, 10>::link_to_T<5>( l ), assuming we are talking about sub-list 5.
This is the first time I've ever played with an iterator so there's probably significant errors. I'm attempting to make an inorder iterative iterator class to work in conjunction with my threaded binary search tree. So the iterator is working over nodes. I only need the iterator to go through my tree in order so I can print all the values and the frequencies of each node. However my dereference doesn't seem to be working probably. This is the method that's giving me trouble:
//-------------------------- inOrderTraverse ------------------------------------
template <typename T>
void ThreadedBST<T>::inOrderTraverse() {
InorderIterator<T>* iter = new InorderIterator<T>(root);
++iter;
while ((*iter) != NULL)
{
cout << (*iter)->getItem() << " " << (*iter)->getFrequency() << endl;
}
}
Particularly the while loop is throwing compiler errors. Here is the exact error:
error C2678: binary '!=' : no operator found which takes a left-hand operand of type 'InorderIterator'
I figured the dereference would bring the node out so I'd actually be comparing the node != NULL but that's not what the error message leads me to believe. Here's the full Iterator class:
#ifndef INORDERITER_H
#define INORDERITER_H
#include <iostream>
#include "ThreadedBST.h"
using namespace std;
//---------------------------------------------------------------------------
// InorderIterator<T> class:
// --
//
// Assumptions:
// -- <T> implements it's own comparable functionality
//---------------------------------------------------------------------------
template <typename T>
class InorderIterator {
public:
InorderIterator(node<T> *); //constructor
InorderIterator<T>& operator++();
node<T>& operator*();
const node<T>& operator*() const;
private:
node<T>* begin;
node<T>* curr;
node<T>* prev;
node<T>* temp;
};
template <typename T>
InorderIterator<T>::InorderIterator(node<T>* root) {
begin = root;
temp = NULL;
while (begin->leftChild != NULL) {
begin = begin->leftChild;
}
}
template <typename T>
InorderIterator<T>& InorderIterator<T>::operator++() {
if (temp == NULL)
temp = begin;
else if (rightChildThread) {
prev = temp;
temp = temp->rightChild;
}
else {
prev = temp;
temp = temp->rightChild;
while (!temp->rightChildThread && (temp->leftChild->getItem() != prev->getItem())) {
temp = temp->leftChild;
}
}
curr = temp;
return *this;
}
template <typename T>
node<T>& InorderIterator<T>::operator*() {
return *curr;
}
template <typename T>
const node<T>& InorderIterator<T>::operator*() const {
return *curr;
}
#endif
Here's the node class if it's relevant for any reason:
#ifndef NODE_H
#define NODE_H
#include <iostream>
using namespace std;
//---------------------------------------------------------------------------
// node<T> class:
// --
//
// Assumptions:
// -- <T> implements it's own comparable functionality
//---------------------------------------------------------------------------
template <typename T>
class node {
public:
node<T>* leftChild;
node<T>* rightChild;
bool leftChildThread;
bool rightChildThread;
node(T value); //constructor
node(T value, node<T>*, node<T>*, bool, bool); //secondary constructor
node(const node<T>&); //copy constructor
void decrementFrequency(); //decrements by 1 the frequency
void incrementFrequency(); //increments by 1 the frequency
int getFrequency(); //returns the frequency
T getItem(); //returns the item
private:
T item;
int frequency;
};
//-------------------------- Constructor ------------------------------------
template <typename T>
node<T>::node(T value) {
item = value;
frequency = 1;
}
//-------------------------- Secondary Constructor ------------------------------------
template <typename T>
node<T>::node(T value, node<T>* left, node<T>* right, bool leftThread, bool rightThread) {
item = value;
frequency = 1;
leftChild = left;
rightChild = right;
leftChildThread = leftThread;
rightChildThread = rightThread;
}
//-------------------------- Copy ------------------------------------
template <typename T>
node<T>::node(const node<T>& copyThis) {
item = copyThis.value;
frequency = copyThis.frequency;
}
//-------------------------- decrementFrequency ------------------------------------
template <typename T>
void node<T>::decrementFrequency() {
frequency--;
}
//-------------------------- incrementFrequency ------------------------------------
template <typename T>
void node<T>::incrementFrequency() {
frequency++;
}
//-------------------------- getFrequency ------------------------------------
template <typename T>
int node<T>::getFrequency() {
return frequency;
}
//-------------------------- getItem ------------------------------------
template <typename T>
T node<T>::getItem() {
return item;
}
#endif
class const_iterator {
public:
Node *current;
const_iterator (Node *n) : current{n}
{
/* the body can remain blank, the initialization is carried
* the the constructor init list above
*/
}
/* copy assignment */
const_iterator operator= (const const_iterator& rhs) {
this->current = rhs.current;
return *this;
}
bool operator == (const const_iterator& rhs) const {
return this->current == rhs.current;
}
bool operator != (const const_iterator& rhs) const {
return this->current != rhs.current;
}
/* Update the current pointer to advance to the node
* with the next larger value
*/
const_iterator& operator++ () {
/*first step is to go left as far as possible(taken care of by begin())
once you go as left as possible, go right one step at a time*/
if(current->right != nullptr){
current = current->right;
//every step, go left again as far as possible
while(current->left != nullptr){
current = current->left;
}
}else{
bool upFromLeft = false;
bool upFromRight = false;
while(upFromLeft == false && upFromRight == false){
//if you have gone all the way up from the right
if(current->parent == nullptr){
upFromRight = true;
current = current->parent;
return *this;
}
//if you have gone all the way back up left
if(current->parent->left == current){
upFromLeft = true;
current = current->parent;
return *this;
}
current = current->parent;
}
}
return *this;
}
Z& operator *() const {
return current->data;
}
};
ADD these functions to your tree in order to use the begin() and end() with your iterator
const const_iterator begin() const {
if(rootPtr == nullptr){
return nullptr;
}
Node* temp = rootPtr;
while(temp->left != nullptr){
temp = temp->left;
}
return const_iterator(temp);
}
/* For the "end" marker
* we will use an iterator initialized to nil */
const const_iterator end() const {
return const_iterator(nullptr);
}
Here's an example of an in-order iterator I wrote in C++...
This iterator assumes that each node in your BST has a pointer to the parent node which is something I don't see in your node class. However, I am not sure its even possible to accomplish an inorder traversal without having a parent pointer.
In short, this example will work if you add a parent pointer to your nodes and update your parent pointers every time you do a node insertion or removal
So I am trying to create my own implementation file which contains instructions for a Queue. I decided to use a linked list to implement the Queue class, meaning that I need to use my own Node struct. Unfortunately, I am stuck and don't know how to properly include this within the file.
This is what I have so far:
#include <string>
#ifndef NODE
template <class DataType>
struct Node
{
DataType data;
Node *next;
};
#endif
template <class DataType>
class Queue
{
public:
Queue();
bool isEmpty() const;
void push(const DataType& parameter);
bool peek(DataType& parameter) const;
bool pop(DataType& parameter);
void makeEmpty();
private:
Node<DataType>* front;
Node<DataType>* end;
};
template <class DataType>
Queue<DataType>::Queue()
: front(0), end(0)
{
}
template <class DataType>
bool Queue<DataType>::isEmpty() const {return 0 == front;}
template <class DataType>
void Queue<DataType>::push(const DataType& parameter)
{
Node<DataType>* node = new Node<DataType>;
node->data = parameter;
node->next = 0;
if (end) end->next = node;
else front = node;
end = node;
}
template <class DataType>
bool Queue<DataType>::peek(DataType& parameter) const
{
if (0 == front) return false; // failed
parameter = front->data;
return true; // success
}
template <class DataType>
bool Queue<DataType>::pop(DataType& parameter)
{
if (0 == front) return false; // failed
parameter = front->data;
Node<DataType>* p = front->next;
delete front;
front = p;
if (front == 0) end = 0;
return true; // success
}
template <class DataType>
void Queue<DataType>::makeEmpty()
{
end = 0;
Node<DataType>* p;
while (front)
{
p = front->next;
delete front;
front = p;
}
}
I'm not sure if I am enclosing the struct by the #ifndef correctly (i'm not even sure if this is the route I should be taking :/), should I be doing something similar to this or should I be doing something else with the code for the struct?
You can just drop the #ifdef/#endif entirely
This is a class template and it may occur many times in several tranlation units, as long as all the occurrences are identical (One Definition Rule)
Alternative
Since Node<> is purely a private concern, I'd make it a nested struct.
Here's a little demo making this more 'modern C++' style.
Edit Thanks to #R.MartinhoFernandes for showing a few more improvements and for reviewing this.
#include <memory>
template <typename T>
struct Queue {
Queue() : front(), end(/*nullptr*/) {}
// Copy-And-Swap idiom
// see http://en.wikibooks.org/wiki/More_C%2B%2B_Idioms/Copy-and-swap
// or http://stackoverflow.com/questions/3279543/what-is-the-copy-and-swap-idiom
void swap(Queue& q) noexcept {
using std::swap;
swap(q.front, front);
swap(q.end, end);
}
Queue(Queue const& q) : front(), end() {
for(auto it=q.front.get(); it; it=it->next.get())
push(it->data);
}
Queue& operator=(Queue q) {
std::swap(*this, q);
return *this;
}
// end Copy-and-swap
// prevent stack overflows in ~Node if the list grows large (say >1k elements)
~Queue() { clear(); }
bool isEmpty() const {
return !front;
}
void push(T const& data) {
Ptr node(new Node(data));
if (end)
end->next = std::move(node);
else
front = std::move(node);
end = node.get();
}
bool peek(T& data) const {
if(front) data = front->data;
return front.get();
}
bool pop(T& data) {
if(!front) return false;
data = front->data;
front = std::move(front->next);
if(!front) end = nullptr;
return true;
}
void clear() {
end = nullptr;
while(front) front = std::move(front->next);
}
private:
struct Node;
typedef std::unique_ptr<struct Node> Ptr;
struct Node {
Node(T data) : data(std::move(data)), next() {}
T data;
Ptr next;
};
Ptr front;
Node* end;
};
#include <iostream>
int main(int argc, const char *argv[]) {
Queue<int> test;
test.push(1);
test.push(2);
test.push(3);
test.push(5);
test.clear();
test.push(32028);
test.push(10842);
test.push(1839);
test.push(23493);
test.push(9857);
int x;
test.peek(x);
while(test.pop(x)) {
std::cout << x << '\n';
}
}
Note: Perhaps the code in push has been golfed a bit too far, but hey, it shows you how modern C++ requires much less handholding (even without std::make_unique).
Note how I think Clang correctly handles the following version (i.e. with implicit std::move):
void push(const DataType& parameter) {
end = ((end? end->next : front) = Ptr(new Node(parameter))).get();
}
I'm not quite sure why gcc rejects it.
I have been struggling for too long a time now with a rather simple question about how to create a generic linked list in c++. The list should be able contain several types of structs, but each list will only contain one type of struct. The problem arises when I want to implement the getNode() function [see below], because then I have to specify which of the structs it should return. I have tried to substitute the structs with classes, where the getNode function returns a base class that is inherited by all the other classes, but it still does not do the trick, since the compiler does not allow the getNode function to return anything but the base class then.
So here is some code snippet:
typedef struct struct1
{
int param1;
(...)
} struct1;
typedef struct struct2
{
double param1;
(...)
} struct2;
typedef struct node
{
struct1 data;
node* link;
} node;
class LinkedList
{
public:
node *first;
int nbrOfNodes;
LinkedList();
void addNode(struct1);
struct1 getNode();
bool isEmpty();
};
LinkedList::LinkedList()
{
first = NULL;
nbrOfNodes = 0;
}
void LinkedList::addNode(struct1 newData)
{
if (nbrOfNodes == 0)
{
first = new node;
first->data = newData;
}
else
{
node *it = first;
for (int i = 0; i < nbrOfNodes; i++)
{
it = it->link;
}
node *newNode = new node;
newNode->data = newData;
it->link = newNode;
}
nbrOfNodes++;
}
bool LinkedList::isEmpty()
{
return !nbrOfNodes;
}
struct1 LinkedList::getNode()
{
param1 returnData = first->data;
node* deleteNode = first;
nbrOfNodes--;
if (nbrOfNodes)
first = deleteNode->link;
delete deleteNode;
return returnData;
}
So the question, put in one sentence, is as follows: How do I adjust the above linked list class so that it can also be used for struct2, without having to create a new almost identical list class for struct2 objects? As I said above, each instance of LinkedList will only deal with either struct1 or struct2.
Grateful for hints or help
There is already a generic link list available in C++, std::list. It will definitely be more efficient & should suffice for your usage.
If you still want to create your own generic link list
You should consider using templates and create a template implmentation of link list.
In c, where templates are not available the data node is stored in the form of a void* pointer. It takes advantage of the fact that a void pointer can point to any generic data type, You might consider that approach as well.
Basic tempaltes are easy.
Just declare the class as template with a templated type variable.
Now everywhere you have the declare type which you want to be generic, in the class, replace the explicit type name with the templated variable name.
For example, in your code, you want struct1 to be generic, so we replace it with T:
template<class T>
class LinkedList {
public:
node *first;
int nbrOfNodes; LinkedList();
void addNode(T);
T getNode();
bool isEmpty();
};
The STL source would be a piece of code to study.
You could also try https://github.com/simonask/ftl/blob/master/list.hpp
Both use templates, which should be understood to be able to make any generic classes.
Here is a generic implementation without using STL. You can create a templated class with a generic type and instantiate the singly_linked_list.
namespace api
{
template <typename T>
class i_list
{
public:
i_list() = default;
virtual ~i_list(){}
/* Add to front*/
virtual int push_front(T t_value) = 0;
/* Return the front item*/
virtual T top_front() = 0;
/* Remove and return the front elenment */
virtual T pop_front() = 0;
/* Add to the back */
virtual int push_back(T t_value) = 0;
/* Returns the back item */
virtual T top_back() = 0;
/* Removes and returns the back item */
virtual T pop_back() = 0;
/* Is key in the list */
virtual bool find(T t_value) = 0;
/* Remove the key from the list */
virtual int erase(T t_value) = 0;
/* Erases the entire list */
virtual void erase_all() = 0;
/* Is the list empty */
virtual bool empty() = 0;
/* return the size of the list */
virtual size_t size() = 0;
};
}
namespace list
{
template<typename T>
struct node
{
T m_data;
node* m_next;
node* m_jump;
int m_order;
node(T t_data) : m_data(t_data), m_next(nullptr) , m_jump(nullptr), m_order(-1){}
};
template<typename T>
class singly_linked_list : public api::i_list<T>
{
public:
singly_linked_list() : m_head(nullptr), m_size(0){}
~singly_linked_list() {erase_all();}
virtual int push_front(T t_value) override;
virtual T top_front() override;
virtual T pop_front() override;
virtual int push_back(T t_value) override;
virtual T top_back() override;
virtual T pop_back() override;
virtual bool find(T t_value) override;
virtual int erase(T t_value) override;
virtual void erase_all() override;
virtual bool empty() override;
virtual size_t size() override;
template<typename U>
friend node<U>* get_head(singly_linked_list<U>& t_list);
private:
node<T>* get_last_node();
node<T>* get_node_until(size_t t_index);
node<T>* find_node(T t_value);
node<T>* get_node_pointer(size_t t_position);
int find_node_index(T t_value);
singly_linked_list<T> get_all_addresses();
node<T>* m_head = nullptr;
size_t m_size;
};
/* O(1) */
template<typename T>
inline int singly_linked_list<T>::push_front(T t_value)
{
node<T>* new_node = new node<T>(t_value);
new_node->m_next = m_head;
m_head = new_node;
m_size++;
return 0;
}
/* O(1) */
template<typename T>
inline T singly_linked_list<T>::top_front()
{
if (empty())
{
std::cout << " list is empty " << std::endl;
return T();
}
return m_head->m_data;
}
/* O(1) */
template<typename T>
inline T singly_linked_list<T>::pop_front()
{
if (empty())
{
std::cout << " list is empty " << std::endl;
return T();
}
/* Value to be returned */
T value = m_head->m_data;
node<T>* next_node = m_head->m_next;
delete(m_head);
m_head = next_node;
m_size--;
return value;
}
/* O(N) */
template<typename T>
inline int singly_linked_list<T>::push_back(T t_value)
{
node<T>* new_node = new node<T>(t_value);
if (empty())
{
m_head = new_node;
m_size++;
return 0;
}
get_last_node()->m_next = new_node;
m_size++;
return 0;
}
/* O(N) */
template<typename T>
inline T singly_linked_list<T>::top_back()
{
if (empty())
{
std::cout << " list is empty " << std::endl;
return T();
}
return get_last_node()->m_data;
}
/* O(N) */
template<typename T>
inline T singly_linked_list<T>::pop_back()
{
T value;
if (empty())
{
std::cout << " list is empty " << std::endl;
return T();
}
if (size() == 1)
{
value = m_head->m_data;
delete(m_head);
m_head = nullptr;
m_size = 0;
return value;
}
node<T>* last_node = get_last_node();
node<T>* last_node_before = get_node_until(size() -1);
value = last_node->m_data;
delete(last_node);
last_node_before->m_next = nullptr;
m_size--;
return value;
}
/* O(N) - Worst case */
template<typename T>
inline bool singly_linked_list<T>::find(T t_value)
{
return find_node(t_value) != nullptr;
}
/* O(N) - Worst case */
template<typename T>
inline int singly_linked_list<T>::erase(T t_value)
{
/* Node with t_value deos not exists */
if (empty())
return -1;
if (size() == 1)
{
delete(m_head);
m_head = nullptr;
m_size = 0;
return 0;
}
int index = find_node_index(t_value);
if (index == -1)
return index;
node<T>* node_to_erase = get_node_until(index + 1);
node<T>* before_node_to_erase = get_node_until(index);
node<T>* after_node_to_erase = get_node_until(index + 2);
before_node_to_erase->m_next = after_node_to_erase;
delete(node_to_erase);
m_size--;
return 0;
}
/* O(N) - Worst case */
template<typename T>
inline void singly_linked_list<T>::erase_all()
{
while(m_head != nullptr)
{
node<T>* next_node = m_head->m_next;
delete(m_head);
m_size--;
m_head = next_node;
}
}
/* O(1) */
template<typename T>
inline bool singly_linked_list<T>::empty()
{
return (m_head == nullptr);
}
/* O(1) */
template<typename T>
inline size_t singly_linked_list<T>::size()
{
return m_size;
}
template<typename T>
inline node<T>* singly_linked_list<T>::get_last_node()
{
node<T>* start_node = m_head;
node<T>* last_node = nullptr;
/* Traverse until the end */
while (start_node != nullptr)
{
last_node = start_node;
start_node = start_node->m_next;
}
return last_node;
}
template<typename T>
inline node<T>* singly_linked_list<T>::get_node_until(size_t t_index)
{
node<T>* start_node = m_head;
node<T>* until_node = nullptr;
/* Traverse until the a node before last node */
size_t index(1);
while (start_node != nullptr)
{
until_node = start_node;
if (index == t_index)
{
return until_node;
}
start_node = start_node->m_next;
index++;
}
return nullptr;
}
template<typename T>
inline node<T>* singly_linked_list<T>::find_node(T t_value)
{
node<T>* start_node = m_head;
/* Traverse until the end */
while (start_node != nullptr)
{
if (t_value == start_node->m_data)
return start_node;
start_node = start_node->m_next;
}
return nullptr;
}
template<typename T>
inline int singly_linked_list<T>::find_node_index(T t_value)
{
node<T>* start_node = m_head;
/* Traverse until the end */
int index(0);
while (start_node != nullptr)
{
if (t_value == start_node->m_data)
return index;
start_node = start_node->m_next;
index++;
}
/* t_value not found*/
return -1;
}
/* Returns the address of the specified node position
form the linke list chain */
template<typename T>
node<T>* singly_linked_list<T>::get_node_pointer(size_t t_position)
{
auto start_node{m_head};
/* Traverse until the end */
size_t i(0);
while (start_node != nullptr)
{
if(i == t_position)
return start_node;
start_node = start_node->m_next;
i++;
}
return nullptr;
}
template<typename U>
node<U>* get_head(singly_linked_list<U>& t_list)
{
return t_list.m_head;
}
}
struct1 and struct2 have different size in bytes, so sizeof(struct1) != sizeof(struct2). Returning the struct from function requires copying it, so c++ requires you to specify the correct type for it so that correct amount of bytes can be copied. To start correct this problem you need to think in the very low level:
struct GenericStruct {
void *ptr;
size_t size;
type_info t;
};
struct1 extract_struct1(GenericStruct &s);
struct2 extract_struct2(GenericStruct &s)
{
if (s.size != sizeof(struct2)) throw -1;
if (s.t != typeid(struct2)) throw -1;
struct2 *s2 = (struct2*)s.ptr;
return *s2;
}
GenericStruct make_generic(const struct1 &ss)
{
GenericStruct s;
s.ptr = (void*)&ss;
s.size = sizeof(struct1);
s.t = typeid(struct1);
return s;
}
GenericStruct make_generic(const struct2 &ss);
the real problem is that these functions can fail on runtime, if the sizes or types do not match. The copying is obviously also needed:
GenericStruct Copy(const GenericStruct &s);
After these basic primitives exists, you can create a class which has copy constructor and assignment operator which uses these functions to implement proper generic struct support.