How to implement iterator design pattern on C++? - c++

I'm curious about how to implement the iterator pattern the way STL does in a stack ADT.
#include <iostream>
#include <vector>
int main() {
std::vector<char> v = { 'a', 'b', 'c', 'd', 'e', 'f'};
std::vector<char>::iterator it = v.begin();
while(it != v.end()) {
std::cout << *it << "->";
++it;
}
std::cout << "\n";
return 0;
}
Output
a->b->c->d->e->f->
so far I have implemented the following code
#include <iostream>
#include <memory>
template<class T>class Node {
private:
T data = 0;
std::shared_ptr<Node<T>> next_node = nullptr;
public:
Node(T data = 0, std::shared_ptr<Node<T>> next_node = nullptr)
: data(data), next_node(next_node)
{
std::cout << "created node[" << data << "]\n";
}
~Node() {
std::cout << "deleted node[" << data << "]\n";
}
// getters and setters
T getData() const {
return this->data;
}
std::shared_ptr<Node<T>> getNextNode() const {
return this->next_node;
}
void setData(T value) {
this->data = value;
}
void setNextNode(std::shared_ptr<Node<T>> node) {
this->next_node = node;
}
};
template<class T>std::ostream& operator<<(std::ostream& o, const std::shared_ptr<Node<T>> node) {
return o << "node["<< node->getData() <<"]-> ";
}
template<class T>class Stack {
private:
std::shared_ptr<Node<T>> top = nullptr;
public:
Stack()
: top(nullptr)
{ /* empty */ }
~Stack() { /* empty */ }
void push(T value) {
if(!top) {
top = std::shared_ptr<Node<T>> (new Node<T>(value));
} else {
top = std::shared_ptr<Node<T>> (new Node<T>(value, top));
}
}
void display() {
if(!top) {
std::cout << "display::The stack is empty.\n";
} else {
std::shared_ptr<Node<T>> p = top;
while(p) {
std::cout << p;
p = p->getNextNode();
}
std::cout << "\n";
}
}
class Iterator {
private:
std::shared_ptr<Node<T>> node;
public:
Iterator(std::shared_ptr<Node<T>> node)
: node(node)
{ /* empty */ }
bool hasMore() {
return node->getNextNode() != nullptr;
}
Iterator getNext() {
return Iterator(node->getNextNode());
}
int getData() {
return node->getData();
}
};
Iterator begin() const {
return Iterator(top);
}
Iterator getIterator() {
Iterator it = Iterator(top);
return it;
}
};
int main() {
Stack<char> stack;
for(char i = 'a'; i < 'f'; ++i) {
stack.push(i);
}
Stack<char>::Iterator it = stack.begin();
while(it.hasMore()) {
std::cout << it.getData() << "->";
it = it.getNext();
}
std::cout << "\n";
return 0;
}
Output:
created node[a]
created node[b]
created node[c]
created node[d]
created node[e]
101->100->99->98->
deleted node[e]
deleted node[d]
deleted node[c]
deleted node[b]
deleted node[a]
My question is how to implement nested template detection for the Iterator class, as you can see the expected output is a char type and I am getting integers.
Can someone help me understand how this is implemented in the STL and how it could be implemented in an ADT?
thanks!!!

