Recursive Reverse Single Linked List - c++

I am trying to just write a basic function that reverses a singly-linked list which is recursive. I was wondering if i tackled this in the right approach? Maybe someone can give me some pointers.
void reverse(Node*& p) {
if (!p) return;
Node* rest = p->next;
if (!rest) return;
reverse(rest);
p->next->next = p;
p->next = NULL;
p = rest;
}

That's not the most efficient way, but to do it, you can call the reverse method with the "next" pointer until there is no next. Once there, set next to previous. After returning from the recursion, set next to previous. See the recursive version here for an example. From the link:
Node * reverse( Node * ptr , Node * previous)
{
Node * temp;
if(ptr->next == NULL) {
ptr->next = previous;
previous->next = NULL;
return ptr;
} else {
temp = reverse(ptr->next, ptr);
ptr->next = previous;
return temp;
}
}
reversedHead = reverse(head, NULL);

This might be helpful
List
{
public:
.....
void plzReverse()
{
Node* node = myReverse(head);
node->next = NULL;
}
private:
Node * myReverse(Node * node)
{
if(node->next == NULL)
{
head = node;
return node;
}
else
{
Node * temp = myReverse(node->next);
temp ->next = node;
return node;
}
}
}
Another solution might be:
List
{
public:
.....
void plzReverse()
{
Node* node = myReverse(head, head);
node->next = NULL;
}
private:
Node * myReverse(Node * node, Node*& rhead)
{
if(node->next == NULL)
{
rhead = node;
return node;
}
else
{
Node * temp = myReverse(node->next,rhead);
temp ->next = node;
return node;
}
}
}

This is what you need:
Node* reverse(Node* p) {
if (p->next == NULL) {
return p;
} else {
Node* t = reverse(p->next); // Now p->next is reversed, t is the new head.
p->next->next = p; // p->next is the current tail, so p becomes the new tail.
p->next = NULL;
return t;
}
}

The recursive solution can look quite pretty, even in C++:
Node* reverse(Node* pivot, Node* backward = 0) {
if (pivot == 0) // We're done
return backward;
// flip the head of pivot from forward to backward
Node* rest = pivot->next;
pivot->next = backward;
// and continue
return reverse(rest, pivot);
}
Most C++ compilers do tail call optimization so there's no reason to believe this to be less efficient than an iterative solution.

Here is the solution that preserves return value as void.
void reverse(Node*& p) {
if (!p) return;
Node* rest = p->next;
if (!rest) {
rest = p;
return;
}
reverse(rest);
p->next->next = p;
p->next = NULL;
p = rest;
}

linkedList *reverseMyNextPointer(linkedList *prevNode, linkedList *currNode)
{
linkedList *tempPtr;
if(!currNode)
return prevNode;
else
{
tempPtr = currNode->next;
currNode->next = prevNode;
return reverseMyNext(currNode,tempPtr);
}
}
head = reverseMyNextPointer(nullptr,head);

Related

C++ Need help on Remove Node function

