I'm trying to represent a singly linked list in C++. I'm adding two elements at the head of the list, 4 and 34. I also have a print method, to print the contents of the linked list.
I have an incorrect head update somewhere, because the print method enters an infinite loop. I tried debugging with breakpoints, and that lead me down the following rabbit hole:
During the second insertion: s.insert(34), I somehow change the value of head to 34, when creating a node for 34. Can someone help me understand how that happened?
Or am I missing the picture entirely? Any help would be greatly appreciated!
#include <vector>
#include <iostream>
using namespace std;
class Node {
public:
Node* next;
int key;
Node(int k) : key(k), next(nullptr) {}; //on s.insert(34), this changes head to 34
};
class SinglyLinkedList {
public:
Node* head;
SinglyLinkedList() : head(nullptr) {};
void insert(int);
void print();
};
void SinglyLinkedList::insert(int x) {
Node n = Node(x);
if (head == nullptr) {
head = &n;
}
else {
n.next = head; // head already points to 34 at this point
head = &n;
}
}
void SinglyLinkedList::print() {
for (Node *i = this->head; i != nullptr; i = i->next)
cout << i->key << endl;
}
int main(){
SinglyLinkedList s = SinglyLinkedList();
s.insert(4);
s.insert(34);
s.print();
}
Related
I want to implement insertion of element at tail of linked list, I want to do it using member function, currently I'm able to do it by creating a function outside of struct, please help me what should be modified to implement it as member function.
my conventional approach:
#include<iostream>
using namespace std;
struct node{
int data;
node *next;
};
node * Insert(int v,node *head){
if(head==NULL){
node *temp=new node;
head=temp;
temp->data=v;
temp->next=NULL;
return head;
}
else{
node *temp=head;
while(temp->next!=NULL){
temp=temp->next;
}
node *temp_new=new node;
temp_new->data=v;
temp_new->next=NULL;
temp->next=temp_new;
return head;
}
}
This is a working example. The idea is that, from the member function, you recursively call node::Insert until you reach the last element, and then only there you create the next one.
#include <iostream>
struct node{
int data;
node *next = nullptr;
node *Insert(int v);
};
node *node::Insert(int v)
{
if (next == nullptr)
{
next = new node;
next->data = v;
return next;
}
else
{
return next->Insert(v);
}
}
int main()
{
node a{3};
a.Insert(2);
a.Insert(5);
std::cout << a.data << ' ' << a.next->data << ' ' << a.next->next->data << ' ' << std::endl;
return 0;
}
See it live on Coliru.
Also: avoid using namespace std.
Addition
As noted in the comment, it is probably a good idea to unroll the recursion. Here is a nonrecursive version of the above code:
#include <iostream>
struct node{
int data;
node *next = nullptr;
node *Insert(int v);
};
node *node::Insert(int v)
{
if (next == nullptr)
{
next = new node;
next->data = v;
return next;
}
else
{
auto p = next;
while (p->next != nullptr)
p = p->next;
p->next = new node;
p = p->next;
p->data = v;
return p;
}
}
int main()
{
node a{3};
a.Insert(2);
a.Insert(5);
std::cout << a.data << ' ' << a.next->data << ' ' << a.next->next->data << ' ' << std::endl;
return 0;
}
See it live on Coliru.
Just by looking at what your insert currently does, it does not make sense to make it a member of node. You can call your insert like this:
node* root = nullptr;
root = Insert(42,root);
to create a list with a single element. On the other hand, you cannot call a member function of node before you have an instance of type node.
The transition is simpler if you write a class that represents the list, not only a single node. Start with this:
struct node{
int data;
node *next;
};
struct linked_list {
node* head;
};
Now the above two lines could look like this:
linked_list l;
l.insert(42);
All you need to do is to move the free function into the class and instead of using the parameter head you use the member head. Also there is no need to return the head anymore:
#include<iostream>
using namespace std;
struct node{
int data;
node *next;
};
struct linked_list {
node* head = nullptr;
void Insert(int v){
if(head==nullptr){
head =new node;
head->data=v;
head->next=nullptr;
}
else{
node *temp=head;
while(temp->next!=nullptr){
temp=temp->next;
}
node *temp_new=new node;
temp_new->data=v;
temp_new->next=nullptr;
temp->next=temp_new;
}
}
};
Note that I did not change anything on the implementation (only NULL -> nullptr and void return, if it had a bug then it still has a bug now ;). You should also provide appropriate constructors for node and linked_list and destructors, because currently this leaks all allocated memory. And last but not least you need to read about the rule of 3/5: What is The Rule of Three?
I was wondering if it would be possible to create a function that would create a linked list, here is my attempt, I would appreciate if anyone could tell me if this is correct or not.
The logic is as follows:
Take in a starting node, the created linked list will be connected to this node
Create all the nodes that need to be created and store their memory addresses in a vector
Loop through the vector linking together all of the nodes
#include <iostream>
#include <vector>
using namespace std;
class node{
public:;
int value;
node *next;
node():value(0),next(NULL){};
};
void CreateList(node& starting_node, int number_of_nodes_to_create){
// Keep track of all the nodes addresses that need to be created
vector <node*> nodes = {};
// Create the nodes
for (int i = 0; i < number_of_nodes_to_create;i++){
node *temp = new node;
nodes.push_back(temp);
}
// Attach the first created node to the starting node
starting_node.next = nodes[0];
// We now have all the new nodes, now we just need to link them all up with pointers
for (int i = 0; i < nodes.size()-1;i++){
nodes[i] ->next = nodes[i+1];
}
}
I am very much a beginner, all criticism is welcome!
You don't need the vector at all. Your function can be simplified to something like this:
#include <iostream>
#include <vector>
using namespace std;
class node{
public:
int value;
node *next;
node() : value(0), next(NULL) {}
};
void CreateList(node* &starting_node, int number_of_nodes_to_create){
// if the list already exists, find the end of it...
node **n = &starting_node;
while (*n) {
n = &((*n)->next);
}
// Create the nodes
while (number_of_nodes_to_create > 0) {
*n = new node;
n = &((*n)->next);
--number_of_nodes_to_create;
}
}
void DestroyList(node *starting_node) {
while (starting_node) {
node *n = starting_node->next;
delete starting_node;
starting_node = n;
}
}
int main() {
node* head = NULL;
CreateList(head, 5);
...
DestroyList(head);
}
Online Demo
Though, it is not usual for a list creation to take an existing node as input. Usually the creation should create the list and then return the 1st (head) node, eg:
#include <iostream>
#include <vector>
using namespace std;
class node{
public:
int value;
node *next;
node() : value(0), next(NULL) {}
};
node* CreateList(int number_of_nodes_to_create){
node *head = NULL, **n = &head;
while (number_of_nodes_to_create > 0) {
*n = new node;
n = &((*n)->next);
--number_of_nodes_to_create;
}
return head;
}
void DestroyList(node *head) {
while (head) {
node *n = head->next;
delete head;
head = n;
}
}
int main() {
node* head = CreateList(5);
...
DestroyList(head);
}
Online Demo
I have one questions regarding searching elements on a Singly Linked List of ints, in this case, using C++. I'm creating my own version of list for exercising. This is the code
Let's suppose I have two search functions. I know we need to traverse the entire list until find the element because we don't have direct access like arrays.
The two functions are:
bool search(int n); // Traverse the list till find n.
bool search(Node* node, int n); Traverse the list till find n only after *node (included)
1 case: My list has the following elements: [0, 1, 2, 3]
If I search for 3 I easily find at the end of the list. Nice.
QUESTIONS:
2 case: My list has the following elements: [0, 1, 2, 3, 3, 3, 4, 5, 6]
If I search for 3 with:
bool search(int n);
I'm going to get the first 3 element always, except if I have a reference to the second or third 3 element to pass to that function:
bool search(Node* node, int n);
My questions is if that is the correct search algorithm in a singly linked list. The two types of functions or if I should have other types.
Bellow is the code for my actual code (I didn't put the code for searching):
SingleLinkedList.h
struct Node {
int data;
Node* next;
Node(int d = 0)
: data {d}, next {nullptr}
{}
};
class SinglyLinkedList {
public:
SinglyLinkedList();
~SinglyLinkedList();
void display();
bool addFirst(const int); // Add a node to the beginning of the list.
bool addFirst(Node*); // Add a node to the beginning of the list.
bool addLast(const int); // Add a node to the end of the list.
bool addLast(Node*); // Add a node to the end of the list.
private:
Node* head;
Node* tail;
};
SinglyLinkedList.h
#include "SinglyLinkedList.h"
#include <iostream>
SinglyLinkedList::SinglyLinkedList()
: head {nullptr}, tail {nullptr}
{}
SinglyLinkedList::~SinglyLinkedList() {
Node* iterationNode = head;
Node* actualNode {nullptr};
while (iterationNode != nullptr) {
actualNode = iterationNode;
iterationNode = iterationNode->next;
delete actualNode;
}
}
void SinglyLinkedList::display() {
std::cout << "################### Displaying Linked List ###################" << std::endl;
if (head == nullptr) {
std::cout << "Linked List is empty!" << std::endl;
}
else {
Node* iterationNode = head;
std::cout << "[ ";
while (iterationNode != nullptr) {
std::cout << iterationNode->data << " ";
iterationNode = iterationNode->next;
}
iterationNode = nullptr;
std::cout << "]" << std::endl;
}
std::cout << "##############################################################" << std::endl;
}
bool SinglyLinkedList::addFirst(const int n) {
Node* element = new Node {n};
if (head == nullptr) {
head = element;
tail = element;
}
else {
element->next = head;
head = element;
}
return true;
}
bool SinglyLinkedList::addFirst(Node* element) {
if (head == nullptr) {
head = element;
tail = element;
}
else {
element->next = head;
head = element;
}
return true;
}
bool SinglyLinkedList::addLast(const int n) {
Node* element = new Node {n};
if (head == nullptr) {
head = element;
tail = element;
}
else {
tail->next = element;
tail = element;
}
return true;
}
bool SinglyLinkedList::addLast(Node* element) {
if (head == nullptr) {
head = element;
tail = element;
}
else {
tail->next = element;
tail = element;
}
return true;
}
Program.cpp
#include <iostream>
#include "SinglyLinkedList.h"
int main() {
{
SinglyLinkedList list;
list.display();
list.addFirst(5);
list.addFirst(4);
list.addFirst(3);
Node* secondNode = new Node {2};
list.addFirst(secondNode);
Node* firstNode = new Node {1};
list.addFirst(firstNode);
Node* zeroNode = new Node;
list.addFirst(zeroNode);
list.addLast(6);
list.display();
}
system("pause");
}
Another question is, how can I protect my struct in a way the user of the program can not mess up changing the links/references directly. For example, in the Program.cpp, any programmer could simply do this:
secondNode->next = zeroNode
The answer to your first question depends on what you need. If you are doing this as a learning project, implement whatever you see fit. What you have described is appropriate for search by value.
The best way to prevent users from directly accessing your Node members in cases like this is to completely abstract the Node type away. You can do this simply by declaring and defining Node in your source file and use forward declarations of Node* in your header. Users who include your header will then not have any notion of your Node type whatsoever.
// SinglyLinkedList.h
class SinglyLinkedList {
//...//
struct Node* head; // head node is forward declared
//...//
}
// SinglyLinkedList.cc
struct Node {
//...
};
// define ll methods
If you do want the user to know about the Node type, one solution is to make its members private, create a public value accessor method, and make the Node a friend of the SinglyLinkedList class.
I'm writing a piece of code to append a node to the end of a singly linked list, but it seems that it doesn't append anything at all. Can anybody give me some idea of what I'm doing wrong?
#include<iostream>
using namespace std;
struct Node{
int val;
Node* next;
Node(int v) : val(v), next(NULL) {}
};
void append(Node &head, int d){
Node n = head;
while(n.next != NULL){
n = *n.next;
}
Node end(d);
n.next = &end;
}
int main(){
Node head(0);
for(int i=1;i<5;i++){
append(head, i);
}
Node n = head;
while(n.next != NULL){ //print the linked list, result is 0
cout << n.val<<" ";
n = *n.next;
}
cout<<n.val<<endl;
return 0;
}
EDIT: I changed the append() method to append a dynamically-allocated node each time, but it still doesn't work.
void append(Node &head, int d){
Node n = head;
while(n.next != NULL){
n = *n.next;
}
Node* end = new Node(d);
n.next = end;
}
You append the local object Node end(d); to the end of the linked list. This object is destroyed upon exist from append and the last list element points to a non-existent object.
A few issues with this.
You make a copies in your append function here Node n = head; and here n = *n.next. You then then finally make a change to the copy rather than the original.
You are assigning Node end(d) on the stack. When append returns it goes out of scope and is deleted.
You can fix both with,
#include<iostream>
#include <memory>
using namespace std;
struct Node{
int val;
std::shared_ptr<Node> next;
Node(int v) : val(v), next(nullptr) {}
};
void append(Node &head, int d){
Node* n = &head;
while(n->next != nullptr){
n = n->next.get();
}
n->next = std::make_shared<Node>(d);
}
int main(){
Node head(0);
for(int i=1;i<5;i++){
append(head, i);
}
Node n = head;
while(n.next != nullptr){
cout << n.val<<" ";
n = *n.next;
}
cout<<n.val<<endl;
return 0;
}
For the edited Question:
You are copying the head to n, then modify n. At the end of your append function, n is destroyed, but head was never touched.
I'm pretty rusty in C++ and I'm trying to implement a double linked list but I am having some reading violations and having some odd values being given.
#include <iostream>
struct Node
{
int val;
Node* next;
Node* prev;
};
class linkedList
{
public:
linkedList(); //constructor
~linkedList(); //destructor
void push_back(int x);
void addtofront(int x);
//void deleteNode(int x);
bool isempty();
void firstelem();
void prnt_tail();
/*void insert_after(int x, int y);
void insert_before(int x, int y);*/
private:
Node* head;
Node* next;
Node* prev;
};
linkedList::linkedList(){};
linkedList::~linkedList(){};
void linkedList::push_back(int x)
{
linkedList* list = this;
Node temp;
temp.val=x;
temp.next=NULL;
temp.prev=NULL;
if (!head)
{
linkedList* list = new linkedList();
list->head;
head = new Node;
head->val = x;
head->next = NULL;
head->prev = NULL;
}
else
{
Node* temp1;
temp1=head;
while (temp1->next!=NULL)
{
temp1 = temp1->next;
}
temp.next= NULL;
temp.prev=temp1;
temp.val = x;
}
};
void linkedList::addtofront(int x)
{
linkedList* list = this;
Node temp;
temp.val=x;
temp.next=NULL;
temp.prev=NULL;
if (!head)
{
linkedList* list = new linkedList();
list->head;
head = new Node;
head->val = x;
head->next = NULL;
head->prev = NULL;
}
else
{
list->head->prev=&temp;
temp.next=head;
head=&temp;
}
};
//void linkedList::deleteNode(int x)
//{
// if(head)
// {
// linkedList *ptr = head;
// while(ptr->node.val != x)
// {
// ptr = ptr->node.next;
// }
// (ptr->node.next)->prev=ptr->node.prev;
// ptr->node.prev=ptr->node.next;
// delete ptr;
// }
// else
// std::cout<<"empty list";
//}
bool linkedList::isempty()
{
if(head)
return false;
else return true;
};
void linkedList::firstelem()
{
std::cout<<head->val;
};
void linkedList::prnt_tail()
{
if(head)
{
Node *temp;
temp=head;
temp=head->next;
std::cout<<temp;
while(temp->next!=NULL)
{
std::cout<<temp->val<<" ";
}
std::cout<<temp->val;
}
else
{
std::cout<<"empty list";
}
};
//linkedList::insert_after(int x, int y)
//{
//
//}
//
//linkedList::insert_before(int x, int y)
//{
//
//}
and my main
#include "linkedlist2.h"
#include <stdlib.h>
#include <iostream>
int main()
{
linkedList example;
if(example.isempty())
std::cout<<"this list is empty "<<"\n";
else
std::cout<<"this list is not empty"<<"\n";
for (int i = 1; i<=20; i++)
{
example.push_back(i);
//example.prnt_tail();
}
example.addtofront(25);
example.firstelem();
std::cout<<"\n";
example.addtofront(28);
example.firstelem();
std::cout<<"\n";
if(example.isempty())
std::cout<<"this list is empty "<<"\n";
else
std::cout<<"this list is not empty"<<"\n";
//example.push_back(26);
//std::cout<<example.head->next->val;
example.firstelem();
std::cout<<"\n";
example.prnt_tail();
std::cout<<"\n";
system("pause");
}
when I run main I get
this list is empty
-858993460
-858993460
this list is not empty
-858993460
CCCCCCCC
I also get the error
Access violation reading location 0xCCCCCCD0.
and the next statement to be executed is the while loop in "void linkedList::prnt_tail()"
I'm fairly sure my problem is in my pointers and all that. Like I said, I'm really rusty so any help you can give would be greatly appreciated, even in things not directly related to my problems.
So, there's a lot of problems in this code. Let's see what we can do:
It's odd that you have next and prev members in both your node objects and your linkedList objects. Let's fix this by making the linkedList object point to the first node (that is, the head node), and then use the members in each node to point to the next object.
This means that we have:
struct Node {
int val;
struct Node* next;
struct Node* prev;
};
class linkedList {
public:
linkedList(); //constructor
~linkedList(); //destructor
void push_back(int x);
void addtofront(int x);
bool isempty();
private:
Node* head;
};
Let's fix a number of errors in your push_back. First, no matter what the state of the linkedList is, we need to create a new Node on the heap, and then we will be placing that Node somewhere in the linkedList.
void linkedList::push_back(int x)
{
Node *node = new Node;
node->next = NULL;
node->prev = NULL;
node->val = x;
if (head == NULL) {
head = node;
} else {
Node *last = head;
while (last->next != NULL)
last = last->next;
last->next = node;
node->prev = last;
}
}
We also need to fix push_front. This code should look somewhat similar to push_back.
void linkedList::addtofront(int x)
{
Node *node = new Node;
node->next = NULL;
node->prev = NULL;
node->val = x;
if (head == NULL) {
head = node;
} else {
node->next = head;
head->prev = node;
head = node;
}
}
If you're going to write a constructor, you probably should do that correctly:
linkedList() {
head = NULL;
}
It's also worth noting that you will want a real destructor to clean up all of these objects that you are creating on the heap. And then you also need to implement the copy constructor and assignment operator.
Apart from a extra useless semicolon, this looks wrong:
linkedList::linkedList(){};
A constructor is supposed to provide initial values for members, and you haven't done so. Leaving pointer members uninitialized is very bad style, and is the cause of many of your problems.
Because these members aren't initialized, when you later read from them (e.g. isEmpty()'s test if (head)) it will be undefined behavior.
To start with, in addToFront and push_back you probably do not want to be creating new linked lists on the heap. You already have a linked list (the one the method is currently being run on) which you want to modify. Don't create new linked lists here.
However, you DO want to create new Nodes on the heap, never on the stack. In at least one place you create a node on the stack, eg
Node temp;
And then later store and use a pointer to that object. As soon as the function quits, that variable is gone and that pointer is pointing to garbage.
in linked list class , (Node* next;) and (Node* prev;) are extera