I am trying to teach myself c++ and I am really confused with linked lists. I have been reading through textbooks and looking online but I am really confused how they work. I found an exercise online that I have been trying to figure out, but I am not getting anywhere with it.
Here is the list.h file:
struct node
{
int val;
struct node *next;
};
int length(struct node *);
void push(struct node **, int); //add to front of list
void append(struct node **, int); //add to rear of list
void print(struct node *, int);
I am having a hard time trying to write the functions for length, push and append.
A linked list is simply a string of Node classes string together, with each owning a pointer whose address is that of the next Node class in the list.
It's pretty simple if you think of it this way:
Coliru: http://coliru.stacked-crooked.com/a/5e71c5e31b58673c
#include <iostream>
//Proper encapsulation is not included for terseness and clarity
class Node {
public:
int num;
Node* next;
Node(int n) :
num(n),
next(nullptr) {
};
~Node() {}
};
int main() {
Node a(0);
Node b(1);
Node c(2);
Node d(3);
Node e(4);
//String the nodes together, linking like metal chainlinks
a.next = &b;
b.next = &c;
c.next = &d;
d.next = &e;
//Can you see how the "link" actually works here?
//Each Node's "next" pointer points to the next node.
std::cout << "Node a: " << a.num << std::endl;
std::cout << "Node b: " << a.next->num << std::endl;
std::cout << "Node c: " << a.next->next->num << std::endl;
std::cout << "Node d: " << a.next->next->next->num << std::endl;
std::cout << "Node e: " << a.next->next->next->next->num << std::endl;
//What if I were to point e to the start of a?
e.next = &a;
std::cout << "Node e->next: " << e.next->num << std::endl;
//It's node a!
//Node e.next is now accessible through the linked list:
std::cout << "Node e->next = a.next->next->next->next->next: " << a.next->next->next->next->next->num << std::endl;
//Usually people just use a for loop for this type of stuff.
//Let's use a lambda function to write one right here:
auto index_func = [](Node* head, size_t index) {
Node* current = head;
Node* next = head->next;
for (int i = 0; i < index; ++i) {
if (next != nullptr) {
//Hey, look at the pointers fly!
current = next;
next = current->next;
} else {
std::cout << "Whoops, we hit a null pointer before we got to our index!" << std::endl;
break;
}
}
return current->num;
};
//This is the same as finding the 6th node in the list (but since it's zero-indexing it's [5])
std::cout << index_func(&a, 5) << std::endl;
//We can also continue to do this:
std::cout << index_func(&a, 499) << std::endl;
//This is me accessing the 500th element, which, since our back links to our head node, it's the 4th node, d.
return 0;
}
You can probably imagine the other shenanigans we can do with linked lists if we decide to insert a Node between a or e simply be reassigning pointers.
void push(struct node **list, int newVal) { //add to front of list
struct node* firstNode = *list;
struct node* newNode = (struct node*) malloc(sizeof(struct node));
if (newNode == NULL) abort();
newNode->val = newVal;
newNode->next = firstNode;
*list = newNode;
}
void append(struct node **list, int newVal){ //add to rear of list
if (*list == NULL) {
push(list, newVal);
return;
}
/* Locate last node in list*/
struct node* curNode = *list;
while (curNode->next != NULL)
curNode = curNode->next;
/* Add a new node at the end of the list */
struct node* newNode = (struct node*) malloc(sizeof(struct node));
if (newNode == NULL) abort();
newNode->val = newVal;
newNode->next = NULL;
curNode->next = newNode;
}
Related
How to reverse linked list using double pointer?
I was learning about double pointers and thought if we can reverse linked list using one pointer only.
Conversion to using a pointer to pointer left as an exercise for the reader. Also has some distinct shortcomings in terms of style.
#include <iostream>
struct node {
int data;
node *next;
};
node *reverse(node *list) {
node *prev = NULL;
node *next;
while (list) {
next = list->next;
list->next = prev;
prev = list;
list = next;
}
return prev;
}
void show_list(node *list) {
while (list != NULL) {
std::cout << list->data << ", ";
list = list->next;
}
}
int main() {
node *list = NULL;
for (int i=0; i<10; i++) {
node *n = new node;
n->next = list;
n->data = i;
list = n;
}
std::cout << "As built: ";
show_list(list);
list = reverse(list);
std::cout << "Reversed: ";
show_list(list);
return 0;
}
If you decide to modify a pointer you received as a parameter, it's probably easier to deal with a reference to a pointer than a pointer to a pointer though.
I am trying to implement a doubly linked list in C++ and have run across a problem.
#include <iostream>
#include <string>
struct Node
{
std::string data;
Node* prev_link;
Node* next_link;
Node(const std::string& data,Node* prev_link=nullptr, Node* next_link=nullptr)
: data{data},prev_link{prev_link},next_link{next_link} {}// constructor
};
Node* insert(Node* new_node,Node* old_node);// insert node before old node
Node* head(Node* node);// returns a pointer to the head i.e. the left end of the linked list
void print_list(Node* node);//takes the head pointer and executes iterative print
void kill_list(Node* tail_node);// deallocates memory by deleting the list
Node* insert(Node* new_node,Node* old_node)
{
if(new_node == nullptr) return old_node;
if(old_node == nullptr) return new_node;
new_node->next_link = old_node;// p of old node connect to new node
if(old_node->prev_link) old_node->prev_link->next_link = new_node;//n of old' node connect to new node if old' node exists
new_node->prev_link = old_node->prev_link;//p of new node connect to old` node
new_node->next_link = old_node;//n of new node connect to old node
return new_node;
}
Node* head(Node* node)
{
while(node->next_link != nullptr) node = node->next_link;
return node;
}
void print_list(Node* node)
{
while(node)
{
std::cout << node->data;
if(node = node->next_link) std::cout << "<->";// if next node is not an end node
}
}
void kill_list(Node* tail_node)
{
Node* temp;
while (tail_node)
{
temp = (tail_node->prev_link)?tail_node->prev_link:tail_node->next_link;
delete tail_node;
tail_node = temp;
}
std::cout << '\n' <<"List destroyed" << std::endl;
}
int main()
{
Node* alphabets = new Node("A");
alphabets = insert(new Node("B"),alphabets);
alphabets = insert(new Node("C"),alphabets);
print_list(alphabets);
std::cout << '\n';
std::cout << "Head:" << head(alphabets)->data << std::endl;
std::cout << "Adjacent:" << head(alphabets)->prev_link->data << std::endl;
kill_list(alphabets);
}
output:
C<->B<->A
Head:A
fish: “./test1” terminated by signal SIGSEGV (Address boundary error)
The head() function returns a pointer to the head node(in this case it's A).
The linked list as well as the head node is printed correctly but I cannot access the node adjacent to the head node. Cannot figure out what I am doing wrong. Any help would be appreciated.
Your error is because there is a null pointer for the neighbor of A. In your insert function, you have this if statement
if(old_node->prev_link) old_node->prev_link->next_link = new_node
However, in the case of A, there is no prev_link but you would still like to assign B. So replacing that with:
old_node->prev_link = new_node;
fixes the issue. However you might want to double check so that this corresponds to your desired logic.
The problem is due to the fact that the prev_link is not set for the head (the prev link is zero for every node), there is an error on the insert function, you never set the prev_link of the old node.
I want to have a node that will be able to point to another node through the function insert. However, I've messed up somehow so that the pointer p does not point to the next Node. I'm unsure of how to use my function in a way such that it will point to the recurred variable a.
This issue is occurring on a AVL tree assignment I've been working on. I've recreated the error in a simpler fashion in the below code.
#include <iostream>
using namespace std;
struct Node {
int data;
Node *next = NULL;
};
Node* insert(Node *a) {
cout << "inserter" << endl;
if (a != NULL) {
a->next = insert(a->next);
}
else {
cout << "inserting" << endl;
Node *a = new Node;
a->data = 10;
a->next = NULL;
}
return a;
}
int main() {
Node *p = new Node;
p->data = 5;
insert(p);
cout << "please" << endl;
cout << p->data << endl;
cout << p->next << endl;
cout << p->next->data << endl;
cout << "done" << endl;
return 0;
}
The output is:
inserter
inserter
inserting
please
5
000000
And then it crashes, as p->next is not pointing to anything. I don't know how I can get it to point to the recurrsed pointer a.
My main objective is to have a->next be changed without using a returning function, instead a void function that can change a->next using an & in the pass by reference. But I'm unsure how to incorporate the & into a pointer. This hasn't been working (Node *&a).
Your main reason for p->next being null is that the pointer you want to return is out of scope when you return it.
Outside of else {}, the new pointer you created is no longer valid.
else {
cout << "inserting" << endl;
a = new Node;
a->data = 10;
a->next = NULL;
}
Because of the Node* before a in your code, you are declaring a new Node pointer, instead of using the one that was passed to the function.
In your code, it doesn't seem like you are implementing a tree. It seems more like you are implementing a linked list.
Whatever. In the way you are doing, you can never track the starting node. You have to save it for traversing the tree/linked list.
struct node
{
int data;
node *next;
};
node *head, *tail;
void createnode(int value)
{
node *temp=new node;
temp->data=value;
temp->next=NULL;
if(head==NULL)
{
head=temp;
tail=temp;
temp=NULL;
}
else
{
tail->next=temp;
tail=temp;
}
}
I'm writing a program in c++ that reverse a linked list in c++.
And I have seen a lot of questions about it but my answer is not on them so please don't mark this as a duplicate!
I want to reverse a linked list using recursion and this is my full program and on Function reverse recursion() there is something wrong with it those programs ends and don't print.
I have tried to Get this function out of my class but it doesn't work and I have tried to make the head global too.
class LinkedList{
public:
Node* Head;
int Length;
LinkedList(Node* head,int c){
Head=head;
Length=c;
}
void ReverseRecursion(Node* temp,Node** Heading){
if(temp->next==0){
*Heading = temp;
cout << "This is the head item==>" << temp->value << " And this
is the Heading now " << *Heading << endl;
return;
}
ReverseRecursion(temp,Heading);
temp->next->next = temp;
temp->next = 0;
}
}
I have insert and delete and print functions in this class But i have test them and they are correct.
And on my main, I save the head element in a local variable on main and every time I pass it to the LinkedList.
And I call this function like this on main :
MyLinked.ReverseRecursion(head,&head);
When calling the recursion function you must pass a different parameter, otherwise you will have an infinite recursion until you get out of memory.
Try this version, where each time you call the function with the next element in the list, until you find the end of the list:
class LinkedList{
public:
Node* Head;
int Length;
LinkedList(Node* head,int c){
Head=head;
Length=c;
}
void ReverseRecursion(Node* temp,Node** Heading){
if(temp->next==0){
*Heading = temp;
cout << "This is the head item==>" << temp->value << " And this
is the Heading now " << *Heading << endl;
return;
}
ReverseRecursion(temp->next,Heading);
temp->next->next = temp;
temp->next = 0;
}
}
EDIT:
I show a complete testing of how my solution works. I intended to do the minimum change necessary to the original code to make it work, and the minimum is changing only one word:
#include <iostream>
using namespace std;
class Node {
public:
int value;
Node * next;
Node(int v, Node * n) : value(v), next(n) {}
};
class LinkedList{
public:
Node* Head;
int Length;
LinkedList(Node* head,int c){
Head=head;
Length=c;
}
void ReverseRecursion(Node* temp,Node** Heading){
if(temp->next==0){
*Heading = temp;
//cout << "This is the head item==>" << temp->value << " And this
//is the Heading now " << *Heading << endl;
return;
}
ReverseRecursion(temp->next,Heading);
temp->next->next = temp;
temp->next = 0;
}
void print() const;
};
void LinkedList::print() const {
cout << '{';
for (Node* node = Head; node != 0; node = node->next)
cout << ' ' << node->value; // value is public ?
cout << " }" << endl;
}
int main()
{
Node n3(3, 0);
Node n2(2, &n3);
Node n1(1, &n2);
LinkedList ll(&n1, 3);
Node *heading;
ll.print();
ll.ReverseRecursion(&n1, &heading);
ll.Head = heading;
ll.print();
return 0;
}
Output:
{ 1 2 3 }
{ 3 2 1 }
I am trying to implement a doubly linked list in C++ and the add function is working properly but the find node function is modifying the list.
All other function like insertAfter, delete depend on this find function and hence they are also not working as expected.
I am new to C++, so I don't completely understand pointers. I simply tried to replicate my Java program in C++. I know for sure that in the find function the pointer to the head node is causing the problem but I don't completely understand how.
Below is my code :
struct Node{
int data;
Node* next;
Node* prev;
Node(int d) {
data = d;
};
};
struct DLL {
Node* head;
Node* tail;
int size;
//Adding a Node to the Doubly LL
void addNode(Node* n) {
//If LL is empty add the first Node
if (tail == NULL) {
tail = n;
head = n;
}
//Else add add node to the tail. Connect n to the tails next and make n the tail
else {
tail->next = n;
n->prev = tail;
tail = n;
tail->next = NULL;
}
size++;
};
//Finding a random Node in the linked List
//It will return the Node with the FIRST occurrence where data = d
Node* findNode(int d) {
//We will start at the head and then traverse through the entire list to find a Node where data = d
Node* start = head;
if (start == NULL) {
cout<<"No element in the List" <<endl;
return NULL;
}
// If head is the Node we are looking for
if (start->data = d) {
cout<< "Node found with matching data : " << start << endl;
return start;
}
//While next pointer is not null, traverse to search for a match.s
while (start->next != NULL) {
start = start->next;
if (start->data == d) {
cout<< "Node found with matching data : " << start << endl;
return start;
}
}
cout << "No node found with matching data = " << d <<endl;
return NULL;
};
};
start->data = d
This line in your second if block is assigning d to start->data rather than comparing the two.
This is a good time to learn about constness.
Node* findNode(int d) {
//We will start at the head and then traverse through the entire list to find a Node where data = d
Node* start = head;
if (start == NULL) {
cout<<"No element in the List" <<endl;
return NULL;
}
// If head is the Node we are looking for
if (start->data = d) {
cout<< "Node found with matching data : " << start << endl;
return start;
}
This function has write access to the list, and you don't want that. Unfortunately, you abuse this access in the last if statement:
if (start->data = d) {
this code assigns the value of d to start->data and then tests if the value assigned to it was not null.
We can mark this function as const easily:
//////////////////////vvvvv/////////////////
Node* findNode(int d) const {
//We will start at the head and then traverse through the entire list to find a Node where data = d
Node* start = head;
if (start == NULL) {
cout<<"No element in the List" <<endl;
return NULL;
}
// If head is the Node we are looking for
if (start->data = d) {
cout<< "Node found with matching data : " << start << endl;
return start;
}
and now the if will generate a compiler error.
A cleaned up version of your code might look something like the following:
#include <iostream>
struct Node {
int data_;
Node* next_ { nullptr };
Node* prev_ { nullptr };
Node(int data) : data_(data) {}
};
struct DLL {
Node* head_ { nullptr };
Node* tail_ { nullptr };
int size_ { 0 };
//Adding a Node to the Doubly LL
void addNode(Node* node) {
//If LL is empty add the first Node
if (tail_ == nullptr) {
tail_ = node;
head_ = node;
node->prev_ = node->next_ = nullptr;
}
//Else add add node to the tail. Connect n to the tails next and make n the tail
else {
tail_->next_ = node;
node->prev_ = tail_;
tail_ = node;
node->next_ = nullptr;
}
size_++;
}
//Finding a random Node in the linked List
//It will return the Node with the FIRST occurrence where data = d
Node* findNode(int data) const {
//We will start at the head and then traverse through the entire list to find a Node where data = d
//While next pointer is not null, traverse to search for a match.s
for (Node* start = head_; start != nullptr; start = start->next_) {
if (start->data_ == data) {
std::cout << "Node found with matching data : " << start << '\n';
return start;
}
}
std::cout << "No node found with matching data = " << data << '\n';
return nullptr;
}
};
int main()
{
DLL dll;
Node n1(1), n3(3), n5(5);
dll.addNode(&n1);
dll.addNode(&n3);
dll.addNode(&n5);
if (dll.findNode(1) != &n1)
std::cerr << "wrong result for findNode(1)\n";
if (dll.findNode(2) != nullptr)
std::cerr << "wrong result for findNode(2)\n";
if (dll.findNode(3) != &n3)
std::cerr << "wrong result for findNode(3)\n";
if (dll.findNode(4) != nullptr)
std::cerr << "wrong result for findNode(4)\n";
if (dll.findNode(5) != &n5)
std::cerr << "wrong result for findNode(5)\n";
}
Live demo: http://ideone.com/X34EgY