Thanks for the comments I be able to fix the problem I was returning the wrong data type on int getData() { return node->getData(); } I just change the int type for T type and everithing works ok!
also change the hasMore method for bool hasMore() { return node != nullptr; }
#include <iostream>
#include <memory>
template<class T>class Node {
private:
T data = 0;
std::shared_ptr<Node<T>> next_node = nullptr;
public:
Node(T data = 0, std::shared_ptr<Node<T>> next_node = nullptr)
: data(data), next_node(next_node)
{
std::cout << "created node[" << data << "]\n";
}
~Node() {
std::cout << "deleted node[" << data << "]\n";
}
// getters and setters
T getData() const {
return this->data;
}
std::shared_ptr<Node<T>> getNextNode() const {
return this->next_node;
}
void setData(T value) {
this->data = value;
}
void setNextNode(std::shared_ptr<Node<T>> node) {
this->next_node = node;
}
};
template<class T>std::ostream& operator<<(std::ostream& o, const std::shared_ptr<Node<T>> node) {
return o << "node["<< node->getData() <<"]-> ";
}
template<class T>class Stack {
private:
std::shared_ptr<Node<T>> top = nullptr;
public:
Stack()
: top(nullptr)
{ /* empty */ }
~Stack() { /* empty */ }
void push(T value) {
if(!top) {
top = std::shared_ptr<Node<T>> (new Node<T>(value));
} else {
top = std::shared_ptr<Node<T>> (new Node<T>(value, top));
}
}
void display() {
if(!top) {
std::cout << "display::The stack is empty.\n";
} else {
std::shared_ptr<Node<T>> p = top;
while(p) {
std::cout << p;
p = p->getNextNode();
}
std::cout << "\n";
}
}
class Iterator {
private:
std::shared_ptr<Node<T>> node;
public:
Iterator(std::shared_ptr<Node<T>> node)
: node(node)
{ /* empty */ }
bool hasMore() {
return node != nullptr;
}
Iterator getNext() {
return Iterator(node->getNextNode());
}
T getData() {
return node->getData();
}
};
Iterator begin() const {
return Iterator(top);
}
Iterator getIterator() {
Iterator it = Iterator(top);
return it;
}
};
int main() {
Stack<char> stack;
for(char i = 'a'; i < 'f'; ++i) {
stack.push(i);
}
Stack<char>::Iterator it = stack.begin();
while(it.hasMore()) {
std::cout << it.getData() << "->";
it = it.getNext();
}
std::cout << "\n";
return 0;
}
Output
created node[a]
created node[b]
created node[c]
created node[d]
created node[e]
e->d->c->b->a->
deleted node[e]
deleted node[d]
deleted node[c]
deleted node[b]
deleted node[a]

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.

A reference of type "Bucket&" (not const qualified) cannot be initialized with a value of type "SortedList." How can this error be fixed?

