Problems with Doubly-Linked List iterator implementation - c++

I am having some problems with a simple Doubly-Linked list class.
Here is all my code for it:
/*
* DLList.h
*
* Created on: Nov 19, 2013
* Author: tyler
*/
#ifndef DLLIST_H_
#define DLLIST_H_
#include <iostream>
using namespace std;
template <typename T>
class DLList{
private:
struct DLLNode{
private:
T data_;
bool visited_;
DLLNode* next_;
DLLNode* prev_;
public:
DLLNode(T data){
this->data_ = data;
visited_ = false;
next_ = NULL;
prev_ = NULL;
}
void setData(T data){
this->data_ = data;
}
void visit(){
visited_ = true;
}
void unvisit(){
visited_ = false;
}
void setNext(DLLNode* next){
this->next_ = next;
}
void setPrev(DLLNode* prev){
this->prev_ = prev;
}
T& getData(){
return data_;
}
bool getVisited(){
return visited_;
}
DLLNode* getNext(){
return next_;
}
DLLNode* getPrev(){
return prev_;
}
};
DLLNode* head_;
DLLNode* tail_;
public:
DLList(){
head_ = NULL;
tail_ = NULL;
}
class DLLiterator{
private:
DLLNode* node;
public:
DLLiterator(){
node = head_;
}
T& operator*(const DLLiterator& iter){
return iter.node->getData();
}
DLLiterator& operator++(const DLLiterator& iter){
if(node->getNext() != NULL)
node = node->getNext;
else
node = NULL;
return *this;
}
};
bool isEmpty(){
return (head_ == NULL);
}
void addNodeEnd(T data){
DLLNode* temp = new DLLNode(data);
if(isEmpty()){
head_ = temp;
tail_ = temp;
}
else{
DLLNode* curr;
curr = tail_;
curr->setNext(temp);
temp->setPrev(curr);
tail_ = temp;
}
}
bool contains(T data){
for(DLLNode* start = head_; start != NULL; start = start->getNext()){
if(start->getData() == data)
return true;
}
return false;
}
void remove(T data){
for(DLLNode* curr = head_; curr != NULL; curr = curr->getNext()){
DLLNode* key = curr;
if(curr->getData() == data){
if(curr == head_){
head_ = key->getNext();
key->getNext()->setPrev(NULL);
delete key;
}
if(curr == tail_){
tail_ = key->getPrev();
key->getPrev()->setNext(NULL);
delete key;
}
else{
DLLNode* prev;
DLLNode* next;
prev = key->getPrev();
next = key->getNext();
prev->setNext(next);
next->setPrev(prev);
delete key;
}
}
}
}
void printList(){
for(DLLNode* curr = head_; curr != NULL; curr = curr->getNext()){
cout << curr->getData() << "\n";
}
}
};
#endif /* DLLIST_H_ */
My problem is that I don't know how to actually use the iterator in an outside class. Everything else is tested and seems to be working fine. Still need to add a simple destructor, but my focus right now is the iterator. Any help would be great.
I tried just doing:
DLLiterator iter;
but that is clearly wrong...
EDIT: This is the operator++ code now:
iterator operator++(){
if(node_->getNext() != NULL)
node_ = node_->getNext;
else
node_ = NULL;
return *this;
}
but now it's asking for an int as an argument...?

Outside the class, you'd have to use the qualified name DLList<whatever>::DLLiterator. You can see that there's little point adding the wart to the nested name, unless you like your names to be hard to read: it just partly duplicates the scope name. I'd rename it iterator.
Now your problem is that it tries to initialise itself using a member of the list, head_, but it doesn't have access to a list to extract the head from. You probably want to follow the example of the standard containers, and create an iterator via a member of the list:
iterator begin() {return iterator(head_);}
and modify the iterator's constructor accordingly.
In C++11, this means users won't usually have to write out the nasty qualified name at all; you could get an iterator with
auto it = list.begin();
Finally, remove the arguments from the iterator's operator* and operator++. Since they are member functions, their operand is passed implicitly as this, not explicitly as an argument.

Related

Holding self-defined objects as fields in other self-defined objects (c++)

