After Googling around for a while I've come to the conclusion that I'm stumped.
The Problem:
Recursively copy a linked list (as well as copy in reverse, but I'll cross that bridge later.)
I have the following code:
// In list.h
struct node {
int data;
node * next;
}
// In list.cpp
// Recursive copy wrapper
int list::copy() {
if(!head) {
return 0;
}
node *new_node = NULL;
return copy(new_node, head);
}
// Recursive copy function
int list::copy(node *& dest, node * src) {
if(!src) {
dest = NULL;
return 0;
}
dest = new node();
dest->data = src->data;
// *dest->next = src->next;* // Not sure what to do here?
return copy(dest->next, src->next) + 1; // count number of nodes copied
}
Note: this is not a homework assignment but rather a question for a preparatory technical interview exam.
At this point, I'm fairly certain I won't be able to achieve this on my own so any help with it would be appreciated. Thanks in advance!
To my understanding, the list needs to be recursively copied first and the reference of the new head needs to point to the head of the copy; this can be done as follows.
int list::copy(node *& dest, node * src)
{
if(!src)
{
dest = NULL;
return 0;
}
dest = new node();
dest->data = src->data;
node* TailCopy = null; // reference to copy of remaining list
int TotalNumOfNodes = 1 + copy(Tail, src->next) + 1;
dest->next = TailCopy; // let copy of head refer to copy of tail
return TotalNumOfNodes;
}
Well, the int list::copy(node *& dest, node * src) is perfectly correct and successfully copies a list tail up to another list tail. The problem lies in the int list() one which is plain non sense: you successfully copies all the nodes of current list in a new chain, and irremediably leak all that memory when done!
If you want to build something that makes sense, you could use your recursive copy in a copy constructor:
list(const list& other) {
copy(head, other.head);
}
This does not use the return value of the copy (could be static) method, by I can confirm that it is the expected value.
Related
I have a new project where I am creating a class for an entry in a doubly linked list. I am utilizing object-oriented style, which I have limited experience with. The constructors and functions were defined in a separate file.
Header File:
#ifndef LISTENTRY_H_JDP
#define LISTENTRY_H_JDP
#include "DATAClass.h"
#include <iostream>
using namespace std;
typedef DATAClass l;
typedef class LISTEntry *listptr;
class LISTEntry
{
DATAClass data;
listptr prev;
listptr next;
public:
LISTEntry();
LISTEntry(DATAClass l);
LISTEntry(LISTEntry &le);
~LISTEntry();
LISTEntry getNext();
void setNext();
LISTEntry getPrev();
void setPrev();
DATAClass getData();
void setData(DATAClass d);
};
#endif // LISTENTRY_H_INCLUDED
Implementation File:
#include "LISTEntry.h"
LISTEntry::LISTEntry()
{
data = data;
prev = NULL;
next = NULL;
}
LISTEntry::LISTEntry(DATAClass l) //take an item of type l and convert it into a LISTEntry
{
data = l;
prev = NULL;
next = NULL;
}
LISTEntry::LISTEntry(LISTEntry &le)
{
data = le.getData();
prev = le.getPrev();
next = le.getNext();
}
LISTEntry::~LISTEntry()
{
}
LISTEntry LISTEntry::getNext()
{
return *next;
}
void LISTEntry::setNext()
{
next = new LISTEntry;
}
LISTEntry LISTEntry::getPrev()
{
return *prev;
}
void LISTEntry::setPrev()
{
prev = new LISTEntry;
}
DATAClass LISTEntry::getData()
{
return data;
}
void LISTEntry::setData(DATAClass d)
{
data = d;
}
The issue is my copy constructor, LISTEntry(LISTEntry &le). So far, I receive the error:
cannot convert 'LISTEntry' to 'listptr {aka LISTEntry*}'
I am also unsure about the get and set functions. I want them to link to new entries of the same type in the list. I guess I am having trouble with the implementation of pointers in the constructor. Can anyone help out?
You could solve the problem by removing the copy constructor, but this hides the problem that caused the error.
Unless l is poorly written (violates the Rules of Three or Five), there is no need for a copy constructor or destructor in LISTEntry. LISTEntry has no special resources of its own and should be able to observe the Rule of Zero. If l is broken, fix l, do not inflict its flaws on other classes.
But this is not what you want to do for a couple reasons.
The underlying problem causing the error message is prev = le.getPrev(); is attempting to assign a copy of the source's LISTEntry's previous node to the new LISTEntry's pointer to the previous node.
prev needs the address of a LISTEntry, not a LISTEntry.
In a linked list LISTEntry LISTEntry::getNext()and LISTEntry LISTEntry::getPrev() should almost certainly not return a copy of the node pointed at. You want to return the pointer. If you do not, you will find that iterating through the linked list is an adventure. You'll be operating on, possibly modifying, copies of nodes rather than the originals. Chaos ensues.
Change them to LISTEntry * LISTEntry::getNext() and remove the dereference in the return statement.
This solves the error, and a few more you hadn't found yet, but leaves you with a different problem, and the same one you'd have if you removed the copy constructor. You now have two LISTEntry with the same prev and next. This can make for an unstable list. With the copy you can blow the crap out of the original's list. Not cool. Be careful. You are actually better off NOT copying the the links and making the copy constructor:
LISTEntry::LISTEntry(const LISTEntry &le) // make everything const until proven otherwise
{
data = le.data; // this is a member function so it can access private variables
// no need for the accessor function
prev = nullptr;
next = nullptr;
}
You also need/want an assignment operator
LISTEntry & operator=(const LISTEntry &le)
{
if (this != &le)
{
data = le.data;
prev = nullptr;
next = nullptr;
}
}
You should also discuss
void LISTEntry::setNext()
{
next = new LISTEntry;
}
with your rubber duck. Ducky wants to know do you plan to link an existing node if you always create a new one? This will make it really hard to insert, remove and sort.
I keep getting a segmentation fault on my deep copy of a linked list. I use this deep copy in my Copy Contructor and my assignment operator (operator=) and have come to the conclusion that it is this that is seg faulting.
bigint::Node* bigint::deepcopy(bigint::Node* target){
bigint::Node* current = target;
bigint::Node*cpy = new Node;
cpy->digit = current->digit;
Node* const hd = cpy;
current = current->next;
while(current != nullptr){
bigint::Node* tmp = new Node;
tmp->digit = current->digit;
cpy->next = tmp;
cpy = cpy->next;
current = current->next;
}
return hd;
}
My Node struct looks like:
private:
struct Node{
int digit;
Node* next;
};
Node* head;
static Node* deepcopy(Node* target);
My class is closed and all, just showing what is in private that is related to this function. Thanks in advance for any advice.
When you use your deepcopy function, you must make sure that the paramater target is not nullptr. So, you should check if (target == nullptr) at the beginning of your deepcopy function.
Also, after the while loop finished, you should set the tail of your new list to nullptr.
From the information you post, it seems you have use ->digit or ->next on a null pointer.
If you still get this error, you'd better provide a example code.
I am learning list in C++ independently, and i have searched many websites about it. However, almost every approach to create a list is the same.
They usually create a struct as the node of a class. I want to create a class without using struct. So I created a class name ListNode which contains an int data and a pointer.
The main member functions of my class are AddNode and show.
Although, this program compiles successfully, it still does not work as I wish.
Here is the header file:
#ifndef LISTNODE_H_
#define LISTNODE_H_
#pragma once
class ListNode
{
private:
int data;
ListNode * next;
public:
ListNode();
ListNode(int value);
~ListNode();
void AddNode(ListNode* node,ListNode* headNode);
void show(ListNode* headNode);
};
#endif
Here is the implementation:
#include "ListNode.h"
#include<iostream>
ListNode::ListNode()
{
data = 0;
next = NULL;
}
ListNode::ListNode(int value)
{
data = value;
next = NULL;
}
ListNode::~ListNode()
{
}
void ListNode::AddNode(ListNode* node,ListNode* headNode) {
node->next = headNode;
headNode =node;
}
void ListNode::show(ListNode* headNode) {
ListNode * traversNode;
traversNode = headNode;
while (traversNode != NULL) {
std::cout << traversNode->data << std::endl;
traversNode = traversNode->next;
}
}
Main function:
#include"ListNode.h"
#include<iostream>
int main()
{
using std::cout;
using std::endl;
ListNode* head = new ListNode();
for (int i = 0;i < 3;i++) {
ListNode* Node = new ListNode(i);
head->AddNode(Node, head);
}
head->show(head);
return 0;
}
As far as I am concerned, the output should be
2
1
0
However, the output is a single zero. There must be something wrong in the AddNode and show function.
Could you please tell me what is wrong with these two functions?
When you call head->AddNode(node, head) you´re passing the memory directions which the pointers point, when the function arguments receive those directions, they are now pointing to the same directions, but those are another pointers, no the ones you declared in main. You could see it like this:
void ListNode::AddNode(ListNode* node,ListNode* headNode) {
/*when the arguments get their value it could be seen as something like:
node = Node(the one from main)
headNode = head(the one from main)*/
node->next = headNode;
/*Here you are modifying the new inserted node, no problem*/
headNode = node;
/*The problem is here, you´re modifying the memory direction
headNode points to, but the headNode argument of the function, no the one declared in main*/
}
So the pointer head in main() always points to the same first node you also declared in main().
In order to fix this you should change your code this way:
void ListNode::AddNode(ListNode* node,ListNode** headNode) {
/* second paramater now receives a pointer to apointer to a node */
node->next = *headNode;//the same as before but due to pointer syntaxis changes a bit
*headNode = node;//now you change the real head
}
And when you call it:
head->AddNode(Node, &head);//you use '&' before head
Now the real head, no the one in the function, will point to the last node you inserted.
I'm writing some C++ code for a simple "Node" class. This is basically a class used to manage a linear linked list. I normally perform this with a struct but I'm trying get a better handle of OOP and classes. What I've got thus far for the Node class is (note: the String class is my version (trimmed down) of a typical "string" class, it implements a copy constructor, assignment overload, destructor, etc. In testing it has worked great and seems completely self contained):
class Node {
public:
//Constructor
//-----------
Node() : next_(0) {} //inline (String constructor called)
//Destructor
//----------
~Node();
//Copy Constructor
//----------------
Node(const Node &);
//Operator Overload: =
//---------------------
//In conjunction with copy constructor. Protects Class.
Node & operator=(const Node &);
private:
String relatedEntry_;
Node * next_;
};
Creating one instance works fine (ie. Node node;) but when I create an instance that calls the Copy Constructor I end up with segfaults at the very end of my program, as it's cleaning up. The difference between using a struct for a linked list vs a class plays tricks with me a little and I think I'm missing something key here. Here is the implementation for the Default Constructor, Copy Constructor, and Overloaded Assignment Operator:
//Constructor inlined
//Destructor
Node::~Node()
{
Node * curr = next_;
while (curr) //cycle through LL and delete nodes
{
Node * temp = curr; //hold onto current
curr = curr->next_; //increment one
delete temp; //delete former current
}
}
//Copy Constructor
Node::Node(const Node & cp)
{
std::cout << "in CopyCon" << std::endl;
relatedEntry_ = cp.relatedEntry_; //calls String class copy constructor/assignment overload
Node * curr = cp.next_; //for clarity, for traversal
while (curr) //copies related entry structure
{
Node * oldNext = next_;
next_ = new Node;
next_->next_ = oldNext; //'next' field (assign prior)
next_->relatedEntry_ = curr->relatedEntry_; //String class copy
curr = curr->next_; //increment
}
}
//OO: =
Node & Node::operator=(const Node & cp)
{
std::cout << "in OO: =" << std::endl;
if (this == &cp)
return *this; //self assignment
delete next_; //delete LL
relatedEntry_ = cp.relatedEntry_; //String Class Assignment Overload
Node * curr = cp.next_; //for clarity, for traversal
while (curr)
{
Node * oldNext = next_; //hold onto old
next_ = new Node;
next_->next_ = oldNext; //set next to old
next_->relatedEntry_ = curr->relatedEntry_; //set this string to cp string
curr = curr->next_; //increment
}
return *this;
}
Note that using the Overloaded Assignment Function seems to work fine (no segfaults) even though it's virtually the same code... I'm assuming it has to do with the fact that both objects are already initialized before the assignment takes place?
//This seems to work ok
Node node1;
Node node2;
node2 = node1;
I've been at this bug for a couple of hours and I have got to get some rest. I'd really appreciate any insight into this. Thanks.
In the copy constructor loop, you have this line:
Node * oldNext = next_;
However, in the first round in the loop the value of next_ can by, well, anything and most likely not NULL. This means that the last node will a have a non-null pointer.
Initialize it to NULL before the loop and it should work.
You have the concepts of a List and a Node mixed up. You should write a List class which manages a sequence of Nodes. Your Node destructor is more or less how your List destructor should look, Node itself doesn't need a destructor.
What is specifically going wrong is that your Node destructor recursively calls itself when you write delete temp; this deletes the rest of the sequence of nodes but then your Node destructor loops around and tries to delete them again.
I'm writing a program as an assignment for school and I though I had worked out all the bugs until I decided to call my copy constructor. The program is interactive (CLI) which basically has two moduals: a .h and .cpp file for the LList class and a .h and .cpp file for the structure of the program and also a 3rd cpp file just for main(). It is suppose to be a program for a hydropower engineering company (fake company) in which the LList nodes hold data for their annual water flow in a river(year and flow). Here is some insight on the class:
//list.h
struct ListItem {
int year;
double flow;
};
struct Node {
ListItem item;
Node *next;
};
class FlowList {
public:
FlowList();
// PROMISES: Creates empty list
FlowList(const FlowList& source);
// REQUIRES: source refers to an existing List object
// PROMISES: create the copy of source
~FlowList();
// PROMISES: Destroys an existing list.
FlowList& operator =(const FlowList& rhs);
// REQUIRES: rhs refers to an existing FlowList object
// PROMISES: the left hand side object becomes the copy of rhs
//....Other member functions
private:
// always points to the first node in the list.
Node *headM;
// Initially is set to NULL, but it may point to any node.
Node *cursorM;
//For node manipulation within interactive CLI
void copy(const FlowList& source);
void destroy();
I belive the memory leak or collision is taking place somewhere within the copy function but cant pin point where.
//list.cpp
FlowList::FlowList() : headM(0), cursorM(0) {}
FlowList::FlowList(const FlowList& source)
{
copy(source);
}
FlowList::~FlowList()
{
destroy();
}
FlowList& FlowList::operator =(const FlowList& rhs)
{
if (this != &rhs)
{
destroy();
copy(rhs);
}
return (*this);
}
//...more function definitions
void FlowList::copy(const FlowList& source)
{
if (source.headM == NULL)
{
headM = NULL;
cursorM = NULL;
return;
}
Node* new_node = new Node;
assert(new_node);
new_node->item.year = source.headM->item.year;
new_node->item.flow = source.headM->item.flow;
new_node->next = NULL;
headM = new_node;
Node* thisptr = new_node;
for(Node* srcptr = source.headM->next; srcptr != NULL; srcptr = srcptr->next)
{
new_node = new Node;
assert(new_node);
new_node->item.year = srcptr->item.year;
new_node->item.flow = srcptr->item.flow;
new_node->next = NULL;
thisptr->next = new_node;
thisptr = thisptr->next;
}
}
void FlowList::destroy()
{
Node* ptr = headM;
Node* post = headM->next;
while (ptr != NULL)
{
delete ptr;
ptr = post;
if (post)
post = ptr->next;
}
headM = NULL;
}
The program works fine if I create a FlowList object, fill it with data from a .dat file; i can then manipulate the data within the program (display, perform calculations, add to the list, remove from list and save data to file) but program crashes (segmentation fault) if I create another FlowList object (within main.cpp).
Any help would be really appreciated.
The initial thing I spot is that it looks like your destroy() function will always segmentation fault if the list is empty:
void FlowList::destroy()
{
Node* ptr = headM;
Node* post = headM->next;
//...
}
If the list is empty, headM is NULL and then you're trying to do headM->next which will always produce a segmentation fault in that case.
I think you might also have a memory leak in your copy constructor if you pass in an empty list. If you look at this code:
void FlowList::copy(const FlowList& source)
{
if (source.headM == NULL)
{
headM = NULL;
cursorM = NULL;
return;
}
//...
}
What if the current list contained 20 items and source is an empty list? You set the current list's headM and cursorM to NULL, but you never call delete on any of the nodes in the current list that you originally used new to create. You probably want to work your destroy() function somewhere into your copy constructor too (you did it for the operator= function).
The last thing I noticed is that you don't initialize cursorM for a non-empty list in your copy() function (#Akusete pointed that out as well). I think I'd recommend that at the beginning of your copy constructor, just initialize cursorM and headM to NULL just to cover your bases.
It looks like you're really close, I think you just really need to think through the boundary case of dealing with empty lists (both on the LHS and RHS) and you'll probably find most of these bugs. Good luck!