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;
}
Related
I have to write a function that will add elements to C-struct, but it can't add the same element. Example:
Input:
1 2 1 3
Output:
ADDED 1
ADDED 2
NOT ADD 1
ADD 3
Elements are taken from array, here's piece of code that uses the function I need to write:
int tab[] = {1,4,1,3,5};
Node* head = 0;
for (size_t i = 0, e = std::size(tab); i != e; ++i) {
bool b = add(head,tab[i]);
cout << tab[i] << (b ? " " : " NOT ")
<< "added" << endl;
}
C-struct Node looks like that:
struct Node {
int data;
Node* next;
};
Here's what I wrote, but it adds all elements from array. I can't change the loop, only add function:
bool add(Node*& head, int data){
Node *n = new Node;
n->data = data;
n->next = 0;
if(!head)
head = n;
else{
Node *tmp = head;
while(tmp->next)
tmp = tmp->next;
tmp->next = n;
}
};
currently you just add the element without looking if it is already present or not
The definition can be something like
bool add(Node*& head, int data){
if(!head) {
head = new Node;
n->data = data;
n->next = 0;
return true;
}
Node *tmp = head;
while (tmp->next) {
if (tmp->data == data)
return false;
tmp = tmp->next;
}
if (tmp->data == data)
return false;
tmp->next = new Node;
tmp->next->data = data;
tmp->next->next = 0;
return true;
}
I encourage you to add a constructor to not have to set the data and next fields each time after you create a new instance
Exemple
Node::Node(int d) : next(0), data(d) {
}
// add should be a static method of Node, to be able to access next and data while they are private
bool add(Node*& head, int data){
if(!head) {
head = new Node(data);
return true;
}
Node *tmp = head;
while (tmp->next) {
if (tmp->data == data)
return false;
tmp = tmp->next;
}
if (tmp->data == data)
return false;
tmp->next = new Node(data);
return true;
}
Here's my attempt. Look for the existing data first then add if not present (no change there from existing code)
bool add(Node*& head, int data) {
Node *tmp = head;
while (tmp) {
if (tmp->data == data)
return false; // data already present
tmp = tmp->next;
}
Node *n = new Node;
n->data = data;
n->next = 0;
if (!head) {
head = n;
}
else {
Node *tmp = head;
while(tmp->next)
tmp = tmp->next;
tmp->next = n;
}
return true; // data added
}
So I did something like that and it works with the data I have. I suppose it works in general
bool add(Node*& head, int data){
Node *n = new Node;
n->data = data;
n->next = 0;
if(!head)
head = n;
else{
Node *tmp = head;
while(tmp->next){
if(tmp->data == data)
return false;
else
tmp = tmp->next;
}
tmp->next = n;
}
};
I decided to practice my linked-list knowledge, and decided to create one in C++!
I ran this code on two different online compilers - one worked, and the other is giving me a segfault. I cannot figure out what the problem is within my code, and am wondering if you can help me.
#include <iostream>
using namespace std;
struct Node {
int val;
Node *next;
Node(int val){
this->val = val;
this->next = NULL;
}
};
class LinkedList {
public:
Node *head;
void insertAtHead(Node *temp)
{
if (head == NULL)
{
head = temp;
}
else
{
temp->next = head;
head = temp;
}
}
void printList()
{
Node *temp = head;
while (temp != NULL)
{
cout << temp->val << endl;
temp = temp->next;
}
}
void insertAtBack(Node *temp)
{
if (head == NULL)
{
head = temp;
return;
}
Node *current = head;
while (current->next != NULL){
current = current->next;
}
current->next = temp;
}
void deleteNode(Node *temp)
{
if (head == NULL)
{
cout << "Empty List";
return;
}
if (head->val == temp->val)
{
head = head->next;
return;
}
Node *current = head;
while (current->next != NULL)
{
if (current->next->val == temp->val)
{
current->next = current->next->next;
return;
}
current = current->next;
}
}
};
int main()
{
Node *temp = new Node(10);
Node *temp2 = new Node(4);
Node *temp3 = new Node(17);
Node *temp4 = new Node(22);
Node *temp5 = new Node(1);
LinkedList x;
x.insertAtHead(temp);
x.insertAtHead(temp2);
x.insertAtBack(temp3);
// x.insertAtBack(temp4);
// x.insertAtBack(temp5);
// x.deleteNode(temp);
x.printList();
return 0;
}
The problem I am encountering is when I use the insertAtBack() method. It gives me a segfault, but I do not see what's wrong with the logic. It is pretty straight forward. The insertAtFront() method works, but once I call insertAtBack() my code fails.
make sure to initialize Node *head to NULL.
After insert temp(which is value 10), temp->next value becomes undefined value, because Node *head is undefined value.
Your LinkedList class is not initializing its head member. You need to add a constructor to initialize head to NULL.
Also, the class is leaking memory, as there is no destructor to free the nodes when a LinkedList instance is destroyed, and deleteNode() doesn't free the node being removed, either.
Try something more like this:
#include <iostream>
using namespace std;
struct Node
{
int val;
Node *next;
Node(int val) : val(val), next(NULL) { }
};
class LinkedList
{
private:
Node *head;
// if you are NOT using C++11 or later, add these
// until you are reading to tackle copy semantics!
/*
LinkedList(const LinkedList &);
LinkedList& operator=(const LinkedList &);
*/
public:
LinkedList() : head(NULL) {} // <-- add this!
~LinkedList() // <-- add this!
{
Node *current = head;
while (current)
{
Node *next = current->next;
delete current;
current = next;
}
}
void insertAtHead(Node *temp)
{
if (!head)
{
head = temp;
}
else
{
temp->next = head;
head = temp;
}
}
void printList()
{
Node *current = head;
while (current)
{
cout << current->val << endl;
current = current->next;
}
}
void insertAtBack(Node *temp)
{
if (!head)
{
head = temp;
return;
}
Node *current = head;
while (current->next) {
current = current->next;
}
current->next = temp;
}
void deleteNode(Node *temp)
{
if (!head)
{
cout << "Empty List";
return;
}
if (head == temp)
{
head = temp->next;
delete temp;
return;
}
Node *current = head;
while (current->next)
{
if (current->next == temp)
{
current->next = temp->next;
delete temp;
return;
}
current = current->next;
}
}
// if you ARE using C++11 or later, add these until
// you are reading to tackle copy and move semantics!
/*
LinkedList(const LinkedList &) = delete;
LinkedList(LinkedList &&) = delete;
LinkedList& operator=(const LinkedList &) = delete;
LinkedList& operator=(LinkedList &&) = delete;
*/
};
int main()
{
Node *temp = new Node(10);
Node *temp2 = new Node(4);
Node *temp3 = new Node(17);
Node *temp4 = new Node(22);
Node *temp5 = new Node(1);
LinkedList x;
x.insertAtHead(temp);
x.insertAtHead(temp2);
x.insertAtBack(temp3);
// x.insertAtBack(temp4);
// x.insertAtBack(temp5);
// x.deleteNode(temp);
x.printList();
return 0;
}
Which can then be simplified further:
#include <iostream>
using namespace std;
struct Node
{
int val;
Node *next;
Node(int val, Node *next = NULL) : val(val), next(next) { }
};
class LinkedList
{
private:
Node *head;
// if you are NOT using C++11 or later, add these
// until you are reading to tackle copy semantics!
/*
LinkedList(const LinkedList &);
LinkedList& operator=(const LinkedList &);
*/
public:
LinkedList() : head(NULL) {} // <-- add this!
~LinkedList() // <-- add this!
{
Node *current = head;
while (current)
{
Node *next = current->next;
delete current;
current = next;
}
}
Node* insertAtHead(int value)
{
Node *temp = new Node(value, head);
if (!head)
head = temp;
return temp;
}
void printList()
{
Node *current = head;
while (current)
{
cout << current->val << endl;
current = current->next;
}
}
Node* insertAtBack(int value)
{
Node **current = &head;
while (*current)
current = &((*current)->next);
*current = new Node(value);
return *current;
}
/*
void deleteNode(Node *temp)
{
Node *current = head, *previous = NULL;
while (current)
{
if (current == temp)
{
if (previous)
previous->next = temp->next;
if (head == temp)
head = temp->next;
delete temp;
return true;
}
previous = current;
current = current->next;
}
cout << "Not found" << endl;
return false;
}
*/
bool deleteValue(int value)
{
Node *current = head, *previous = NULL;
while (current)
{
if (current->val == value)
{
if (previous)
previous->next = temp->next;
if (head == temp)
head = temp->next;
delete temp;
return true;
}
previous = current;
current = current->next;
}
cout << "Not found" << endl;
return false;
}
// if you ARE using C++11 or later, add these until
// you are reading to tackle copy and move semantics!
/*
LinkedList(const LinkedList &) = delete;
LinkedList(LinkedList &&) = delete;
LinkedList& operator=(const LinkedList &) = delete;
LinkedList& operator=(LinkedList &&) = delete;
*/
};
int main()
{
LinkedList x;
x.insertAtHead(10);
x.insertAtHead(4);
x.insertAtBack(17);
// x.insertAtBack(22);
// x.insertAtBack(1);
// x.deleteValue(10);
x.printList();
return 0;
}
I am trying to implement a generic single linked list. So far I have everything done correctly but I cannot get my search function to work properly. It should print "yes"in the output but nothing happens.
Here is my code:
#ifndef LinkedList_hpp
#define LinkedList_hpp
#include <iostream>
template<class T>
struct Node {
T data;
Node<T>* next;
};
template<class T>
class SingleLinkedList {
private:
Node<T>* head;
Node<T>* tail;
public:
SingleLinkedList() {
head = nullptr;
tail = nullptr;
}
void createNode(const T& theData) {
Node<T>* temp = new Node<T>;
temp->data = theData;
temp->next = nullptr;
if(head == nullptr) {
head = temp;
tail = temp;
temp = nullptr;
}
else {
tail->next = temp;
tail = temp;
}
}
void display() {
Node<T>* temp = new Node<T>;
temp = head;
while(temp != nullptr) {
std::cout << temp->data << "\t";
temp = temp->next;
}
}
void insert_start(const T& theData) {
Node<T>* temp = new Node<T>;
temp->data = theData;
temp->next = head;
head = temp;
}
void insert_position(int pos, const T& theData) {
Node<T>* previous = new Node<T>;
Node<T>* current = new Node<T>;
Node<T>* temp = new Node<T>;
current = head;
for(int i = 1; i < pos; i++) {
previous = current;
current = current->next;
}
temp->data = theData;
previous->next = temp;
temp->next = current;
}
void delete_first() {
Node<T>* temp = new Node<T>;
temp = head;
head = head->next;
delete temp;
}
void delete_last() {
Node<T>* previous = new Node<T>;
Node<T>* current = new Node<T>;
current = head;
while(current->next != nullptr) {
previous = current;
current = current->next;
}
tail = previous;
previous->next = nullptr;
delete current;
}
void delete_position(int pos) {
Node<T>* previous = new Node<T>;
Node<T>* current = new Node<T>;
current = head;
for(int i = 1; i < pos; i++) {
previous = current;
current = current->next;
}
previous->next = current->next;
}
bool search(Node<T>* head, int x) {
struct Node<T>* current = head;
while (current != NULL) {
if (current->data == x)
return true;
current = current->next;
}
return false;
}
};
#endif /* LinkedList_hpp */
Here is the main.cpp:
#include <iostream>
#include "LinkedList.hpp"
int main(int argc, const char * argv[]) {
SingleLinkedList<int> obj;
obj.createNode(2);
obj.createNode(4);
obj.createNode(6);
obj.createNode(8);
obj.createNode(10);
std::cout<<"\n--------------------------------------------------\n";
std::cout<<"---------------Displaying All nodes---------------";
std::cout<<"\n--------------------------------------------------\n";
obj.display();
std::cout<<"\n--------------------------------------------------\n";
std::cout<<"-----------------Inserting At End-----------------";
std::cout<<"\n--------------------------------------------------\n";
obj.createNode(55);
obj.display();
std::cout<<"\n--------------------------------------------------\n";
std::cout<<"----------------Inserting At Start----------------";
std::cout<<"\n--------------------------------------------------\n";
obj.insert_start(50);
obj.display();
std::cout<<"\n--------------------------------------------------\n";
std::cout<<"-------------Inserting At Particular--------------";
std::cout<<"\n--------------------------------------------------\n";
obj.insert_position(5,60);
obj.display();
std::cout<<"\n--------------------------------------------------\n";
std::cout<<"----------------Deleting At Start-----------------";
std::cout<<"\n--------------------------------------------------\n";
obj.delete_first();
obj.display();
std::cout<<"\n--------------------------------------------------\n";
std::cout<<"-----------------Deleing At End-------------------";
std::cout<<"\n--------------------------------------------------\n";
obj.delete_last();
obj.display();
std::cout<<"\n--------------------------------------------------\n";
std::cout<<"--------------Deleting At Particular--------------";
std::cout<<"\n--------------------------------------------------\n";
obj.delete_position(4);
obj.display();
std::cout<<"\n--------------------------------------------------\n";
system("pause");
Node<int>* head = NULL;
obj.search(head, 8) ? printf("Yes") : printf("No");
return 0;
}
You can see that I search for the value 8 and it should print yes since 8 is still in the linked list.
This is your search function:
bool search(Node<T>* head, int x) {
struct Node<T>* current = head;
while (current != NULL) {
if (current->data == x)
return true;
current = current->next;
}
return false;
}
It uses the argument head passed into as the first argument, instead of the SingleLinkedList<T>::head member variable.
And since you call it passing a null pointer as the first argument, you will not find anything.
Simple fix: Remove the first argument from the search function:
bool search(T x) { ... }
As you see I also changed the argument of the value you search for to the template type.
This line:
Node<int>* head = NULL;
mean you are passing NULL into your search method.
Your search method should not take a head parameter at all - head is already a member of your class.
Also note: you have lots of memory leaks like this:
Node<T>* temp = new Node<T>;
temp = head;
You don't need to allocate memory for a pointer that you are just going to overwrite with a new value, just use
Node<T>* temp = head;
so I was trying to build this project on deque using the doubly linked list. but when I build it. it says build but gives threads and doesn't give the output as required.
I have re-implemented the major problem(copy constructor) and all the functions again and again but then it still gives me new threads every time.
this is the header file.
#pragma once
#include <stdexcept>
using namespace std;
class Node
{
public:
int data;
Node* next;
Node* previous;
Node();
Node(const int &x);
};
class Deque
{
public:
Deque();
Deque(const Deque &d);
Deque &operator= (const Deque &d);
~Deque();
void insertFront(const int &x);
void insertBack(const int &x);
int removeFront();
int removeBack();
int peekFront();
int peekBack();
bool empty() const;
int size()const;
friend ostream& operator << (ostream &out, const Deque &d);
private:
Node* front;
Node* rear;
};
this will be the .cpp (implementation file.)
//
// Deque_cmpt225.cpp
// Deque_cmpt225
//
// Created by Aryan Arora on 2017-10-09.
// Copyright © 2017 Aryan Arora. All rights reserved.
//
#include "Deque_cmpt225.h"
#include <iostream>
#include <stdexcept>
using namespace std;
Node:: Node()
{
previous = nullptr;
next = nullptr;
data = 0;
}
Node:: Node(const int &x)
{
Node();
data = x;
}
Deque:: Deque() //Empty Deque.
{
front = nullptr;
rear = nullptr;
}
Deque:: ~Deque()
{
if (this->empty())
return;
else{
Node* temp;
while (this->front->next != nullptr){
temp = this->front;
this->front = this->front->next;
delete temp;
}
temp = this->front;
this->front = nullptr;
this->rear = nullptr;
delete temp;
}
}
Deque:: Deque (const Deque &d) //Copy Constructor
{
if (d.empty()) //Deque is empty.
{
return;
}
Node* temp = d.front;
int x;
if (temp->next == nullptr) //Deque of just one node
{
x = temp->data;
Node *n1 = new Node (x);
n1->next = nullptr;
n1->previous = nullptr;
this->front = n1;
this->rear = n1;
}
else //Deque has more than one node
{
while (temp!= nullptr)
{
this->insertBack(temp->data);
temp = temp -> next;
}
}
}
Deque& Deque:: operator=(const Deque &d) //============================check again
{
if (this == &d)
return *this;
else
{
this->~Deque(); //DELETING THE DEQUE
Node* temp = d.front; //COPYING EACH NODE
while (temp != NULL)
{
this->insertBack(temp->data); //INSERTING AT THE BACK
temp = temp->next; //POINTING TEMP TO NEXT NODE
}
}
return *this;
}
void Deque:: insertFront(const int &x)
{
Node* temp = new Node(x);
temp->next = nullptr;
temp->previous = nullptr;
if (empty())
{
this->front = temp;
this->rear = temp;
}
else
{
temp->next = this->front;
temp->previous = nullptr;
this->front->previous = temp;
this->front = temp;
}
}
void Deque:: insertBack(const int &x)
{
Node* temp = new Node(x);
temp->next = nullptr;
temp->previous = nullptr;
if (empty())
{
this->front = temp;
this->rear = temp;
}
else
{
temp->next = nullptr;
temp->previous = this->rear;
this->rear->next = temp;
this->rear = temp;
}
}
int Deque:: removeFront()
{
if (empty()) //=================runtime error
{
throw std::runtime_error("The que is empty.");
}
else{
Node* temp;
temp = this->front;
int x = temp->data;
if ( this->front->next != nullptr )
{
this->front = this->front->next;
this->front->previous = nullptr;
}
else
{
this->front = nullptr;
this->rear = nullptr;
}
delete temp;
return x;
}
}
int Deque:: removeBack()
{
if (empty()) //=================runtime error
{
throw std::runtime_error("The que is empty.");
}
else{
Node* temp = this->rear;
int x = temp->data;
if ( this->rear->previous != nullptr )
{
this->rear = this->rear->previous;
this->rear->next = nullptr;
}
else
{
this->rear = nullptr;
this->front = nullptr;
}
delete temp;
return x;
}
}
int Deque:: peekFront()
{
if (empty()) //=================runtime error
{
throw std::runtime_error("The que is empty.");
}
else
{
return this->front->data;
}
}
int Deque:: peekBack()
{
if (empty()) //=================runtime error
{
throw std::runtime_error("The que is empty.");
}
else
{
return this->rear->data;
}
}
bool Deque:: empty() const
{
if (this->front == nullptr && this->rear == nullptr)
return true;
else
return false;
}
int Deque:: size() const
{
Node* temp = this->front;
int count = 0;
while (temp != nullptr)
{
count++;
temp = temp->next;
}
return count;
}
ostream& operator << (ostream &out, const Deque &d)
{
Node* temp = d.front;
out << "NULL -> ";
while (temp != nullptr)
{
out << temp->data << " <-> ";
temp= temp->next;
}
out << "<- NULL" << endl;
return out;
}
thanks in advance.
Your code has many problems..
Your Node constructor doesn't delegate properly..
Node::Node()
{
previous = nullptr;
next = nullptr;
data = 0;
}
Node::Node(const int &x)
{
Node(); //Creates a temporary node that gets destroyed immediately..
data = x;
}
It's much simpler if you change it to:
Node::Node() : Node(0) //Delegating constructor.
{
}
Node::Node(const int &x) : previous(nullptr), next(nullptr), data(x)
{
}
This point isn't really a problem, but worth mentioning.. You keep setting the Node pointers to nullptr right after construction. This is not necessary because your constructor already does that..
Node* temp = new Node(x);
temp->next = nullptr; //Not needed anymore with the above fixes.
temp->previous = nullptr; //Not needed anymore with the above fixes.
You never initialize your variables in the copy constructor..
In your constructor, you have (I changed it, but it has the same meaning):
Deque::Deque() : front(nullptr), rear(nullptr)
{
}
But in your copy constructor, you have:
Deque::Deque(const Deque &d)
{
//Other code here.. You never initialized front and rear to nullptr..
}
You never set front and rear to nullptr so empty() returns false since they are a "random" uninitialized value.. Then in insertBack you go on to access this and boom.. Access Violation.
To fix it, you do:
Deque::Deque(const Deque &d) : front(nullptr), rear(nullptr)
{
//Other code here..
}
Next issue is that your copy assignment operator is calling the destructor!
Deque& Deque::operator=(const Deque &d)
{
if (this == &d)
return *this;
else
{
this->~Deque() //YOU CANNOT DO THIS.. Create a private member function for cleaning up.. Then call that function in your destructor and call that function here.. You cannot invoke the destructor like this.
}
//....
}
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.