Im trying to implement a few data structures in c++, just to understand them better.
I have a question about the implementation. In general, if I have self-defined objects as fields of another objects, is it better to define a pointer to heap allocated memory of the object, or just a field of the object?
Consider the following example:
I tried to implement a basic stack as linked list, so one of the field (actually the only one) of the stack is a linked list, but Im not sure if this field should be a pointer to linked list (which is allocated in heap memory and initiallized in the constructor) or just a linked list.
Here's the implementation;
#ifndef STACKASLINKEDLIST_H
#define STACKASLINKEDLIST_H
#include "LinkedList.h"
template <class T>
class StackAsLinkedList
{
public:
//|-------------------- Constructors --------------------
StackAsLinkedList(){}
//|-------------------- Methods --------------------
void push(const T& toAdd){
data.add(toAdd,0);
}
T& pop() {
return data.remove(0);
}
T& peek() const{
T tmp = pop();
push(tmp);
return tmp;
}
bool isEmpty() const {
return data.isEmpty();
}
//|-------------------- Friend functions --------------------
friend std::ostream& operator<<(std::ostream& out, const StackAsLinkedList<T>& mStack){
out<<mStack.data;
return out;
}
//|-------------------- Destructors --------------------
virtual ~StackAsLinkedList(){}
protected:
private:
LinkedList<T> data;
};
#endif // STACKASLINKEDLIST_H
As I wrote it, I used as a filed just the LinkedList it self, Im not sure if its worst or better and if the implementation of the destructor works fine. Basically, in my implementation of LinkedList, anytime I push something to the stack a new Link appended to the LinkedList and this Link is allocated in the heap memory, so I do want the destructor of the stack to erase this memory.
I'd really appreciate a guidance/tips here. What is the best way to deal with the questions I asked? (Also I'd really appreciate any suugestions about improvements of the implemtation).
In case it is important to the question, here is my implementation of LinkedList
#ifndef LINKEDLIST_H
#define LINKEDLIST_H
#include "List.h"
#include "Link.h"
template <class T>
class LinkedList : public List<T>
{
public:
//|-------------------- Constructors --------------------
LinkedList(): List<T>(),head(NULL) {} //|Default constructor.
LinkedList(const LinkedList<T>& other): List<T>() { //|Copy constructor.
head = other.head;
Link<T>* otherCurr = other.head->next;
Link<T>* thisCurr = head;
while(otherCurr){
thisCurr->next = new Link<T>(otherCurr->m_data);
thisCurr = thisCurr->next;
otherCurr = otherCurr->next;
this->m_size++;
}
}
//|-------------------- Methods --------------------
bool isEmpty() const {
return head==NULL;
}
int getSize() const {
return this->m_size;
}
void add(T data,int index ){ //|Complexity time is O(n) because complexity time of getLink() is O(n).
//|If we had a pointer to the position, this function complexity would be O(1).
if(index > this->m_size){
std::cout<<"Out Of Bounds"<<std::endl;
return;
}
else if (index == this->m_size)
addLast(data);
else if (index == 0)
addFirst(data);
else{
Link<T>* toAdd = new Link<T>(data);
Link<T>* prevLink = getLink(index-1);
Link<T>* indexLink = prevLink->next;
prevLink->next = toAdd;
toAdd->next = indexLink;
}
this->m_size++;
}
void set(int index, T data){
if(index >= this->m_size){
std::cout<<"Out Of Bounds"<<std::endl;
return;
}
Link<T>* indexLink = getLink(index);
indexLink->m_data = data;
}
T remove(int index){
if(head== NULL){
std::cout<<"The list is empty"<<std::endl;
return NULL;
}
if(index > this->m_size-1){
std::cout<<"Out Of Bounds"<<std::endl;
return NULL;
}
if (index ==0 ){
Link<T>* tmp = head;
head = head->next;
T toReturn = tmp->m_data;
delete tmp;
return toReturn;
}
Link<T>* prevLink = getLink(index-1);
Link<T>* tmp = prevLink->next;
prevLink->next = tmp->next;
T toReturn = tmp->m_data;
delete tmp;
this->m_size--;
return toReturn;
}
//|-------------------- Operator overload --------------------
T operator[](int index) const { //|Complexity time is O(n).
Link<T>* relevantLink = getLink(index);
if(relevantLink)
return relevantLink->m_data;
else
return NULL;
}
bool operator==(const List<T>& other) const{ //|Complexity time is O(n).
if(! (typeid(other) == typeid(*this)))
return false;
if(this->m_size != other.getSize())
return false;
Link<T>* thisCurr = head;
int i=0;
while(thisCurr != NULL ){
if(thisCurr->m_data != other[i])
return false;
i++;
thisCurr = thisCurr->next;
}
return true;
}
//|-------------------- Friend functions --------------------
friend std::ostream& operator<<(std::ostream& out, const LinkedList<T>& mList){
Link<T>* curr = mList.head;
while(curr->next){
out<< (*curr)<<" -> ";
curr = curr->next;
}
out<<(*curr);
return out;
}
//|-------------------- Destructors --------------------
virtual ~LinkedList(){
Link<T> *curr, *prev;
curr= head;
while(curr){
prev = curr;
curr = curr->next;
delete prev;
}
}
private:
//|-------------------- Private fields --------------------
Link<T>* head;
//|-------------------- Private Methods --------------------
Link<T>* getLink(int index) const{ //|Complexity time is O(n).
if(index >= this->m_size -1){
std::cout<<"Out of bounds"<<std::endl;
return NULL;
}
int counter =0;
Link<T>* curr = head;
while(counter < index){
counter++;
curr = curr->next;
}
return curr;
}
void addFirst(T data){
Link<T>* toAdd = new Link<T>(data);
if (head == NULL){
head = toAdd;
return;
}
toAdd->next = head;
head = toAdd;
}
void addLast(T data){
Link<T>* toAdd = new Link<T>(data);
if (head == NULL){
head = toAdd;
return;
}
Link<T>* curr = head;
while (curr->next != NULL)
curr = curr->next;
curr->next = toAdd;
}
};
#endif // LINKEDLIST_H