I have stressed my head out the last few days to figure out how to get this remove() function to work. I'm still a student and data structure is no joke.
I really need help on how to get this function to remove a specific number on the list from user input. Doesn't matter what I try, it still could not work right.
For example, the list is: [1, 2, 3]
I want to delete number 2 on the list. I want the remove() function to traverse thur the list, if it found number 2, then delete number 2.
class SortedNumberList {
public:
Node* head;
Node* tail;
SortedNumberList() {
head = nullptr;
tail = nullptr;
}
void Insert(double number) {
Node* newNode = new Node(number);
if (head == nullptr) {
head = newNode;
tail = newNode;
}
else {
tail->SetNext(newNode);
tail = newNode;
}
}
// Removes the node with the specified number value from the list. Returns
// true if the node is found and removed, false otherwise.
bool Remove(double number) {
Node* temp = head;
if (temp == nullptr) {
return false;
}
if (head->GetData() == number) {
head = head->GetNext();
return true;
}
else{
while (temp != nullptr) {
Node* curNode = temp;
Node* preNode = nullptr;
preNode = curNode->GetPrevious();
temp = temp->GetNext();
if (curNode->GetData() == number) {
preNode = curNode->GetNext();
return true;
}
delete curNode;
}
}
delete temp;
}
};
class Node {
protected:
double data;
Node* next;
Node* previous;
public:
Node(double initialData) {
data = initialData;
next = nullptr;
previous = nullptr;
}
Node(double initialData, Node* nextNode, Node* previousNode) {
data = initialData;
next = nextNode;
previous = previousNode;
}
Edit: I'm able to solve my own issue, thank you everyone.
bool Remove(double number) {
// Your code here (remove placeholder line below)
Node* temp = head; //Make a temporary node point to head.
if (temp == nullptr || head == nullptr) { //if user don't provide input, return false.
return false;
}
if (head->GetData() == number) { //If number need to delete is at head.
head = head->GetNext();
return true;
}
else {
while (temp != nullptr) { //Travese temp node throught out a list.
Node* curNode = temp->GetNext(); //Make a current node point at temp next.
Node* preNode = temp;
Node* sucNode = curNode->GetNext();
if(curNode->GetData() == number) { //Delete a node if number is found on the list
if (curNode->GetNext() == nullptr) { //Delete at tail.
preNode->SetNext(nullptr);
tail = preNode;
delete curNode;
return true;
}
if (curNode->GetNext() != nullptr) {
preNode->SetNext(sucNode);
sucNode->SetPrevious(preNode);
delete curNode;
return true;
}
}
temp = temp->GetNext();
}
}
return false;
}
};
You should make Node a friend class of SortedNumberList or define former inside the later class which simplifies the code somewhat. It's personal preference but it leads to less unnecessary boilerplate code (getters and setters).
In a double linked list you do not need to keep track of the last as you do need on single linked lists because you have both pointers available.
The quest is just a matter of iterating to find the value, taking care to cut it early when we pass the mark since it is a sorted list.
Then delete the object and update the link pointers.
bool Remove(double number) {
// Loop through the entire list
Node* temp = head;
while ( temp != nullptr) {
// There is no point looking forward if the list is sorted
if (temp->data > number ) return false;
// Compare to find
if (temp->data == number) {
// Get the pointers so we can delete the object
Node* prev = temp->previous;
Node* next = temp->next;
// Delete object
delete temp;
// Update previous pointers
if ( prev==nullptr ) {
head = next;
} else {
prev->next = next;
}
// Update next pointers
if ( next==nullptr ) {
tail = prev;
} else {
next->previous = prev;
}
// Indicate success
return true;
}
}
// We iterated to the end and did not find it
return false;
}

Merge sort with doubly linked lists (using the tail-head representation)

