I'm writing list and iterator classes function and I'm almost done, but I get some errors in the main file, that when I write the list remove_all function, but when I delete it there is no error anywhere, I don't know why!! Also, actually I'm not sure about my Iterator operators and the bool Iterator::is_item()
Any help is appreciated. Thanks
here is my codes:
Node.h
pragma once
namespace list_1
{
template <typename T>
struct Node
{
T data;
Node<T> *next;
// Constructor
// Postcondition:
Node<T> (T d);
};
template <typename T>
Node<T>::Node(T d)
{
}
}
Iterator.h
// Template CLASS PROVIDED: Iterator
#pragma once
#include "Node.h"
namespace list_1
{
template<typename T>
class Iterator
{
public:
Iterator<T> (Node<T> *np);
// precondition: is_item is true
// post condition n points to the next item in the list
void operator++();
// precondition:
// postcondition: returns true if there is a valid item
bool is_item();
// precondition: is_item == true
// postcondition returns data that n is pointing at
T operator* ();
private:
Node<T>* n;
};
List.h
#ifndef LIST_H
#define LIST_H
#include "Node.h"
#include "Iterator.h"
namespace list_1
{
template <typename T>
class list
{
public:
// CONSTRUCTOR
list( );
// postcondition: all nodes in the list are destroyed.
~list();
// MODIFICATION MEMBER FUNCTIONS
//postcondition: entry is added to the front of the list
void insert_front(const T& entry);
//postcondition: entry is added to the back of the list
void add_back(const T& entry);
// postcondition: all nodes with data == entry are removed from the list
void remove_all(const T& entry);
// postcondition: an iterator is created pointing to the head of the list
Iterator<T> begin(void);
// CONSTANT MEMBER FUNCTIONS
// postcondition: the size of the list is returned
int size( ) const;
private:
Node<T>* head;
};
Your syntax errors are because you are missing a couple closing curly brackets on your "else" blocks at the end of the remove_all function.
Try replacing it with this
(edit: included the suggestion about cout mentioned in the comments above)
void list<T>::remove_all(const T& entry)
{
if(head == 0)
{
std::cout<<" node cannot be delted";
}
else
{
Node<T> *curr = head;
Node<T> *trail = 0;
while( curr != 0)
{
if(curr->entry == entry)
{
break;
}
else
{
trail = curr;
curr = curr->next;
}
}
if(curr == 0)
{
std::cout<<" Node " << entry<< " is not found";
}
else
{
if ( head == curr)
{
head = head->next;
}
else
{
trail->next = curr->next;
}
} // missing this one
delete curr;
} // and this one as well
}
Related
I am trying to remove the element from linked list recursively, but the remove function is not working. I need some help in solving this.
My node.h function
#ifndef NODE_
#define NODE_
template<class ItemType>
class Node {
private:
ItemType item; // A data item
Node<ItemType>* next; // Pointer to next node
public:
Node();
Node(const ItemType& anItem);
Node(const ItemType& anItem, Node<ItemType>* nextNodePtr);
void setItem(const ItemType& anItem);
void setNext(Node<ItemType>* nextNodePtr);
ItemType getItem() const;
Node<ItemType>* getNext() const;
}; // end Node
#include "Node.cpp"
#endif
My node.cpp file:
#include "Node.h"
template<class ItemType>
Node<ItemType>::Node() : next(nullptr)
{
} // end default constructor
template<class ItemType>
Node<ItemType>::Node(const ItemType& anItem) : item(anItem), next(nullptr)
{
} // end constructor
template<class ItemType>
Node<ItemType>::Node(const ItemType& anItem, Node<ItemType>* nextNodePtr) :
item(anItem), next(nextNodePtr)
{
} // end constructor
template<class ItemType>
void Node<ItemType>::setItem(const ItemType& anItem)
{
item = anItem;
} // end setItem
template<class ItemType>
void Node<ItemType>::setNext(Node<ItemType>* nextNodePtr)
{
next = nextNodePtr;
} // end setNext
template<class ItemType>
ItemType Node<ItemType>::getItem() const
{
return item;
} // end getItem
template<class ItemType>
Node<ItemType>* Node<ItemType>::getNext() const
{
return next;
} // end getNext
My main function:
#include <iostream>
#include "Node.h"
using namespace std;
// Function to insert an item into the front of a linked list
template<class T>
void insert(Node<T>* &headPtr, const T& entry)
{
// Create a new node and have the next pointer point to current front
Node<T> *newNodePtr = new Node<T>( entry , headPtr );
// Current front now becomes this new node
headPtr = newNodePtr;
}
// Recursive function to remove an item from a linked list
// Returns true if the operation was done; false, otherwise
template< typename T >
bool removes(Node<T>* &nodePtr, T target)
{
if(!nodePtr)
{
return false;
}
if(nodePtr->getNext() != NULL)
{
Node<T>*next = nodePtr->getNext();
removes(next,target);
if(nodePtr->getNext()->getItem()==target)
{
Node<T>*del = nodePtr;
nodePtr->setNext(nodePtr->getNext()->getNext());
delete del;
return true;
}
//nodePtr->setNext(nodePtr->getNext());
}
}
// Recursive function to display the contents of a linked list
// in the reverse order.
template<class T>
void display(Node<T> *currNodePtr)
{
// YOUR CODE GOES HERE - CHECK YOUR NOTES!
Node<T> *curr=currNodePtr;
if(curr!=NULL)
{
cout<<curr->getItem();
display(curr->getNext());
}
cout<<endl;
}
int main()
{
// (1) Declare an empty linked list of unsigned values
// based on the Node class and call it myList
Node<unsigned>*myList;
// (2) Read in values from standard input. Non-negative
// values are inserted into myList and a negative
// value terminates input.
int data=0;
unsigned k;
while(cin>>data)
{
if (data>=0)
{
k=data;
insert(myList,k);
}
else
{
break;
}
}
cout<<"out of loop";
// (3) Display the contents of the linked list myList
// in the order they were entered (hence, the display()
// function displays myList in reverse order!
display(myList);
// (4) Read in values from standard input. Non-negative
// values are removed from myList and a negative
// value terminates input.
int data1=0;
unsigned m;
while(cin>>data1)
{
if (data1>=0)
{
m=data1;
removes(myList,m);
}
else
{
break;
}
}
// (5) Display the contents of the linked list myList
// in the order they were entered (hence, the display()
// function displays myList in reverse order!
cout<<endl;
display(myList);
}
The remove function is in main. It is not removing the correct element. For example, in the list of 1 2 3 4 5, if I try to remove 3 it is removing 2.
I am learning about linked lists, and I decided to try implementing linked lists in C++ on my own.
I made a Node class with attributes int val and Node* ptr.
Then I made a Linked_list class with the attribute first_node, and the constructor functions work.
The append() function 'appends' a node to the list (like in Python). I first thought of just making ptr a reference to the node's pointer and then changing it when its null, but references once made, can't be changed to refer to any other variable, so I made another variable prev_ptr that points to the Node's pointer (which makes it a Node**).
Every loop, it checks if ptr is NULL, if not, ptr and prev_ptr get updated to the next Node's pointer value, and the address of the next Node's pointer value, respectively.
This keeps happening until it finds a null pointer, and then changes it to the inputted node's address.
But I'm getting an error saying:
Exception thrown: write access violation. prev_ptr was 0x4.
I can't figure out what is wrong.
Classes:
#include <iostream>
#include <string>
#include <cmath>
class Node {
public:
int val;
Node* ptr = nullptr;
Node(int Val = NULL) {
val = Val;
}
};
class Linked_list {
public:
Node first_node;
Linked_list(int F) {
Node f(F);
first_node = f;
}
void append(Node& element) {
Node* ptr = first_node.ptr;
Node** prev_ptr = &first_node.ptr;
while (true) {
if (ptr == nullptr) {
*prev_ptr = &element;
break;
}
ptr = (*ptr).ptr;
prev_ptr = &((*ptr).ptr);
}
}
};
main()
int main() {
Linked_list list(5);
Node three(3);
list.append(three);
Node four(4);
list.append(four);
return 0;
}
ptr = (*ptr).ptr;
prev_ptr = &((*ptr).ptr);
First you advance ptr to the next node. Then, you use ptr again forgetting that it has already been advanced: (*ptr).ptr now points two nodes forward, and we don't know if we can go that much far.
Perhaps you need to swap the assignments.
prev_ptr = &((*ptr).ptr);
ptr = (*ptr).ptr;
(Further, why not ptr->ptr?)
Okay, you're doing a few things in an odd fashion. First, your Linked_List should probably NOT have a Node for firstNode. It should have a Node *. After all, an empty list is possible. So is (normally) deleting the first node. Also, there's an informal naming convention of calling it head. There's also a standard convention of calling the link in your Node next rather than ptr.
But there are two simpler methods for your append() method. First, you can also keep a Node * tail in Linked_List. This is common. It points to the last node in the list. If you do that, then append looks like:
void append(Node &nodeToAppend) {
if (head == nullptr) {
head = &nodeToAppend;
tail = &nodeToAppend;
}
else {
tail->next = nodeToAppend;
tail = &nodeToAppend;
}
}
However, it's also worthwhile to be able to insert anywhere or append without a tail:
void append(Node &nodeToAppend) {
if (head == nullptr) {
head = &nodeToAppend;
}
else {
Node *ptr = head;
while (ptr->next != nullptr) {
ptr = ptr->next;
}
ptr->next = &nodeToAppend;
}
}
An insert in some sort of sorted order would be nearly identical, although slightly different. The while-loop would look like:
while (ptr->next != nullptr && ptr->value < nodeToAppend.value) ...
but would otherwise be identical.
This code doesn't solve your immediate issue, but answers a question raised in the comments.
Linked lists are usually (where I taught) a 300-400 level assignment. There are a lot of principles that one must be competent in to write a decent linked list. First, I'll show the main.cpp and its output.
main.cpp
#include "list.hpp"
#include <iostream>
template <typename Container>
void print(Container& container, std::ostream& sout = std::cout)
{
for (auto i : container) {
sout << i << ' ';
}
sout << '\n';
}
int main()
{
List<int> list;
for (int i = 1; i <= 10; ++i) {
list.push_back(i);
}
print(list);
list.erase(list.find(4));
print(list);
list.erase(list.find(1));
print(list);
list.erase(list.find(10));
print(list);
}
Output:
1 2 3 4 5 6 7 8 9 10
1 2 3 5 6 7 8 9 10
2 3 5 6 7 8 9 10
2 3 5 6 7 8 9
It doesn't test every aspect of the linked list, but it serves to demonstrate what a user should be expected to work with. Users will want to interact directly with the list and its iterators in C++. You create a Node, and then add the Node to your list. That's a level of DIY that no user wants to be bothered with. In the code below, you'll see that a Node is still used, but it only exists within the List class. Users will never see a Node.
You can look in functions like push_back() (similar to your append) for specific answers related to your question.
To explain it a bit more, the pointers are key. Yes, I declare a local Node* that will go out of scope, but the object created continues to exist on the heap. And the list is able to keep track of these Nodes due to how linked lists work, namely that the Nodes know where their neighbors live (hold their addresses).
There is also a List<T>::iterator class. In the declaration, functions marked as // minimum are required if you want to use your linked list in a range-based for loop. The other functions do work toward satisfying the requirements of LegacyBidirectionalIterator; this is the level of iterator used by std::list in the C++ Standard Library.
The code below should only be considered a decent example (Hopefully not too presumptuous on my part). It is lacking some functionality that's found in std::list, and likely does a few things in non-optimal manners. A big thing that will need tweaking is removing the member function find() and make the class work with std::find().
list.hpp
#ifndef MY_LIST_HPP
#define MY_LIST_HPP
#include <algorithm> // std::swap
#include <cstddef> // std::size_t
/*
* Pre-declare template class and friends
*/
template <typename T>
class List;
template <typename T>
void swap(List<T>& lhs, List<T>& rhs);
/*
* List Class Declaration
*/
template <typename T>
class List {
public:
List() = default;
List(T val);
List(const List& other);
List(List&& other);
~List();
void push_front(T val);
void push_back(T val);
class iterator;
iterator begin();
iterator end();
iterator find(T val);
std::size_t size() const;
iterator erase(iterator toErase); // Implement
void clear();
bool operator=(List other);
friend void swap<T>(List& lhs, List& rhs);
private:
struct Node {
T data;
Node* prev = nullptr;
Node* next = nullptr;
Node(T val) : data(val) {}
};
Node* m_head = nullptr;
Node* m_tail = nullptr;
std::size_t m_size = 0;
// Helper functions
void make_first_node(T val);
Node* find_node(T val);
};
/*
* List Iterator Declaration
*/
template <typename T>
class List<T>::iterator {
public:
iterator() = default;
iterator(List<T>::Node* node); // minimum
T& operator*(); // minimum
iterator& operator++(); // minimum
iterator operator++(int);
iterator& operator--();
iterator operator--(int);
bool operator==(const iterator& other); // minimum
bool operator!=(const iterator& other); // minimum
private:
Node* m_pos = nullptr;
};
/*
* List Implementation
*/
template <typename T>
List<T>::List(T val) : m_head(new Node(val)), m_tail(m_head), m_size(1) {}
template <typename T>
List<T>::List(const List<T>& other) {
m_head = new Node((other.m_head)->data);
m_tail = m_head;
m_size = 1;
Node* walker = (other.m_head)->next;
while (walker) {
push_back(walker->data);
++m_size;
walker = walker->next;
}
}
template <typename T>
List<T>::List(List&& other) : List() {
swap(*this, other);
}
template <typename T>
List<T>::~List() {
clear();
}
template <typename T>
void List<T>::push_front(T val)
{
if (!m_head) {
make_first_node(val);
return;
}
Node* tmp = new Node(val);
tmp->next = m_head;
m_head->prev = tmp;
m_head = tmp;
++m_size;
}
template <typename T>
void List<T>::push_back(T val) {
if (!m_head) {
make_first_node(val);
return;
}
Node* tmp = new Node(val);
tmp->prev = m_tail;
m_tail->next = tmp;
m_tail = tmp;
++m_size;
}
template <typename T>
typename List<T>::iterator List<T>::begin() {
return iterator(m_head);
}
template <typename T>
typename List<T>::iterator List<T>::end() {
return iterator(nullptr);
}
template <typename T>
typename List<T>::iterator List<T>::find(T val) {
return iterator(find_node(val));
}
template <typename T>
std::size_t List<T>::size() const {
return m_size;
}
template <typename T>
typename List<T>::iterator List<T>::erase(typename List<T>::iterator toErase)
{
Node* node = find_node(*toErase);
if (node->prev) {
node->prev->next = node->next;
} else {
m_head = node->next;
}
if (node->next) {
node->next->prev = node->prev;
} else {
m_tail = node->prev;
}
Node* toReturn = node->next;
delete node;
return toReturn;
}
template <typename T>
void List<T>::clear() {
Node* tmp = m_head;
while (m_head) {
m_head = m_head->next;
delete tmp;
tmp = m_head;
}
m_tail = nullptr;
m_size = 0;
}
template <typename T>
bool List<T>::operator=(List other) {
swap(*this, other);
return *this;
}
template <typename T>
void List<T>::make_first_node(T val) {
m_head = new Node(val);
m_tail = m_head;
m_size = 1;
}
template <typename T>
typename List<T>::Node* List<T>::find_node(T val) {
if (!m_head) {
return nullptr;
}
Node* walker = m_head;
while (walker != nullptr && walker->data != val) {
walker = walker->next;
}
return walker;
}
template <typename T>
void swap(List<T>& lhs, List<T>& rhs) {
using std::swap;
swap(lhs.m_head, rhs.m_head);
swap(lhs.m_tail, rhs.m_tail);
swap(lhs.m_size, rhs.m_size);
}
/*
* List Iterator Implementation
*/
template <typename T>
List<T>::iterator::iterator(Node* node) : m_pos(node) {}
template <typename T>
T& List<T>::iterator::operator*() {
return m_pos->data;
}
template <typename T>
typename List<T>::iterator& List<T>::iterator::operator++() {
m_pos = m_pos->next;
return *this;
}
template <typename T>
typename List<T>::iterator List<T>::iterator::operator++(int) {
iterator tmp(m_pos);
++(*this);
return tmp;
}
template <typename T>
typename List<T>::iterator& List<T>::iterator::operator--() {
m_pos = m_pos->prev;
return *this;
}
template <typename T>
typename List<T>::iterator List<T>::iterator::operator--(int) {
iterator tmp(m_pos);
--(*this);
return tmp;
}
template <typename T>
bool List<T>::iterator::operator==(const iterator& other) {
return m_pos == other.m_pos;
}
template <typename T>
bool List<T>::iterator::operator!=(const iterator& other) {
return !(*this == other);
}
#endif
Code and explaination
I think this code should work as well, so there is no need to have two pointers. It's based on an example of “good taste” that Linus Torvalds gave in an interview.
void append(Node &element)
{
Node** cursor = &first_node.ptr;
while ((*cursor) != nullptr)
cursor = &(*cursor)->ptr;
*cursor = &element;
}
It eliminates the need for multiple pointers, it eliminates edge cases and it allows us to evaluate the condition of the while loop without having to let go of the pointer that points to the next element. This allows us to modify the pointer that points to NULL and to get away with a single iterator as opposed to ptr and prev_ptr.
Naming conventions
Also the norm is to call the first node in the linked list head and to call the pointer to the next node next instead of ptr, so I will rename them in the following code.
void append(Node &new)
{
Node** cursor = &head.next;
while ((*cursor) != nullptr)
cursor = &(*cursor)->next;
*cursor = &new;
}
I'm new to working with class templates and am simply trying to define a temporary node 'temp' in a class associated with the Linked List, which sets the string that the node stores to some temporary string that is created in the function TowerHanoi::set_Discs(size_t disc) via user input. When I call the function temp->set_data(tmp_str) i get a segmentation fault. I tried calling temp->set_data("hello"); on its own and i still get the error.
I'm not sure what's going on here and i've tried researching into it but to no avail. I'm probably missing something obvious, but i'm just quite lost now. Let me know if you need more code. Thanks.
TowerHanoi.cpp:
#include "TowerHanoi.h"
#include <iostream>
#include <cstdlib>
using namespace std;
using oreilly_A2::node;
namespace oreilly_A2 {
TowerHanoi::TowerHanoi() {
for (int i=0;i<2;i++) {
rod[i] = LStack<node<std::string> >();
}
}
TowerHanoi::TowerHanoi(size_t numDiscs) {
for (int i=0; i < 2; i++) {
rod[i] = LStack<node<string> >();
}
discs = numDiscs;
}
void TowerHanoi::set_Discs(size_t disc) {
node<string>* temp=NULL;
while (disc != 0) {
string tmp_str;
for (size_t i=0; i<disc; i++) {
tmp_str.append("x");
}
disc--;
temp->set_data(tmp_str);
rod[0].push(temp);
}
void TowerHanoi::print_Game() {
for (size_t s=1; s<discs; s++) {
cout << " ";
for (size_t o=1; o<discs-s;o++) {
cout << " ";
}
//cout << tmp_node->data() << endl;
cout << "x" << endl;
}
}
}
node.h file:
#ifndef NODE_CAMERON_H
#define NODE_CAMERON_H
#include <string>
namespace oreilly_A2 {
template <typename Item>
class node {
public:
node(); //constructor for node
node(const Item val, node* newNext); //constructor with parameters
~node(); //destructor
void set_data(Item new_data); //set the word that this node contains
void set_link(node* new_link); //set the 'next' node
void set_previous(node* new_prev);
Item data() const; //return this node's word
const node* link() const; //return next
const node* back() const;
node* link(); //return next
node* back();
private:
node* next; //the next node
node* previous;
Item word; //the word this node contains
};
}
#include "Node.template"
#endif
node.template file:
namespace oreilly_A2 {
template <typename Item>
node<Item>::node() {
next=NULL;
previous=NULL;
}
//Node.template
template <typename Item>
node<Item>::node(const Item val, node* newNext=NULL) {
word = val;
next = newNext;
}
template <typename Item>
node<Item>::~node() {
delete next;
delete previous;
delete word;
}
template <typename Item>
void node<Item>::set_data(Item new_data){
word = new_data;
}
template <typename Item>
void node<Item>::set_link(node* new_link){
next = new_link;
}
template <typename Item>
void node<Item>::set_previous(node* new_back) {
previous = new_back;
}
template <typename Item>
Item node<Item>::data() const { //return the word
return word;
}
template <typename Item>
const node<Item>* node<Item>::link() const { //return next node (const function)
return next;
}
template <typename Item>
const node<Item>* node<Item>::back() const { //return previous node (const)
return previous;
}
template <typename Item>
node<Item>* node<Item>::link() {
return next; //return next node (non-const)
}
template <typename Item>
node<Item>* node<Item>::back() { //return previous node (const)
return previous;
}
}
Unless I have missed something the temp variable is NULL at the time of calling set_data. As any regular object you need to first initialized it.
node<string>* temp=new node<string>();
And then freeing it when appropriate to avoid memory leaks.
This is not the case with temp_str because the later is not a pointer, it's a value so it gets initialized automatically (and also freed automatically when it gets out of scope).
You have initialized temp as NULL. So when you are trying to do temp->set_data(tmp_str); you are actually trying to access NULL pointers.
All you need to do is initialize temp. I have correct the code below
void TowerHanoi::set_Discs(size_t disc) {
node<string>* temp=new node<string>();
while (disc != 0) {
string tmp_str;
for (size_t i=0; i<disc; i++) {
tmp_str.append("x");
}
disc--;
temp->set_data(tmp_str);
rod[0].push(temp);
}
To avoid memory leak you need to delete all the memory allocated after you are done.
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.