Linkedlist template with class object not working

I have created this Dictionary class and a Linkedlist template which takes this class as the type. In the main() function I am trying to make an object of Dictionary class and passing the Dictionary as the type for Linkedlist template. Later when I pass the created Dictionary class object to LinkedList's insertHead() or initHead() function and try to print the data through accessing the head's data and calling Dictionary member function print(), It does not prints the data (32, A). insertHead() prints a "0-" and initHead() gives segmentation fault. Is there a way I can fix the issue?
class Dictionary {
public:
int index;
string data;
public:
Dictionary(int index = 0, string data = ""){
this->index = index;
this->data = data;
}
Dictionary(string data){
this->data = data;
}
void setIndex(int index){
this->index = index;
}
void setData(string data){
this->data = data;
}
Dictionary operator=(Dictionary const & obj){
Dictionary dict;
dict.index = obj.index;
dict.data = obj.data;
return dict;
}
void print(){
cout << index << "-" << data << endl;
}
friend bool operator== (const Dictionary &d1, const Dictionary &d2);
friend bool operator!= (const Dictionary &d1, const Dictionary &d2);
};
bool operator== (const Dictionary &d1, const Dictionary &d2){
return (d1.data == d2.data);
}
bool operator!= (const Dictionary &d1, const Dictionary &d2){
return !(d1 == d2);
}
int main(){
Dictionary d(32, "A");
LinkedList<Dictionary> l;
l.insertHead(d);
l.head->data.print();
}
Here is the code for LinkedList template class:
#include <iostream>
using namespace std;
template <typename T>
class Node {
public:
T data;
Node *next;
Node *prev;
Node(){};
};
template <typename T>
class LinkedList {
public:
Node<T> *head;
Node<T> *tail;
public:
LinkedList(){
head = NULL;
tail = NULL;
}
void initHead(T item){
head->next = NULL;
head->prev = NULL;
head->data = item;
}
void insertHead(T item){
Node<T> *tmp = new Node<T>();
if (head == nullptr){
head = tmp;
head->prev = nullptr;
head->data = item;
head->next = nullptr;
tail = tmp;
} else {
tmp->next = head;
tmp->data = item;
tmp->prev = nullptr;
head->prev = tmp;
head = tmp;
}
}
void insertLast(T item){
Node<T> *tmp = new Node<T>();
tmp->data = item;
if (head == nullptr){
head = tmp;
head->prev = nullptr;
head->next = nullptr;
tail = tmp;
} else {
tmp->prev = tail;
tail->next = tmp;
tmp->next = nullptr;
tail = tmp;
}
}
void insertNext(T item){
Node<T> *tmp = new Node<T>();
tmp->next = nullptr;
tmp->data = item;
tmp->prev = nullptr;
Node<T> *iter = head;
while (iter != nullptr){
if (iter->next == nullptr){
iter->next = tmp;
tmp->prev = iter;
return;
}
iter = iter->next;
}
}
// Returns 0 if Not found. Always add a check
// for 0 before accessing the tmp->data
Node<T>* find(T item){
Node<T> *tmp = head;
while(tmp && tmp->data != item){
tmp = tmp->next;
}
return tmp;
}
bool deleteNode(Node<T>* node){
if (node == nullptr){
return false;
} else if (node == head){
head = node->next;
delete node;
return true;
} else {
Node<T> *tmp = head;
while (tmp){
if (tmp->next == node){
tmp->next = node->next;
delete node;
return true;
}
tmp = tmp->next;
}
}
return false;
}
void print(){
Node<T> *tmp;
tmp = head;
while (tmp != nullptr){
cout << tmp->data << "->";
tmp = tmp->next;
}
cout << endl;
}
};
In the function insertHead I changed the head->data = item to next lines
head->data.index = item.index; head->data.data = item.data;
then it printed 32-A. So you have a problem with = operator overloading. Then I changed your overloading as follows:
void operator=(const Dictionary & obj){ index = obj.index; data = obj.data; }
The = operation on your Dictionary works fine now.
If you want to use original signature as you state in comments you should update previous overloading function as:
Dictionary& operator=(Dictionary const & obj){
this->index = obj.index;
this->data = obj.data;
return *this;
}
I want to improve the answer with a self assignment check. While overloading = operator, internals goes like this:
Deallocate the memory hold by this
Allocate the memory for given parameter object
Copy values and return
Therefore, if you try something like:
Dictionary dummyDict;
dummyDict=dummyDict;
your program will blow. So the final answer will be:
Dictionary& operator=(Dictionary const & obj){
if(this == &obj){
return *this;
}
this->index = obj.index;
this->data = obj.data;
return *this;
}