I want to implement a merge-sorting algorithm, that is good for a doubly linked list with two "watches".
The watches are: head and tail, where head->prev is equal to NULL, head->next is equal to the first item, tail->prev is equal to the last item and tail->next is equal to NULL
Here is a graphic representation on how a doubly linked list would look like:
I have implemented the merge sort algorithm as such:
//Function to merge two halves of list.
struct Node *merge(struct Node *first, struct Node *second)
{
//base cases when either of two halves is null.
if (!first)
return second;
if (!second)
return first;
//comparing data in both halves and storing the smaller in result and
//recursively calling the merge function for next node in result.
if (first->data < second->data)
{
first->next = merge(first->next,second);
first->next->prev = first;
first->prev = NULL;
//returning the resultant list.
return first;
}
else
{
second->next = merge(first,second->next);
second->next->prev = second;
second->prev = NULL;
//returning the resultant list.
return second;
}
}
//Function to split the list into two halves.
struct Node *splitList(struct Node *head)
{
//using two pointers to find the midpoint of list
struct Node *fast = head,*slow = head;
//first pointer, slow moves 1 node and second pointer, fast moves
//2 nodes in one iteration.
while (fast->next && fast->next->next)
{
fast = fast->next->next;
slow = slow->next;
}
//slow is before the midpoint in the list, so we split the
//list in two halves from that point.
struct Node *temp = slow->next;
slow->next = NULL;
return temp;
}
//Function to sort the given doubly linked list using Merge Sort.
struct Node *sortDoubly(struct Node *head)
{
if (!head || !head->next)
return head;
//splitting the list into two halves.
struct Node *second = splitList(head);
//calling the sortDoubly function recursively for both parts separately.
head = sortDoubly(head);
second = sortDoubly(second);
//calling the function to merge both halves.
return merge(head, second);
}
source: geeksforgeeks
However, upon running the code, when I try to write the sorted doubly linked list, I get an error, when the deconstructor tries deleting the last item, as the algorithm is not working with a head-tail type doubly linked list.
What is a fix I could try?
The full code here:
#include <fstream>
#include <iostream>
using namespace std;
class node {
public:
int value;
node* prev;
node* next;
};
class DLLista {
private:
node* head;
node* tail;
public:
DLLista();
~DLLista();
node* createNode(int value);
void freeNode(node* p);
void insertBefore(node* p, int value);
void insertAfter(node* p, int value);
void deleteBefore(node* p);
void deleteAfter(node* p);
void deleteNode(node* p);
void push_back(node* p);
void push_front(node* p);
void printFront();
void printBack();
node* firstItem();
node* lastItem();
};
DLLista::DLLista() {
head = new node;
tail = new node;
head->prev = NULL;
head->next = tail;
tail->prev = head;
tail->next = NULL;
}
DLLista::~DLLista() {
while (head->next != tail) {
deleteNode(lastItem());
}
delete head;
delete tail;
}
node* DLLista::createNode(int value) {
node* newnode = new node;
newnode->value = value;
newnode->prev = newnode->next = NULL;
return newnode;
}
void DLLista::freeNode(node* p) {
delete p;
}
void DLLista::insertBefore(node* p, int value) {
node* newnode = createNode(value);
p->prev->next = newnode;
newnode->prev = p->prev;
newnode->next = p;
p->prev = newnode;
}
void DLLista::insertAfter(node* p, int value) {
node* newnode = createNode(value);
newnode->next = p->next;
newnode->prev = p;
p->next->prev = newnode;
p->next = newnode;
}
void DLLista::deleteBefore(node* p) {
node* del = p->prev;
if (del != NULL) {
del->prev->next = p;
p->prev = del->prev;
freeNode(del);
}
else {
cout << "Error:deleteBefore";
}
}
void DLLista::deleteAfter(node* p) {
node* del = p->next;
if (del != NULL) {
p->next = del->next;
del->next->prev = p;
freeNode(del);
}
else {
cout << "Error:deleteAfter";
}
}
void DLLista::deleteNode(node* p) {
if (p != head && p != tail) {
p->prev->next = p->next;
p->next->prev = p->prev;
freeNode(p);
}
else {
cout << "Error:deleteNode";
}
}
void DLLista::push_back(node* p) {
tail->prev->next = p;
p->prev = tail->prev;
p->next = tail;
tail->prev = p;
}
void DLLista::push_front(node* p) {
head->next->prev = p;
p->next = head->next;
p->prev = head;
head->next = p;
}
void DLLista::printFront() {
node* p = head->next;
while (p != tail) {
cout << p->value << " ";
p = p->next;
}
}
void DLLista::printBack() {
node* p = tail->prev;
while (p != head) {
cout << p->value << " ";
p = p->prev;
}
}
node* DLLista::firstItem() {
return head->next;
}
node* DLLista::lastItem() {
return tail->prev;
}
//Implementation of merge sort algorithm
void input(const char* file, DLLista& list) {
ifstream fin(file);
int n;
fin >> n;
int tmp;
for (int i = 0; i < n; i++) {
fin >> tmp;
node* newnode = list.createNode(tmp);
list.push_back(newnode);
}
}
node* merge(node* first, node* second) {
if (first == NULL) {
return second;
}
if (second == NULL) {
return first;
}
if (first->value < second->value) {
first->next = merge(first->next, second);
first->next->prev = first;
first->prev = NULL;
return first;
}
else {
second->next = merge(first, second->next);
second->next->prev = second;
second->prev = NULL;
return second;
}
}
node* split(node* head) {
node* fast = head;
node* slow = head;
while (fast->next && fast->next->next) {
fast = fast->next->next;
slow = slow->next;
}
node* tmp = slow->next;
slow->next = NULL;
return tmp;
}
node* sort(node* head) {
if (head == NULL || head->next == NULL) {
return head;
}
node* second = split(head);
head = sort(head);
second = sort(second);
return merge(head, second);
}
int main() {
DLLista list;
input("input1.txt ", list);
list.printFront();
node* head = list.firstItem()->prev;
sort(head);
}
input1.txt:
6
1 2 6 5 4 3
expected output:
1 2 3 4 5 6