The error occurs in my SortedList class in function method sortList. I have tried to rename, remove, move, and manipulate certain things to no avail. I will show you a good amount of code so that you can see where I'm coming from.
void SortedList::sortList(const vector <double>& list) {
BucketSort bucketA;
bucketA.insert(list);
bucketA.createSortedList(*this); // <--- Problem here, on this one line.
// The * is highlighted in red in my IDE.
}
Error: A reference of type "Bucket&" (not const qualified) cannot be initialized with a value of type "SortedList"
For reference, if you need to see to get a context of my error:
SortedList.h:
#ifndef SORTEDLIST_H
#define SORTEDLIST_H
#include "bucketsort.h"
#include <vector>
using namespace std;
class SortedList
{
public:
SortedList();
void sortList(const vector <double>& list);
~SortedList();
private:
};
#endif
Bucketsort.h:
#ifndef BUCKETSORT_H
#define BUCKETSORT_H
#include "bucket.h"
#include <iostream>
#include <vector>
#include <iomanip>
using namespace std;
const int DEFAULTCAPACITY = 10;
class BucketSort
{
public:
// Constructors:
BucketSort();
// Functions:
void print() const;
void insert(const vector <double>& v) const;
void createSortedList(Bucket& a);
//
~BucketSort();
private:
Bucket ** a;
};
#endif
Bucketsort.cpp:
#include "bucketsort.h"
BucketSort::BucketSort() {
a = new Bucket*[DEFAULTCAPACITY]();
}
void BucketSort::print() const {
for (int i = 0; i < DEFAULTCAPACITY; ++i) {
if (a[i] != nullptr) {
a[i]->print();
}
}
}
void BucketSort::insert(const vector <double>& v) const {
int index;
for (int i = 0; i < v.size(); ++i) {
index = v[i] * 10;
if (a[index] == nullptr) {
Bucket* newBucket = new Bucket;
a[index] = newBucket;
}
a[index]->insert(v[i]);
}
}
void BucketSort::createSortedList(Bucket& a){
}
BucketSort::~BucketSort() {
for (int i = 0; i < DEFAULTCAPACITY; ++i) {
if (a[i] != nullptr) {
a[i]->deleteBucket();
}
}
delete a;
a = nullptr;
}
Bucket.h:
#ifndef BUCKET_H
#define BUCKET_H
#include <iostream>
using namespace std;
class Node
{
public:
Node() : item(0.0), link(nullptr) {}
Node(double newItem, Node *newLink) : item(newItem), link(newLink) {}
Node* getLink() const { return link; }
double getItem() const { return item; }
void setItem(double newItem) { item = newItem; }
void setLink(Node *newLink) { link = newLink; }
~Node() {}
private:
double item;
Node *link;
};
class Bucket
{
public:
Bucket();
void insert(double value);
void testPrint() const;
void print() const;
int getNumberOfElements() const;
void deleteBucket();
~Bucket();
private:
Node * ptrToFirst;
Node *ptrToLast;
int numberOfElements;
};
#endif
Bucket.cpp:
#include "bucket.h"
Bucket::Bucket() {
ptrToFirst = nullptr;
ptrToLast = nullptr;
numberOfElements = 0;
}
void Bucket::insert(double value) {
if (numberOfElements != 0) {
Node *newNode = new Node(value, nullptr);
if (value < ptrToFirst->getItem()) {
newNode->setLink(ptrToFirst);
ptrToFirst = newNode;
}
else if (value > ptrToLast->getItem()) {
ptrToLast->setLink(newNode);
ptrToLast = newNode;
}
else if (value != ptrToFirst->getItem()) {
Node *current = ptrToFirst;
while (value > current->getLink()->getItem()) {
current = current->getLink();
}
if (current->getLink()->getItem() != value) {
newNode->setLink(current->getLink());
current->setLink(newNode);
}
}
}
else {
ptrToFirst = new Node(value, ptrToLast);
ptrToLast = ptrToFirst;
}
++numberOfElements;
}
void Bucket::testPrint() const {
cout << "Pointer to first: " << ptrToFirst << endl;
cout << "Pointer to last: " << ptrToLast << endl;
if (ptrToFirst != nullptr && ptrToLast != nullptr) {
cout << "Value of ptrToFirst: " << ptrToFirst->getItem() << endl;
cout << "Value of ptrToLast: " << ptrToLast->getItem() << endl;
}
cout << "Number of elements: " << numberOfElements << endl;
cout << "Contents of bucket: " << endl;
Node *current = ptrToFirst;
while (current != nullptr) {
cout << current->getItem() << " ";
current = current->getLink();
}
cout << endl;
}
void Bucket::print() const {
Node *current = ptrToFirst;
while (current != nullptr) {
cout << current->getItem() << " ";
current = current->getLink();
}
}
int Bucket::getNumberOfElements() const {
return numberOfElements;
}
void Bucket::deleteBucket() {
Node *trailingCurrent;
while (ptrToFirst != nullptr) {
trailingCurrent = ptrToFirst;
ptrToFirst = ptrToFirst->getLink();
delete trailingCurrent;
trailingCurrent = nullptr;
}
ptrToLast = nullptr;
numberOfElements = 0;
}
Bucket::~Bucket() {
deleteBucket();
}
Help?
void SortedList::sortList(const vector <double>& list) {
[...]
bucketA.createSortedList(*this); // <--- Problem here
In the above line, this is of type SortedList *, so *this is of type SortedList &.
... and yet, your createdSortedList method requires an argument of a different type, Bucket &:
void createSortedList(Bucket& a);
Since a SortedList and a Bucket are not the same type, and there is no way (that the compiler knows about) to convert a SortedList object into a Bucket object, the compiler is rightly flagging the call as an error.
To solve the problem, you either need to change createSortedList to take a SortedList & as its argument, instead of a Bucket &, or change your call to pass in a Bucket & instead of a SortedList &.

Implementing Queue Using LinkedList [duplicate]

This question already has answers here:
How come a non-const reference cannot bind to a temporary object?
(11 answers)
Closed 5 years ago.
So, i'm attempting to implement this Queue using my LinkedList that I previously created. I've provided the code for both classes. Currently, I'm work on attempting to get pop and push to work without changing the function prototype (it's for an assignment).
When looking specifically at peek(I haven't quite finished pop), for some reason, when I run the code, I get strange pointer error.
Error C2440 'default argument': cannot convert from 'int' to 'int &'
I'm not sure exactly what that means in this context. The function is suppose to look at the object at the top of the queue without removing it, and return true or false based upon if the operation was successful or not.
Here is the info for QUEUE.
#ifndef _QUEUE_H
#define _QUEUE_H 1
#include "QueueInterface.h"
#include "LinkedList.hpp"
template <typename T>
class Queue : public QueueInterface<T>
{
protected:
LinkedList<T> _list;
int count;
public:
unsigned size() const
{
return count;
}
bool push(const T& val = T{})
{
_list.push(val);
count++;
return true;
}
bool empty() const
{
return _list.isEmpty();
}
bool pop(T& val = T{})
{
return true;
}
bool peek(T& val = T{}) const
{
std::cout << _list.last() << std::endl;
return true;
}
void clear()
{
_list.clear();
}
int search(const T& target = T{}) const
{
return _list.search(target);
}
//
// Internal consistency check
//
void toString()
{
_list.toString();
}
public:
virtual bool check() const
{
return _list.check();
}
};
#endif
Here is Linked List.
#ifndef _LINKED_LIST_GUARD
#define _LINKED_LIST_GUARD 1
#include <iostream>
#include "ListInterface.h"
template <typename T>
class LinkedList : public ListInterface<T>
{
public:
int count = 0;
LinkedList()
{
_head = new Node;
_tail = new Node;
_head->_next = _tail;
}
private:
//
// Private node class to facilitate linked list
//
class Node
{
public:
T _data;
Node* _next;
// Constructor: default
Node(T d = T{}, Node* n = nullptr) : _data(d), _next(n) {}
~Node() { _next = nullptr; }
};
//
// Prevent copying and assigning
//
LinkedList(const LinkedList& rhs) {}
const LinkedList& operator=(const LinkedList& rhs) {}
public:
//
// LinkedList instance variables; we use dummy head and tail nodes in this implementation
unsigned _size;
Node* _head;
Node* _tail;
// Returns the first element in the list
T& first() const
{
return _head->_next->_data;
}
// Adds an item to the LEFT side of the linked list
void push(const T& x)
{
// Creates a new node with the user input data.
Node* current = new Node;
current->_data = x;
current->_next = _head->_next;
_head->_next = current;
count++;
}
// ASK ABOUT
T& operator[](unsigned n)
{
int position = 1;
if (n != count)
{
throw("Invalid Position");
}
for (Node* current = _head->_next; current != _tail; current = current->_next, position++)
{
if (position == n)
{
return current -> _data;
}
}
}
void clear()
{
do
{
pop();
} while (count != 0);
}
bool contains(const T& target) const
{
for (Node* current = _head->_next; current != _tail; current = current->_next)
{
if (current->_data == target)
return true;
}
return false;
}
bool pop()
{
if (_head->_next == _tail)
{
std::cout << "unable to pop, list is empty";
return false;
}
if (_head->_next != _tail)
{
Node* deleteNode = _head->_next;
_head->_next = _head->_next->_next;
delete deleteNode;
count--;
return true;
}
return false;
}
T& last() const
{
if (_head->_next == _tail)
{
std::cout << "LIST IS EMPTY" << std::endl;
}
if (_head->_next != _tail)
{
for (Node* current = _head->_next; current != _tail; current = current->_next)
{
if (current->_next == _tail)
return current->_data;
}
}
}
// ASK ABOUT
int search(const T& target = T{}) const
{
int position = 1;
for (Node* current = _head->_next; current != _tail; current = current->_next)
{
if (current->_data == target)
{
return position;
}
else position++;
}
return -1;
}
bool isEmpty() const
{
if (_head->_next == _tail)
{
return true;
}
return false;
}
unsigned size() const
{
return count;
}
bool remove(const T& target)
{
Node* deleteNode = nullptr;
Node* trailer = _head;
Node* current = _head->_next;
while (current != _tail && current-> _data != target)
{
trailer = current;
current = current->_next;
}
if (current->_data == target)
{
deleteNode = current;
current = current->_next;
trailer->_next = current;
delete deleteNode;
count--;
return true;
}
else
std::cout << "unable to remove, item not in list" << std::endl;
return false;
}
//FOR TESTING
void toString()
{
for (Node* current = _head->_next; current != _tail; current = current->_next)
{
std::cout << current->_data << std::endl;
}
}
//
// Internal consistency check
//
public:
virtual bool check() const
{
bool sizeConsistent = isSizeConsistent();
bool headTailConsistent = isEndConsistent();
if (!sizeConsistent) std::cerr << "Size inconsistent" << std::endl;
if (!headTailConsistent) std::cerr << "Head / Tail inconsistent" << std::endl;
return sizeConsistent && headTailConsistent;
}
//
// Stated size is accurate to the entire list
//
bool isSizeConsistent() const
{
int count = 0;
for (Node* current = _head->_next; current != _tail; current = current->_next)
{
count++;
}
return size() == count;
}
//
// Checks that the head and tail are defaulted properly and the
// respective next pointers are appropriate.
//
bool isEndConsistent() const
{
if (_head->_data != T{}) return false;
if (_tail->_data != T{}) return false;
if (_head->_next == nullptr) return false;
if (_tail->_next != nullptr) return false;
if (isEmpty() && _head->_next != _tail) return false;
if (!isEmpty() && _head->_next == _tail) return false;
return true;
}
};
#endif
And finally, here is my main. The top portion is to test the functionality for LinkedList. The bottom portion is what I was working with to test queue.
#include "Queue.hpp"
#include "LinkedList.hpp"
#include <string>
#include <iostream>
int main()
{
LinkedList<int> list;
LinkedList<int> listEmpty;
Queue<int> list2;
list.push(1);
list.push(2);
list.push(3);
list.push(4);
list.push(5);
list.remove(1);
std::cout << "List contains 4? " << list.contains(4) << std::endl;
std::cout << "List empty? " << list.isEmpty() << std::endl;
std::cout << "List size: " << list.size() << std::endl;
std::cout << "Last in list? " << list.last() << std::endl;
std::cout << "What is in position 4? " << list[4] << std::endl;
std::cout << "Search " << list.search(10) << std::endl;
//std::cout << "3 is in position " << list.search() << std::endl;
std::cout << " " << std::endl;
list.toString();
list.clear();
std::cout << "///////////////////////////////////////////////////////////////////////////////" << std::endl;
list.push(4);
list.toString();
std::cout << "///////////////////////////////////////////////////////////////////////////////" << std::endl;
std::cout << "QUEUE STUFF" << std::endl;
std::cout << "///////////////////////////////////////////////////////////////////////////////" << std::endl;
list2.push(1);
list2.push(2);
list2.push(6);
list2.push(3);
list2.push(4);
list2.push(5);
std::cout << "Queue empty? " << list2.empty() << std::endl;
std::cout << "Queue size: " << list2.size() << std::endl;
std::cout << "First in Queue? " << list2.peek() << std::endl;
std::cout << "What position is 6 in? : " << list2.search(6) << std::endl;
list2.toString();
std::cout << " " << std::endl;
system("pause");
I guess my question is this, what steps can I take to go about fixing this particular function?
Thanks in advance!
The problem with your code is that peek, as you said, should not modify the Queue and neither take any parameter because it merely looks at the top of the structure and returns either true or false.
So a solution is to remove the parameter in peak as follows and everything compiles and runs.
bool peek() const
{
std::cout << _list.last() << std::endl;
return true;
}
Specifically, the error you get is because you cannot assign to a non-const lvalue reference an rvalue reference.
This is exactly what you are doing in T& val = T{}. T{} is an rvalue and clearly, val is a non-const reference to T.
You can try using bool peek(const T& val = T{}) const and see by yourself that everything compiles fine.

Adding an Instance to a Linked List using a Node

I'm having trouble understanding on how would I call the add function in main if I want to add an instance to list.
#include "object.h"
class list {
private:
struct Node
{
object objectInfo;
Node *next;
};
int size;
Node *head;
public:
list();
list(const list& otherlist);
~list();
void Add(const Node myObject);
my Main
int main() {
object myObject;
myObject.setTitle("Object 1");
myObject.setPrice(78.58);
myObject.setISBN("515161611");
cout << myObject << endl;
list myList;
myList.Add(myObject);
return 0;
}
my Function in cpp
void list::Add(const Node myObject) {
Node* temp;
temp = new Node;
temp->objectInfo = myObject.objectInfo;
temp->next = head;
head = temp;
size++;
}
Im having trouble on this line myList.Add(myObject);
keeps saying void list::Add(const list&)':cannot convert argument 1 from 'object' to 'const list::Node'
also no instance of overloaded function "list::Add" matches the argument list
You are trying to pass an object of type object into a function that takes a parameter of type Node. const Node myObject should be const object myObject.
This might give you some ideas:
#include <iostream>
#include <string>
template <typename Object>
class List {
class Node : public Object {
//static int& count() { static int c=0; return c; }
public:
Node* next;
Node() : next(nullptr) {
//std::cout << ++count() << " Nodes\n";
}
Node(const Object& obj) : next(nullptr), Object(obj) {
//std::cout << ++count() << " Nodes\n";
}
~Node() {
//std::cout << --count() << " Nodes\n";
}
};
Node *head, *tail;
int size;
public:
class iterator {
Node *cur_node;
public:
iterator(Node* node) { cur_node = node; }
Object& operator * () const { return *cur_node; }
bool operator != (const iterator& iter) const { return iter.cur_node != cur_node; }
iterator& operator ++() { if(cur_node) cur_node = cur_node->next; return *this; }
};
class iterator_const {
const Node *cur_node;
public:
iterator_const(const Node* node) { cur_node = node; }
const Object& operator * () const { return *cur_node; }
bool operator != (const iterator_const& iter) const { return iter.cur_node != cur_node; }
iterator_const& operator ++() { if(cur_node) cur_node = cur_node->next; return *this; }
};
iterator begin() { return iterator(head); }
iterator end() { return iterator(nullptr); }
iterator_const begin() const { return iterator_const(head); }
iterator_const end() const { return iterator_const(nullptr); }
template <typename ...Args>
void Add(const Object& obj, Args...more) {
Node *new_node = new Node(obj);
++size;
if(!tail) { tail = head = new_node; }
else { tail->next = new_node; tail = new_node; }
Add(more...);
}
void Add() {}
int Size() const { return size; }
List() : head(nullptr), tail(nullptr), size(0) {}
List(const List& src) : head(nullptr), tail(nullptr), size(0) {
for(auto&& entry : src) {
Add(entry);
}
}
~List() {
Node* p = head;
while(p) {
Node* next = p->next;
delete p;
p = next;
}
}
};
struct MyObjectType {
std::string name;
int age;
MyObjectType(std::string name, int age) : name(name), age(age) {}
friend std::ostream& operator << (std::ostream& os, const MyObjectType& obj) {
return os << "{\"" << obj.name << "\":" << obj.age << "}";
}
};
template <typename T>
void PrintList(const List<T>& list) {
std::cout << "Size: " << list.Size() << "\n";
for(const auto &elem : list) {
std::cout << " " << elem << "\n";
}
}
int main() {
using MyList = List<MyObjectType>;
MyList list_one;
list_one.Add(
MyObjectType("Harry",32),
MyObjectType("Lisa", 66),
MyObjectType("Buddy", 2),
MyObjectType("Skippy", 21)
);
MyList list_two(list_one);
list_two.Add(
MyObjectType("Horse", 10),
MyObjectType("Mule", 11)
);
std::cout << "list_one:\n";
PrintList(list_one);
std::cout << '\n';
std::cout << "list_two:\n";
PrintList(list_two);
}

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