Segmentation fault error thrown with certain compilers for linked list implementation

I'm getting segmentation fault error with the follow main function.
The header file has a linked list implementation with an iterator class and different testing members.
The thing is that the segmentation fault error shows up on a certain compilers and goes away on other. I tried using GDB to debug for any errors, but the program executes fine.
This is really bugging me as I cannot find the reason this would throw a segmentation fault error.
Any help is greatly appreciated.
EDIT:
I noticed that with this updated main, the logic is flawed and does not insert the node at the specified location. So, I'll have to do some more debugging to figure out the issue.
It seems the else if block inside insert() is executed instead of the else block.
Main.cpp
#include <iostream>
#include "List.h"
int main(){
List<double> l;
l.push_back(1.1);
l.push_back(2.2);
l.insert(l.begin()++, 3.3);
l.printList();
}
List.h
#include <cstdint>
#include <iostream>
#include <memory>
template<typename T>
class List
{
public:
class Node {
public:
Node(T value) : value_(value) {}
Node(T value, Node* prev, Node* next) : value_(value), prev_(prev), next_(next) {}
T value_;
Node* next_;
Node* prev_;
};
Node* head_;
Node* tail_;
//! An iterator over the list
class iterator
{
public:
Node* iNode;
iterator(Node* head): iNode(head){ }
~iterator() {}
T& operator*() {
return iNode -> value_;
}
iterator& operator++() {
iNode = iNode->next_;
return *this;
}
iterator operator++(int ignored) {
iNode = iNode->next_;
return *this;
}
iterator& operator--() {
iNode = iNode->prev_;
return *this;
}
//! Is this iterator pointing at the same place as another one?
bool operator== (const iterator& it) const {
return this->iNode == it.iNode;
}
//! Is this iterator pointing at a different place from another?
bool operator!= (const iterator& it) const {
return this->iNode != it.iNode;
}
};
//! Default constructor
List() :tail_(nullptr) {}
void push_back_node(T value)
{
Node* newnode = new Node(value, tail_, nullptr); //make and link new tail node
if (tail_)
{
tail_->next_ = newnode; // link in new node
}
else
{
head_ = newnode;
}
tail_ = newnode; // update tail
}
//! Copy constructor
List(const List& lst) : head_(nullptr), tail_(nullptr)
{
Node* cur = lst.head_; //get first source item.
while (cur) // if there is a source item to copy
{
push_back_node(cur->value_); // stick the item on the end of this list
cur = cur->next_; // get next source item
}
}
void clear()
{
while (head_)
{
delete std::exchange(head_, head_->next_);
}
tail_ = head_;
}
//! Copy assignment operator
List& operator= (const List& list_copy) {
List tmp(list_copy);
clear();
std::swap(*this, tmp);
return *this;
}
//! Move constructor
List(List&& move) {
head_ = std::move(move.head_);
tail_ = std::move(move.tail_);
}
////! Move assignment operator
List& operator= (List&& list) {
head_ = std::move(list.head_);
tail_ = std::move(list.tail_);
return *this;
}
//! Destructor
~List() {}
//
// Accessors:
//
//! How many elements are in this list?
size_t size() const {
size_t size = 0;
auto temp = head_;
while (temp != nullptr)
{
size++;
temp = temp->next_;
}
return size;
}
//! Is this list empty?
bool empty() const {
return tail_ == nullptr && head_ == nullptr;
}
//! Get an iterator to the beginning of the list
iterator begin() {
return List<T>::iterator(head_);
}
//! Get an iterator just past the end of the list
iterator end() {
return List<T>::iterator(tail_);
}
//
// Mutators:
//
//! Copy an element to the front of the list
void push_front(const T& value) {
Node* node = new Node(value);
if (head_ == nullptr) {
head_ = node;
}
else {
node->next_ = head_;
head_ = node;
}
}
//! Move an element to the front of the list
void push_front(T&& value) {
Node* node = new Node(value);
if (head_ == nullptr) {
head_ = node;
}
else {
node->next_ = head_;
head_ = node;
}
}
//! Copy an element to the back of the list
void push_back(const T& value) {
Node* node = new Node(value);
if (tail_) {
tail_->next_ = node;
tail_ = tail_->next_;
}
else {
head_ = node;
tail_ = head_;
}
}
//! Add an element to the back of the list
void push_back(T&& value) {
Node* node = new Node(value);
if (tail_) {
tail_->next_ = node;
tail_ = tail_->next_;
}
else {
head_ = node;
tail_ = head_;
}
}
iterator insert(iterator position, const T& value) {
Node* newNode = new Node(value);
if (position == List<T>::iterator(head_)) {
newNode->next_ = head_;
head_ = newNode;
}
else if (!position.iNode->next_) {
position.iNode->next_ = newNode;
}
else {
Node* curr = head_;
while (curr->next_ != position.iNode)
{
curr = curr->next_;
}
newNode->next_ = curr->next_;
curr->next_ = newNode;
}
return position;
}
void printList() const{
auto node = head_;
while (node != nullptr)
{
std::cout << node -> value_ << " ";
node = node->next_;
}
}
iterator insert(iterator position, T&& value){
Node* newNode = new Node(value);
if (position == List<T>::iterator(head_)) {
newNode->next_ = head_;
head_ = newNode;
}
else if (!position.iNode->next_) {
position.iNode->next_ = newNode;
}
else {
Node* curr = head_;
while (curr->next_ != position.iNode)
{
curr = curr->next_;
}
newNode->next_ = curr->next_;
curr->next_ = newNode;
}
return position;
}
//! Remove an element from an arbitrary location
void erase(iterator it) {
Node* temp = it.iNode->next_;
// Copy data of the next node to current node
it.iNode->value_ = it.iNode->next_->value_;
// Perform conventional deletion
it.iNode->next_ = it.iNode->next_->next_;
free(temp);
}
};
Node(T value) : value_(value) {}
does not point prev_ or next_ anywhere useful, so
Node* node = new Node(value);
produces a node that is a timebomb unless you later set its prev_ and next_ members to point somewhere safe. push_back doesn't do this.
Solution:
Use the
Node(T value, Node* prev, Node* next) : value_(value), prev_(prev), next_(next) {}
instead:
Node* node = new Node(value, nullptr, nullptr);
You will find a similar defects in all of the variants of push_back, push_front, and insert. You can also use the Node(T value, Node* prev, Node* next) constructor to simplify some of the work adding, pushing and inserting nodes by using the surrounding nodes in place of the nullptrs