How to insert a node in a linked list after a given index

I am trying to insert a node at a both given index in a linked list and just at the end, but I don't understand the syntax or even conceptually what I am doing.
I have an insertTail function and an insertAfter function for both of these problems, but I'm not sure I am implementing them correctly.
void insertTail(T value) {
if (head == NULL) {
insertHead(value);
}
else {
T tailNode = Node(value);
Node* tempPtr = head;
while (tempPtr != NULL) {
tempPtr = tempPtr->next;
}
next = tailNode->data;
}
};
void insertAfter(T value, T insertionNode) {
Node* tempPtr = head;
while (tempPtr->data != insertionNode) {
tempPtr = tempPtr->next;
}
Node* afterNode = new Node(value);
afterNode->next = tempPtr->next;
tempPtr->next = afterNode;
};
My code won't even compile with what I have currently. It gives an error for the first line in the else statement in the insertTail function that reads
'initializing': cannot convert from 'LinkedList<std::string>::Node' to 'std::basic_string<char,std::char_traits<char>,std::allocator<char>>'
Both of your functions are implemented all wrong. They need to look more like this instead (assuming a single-linked list is being used):
void insertTail(T value) {
if (!head) {
insertHead(value);
}
else {
Node* tailNode = head;
while (tailNode->next) {
tailNode = tailNode->next;
}
tailNode->next = new Node(value);
}
}
void insertAfter(T value, Node *insertionNode) {
if (!insertionNode) {
insertTail(value);
}
else {
Node* newNode = new Node(value);
newNode->next = insertionNode->next;
insertionNode->next = newNode;
}
}

Linked list head pointer not getting updated when called by reference

I have written two functions to insert nodes in a Linked List. While one function (insertNth) updates the head pointer, the second one (sortedInsert) does not update the head pointer across function calls. The push function is taking a reference to the head pointer.
struct node
{
int data;
node *next;
};
void printList(node *head)
{
node *current = head;
while(current!=NULL)
{
cout<<current->data<<" ";
current = current->next;
}
}
void push(node* &head, int data)
{
node *newNode = new node();
newNode->data = data;
newNode->next = head;
head = newNode;
}
void insertNth(node *&head, int index, int val)
{
node *current = head;
int cnt = 0;
while(current!=NULL)
{
if(cnt == index)
{
if(cnt==0)
{
push(head, val);
}
else
{
push(current->next, val);
}
}
current=current->next;
cnt++;
}
}
void sortedInsert(node *head, int val)
{
node *current = head;
if(head != NULL && val < head->data)
{
node *newNode = new node();
push(head,val);
return;
}
while(current!=NULL)
{
if(current->data < val && current->next->data > val)
{
push(current->next, val);
return;
}
current = current->next;
}
}
int main()
{
node *head;
push(head, 3);
cout<<"\n";
printList(head);
cout<<"\nInsertNth: ";
insertNth(head,0, 2);
printList(head);
cout<<"\nsortedInsert: ";
sortedInsert(head, 1);
printList(head);
return 0;
}
I'm getting following as output:
3
InsertNth: 2 3
sortedInsert: 2 3
Why is the third line not printing 1 2 3?
//
Update
//
The correct SortedInsert is as follows:
void sortedInsert(node *&head, node *newNode)
{
node *current = head;
if(head == NULL || newNode->data < head->data)
{
newNode->next = head;
head = newNode;
return;
}
while(current!=NULL && current->next != NULL)
{
if(current->data < newNode->data && current->next->data > newNode->data)
{
newNode->next = current->next;
current->next = newNode;
return;
}
current = current->next;
}
if(current->next == NULL)
{
current->next = newNode;
newNode->next = NULL;
}
}
A sample was requested. Note that I did it as a template, but you could skip the template business and instead of a T* you can use struct node *. It's not general purpose, but might be easier to understand.
template <class T>
class MyLinkedList {
class Entry {
public:
Entry * previous;
Entry * next;
T * node;
}
Entry * head;
Entry * tail;
void push(T * nodeToPush) { pushBefore(head, nodeToPush); }
void insertNth(int whereToInsert, T * nodeToInsert) {
... find the nth Entry pointer
pushBefore(head, nodeToPush);
}
private:
void pushBefore(Entry *entry, T * nodeToPush) {
Entry *newEntry = new Entry();
newEntry->node = nodeToPush;
if (entry != NULL) {
newEntry->previous = entry->previous;
}
newEntry->next = entry;
entry->previous = newEntry;
if (head == entry) {
head = newEntry;
}
if (tail == NULL) {
tail = newEntry;
}
}
// Other methods as necessary, such as append, etc.
}
Other than passing in a pointer to the objects you're inserting into your linked list, at no point do you have to pass pointers around in a fashion where your methods are also performing side effects on those pointer. The class should know how to manage a class, and no weird passing of variables all over.
Performing side effects on your arguments should be done with GREAT caution. If you're passing an object to a method, then it's fair to manipulate the object. But I really don't like passing pointers and having methods modify the pointers themselves.
That IS going to lead to (at best) confusion.
Note: I did NOT test this code. It might not quite be perfect.

