I am trying to create a function for adding at the end for doubly linklist. I can't pinpoint out why it does not print out anything.
There was no error coming out when I build the program.
I am making sure
1. new node check if the head has any value first
created following pointer that is previous current
I connected previous node to new node and new node point to previous node while new node point out to nullptr as next.
#include "pch.h"
#include <iostream>
using namespace std;
class list;
class node {
public:
int data;
node *next;
node *prev;
friend class list;
};
class list {//double list
node* head;
node* tail;
public:
list(){ head = nullptr; tail = nullptr; head->next = tail; tail->prev = head;}
node* pushback(int newdata) {
node* curr = new node;
curr->data = newdata;
curr->next = nullptr;
if (head == nullptr) {
head = curr;
return head;
}
node*precurr = head;
while (precurr->next != nullptr){
precurr = precurr->next;
}
precurr->next = curr;
curr->prev = precurr;
return head;
}
void print() {
while (head->next != nullptr) {
cout << head->data << " " << endl;
head = head->next;
}
}
};
int main()
{
list test;
test.pushback(1);
test.pushback(2);
test.pushback(3);
test.pushback(4);
test.pushback(5);
test.pushback(6);
test.print();
return 0;
}
You have done a lot of things correctly, but you are confused on your constructor and on your use of the ->prev and tail pointers.
You immediate issue with your constructor, as identified in the comments, is you set head and tail to nullptr and then immediately derefernce both head and tail attempting to make head and tail self-referencing (which is only needed in a circular linked-list).
list(){ head = nullptr; tail = nullptr; head->next = tail; tail->prev = head;}
With head and tail to set to nullptr, you don't have a pointer to a valid node than can be dereferenced. Your attempt to set head->next = tail; tail->prev = head; fails immediately resulting in a SegFault.
For purposes on a normal non-circular list, you simply omit setting head->next and tail->prev in your constructor, e.g.
list() { head = nullptr; tail = nullptr; }
If you want to make your list a circular list, then you will make head and tail self-referencing in:
node *pushback (int newdata) {
...
if (head == nullptr) /* for circular-list 1st node initialization */
head = tail = head->prev = head->next = tail->prev = tail->next = curr;
(note: a tail pointer is optional with a circular list as head->prev always points to the last node in the list)
Since your question pertains to a double-linked-list and not a circular list, you simply need to set both head and tail equal to the new node curr for the addition of the 1st node, e.g.
node *pushback (int newdata) {
node *curr = new node;
curr->data = newdata;
curr->next = curr->prev = nullptr;
if (head == nullptr)
head = tail = curr;
For all other nodes, there is NO iteration required (that's what a tail pointer is for), you simply set curr->prev to tail, tail->next to curr and then update the tail pointer to the new end node by setting tail = curr;, e.g.
else {
curr->prev = tail;
tail->next = curr;
tail = curr;
}
return head;
}
The purpose of a double-linked-list is to allow you to iterate in both the forward and reverse direction over your nodes. For example:
void printfwd() {
node *iter = head;
while (iter != nullptr) {
std::cout << ' ' << iter->data;
iter = iter->next;
}
std::cout.put('\n');
}
void printrev() {
node *iter = tail;
while (iter != nullptr) {
std::cout << ' ' << iter->data;
iter = iter->prev;
}
std::cout.put('\n');
}
(the iteration scheme is slightly different for a circular list since you can iterate from any node in both forward and reverse direction without needed to start from head or tail. To insert in order for a circular list, you simply insert a new tail node).
Don't develop bad habits. Why is “using namespace std;” considered bad practice? Currently all you have to deal with is cout and endl, go ahead and remove using namespace std; and simply prefix cout and endl with std::.
Putting it altogether, you would have:
#include <iostream>
class list;
class node {
public:
int data;
node *next;
node *prev;
friend class list;
};
class list {//double list
node *head;
node *tail;
public:
list() { head = nullptr; tail = nullptr; }
node *pushback (int newdata) {
node *curr = new node;
curr->data = newdata;
curr->next = curr->prev = nullptr;
if (head == nullptr)
head = tail = curr;
else {
curr->prev = tail;
tail->next = curr;
tail = curr;
}
return head;
}
void printfwd() {
node *iter = head;
while (iter != nullptr) {
std::cout << ' ' << iter->data;
iter = iter->next;
}
std::cout.put('\n');
}
void printrev() {
node *iter = tail;
while (iter != nullptr) {
std::cout << ' ' << iter->data;
iter = iter->prev;
}
std::cout.put('\n');
}
};
int main() {
list test;
for (int i = 1; i <= 10; i++)
test.pushback(i);
std::cout << "\nforward:\n";
test.printfwd();
std::cout << "\nreverse:\n";
test.printrev();
}
Example Use/Output
$ ./bin/ll_double_int
forward:
1 2 3 4 5 6 7 8 9 10
reverse:
10 9 8 7 6 5 4 3 2 1
Look things over and let me know if you have further questions.
Related
I'm solving problems in algorithms and I have to reverse a forward linked list.
Here is my code:
For a node:
struct Node{
int value;
Node* next;
};
For reversing, here is the algorithm I made:
Node* reverse(Node* head){
Node* node = head->next;
Node* sentry = new Node;
sentry->next = head;
while(node != nullptr){
head->next = node->next;
node->next = sentry->next;
sentry->next = node;
node = head->next;
}
return sentry;
}
Here is a print function to test:
void print(Node* head){
Node* node = head->next;
while(node != nullptr){
std::cout << node->value << '-';
node = node->next;
}
}
The problem is that the reversed list has as last node the head, so when I try to do: delete head; before return sentry; to delete that node I get Core Dump error. I know that I can just search in internet a method to reverse the list, but I want to understand why this happens, why can't I just delete the head node.
Edit: here's is the code deleting the head:
Node* reverse(Node* head){
Node* node = head->next;
Node* sentry = new Node;
sentry->next = head;
while(node != nullptr){
head->next = node->next;
node->next = sentry->next;
sentry->next = node;
node = head->next;
}
delete head; // head = nullptr; also doesn't work.
return sentry;
}
Here is a main function to test:
int main(){
Node* node5 = new Node{5,nullptr};
Node* node4 = new Node{4,node5};
Node* node3 = new Node{3,node4};
Node* node2 = new Node{2,node3};
Node* node1 = new Node{1,node2};
Node* head = new Node;
head->next = node1;
head->value;
print(reverse(head));
return 0;
}
Let's look at your code:
void print(Node* head){
Node* node = head->next;
while(node != nullptr){
std::cout << node->value << '-';
node = node->next;
}
}
This code will never print the head. Slightly better code would be:
void print(Node* head) {
for (Node * node = head; node != nullptr; node = node->next) {
std::cout << node->value << '-';
}
}
Now, from your code in main it looks like you don't expect to print the head -- you're using it as a pointer. That would be odd. You basically have an extra, empty node just hanging out. So your main could do this:
int main(){
Node* node5 = new Node{5,nullptr};
Node* node4 = new Node{4,node5};
Node* node3 = new Node{3,node4};
Node* node2 = new Node{2,node3};
Node* head = new Node{1,node2};
std::cout << "Original version: ";
print(head);
std::cout << "\n\n";
std::cout << "Reversed version: ";
print(reverse(head));
std::cout << "\n";
return 0;
}
Finally, your reverse method is flat out broken. You shouldn't have to allocate anything.
Linked lists and other forms of linked structures (like trees) can be very confusing. At this stage in your learning, drawing pictures REALLY helps. I did so for years and years, and I still do when it gets complicated.
Note * reverse(Node *head) {
Node * prev = nullptr;
while (head != nullptr) {
Node * nextNode = head->next;
head->next = prev;
prev = head;
head = nextNode;
}
return prev;
}
There's probably a more elegant way to do this, but I don't want to think that hard :-)
Think about what this does. It keeps track of the previous node. The first time through the loop, there is no previous node. After that, the previous node is the old head, then old head->next, et cetera.
At each node, it sets the next pointer to this previous node. So head->next becomes nullptr (it's the new end of the list). Old Head->next->next comes old head, et cetera.
I haven't tested this code.
This is my final copy with a compile and output:
^ make Foo && Foo
g++ Foo.cpp -o Foo
Original: 1 : 2 : 3 : 4 : 5 :
Reversed: 5 : 4 : 3 : 2 : 1 :
^ cat Foo.cpp
#include <iostream>
struct Node{
Node (int v): value(v) {}
int value = 0;
Node* next = nullptr;
};
void print(Node* head);
Node * reverse(Node* head);
int main() {
// This part is gross, but I was in a hurry
Node * head = new Node(1);
head->next = new Node(2);
head->next->next = new Node(3);
head->next->next->next = new Node(4);
head->next->next->next->next = new Node(5);
std::cout << "Original: ";
print(head);
std::cout << "\n\nReversed: ";
print(reverse(head));
std::cout << "\n";
}
void print(Node* head) {
for (Node * node = head; node != nullptr; node = node->next) {
std::cout << node->value << " : ";
}
}
Node * reverse(Node *head) {
Node * prev = nullptr;
while (head != nullptr) {
Node * nextNode = head->next;
head->next = prev;
prev = head;
head = nextNode;
}
return prev;
}
I'm trying to implement my singly linked list , and I have this problem:
When I'm trying to pushBack some elements in my linked list , it will print only the first one which I added.For example , if I try to pushBack 2,3,4 - it will print only 2.
In case if I want to pushUp some elements in my linked list , it will print only the third one which I added. For example , if I try to pushUp 2,3,4 - it will print only 4.
This is my code:
enter code here
#include<iostream>
#include<vector>
using namespace std;
struct Node {
int data;
Node* next;
};
class LinkedList {
private:
// Create pointers for head and tail
Node *head , *tail;
public:
LinkedList(){
// Initiate them as null pointers
head = NULL;
tail = NULL;
}
public:
void pushBack(int value){
// Should add a node at the end of the linked list
Node* temp = new Node(); // temporary node which should be added
temp->data = value; // value to store
temp->next = NULL; // pointer to the next node
if(head != NULL){
// If there are some elements , then
temp->next = tail->next;
tail = temp;
}
if(head == NULL){
// If there are no elements , our node will be a head and a tail in the same time.
head = temp;
tail = temp;
}
}
void pushUp(int value){
// Shound add a node at the beginning of the linked list
Node* temp = new Node();
temp->data = value;
temp->next = NULL;
if(head == NULL){
// If there are no elements , our node will be a head and a tail in the same time.
head = temp;
tail = temp;
}
if(head != NULL){
// If there are some elements , just make our node to be new head.
temp->next = head->next;
head = temp;
}
}
void traversal(){
Node *temp = new Node();
temp = head;
while(temp != NULL){
cout << temp->data << " ";
temp = temp->next;
}
}
};
int main(){
// Pointer for our first node.
LinkedList a;
a.pushUp(2);
a.pushUp(124);
a.pushUp(3);
// a.pushBack(2);
// a.pushBack(124);
// a.pushBack(3); // Outputs only 2
a.traversal(); // Outputs only 3
}
You are missing edge cases. When you add the first node you are pointing it via head and tail ok but then you should check if there is only one node by comparing the address. And you should consider it for both function because if there is only one node head tail will change or head will be overwritten in your code.
class LinkedList {
private:
// Create pointers for head and tail
Node *head , *tail;
public:
LinkedList(){
// Initiate them as null pointers
head = NULL;
tail = NULL;
}
public:
void pushBack(int value){
// Should add a node at the end of the linked list
Node* temp = new Node(); // temporary node which should be added
temp->data = value; // value to store
temp->next = NULL; // pointer to the next node
if(head != NULL){
// If there are some elements , then
if(tail!=NULL){
tail->next = temp;
}else {
tail = temp;
head->next = tail;
}
}else {
// If there are no elements , our node will be a head and a tail in the same time.
head = temp;
}
}
void pushUp(int value){
// Shound add a node at the beginning of the linked list
Node* temp = new Node();
temp->data = value;
temp->next = NULL;
if(head == NULL){
// If there are no elements , our node will be a head and a tail in the same time.
head = temp;
}else {
// If there are some elements , just make our node to be new head.
if(tail != NULL){
temp->next = head;
head = temp;
}else {
tail = head;
head = temp;
temp->next = tail;
}
}
}
void traversal(){
Node *temp = new Node();
temp = head;
while(temp != NULL){
cout << temp->data << " ";
temp = temp->next;
}
}
};
```
This code is supposed to reverse a linked list. The following code returns an empty linked list even when provided with a non empty list.
class Solution {
public:
ListNode* reverseList(ListNode* head) {
ListNode* curr, *prev, *next;
if (head == NULL)
{
return head;
}
curr = head;
prev = NULL;
while (curr != NULL)
{
next = curr -> next;
curr -> next = prev;
prev = curr;
curr = next;
}
head = prev;
return head;
}
};
While this code strangely works where I added a cout statement just to check if the else was triggered.
class Solution {
public:
ListNode* reverseList(ListNode* head) {
ListNode* curr, *prev, *next;
if (head == NULL)
{
cout << "Triggered";
return head;
}
curr = head;
prev = NULL;
while (curr != NULL)
{
next = curr -> next;
curr -> next = prev;
prev = curr;
curr = next;
}
head = prev;
return head;
}
};
Can someone please explain why this is happening?
Pretty simple, you have to initialize the pointers, else it leads to unexpected behavior that includes not showing it at all or just showing it if an initialized cout is triggered - but it doesn't have to do anything and that's up to your compiler implementation.
//cpp17
listNode* curr{}, *prev{}, *next{};
//before
listNode* curr = nullptr, *prev = nullptr, *next = nullptr;
It is still not in the reverse order as you intended to do.
class Solution {
public:
ListNode* reverseList(ListNode* head) {
listNode* curr{}, *prev{}, *next{};
//ListNode* curr, *prev, *next;
if (head == NULL)
{
return head;
}
curr = head;
prev = NULL;
while (next != NULL)
{
next = curr -> next;
curr -> next = prev;
prev = curr;
curr = next;
}
head = prev;
return head;
}
};
cheers :)
Like mentioned before I found time to write a solution for an other approach of solving your problem to reverse a linked list via class. For a better understanding for beginners I skipped the rule of three/five and initialized the list in the main function and not via constructor in the class:
#include <iostream>
class listElement
{
std::string data;
listElement* next;
listElement* last;
public:
void setData(std::string);
void append(std::string);
void displayElements();
void reverseDisplayElements(listElement*);
void freeMemory();
listElement* reverseList(listElement*);
};
void listElement::setData(std::string newData)
{
last = this;
data = newData;
next = nullptr;
}
void listElement::append(std::string newData)
{
// Double linked list
// last->next = new listElement();
// last->next->data = newData;
// last->next->next = nullptr;
// last = last->next;
// Singly linked list
//has next the value nullptr?
//If yes, next pointer
if (next == nullptr)
{
next = new listElement();
next->data = newData;
next->next = nullptr;
}
//else the method again
else
next->append(newData);
}
listElement* listElement::reverseList(listElement* head)
{
//return if no element in list
if(head == nullptr)
return nullptr;
//initialize temp
listElement* temp{};
while(head != nullptr){
listElement* next = head->next;
head->next = temp;
temp = head;
head = next;
}
return temp;
}
void listElement::displayElements()
{
//cout the first entry
std::cout << data << std::endl;
//if the end is not reached, call method next again
if (next != nullptr)
next->displayElements();
}
void listElement::reverseDisplayElements(listElement*head)
{
//recursiv from the last to the list beginning - stop
listElement *temp = head;
if(temp != nullptr)
{
if(temp->next != nullptr)
{
reverseDisplayElements(temp->next);
}
std::cout << temp->data << std::endl;
}
}
void listElement::freeMemory()
{
//If the end is not reached, call the method again
if (next != nullptr)
{
next->freeMemory();
delete(next);
}
}
int main ()
{
//Pointer to the Beginning of the list
listElement* linkedList;
//Creating the first element
linkedList = new listElement();
//Write data in the first element
linkedList->setData("Element 1");
//add more elements
linkedList->append("Element 2");
linkedList->append("Element 3");
linkedList->append("Element 4");
//display list
linkedList->displayElements();
//space divider
std::cout << "\nPrint in reverse order:" << std::endl;
//display list in reverse order
//pass list beginning as stop point
linkedList->reverseDisplayElements(linkedList);
std::cout << std::endl;
linkedList->displayElements();
std::cout << "\nReverse elements:" << std::endl;
linkedList = linkedList->reverseList(linkedList);
linkedList->displayElements();
std::cout << std::endl;
//destruct the list and free memory
linkedList->freeMemory();
delete(linkedList);
return 0;
}
Btw. there are many different solutions for that task.
How do I make my program print the Linked List backwards? I got the printForward function working fine but the printBackwards function just doesn't seem to do anything. I think I'm on the right track but I'm a little stuck right now. I think the while loop isn't running because temp is NULL for some reason.
Any help would be great.
Thanks
List.h
#include <iostream>
using namespace std;
class LinkedList
{
private:
struct Node
{
int data;
Node * next;
Node * prev;
};
Node * head, *tail;
public:
LinkedList();
bool addAtBeginning(int val);
bool remove(int val);
void printForward() const;
void printBackward() const;
};
#endif
List.cpp
#include "List.h"
LinkedList::LinkedList()
{
head = NULL;
tail = NULL;
}
bool LinkedList::addAtBeginning(int val)
{
Node* temp;
temp = new Node;
temp->data = val;
temp->next = head;
head = temp;
return false;
}
bool LinkedList::remove(int val)
{
return false;
}
void LinkedList::printForward() const
{
Node* temp = head;
while (temp != NULL) {
cout << temp->data << " ";
temp = temp->next;
}
cout << endl;
}
void LinkedList::printBackward() const
{
Node* temp = tail;
while (temp != NULL) {
cout << temp->data << " ";
temp = temp->prev;
}
cout << endl;
}
app.cpp
#include "list.h"
int main()
{
LinkedList aList;
aList.addAtBeginning(3);
aList.addAtBeginning(10);
aList.addAtBeginning(1);
aList.addAtBeginning(7);
aList.addAtBeginning(9);
aList.addAtBeginning(12);
aList.printForward();
aList.printBackward();
system("pause");
return 0;
}
I find it a bit odd that you only have an addAtBeginning method, and no method to add at the end, the latter which I would consider to be normal use of a linked list. That being said, I think the immediate problem here is that you never assign the tail to anything. Try this version of addAtBeginning:
bool LinkedList::addAtBeginning(int val)
{
Node* temp;
temp = new Node;
temp->data = val;
temp->next = head;
if (head != NULL)
{
head->prev = temp;
}
if (head == NULL)
{
tail = temp;
}
head = temp;
return false;
`}
The logic here is that for the first addition to an empty list, we assign the head and tail to the initial node. Then, in subsequent additions, we add a new element to the head of the list, and then assign both the next and prev pointers, to link the new node in both directions. This should allow you to iterate the list backwards, starting with the tail.
Update addAtBeginning function with given:
bool LinkedList::addAtBeginning(int val)
{
Node* temp;
temp = new Node;
temp->data = val;
temp->prev = temp->next = NULL;
// If adding first node, then head is NULL.
// Then, set Head and Tail to this new added node
if(head == NULL){
// If this linked list is circular
temp->next = temp->prev = temp;
head = tail = temp;
}else{ // If we already have at least one node in the list
// If this linked list is circular
temp->prev = head->prev;
temp->next = head;
head->prev = temp;
head = temp;
}
return false;
}
But remember, if you copy this function with the parts that it makes this list circular, you will get an infinite loop. So, either change print function or dont copy that parts.
I am trying to write a reverse print function as part of a doubly linked list. Here are the relevant functions that I have written:
void PLAYER::AddNode(int addID, std::string addName){
nodePtr n = new node; //creates a new node pointer
n->next = NULL; //Make next null
n->prev = NULL; // this will set this to be the ending node
n->ID = addID; //These two lines pass the information into the node
n->name = addName; // ID# and Name Information
if(head != NULL){ // This checks to see if a list is set up.
curr = head; // Make this point to the head.
while(curr->next != NULL){ // Loops through until the NULL is found
curr = curr->next;
}
curr->next = n; //Make the currnet node point to N
n->prev = curr; //Make the previous node connect to curr
n->next = tail; // connect new node to the tail.
}
else{
head = n; //If there is no list, this makes N the first node.
}
Here is the class that prototypes the functions to be used.
class PLAYER
{
public: // Functions go inside PUBLIC
PLAYER();
void AddNode(int addID, std::string addName);
void DeleteNode(int delPlayer);
void SortNode();
void PrintList();
void InsertHead(int AddID, std::string addName);
void PrintReverse();
private: //Variables go into here
typedef struct node{
// ...
std::string name;
int ID;
node* next;
node* prev;
}* nodePtr;
nodePtr head, curr, temp, prev, test, tail;
};
And finally my attempt to create a reverse traversing function to print backwards.
void PLAYER::PrintReverse()
{
curr = head;
while(curr->next != NULL) //Get to the end of the list
{
curr = curr->next;
}
while(curr->prev != NULL) //Work backward and print out the contents
{
std::cout << curr->ID << " " << curr->name << endl;
curr = curr->prev;
}
}
What I would like to do is inside the PrintReverse() function have it initialize via the tail pointer, however I can not figure out the functions to add to PrintReverse() and to AddNode() in order to have the new nodes pointed to by tail.
This is my first question posting here, I hope I covered all my bases. Thank you for any help I can find.
EDIT:
Thank you for all your input. I am relearning data structures and yes this is some self imposed homework on my part to begin to get the logic flowing again.
I will make the changes when I get home tonight.
The following changes would need to be considered.
The PrintReverse function would not need the forward pass to obtain the tail.
void PLAYER::PrintReverse()
{
curr = tail;
while(curr != NULL) //Work backward and print out the contents
{
std::cout << curr->ID << " " << curr->name << endl;
curr = curr->prev;
}
}
There is a problem in how tail is handled in the AddNode function. See the lines where the comments contain [CHANGED] and [ADDED]:
if(head != NULL){ // This checks to see if a list is set up.
curr = head; // Make this point to the head.
while(curr->next != NULL){ // Loops through until the NULL is found
curr = curr->next;
}
curr->next = n; //Make the currnet node point to N
n->prev = curr; //Make the previous node connect to curr
n->next = NULL; // [CHANGED]: we want the last node not to have a successor.
}
else{
head = n; //If there is no list, this makes N the first node.
}
tail = n; // [ADDED]: the last node added is the new tail.
However, a simpler solution is to avoid again the forward pass, and start from tail.
if(tail != NULL){ // This checks to see if a list is set up.
tail->next = n; //Make the old tail node point to N
n->prev = tail;
n->next = NULL;
}
else{
head = n; //If there is no list, this makes N the first node.
}
tail = n; // The last node added is the new tail.