Returning node with minimum value in a binary search tree implemented with templates and unique_ptr

I am trying to implement BST with unique_ptr. I want to return the node with the minimum value in BST. I know how to return the minimum value and I wrote the function for it but what if I want to return node? Is it possible with the classes I have?
#include <iostream>
#include <memory>
template<class T>
class BinarySearchTree{
struct TreeNode;
typedef std::unique_ptr<TreeNode> spTreeNode;
struct TreeNode{
T data;
spTreeNode left;
spTreeNode right;
TreeNode(const T & value):data(value),left(nullptr),right(nullptr){}
};
spTreeNode root;
bool insert(spTreeNode &node);
void print(const spTreeNode&) const ;
public:
BinarySearchTree();
void insert( const T & node);
void print()const;
T getMin();
};
template<class T>
BinarySearchTree<T>::BinarySearchTree():root(nullptr){}
template<class T>
void BinarySearchTree<T>::insert(const T & ref)
{
std::unique_ptr<TreeNode> node(new TreeNode(ref));
if (root == nullptr) {
root = std::move(node);
} else {
TreeNode* temp = root.get();
TreeNode* prev = root.get();
while (temp != nullptr) {
prev = temp;
if (temp->data < ref)
temp = temp->right.get();
else
temp = temp->left.get();
}
if (prev->data < ref)
prev->right = std::move(node);
else
prev->left = std::move(node);
}
}
template<class T>
T BinarySearchTree<T>::getMin()
{
TreeNode* temp = root.get();
TreeNode *prev = nullptr;
while (temp)
{
prev = temp;
temp = temp->left.get();
}
return prev->data;
}
int main()
{
BinarySearchTree<int> bst;
bst.insert(13);
bst.insert(3);
bst.insert(5);
bst.insert(31);
bst.insert(511);
bst.insert(311);
std::cout << bst.getMin(); // Works but what if I want to return the Node?
return 0;
}
You would have to decide the interface you want. Do you want to return a const pointer to the extant TreeNode? A const reference to the TreeNode? A copy of the TreeNode? The key is to think about how long references/pointers will be valid.
I frankly don't think any of those are good ideas for a public interface. So let's say you made getMinNode() private, and kept getMin() public:
// Returns non-owning pointer; do not attempt to delete TreeNode.
template<class T>
const BinarySearchTree<T>::TreeNode* BinarySearchTree<T>::getMinNode() const
{
// Like getMin(), but return prev
// Does this work for empty BinarySearchTree?
TreeNode* temp = root.get();
TreeNode *prev = nullptr;
while (temp)
{
prev = temp;
temp = temp->left.get();
}
return prev;
}
template<class T>
T BinarySearchTree<T>::getMin() const // member function is const
{
return getMinNode()->data;
}