Reverse doubly-link list in C++

I've been trying to figure out how to reverse the order of a doubly-linked list, but for some reason, in my function void reverse() runs while loop once and then crashes for some reason. To answer some questions ahead, I'm self-teaching myself with my brothers help. This isn't all of the code, but I have a display() function which prints all nodes chronologically from start_ptr and a switch which activates certain functions like
case 1 : add_end(); break;
case 2 : add_begin(); break;
case 3 : add_index(); break;
case 4 : del_end(); break;
case 5 : del_begin(); break;
case 6 : reverse(); break;
This is the geist of my code:
#include <iostream>
using namespace std;
struct node
{
char name[20];
char profession[20];
int age;
node *nxt;
node *prv;
};
node *start_ptr = NULL;
void pswap (node *pa, node *pb)
{
node temp = *pa;
*pa = *pb;
*pb = temp;
return;
}
void reverse()
{
if(start_ptr==NULL)
{
cout << "Can't do anything" << endl;
}
else if(start_ptr->nxt==NULL)
{
return;
}
else
{
node *current = start_ptr;
node *nextone = start_ptr;
nextone=nextone->nxt->nxt;
current=current->nxt;
start_ptr->prv=start_ptr->nxt;
start_ptr->nxt=NULL;
//nextone=nextone->nxt;
while(nextone->nxt!= NULL)
{
pswap(current->nxt, current->prv);
current=nextone;
nextone=nextone->nxt;
}
start_ptr=nextone;
}
}
Try this:
node *ptr = start_ptr;
while (ptr != NULL) {
node *tmp = ptr->nxt;
ptr->nxt = ptr->prv;
ptr->prv = tmp;
if (tmp == NULL) {
end_ptr = start_ptr;
start_ptr = ptr;
}
ptr = tmp;
}
EDIT: My first implementation, which was correct but not perfect.
Your implementation is pretty complicated. Can you try this instead:
node * reverse(Node * start_ptr)
{
Node *curr = start_ptr;
Node * prev = null;
Node * next = null;
while(curr)
{
next = curr->nxt;
curr->nxt = prev;
curr->prv = next;
prev = curr;
curr = next;
}
return start_ptr=prev;
}
Here is my updated solution:
node * reverse()
{
node *curr = start_ptr;
node * prev = NULL;
node * next = NULL;
while(curr)
{
next = curr->nxt;
curr->nxt = prev;
curr->prv = next;
prev = curr;
curr = next;
}
return start_ptr=prev;
}
The logic was correct. But the issue was that I was accepting in input argument start_ptr. Which means that I was returning the local copy of it. Now it should be working.
You can simplify your reverse() quite a bit. I'd do something like this:
void reverse()
{
if(start_ptr == NULL)
{
cout << "Can't do anything" << endl;
}
else
{
node *curr = start_ptr;
while(curr != NULL)
{
Node *next = curr->next;
curr->next = curr->prev;
curr->prev = next;
curr = next;
}
start_ptr = prev;
}
}
Explanation: The basic idea is simply to visit each Node and swap the links to previous and next. When we move curr to the next Node, we need to store the next node so we still have a pointer to it when we set curr.next to prev.
Simple solution. reverses in less than half a number of total iterations over the list
template<typename E> void DLinkedList<E>::reverse() {
int median = 0;
int listSize = size();
int counter = 0;
if (listSize == 1)
return;
DNode<E>* tempNode = new DNode<E>();
/**
* A temporary node for swapping a node and its reflection node
*/
DNode<E>* dummyNode = new DNode<E>();
DNode<E>* headCursor = head;
DNode<E>* tailCursor = tail;
for (int i = 0; i < listSize / 2; i++) {
cout << i << "\t";
headCursor = headCursor->next;
tailCursor = tailCursor->prev;
DNode<E>* curNode = headCursor;
DNode<E>* reflectionNode = tailCursor;
if (listSize % 2 == 0 && listSize / 2 - 1 == i) {
/**
* insert a dummy node for reflection
* for even sized lists
*/
curNode->next = dummyNode;
dummyNode->prev = curNode;
reflectionNode->prev = dummyNode;
dummyNode->next = reflectionNode;
}
/**
* swap the connections from previous and
* next nodes for current and reflection nodes
*/
curNode->prev->next = curNode->next->prev = reflectionNode;
reflectionNode->prev->next = reflectionNode->next->prev = curNode;
/**
* swapping of the nodes
*/
tempNode->prev = curNode->prev;
tempNode->next = curNode->next;
curNode->next = reflectionNode->next;
curNode->prev = reflectionNode->prev;
reflectionNode->prev = tempNode->prev;
reflectionNode->next = tempNode->next;
if (listSize % 2 == 0 && listSize / 2 - 1 == i) {
/**
* remove a dummy node for reflection
* for even sized lists
*/
reflectionNode->next = curNode;
curNode->prev = reflectionNode;
}
/**
* Reassign the cursors to position over the recently swapped nodes
*/
tailCursor = curNode;
headCursor = reflectionNode;
}
delete tempNode, dummyNode;
}
template<typename E> int DLinkedList<E>::size() {
int count = 0;
DNode<E>* iterator = head;
while (iterator->next != tail) {
count++;
iterator = iterator->next;
}
return count;
}
I suggest maintaining a link to the last node.
If not, find the last node.
Traverse the list using the "previous" links (or in your case, prv).
There is no need to actually change the links around. Traversing using the prv pointer will automatically visit the nodes in reverse order.
Look at
valuesnextone=nextone->nxt->nxt;
Here nextone->nxt can be null.
Apart from that, try to use pointers to pointers in the swap function.
Your pswap function is wrong
your should swap the pointer not try to create temporary objects and swap them.
Should be like that (there might be other mistake later)
void pswap (node *&pa, node *&pb)
{
node* temp = pa;
pa = pb;
pb = temp;
return;
}
A very simple and O(n) solution using two pointers:
start = head of the doubly LL
struct node *temp, *s;
s = start;
while(s != NULL){
temp = s->prev;
s->prev = s->next;
s->next = temp;
s = s->prev;
}
//if list has more than one node
if(current != NULL){
start = temp->prev;
}
My code for reversing doubly linked list,
Node* Reverse(Node* head)
{
// Complete this function
// Do not write the main method.
if(head != NULL) {
Node* curr = head;
Node* lastsetNode = curr;
while(curr != NULL) {
Node* frwdNode = curr->next;
Node* prevNode = curr->prev;
if(curr==head) {
curr->next = NULL;
curr->prev = frwdNode;
lastsetNode = curr;
}
else {
curr->next = lastsetNode;
curr->prev = frwdNode;
lastsetNode = curr;
}
curr = frwdNode;
}
head = lastsetNode;
}
return head;
}
I thought I'd add a recursive solution here.
node* reverse_and_get_new_head(node* head) {
if (head == nullptr) { return nullptr; }
// This can be avoided by ensuring the initial,
// outer call is with a non-empty list
std::swap(head->prev, head->next);
if (head->prev == nullptr) { return head; }
return reverse_and_get_new_head(head->prev);
}
void reverse() {
start_ptr = reverse_and_get_new_head(start_ptr);
}