How to implement push_front() method for a singly linked list as its member function? The code below does not compile (error: lvalue required as left operand of assignment), because you cannot assign to this pointer. What is a way round this?
#include<algorithm>
using namespace std;
class ListElem{
public:
ListElem(int val): _val(val){}
ListElem *next() const { return _next; }
void next(ListElem *elem) { _next = elem; }
void val(int val){ _val = val; }
int val() const { return _val;}
void print();
void push_front(int);
private:
ListElem *_next;
int _val;
};
void ListElem::push_front(int val)
{
ListElem *new_elem = new ListElem(val); //new node
new_elem->next( this ); // new node points to old head
this = new_elem; // make new node the new head, error!
return;
}
void ListElem::print()
{
ListElem *pelem = this;
while(ListElem *pnext_elem = pelem->next())
{
cout << pelem->val() << ' ';
pelem = pnext_elem;
}
cout << pelem->val() << endl;
}
int main()
{
//initialization
ListElem *head = new ListElem(1);
ListElem *elem = head;
for (int ix = 2; ix < 10; ++ix)
{
ListElem *elem_new = new ListElem(ix);
elem -> next(elem_new);
elem = elem_new;
}
head->print();
//insert at the beginning
head->push_front(7);
head->print();
}
Logically, push_front() must be a method of List class and not of a ListElement class
You're using this incorrectly. You want to have a static member called, say, ListElem *head and use that where you were using this. You'll also have to initialise it.
If you really want to do it that way, you can do it like this:
void ListElem::push_front(int val)
{
ListElem *new_elem = new ListElem(_val);
_val = val;
new_elem->next(_next);
_next = new_elem;
}
This will replace the data in the "current" node with the new data, and move the "current" data to the new node, which will yield the same list content.
But it's not really correct to conflate a list with its nodes.
The book you linked takes a very non-OO approach to the whole thing (both the Java and the C++ examples look like transliterated C), and conflating the type of a list with the type of its nodes is pretty certain to lead to bugs later.
For instance, if you do this
ListElem* x = head;
head->push_front(99);
then the contents of *x will have changed, which isn't really what you would expect.
Related
This my C++ code:
#include <iostream>
class Node
{
public:
int data;
Node* prev;
Node* next;
};
class Doublyll
{
private:
Node* head;
Node* tail;
public:
Doublyll();
Doublyll(int A[], int num);
~Doublyll();
friend std::ostream& operator<<(std::ostream& os, const Doublyll& src);
int Length(Node* p);
};
// Default Constructor will SET head and tail to NULL
Doublyll::Doublyll()
: head(NULL), tail(NULL)
{
}
// Explicit Construcor
Doublyll::Doublyll(int A[], int num)
: head(NULL), tail(NULL)
{
// std::cout << "Explicit Constructor called!\n";
Node** p = &head;
for (int i = 0; i < num; i++)
{
Node* t = new Node;
t->data = A[i];
if (head == NULL)
t->prev = NULL;
else
t->prev = tail;
t->next = NULL;
*p = t;
p = &(t->next);
tail = t;
}
}
// Destructor
Doublyll::~Doublyll()
{
// std::cout << "Desctructor called!\n";
Node* p = head;
Node* tmp;
while (p != NULL)
{
tmp = p;
p = p->next;
delete tmp;
}
}
// Display using Overloading << Operator
std::ostream& operator<<(std::ostream& os, const Doublyll& src)
{
Node* tmp;
for (tmp = src.head; tmp != NULL; tmp = tmp->next)
std::cout << tmp->data << " ";
std::cout << std::endl;
return os;
}
// Find Length how much Node in linked list
int Doublyll::Length(Node* p)
{
static int count = 0;
if (p != NULL)
{
count++;
Length(p = p->next);
}
return count;
}
int main()
{
int A[] = {2, 4, 6, 8, 10, 12, 14};
int size = sizeof(A) / sizeof(A[0]);
// Create object and linked list
Doublyll l1(A, size);
// Display linked list
std::cout << l1;
// Get length of linked list
int c = l1.Length(l1.head);
std::cout << c << std::endl;
return 0;
}
As you can see, I try to practice Doubly Linked List. Then, I want to count total Node in my linked list.
You can see in int Doublyll::Length(Node* p) I try to Count it using Recursion. Just because I want to practice it with Recursion. But, in my main() somewhow this code: int c = l1.Length(l1.head); said "Head is inaccessible"
I know that is because Head is Private in my Doublyll class. And I can simply change it to Public. OR I can write a function getHead() which will return Head pointer and then pass it as arguments.
So, Is there a way to dircetly pass it from my main() without change the member to public or write a getHead() function? or maybe there's another way to write a Recursion based on my problem, which in the future can also implement it to another recursion like display()? Because it seems like difficult to access if everything is inside class.
Maybe you can also review how I create a Doubly Linked List. Thank you!
Make int Doublyll::Length(Node *p) a private member function and add a public int Doublyll::Length() that takes no arguments and does:
int Doublyll::Length()
{
return Length(head);
}
(also you should probably make both of them const - int Doublyll::Length() const since they shouldn't modify anything)
Then just call l1.Length() in main.
Users of Doublyll shouldn't know about the internals of the class, and it doesn't make sense to ask a Doublyll object for the length from some node that it might not even own. Making Length(Node *p) private prevents nonsense things like l1.Length(l2.head).
As for your implementation of int Doublyll::Length(node *p) it's just wrong. As a comment mentions, you're using a static int count to track the length which will give you the wrong answer if you call the function multiple times. Plus your recursion is wrong since you aren't using the result of the recursive call. Do something like this instead:
int Doublyll::Length(Node *p) const
{
// Base case - no nodes
if (p == nullptr)
return 0;
// Recursive case
return 1 + Length(p->next);
}
Or a solution that allows for tail call optimization:
int Doublyll::Length(Node *p, int count) const
{
// Base case - no more nodes - return count
if (p == nullptr)
return count;
// Recursive case - increment count and go to the next node
return Length(p->next, count+1);
}
int Doublyll::Length() const
{
return Length(head, 0);
}
A common technique when implementing recursive functions is to have one public non-recursive function to start things off (say, Doublyll::Length()), and a second private helper function that actually performs the recursion (something like Doublyll::LengthRecursive()).
This could look something like:
int Doublyll::LengthRecursive(Node* p)
{
static int count = 0;
if (p != NULL)
{
count++;
Length(p = p->next);
}
return count;
}
int Doublyll::Length()
{
return LengthRecursive(head);
}
One way of handling a situation like this is to use two member functions: one that is the public interface and one that is private but has the signature you want for the recursive call.
For example:
class Doublyll
{
private:
Node* head;
Node* tail;
int LengthAux(Node* p); //private recursive implementation
public:
Doublyll();
Doublyll(int A[], int num);
~Doublyll();
friend std::ostream& operator<<(std::ostream& os, const Doublyll& src);
int Length(); // public interface
};
int Doublyll::Length() {
return LengthAux(head);
}
// Find Length how much Node in linked list
int Doublyll::LengthAux(Node* p)
{
static int count = 0;
if (p != NULL)
{
count++;
LengthAux(p->next);
}
return count;
}
...
This is a pretty common pattern used by implementations involving recursion. It is the nature of recursive calls that the signature of the recursive guts of the function is often different than the natural signature of calling the function externally.
I am trying to insert a number at a certain position in a linked list. However I cannot access the next pointer normally because it is a private member, and have to use a getNext function. I am unsure of how to assign next pointers with this function as it gives me errors.
#pragma once
class IntListNode {
public:
IntListNode(int e, IntListNode *nextptr):
elem(e), next(nextptr) { }
int &getElement() {return elem;}
IntListNode *getNext() {return next;}
private:
int elem; // linked list element value
IntListNode *next; // next item in the list
};
This is the code I have attempted but I keep receiving errors.
void IntegerList::AddAtPosition(int num, int placement)
{
IntListNode* temp1 = head;
IntListNode* temp2 = head;
temp1->getElement() = num;
if (placement == 0)
{
head = temp1;
}
else
{
for (int i = 0; i < placement - 2; i++)
{
temp2 = temp2->getNext();
}
temp1->getNext() = temp2->getNext();
temp2->getNext() = temp1;
//THe Lines getting errors
}
}
Error message:
E0137 "expression must be a modifiable lvalue"
Change your getNext() method to this: IntListNode*& getNext() {return next;}.
The IntListNode *getNext() version will return the value of next member but not it's address so this line is not modifiable: tempX->getNext() = tempY;
Edit
Based on the restrictions/conditions mentioned by the OP, I can think of only way to this is:
*temp1 = IntListNode(temp1->getElement(), temp2->getNext());
*temp2 = IntListNode(temp2->getElement(), temp1);
I'm implementing an unordered linked list in C++ based on first principles. My (partially complete so far) implementation is:
#include <iostream>
class Node {
int m_data;
Node *m_next;
public:
Node(int data)
{
m_data = data;
m_next = nullptr;
}
int getData() { return m_data; }
void setData(int data) { m_data = data; }
Node* getNext() { return m_next; }
void setNext(Node *next) { m_next = next; }
};
class UnorderedList {
public:
Node *m_head;
public:
UnorderedList()
{
m_head = nullptr;
}
bool isEmpty() { return m_head == nullptr; }
void appendToHead(int data)
{
Node temp = Node(data);
temp.setNext(m_head);
m_head = &temp;
}
void remove(int data);
bool search(int data);
};
int main()
{
UnorderedList list1;
list1.appendToHead(32);
list1.appendToHead(47);
list1.appendToHead(90);
std::cout << list1.m_head->getData() << '\n';
std::cout << list1.m_head->getNext()->getData() << '\n';
return 0;
}
I am able to correctly print the head of the list as '90', but the next line (i.e. getNext()->getData()) gets printed as a large random number (281314120). What is the reason for this?
void appendToHead(int data)
{
Node temp = Node(data);
temp.setNext(m_head);
m_head = &temp;
}
Never store the address of an object with automatic storage duration. That object (in this case, temp) will cease to exist when appendToHead method completes.
You did that and invoked Undefined Behavior. You probably wanted to do:
void appendToHead(int data)
{
Node* temp = new Node(data);
temp->setNext(m_head);
m_head = temp;
}
You should also consider satisfying The Rule Of Five
Rather than raw pointers, additionally explore the use of std::unique_ptr.
During debugging the second execution of while loop the code below produces an out_of_range exception. I noticed that:
before stack.top():
after stack.top():
Does anyone know why this happens and how to fix it?
#include <iostream>
#include <stack>
#include <vector>
#include <memory>
#include <functional>
int replacement;
int toreplace;
class Node
{
public:
int id_;
std::vector<Node*> children;
Node* at(int i)
{
return children.at(i);
}
std::vector<Node*> GetChildren() {
return children;
}
Node(int id_) {
this->id_ = id_;
}
};
class CPreorderStackFrame
{
public:
Node* node_;
CPreorderStackFrame* root_;
int index_;
explicit CPreorderStackFrame(Node* node_, CPreorderStackFrame* root_, int index_)
{
this->node_ = node_;
this->root_ = root_;
this->index_ = index_;
}
void replaceChildrenByIndex(Node* replace, int index)
{
replace->id_ = node_->at(index)->id_;
delete node_->GetChildren()[index];
node_->GetChildren()[index] = replace;
}
bool hasChildren() {
return !(node_->GetChildren().empty());
}
};
void pre_order_traverse(Node* root,
std::function<std::unique_ptr<Node>(Node*)> visit)
{ // always: root != NULL
std::stack<CPreorderStackFrame> mystack;
mystack.push(CPreorderStackFrame(root, NULL, NULL));
while (!mystack.empty())
{
CPreorderStackFrame cur = mystack.top();
mystack.pop();
std::unique_ptr<Node> replace = visit(cur.node_);
if (replace)
{
cur.root_->replaceChildrenByIndex(replace.release(), cur.index_);
}
else if (cur.hasChildren())
{
for (int i = cur.node_->GetChildren().size() - 1; i >= 0; --i)
{ //preorder requires right to left
Node *topush = cur.node_->at(i);
if (topush)
{
CPreorderStackFrame nextFrame(topush, &cur, i);
mystack.emplace(nextFrame); //hier ist noch alles richtig
}
}
}
}
}
std::unique_ptr<Node> print_visit(Node* node) {
std::cout << node->id_ << ' ';
return NULL;
}
std::unique_ptr<Node> replace_visit(Node* node) {
std::cout << node->id_ << ' ';
if (node->id_ == toreplace) {
std::unique_ptr<Node> retval(new Node(replacement));
return retval;
}
return NULL;
}
int main() {
toreplace = 3;
replacement = 8;
Node *a = new Node(1);
Node *b = new Node(2);
Node *c = new Node(3);
Node *d = new Node(4);
Node *e = new Node(5);
Node *f = new Node(3);
Node *g = new Node(3);
Node *h = new Node(42);
Node *i = new Node(42);
a->children.push_back(b);
a->children.push_back(c);
a->children.push_back(d);
a->children.push_back(e);
b->children.push_back(f);
b->children.push_back(g);
b->children.push_back(h);
b->children.push_back(i);
pre_order_traverse(a, replace_visit);
return 0;
}
One problem is
std::vector<Node*> GetChildren()
which means that
delete node_->GetChildren()[index];
node_->GetChildren()[index] = replace;
is destroying an object, but only replacing its address in a copy of the vector.
Dereferencing that element in the original vector is undefined.
You need to return by reference, or move the removal code into Node.
Another problem, and the immediate cause of your observations, is that
CPreorderStackFrame nextFrame(topush, &cur, i);
mystack.emplace(nextFrame);
is storing a pointer to the automatic object cur, whose lifetime ends with the end of the iteration.
Dereferencing the pointer after that is undefined.
Most (probably all) compilers will reuse that object's storage for the next iteration, which means that all your CPreorderStackFrames store the same pointer, and not a single one of them is valid by the time you dereference it.
It looks like the root doesn't need to be a pointer at all.
I'm trying to implement a templated singly linked list and I'm fairly new to C++
#include <iostream>
#include <string>
#define NEWL "\n"
#define PRINT(s) std::cout << s
#define PRINTL(s) std::cout << s << NEWL
#define PRINTERR(e) std::cerr << e << NEWL
////// Class for a Node
template<class Data> class Node {
Node<Data>* next_ptr;
Data data;
public:
Node(Node<Data>* nxt_ptr) :next_ptr(nxt_ptr) {};
Node(Data d, Node<Data>* nxt_ptr) :data(d), next_ptr(nxt_ptr) {};
Node<Data>* get_next() { return next_ptr; }
Data& get_data() { return data; }
friend std::ostream& operator<<(std::ostream& out, const Node<Data>& node) {
out << node.data;
return out;
};
};
////// Class for a SinglyLinkedList
template<class Data> class SLinkedList {
Node<Data>* head_ptr;
int max_size;
public:
SLinkedList() : head_ptr(nullptr) {};
bool is_empty() {
return head_ptr == nullptr;
};
bool is_full() {
return get_size() == max_size;
};
int get_size() {
if (is_empty()) {
return 0;
}
int count = 0;
for (Node<Data>* it_ptr = head_ptr; it_ptr != nullptr; it_ptr = it_ptr->get_next()) {
count++;
}
return count;
};
void add(Data d) {
if (is_full()) {
throw std::exception("List is full!");
}
Node<Data> new_node(d, head_ptr);
head_ptr = &new_node;
};
void print_content() {
int count = 1;
PRINTL("This list contains:");
for (Node<Data>* it_ptr = head_ptr; it_ptr != nullptr; it_ptr = it_ptr->get_next()) {
PRINTL("\t["<< count << "]" << " at " << it_ptr << " : " << *it_ptr);
count++;
}
}
};
////// Main function
int main()
{
SLinkedList<int> sll;
sll.add(42);
sll.print_content();
}
I can't get this to work. Somehow iterating the list with for-loops does not work. It always results in an Reading Access Violation Exception about a pointer to 0xCCCCCCD0 and I have no idea how to fix this.
Your add function is incorrect
Node<Data> new_node(d, head_ptr);
creates a new function local Node in add. You then set head to the address of that local variable. When the function ends all local variables are destroyed so now head points to an object that no longer exists.
To fix that you need to use the new keyword to create a dynamic object that will live on after the function ends.
Node<Data>* new_node = new Node(d, head_ptr);
head_ptr = new_node;
The down side with this is you need to remember to call delete on all of the nodes you created in the list destructor.
You also have some other bugs in your code. You never set max_size in your constructor so using it at all except to give it a value is undefined behavior as we have no idea what the value of it is going to be. You also never increase the size of the list when you add nodes into the list.