Linked list outputting different values to cout

I'm writing a linked list container for my homework. Using Qt 4.7 and gcc 4.4, I've found some problems in the code that I guess they are related to memory management or garbage collection.
After using the << operator to display the list, all data of list is changed. for example, after construction and setting a list like l,
std::cout<<l<<std::endl;
std::cout<<l<<std::endl;
prints:
Data = [-10, 3, 2, 8, 1, -1, -2, ] // this is correct
Data = [0, 149560240, 149560192, 149558336, 149560256, 149558320, 149560208, ]
My linked list is:
#ifndef LINKEDLIST1_H_
#define LINKEDLIST1_H_
#include <iostream>
template<class T> class LinkedList1;
template<class T> class Node;
template<class T>
class Node
{
friend class LinkedList1<T> ;
public:
Node(const T& value) :
Data(value), Next(NULL)
{
}
Node() :
Next(NULL)
{
}
T Data;
Node* Next;
};
template<class T>
class LinkedList1
{
public:
LinkedList1() :
size(-1), first(NULL)
{
}
~LinkedList1()
{
Node<T>* i = this->first;
Node<T>* j = this->first;
while(j!=NULL)
{
j=i->Next;
delete i;
i=j;
}
}
// Operations on LinkedList
Node<T>* First()
{
return first;
}
int Size()
{
return size + 1;
}
int Count()
{
int size = 0;
Node<T>* current = this->firstFirst();
while(current != NULL)
{
size++;
current = current->Next;
}
this->size = size;
return this->Size();
}
bool IsEmpty()
{
return this->Size() == 0;
}
void Prepend(Node<T>* value) //O(1)
{
value->Next = this->first;
this->first = value;
this->size++;
}
void Prepend(const T& value) //O(1)
{
Node<T>* item = new Node<T>(value);
item->Next = this->first;
this->first = item;
this->size++;
}
void Append(Node<T>* value)
{
if(this->IsEmpty())
{
this->first = value;
this->size++;
}
else
{
Node<T>* current = this->First();
while(current->Next != NULL)
current = current->Next;
current->Next = value;
value->Next = NULL;
this->size++;
}
}
void Append(const T& value)
{
Node<T>* temp= new Node<T>(value);
this->Append(temp);
}
void Insert(Node<T>* location, Node<T>* value) //O(n)
{
Node<T>* current = this->first;
Node<T>* before = current;
while(current != NULL)
{
before = current;
current = current->Next;
if(current == location)
{
before->Next = value;
value->Next = current;
this->size++;
break;
}
}
}
void Insert(Node<T>* location, const T& value)
{
Node<T>* temp = new Node<T>(value);
this->Insert(location,temp);
}
Node<T>* Pop()
{
if(this->IsEmpty())
return NULL;
else
{
Node<T>* current = this->first;
Node<T>* before = current;
while(current->Next != NULL)
{
before = current;
current = current->Next;
before->Next = current;
}
before->Next = NULL;
this->size--;
return current;
}
}
Node<T>* PopF()
{
if(!this->IsEmpty())
{
Node<T>* head = this->first;
this->first = this->first->Next;
this->size--;
return head;
}
else
return NULL;
}
Node<T>* Remove(Node<T>* location)
{
// validating by IsEmpty is not necessary for this operation,
// while statement's condition guarantees validation
Node<T>* current = this->first;
Node<T>* before = current;
while(current != NULL)
{
before = current;
current = current->Next;
before->Next = current;
if(current == location)
{
before->Next = current->Next;
current->Next=NULL;
return current;
}
}
return NULL; // Not found...
}
void Inverse()
{
if(this->IsEmpty())
return;
else
{
Node<T>* r = NULL;
Node<T>* q = this->first;
Node<T>* p = this->first;
while(q != NULL)
{
p = p->Next;
q->Next = r;
r = q;
q = p;
}
this->first = r;
}
}
// Ordered insertion. implement this: foreach i,j in this; if i=vale: i+=vale, break; else if i<=value<=j: this.insert(j,value),break
friend std::ostream& operator<<(std::ostream& out, const LinkedList1 item)
{
out<<"Data = [";
Node<T>* current = item.first;
while(current != NULL)
{
out << current->Data << ", ";
current = current->Next;
}
out<<"]";
return out;
}
void HelperOutput(std::ostream& out, const LinkedList1 item) const
{
out<<item;
}
Node<T>* operator[](const int& index)
{
int i=0;
Node<T>* current = this->first;
while(i<=index && current!=NULL)
{
if(i=index)
return current;
else
{
i++;
current=current->Next;
}
}
}
public:
int size;
Node<T>* first;
};
#endif /* LINKEDLIST1_H_ */
friend std::ostream& operator<<(std::ostream& out, const LinkedList1 item)
{
out<<"Data = [";
Node<T>* current = item.first;
while(current != NULL)
{
out << current->Data << ", ";
current = current->Next;
}
out<<"]";
return out;
}
first item in output of second call is always 0. So I Thinked I've set first to NULL in somewhere in code; but I checked out all of methods and there was nothing like that. In addition, printed value is not the pointer itself; it's pointer's Data. Somewhere somebody changes Datas of all Node<T>*s in my list.
Is this a memory management or garbage collection issue? if not, what I'm doing wrong?
One thing that stands out here is that your signature is:
std::ostream& operator<<(std::ostream& out, const LinkedList1 item)
Instead of:
std::ostream& operator<<(std::ostream& out, const LinkedList1& item)
So, you are invoking a copy of your LinkedList. I suspect the issue here is that you have not correctly implemented your copy and assignment operators for LinkedList1, such that the the copy references the original content, and the destructor is making the original object into garbage.
I would recommend adding the following to your definition of LinkedList1:
private:
// The following declarations disallow copy and assignment. Do not implement.
LinkedList1(const LinkedList1&);
LinkedList1& operator=(const LinkedList1&);
Adding the above will lead to linker errors for the original signature that you had. I would then recommend passing the linked list by const reference, and your problem should disappear.
As an aside, I notice that many of your functions can be made const but aren't. For example, you have int Size() instead of int Size()const. One should generally mark as const anything that can be so-marked. This is known as "const-correctness" and can avoid a large number of issues.
Also, minor style nitpick: you have if...else statements where one has braces and the other doesn't. I would strongly recommend that you use braces in all cases as this leads to more readable code.