I'm fairly bad at coding so I really need some help as this homework is dued by Wednesday. I have seen mergesort normally split into three functions: (mergesort, sortedmerge, frontbacksplit, etc). But my professor's array based mergesort is done in one function so I'm assuming he wants us to only use one function as well for this linked list... (unless it is possible to implement a function within a function?) We have to write the function "struct listnode * mergesort(struct listnode *data)" and submit it to him. What I have done so far (I think) is splitting the linked list into 2 sub linked list but now I don't know how to "recursively" sort them.. Professor told us to write the function in C or C++, but the test code he provided us below is in C.
#include <stdio.h>
#include <stdlib.h>
struct listnode { struct listnode * next;
long value; } ;
//This is the function I need to write:
struct listnode * mergesort(struct listnode *data)
{ int temp, finished = 0;
struct listnode *i, *j, *tail, *head, *ahead, *bhead, *atail, *btail;
if ( a == NULL )
return;
head = data;
tail = head->next;
ahead = head;
bhead = tail;
i = ahead;
j = bhead;
tail = tail->next;
while ( tail !=NULL ) {
atail = tail;
i->next = atail;
i = i->next;
tail = tail->next;
btail = tail;
j->next = btail;
j = j->next;
tail = tail->next;
}
};
//Testing code provided by professor:
int main(void)
{
long i;
struct listnode *node, *tmpnode, *space;
space = (struct listnode *) malloc( 500000*sizeof(struct listnode));
for( i=0; i< 500000; i++ )
{ (space + i)->value = 2*((17*i)%500000);
(space + i)->next = space + (i+1);
}
(space+499999)->next = NULL;
node = space;
printf("\n prepared list, now starting sort\n");
node = mergesort(node);
printf("\n checking sorted list\n");
for( i=0; i < 500000; i++)
{ if( node == NULL )
{ printf("List ended early\n"); exit(0);
}
if( node->value != 2*i )
{ printf("Node contains wrong value\n"); exit(0);
}
node = node->next;
}
printf("Sort successful\n");
exit(0);
}
The general approach:
if( list contains 0 or 1 item)
return the list; // it is already sorted
split the list into halves;
mergesort( first part);
mergesort( second part);
merge sorted parts;
return the merged list;
A list contains 0 or 1 item condition:
head == NULL || head->next == NULL
To split the list, you need to find its middle:
ahead = atail = head; // first item
btail = head->next; // second item
while(btail->next != NULL) // anything left
{
atail = atail->next;
btail = btail->next;
if( btail->next)
btail = btail->next;
}
bhead = atail->next; // disconnect the parts
atail->next = NULL;
To merge two sorted lists:
if(ahead->value <= bhead->value) // set the head of resulting list
head = tail = ahead, ahead = ahead->next;
else
head = tail = bhead, bhead = bhead->next;
while(ahead && bhead)
if(ahead->value <= bhead->value) // append the next item
tail = tail->next = ahead, ahead = ahead->next;
else
tail = tail->next = bhead, bhead = bhead->next;
if(ahead) // once one part got exhausted append the remaining other part
tail->next = ahead;
else
tail->next = bhead;
Related
Not sure if there is a simple and better way to implement this function?
void insert(Node* &head, int element, int position) {
Node* current = new Node;
current->data = element;
current->next = NULL;
if (position == 1) {
current->next = head;
head = current;
return;
}
else {
Node * current2 = head;
for (int i = 0; i < position - 2; i++) {
current2 = current2->next;
}
current2->next = current2->next;
current2->next = current;
}
}
A better way would be to make this function without null pointer access. You are missing all the necessary error checking.
But if you have to use this function you are already doing something wrong. The operation takes O(n) time. And if you build your list using only this function then you already have O(n^2) time. Using a balanced tree or heap would give you O(n * log n) time which makes a huge difference even for relatively small n. So think again why you need to insert at a given position and think about more suitable data structures.
A simpler implementation, and actually used in real code a lot, is to implement insert_before(before, data) or insert_after(after, data) with a doubly linked list. Both of which would get an item in the list and a new item to insert and place the new item before or after the old one on O(1) time.
Some boundary check is needed (please find the comments inline):
int listLen(Node *head)
{
int len = 0;
while (head != nullptr)
{
len++;
head = head->next;
}
return len;
}
void insert(Node* &head, int element, int position)
{
if (head == nullptr) // do nothing if head is nullptr
return;
if (position < 0) // insert to the begin if position is negative
position = 0;
else
{
int len = listLen(head);
if (len < position) // position is out of range, insert to the end
{
position = len;
}
}
if (position == 0)
{
Node *next = head;
head = new Node(element);
head->next = next;
}
else
{
int curPos = 0;
Node *curNode = head;
while (curPos < position - 1) // move to position
{
curNode = curNode->next;
curPos++;
}
Node *next = curNode->next; // do insertion
curNode->next = new Node(element);
curNode->next->next = next;
}
}
I have been struggling for hours on end with this problem. My goal is to sort a linked list using only pointers (I cannot place linked list into vec or array and then sort). I am given the pointer to the head node of the list. The only methods i can call on the pointers are head->next (next node) and head->key (value of int stored in node, used to make comparisons). I have been using my whiteboard excessively and have tried just about everything I can think of.
Node* sort_list(Node* head)
{
Node* tempNode = NULL;
Node* tempHead = head;
Node* tempNext = head->next;
while(tempNext!=NULL) {
if(tempHead->key > tempNext->key) {
tempNode = tempHead;
tempHead = tempNext;
tempNode->next = tempNode->next->next;
tempHead->next = tempNode;
tempNext = tempHead->next;
print_list(tempHead);
}
else {
tempHead = tempHead->next;
tempNext = tempNext->next;
}
}
return head;
}
Since it's a singly linked list, we can do: (psuedo code)
bool unsorted = true;
while(unsorted) {
unsorted = false;
cur = head;
while(cur != nullptr) {
next = cur->next;
if(next < cur) {
swap(cur, next)
unsorted = true;
}
cur = cur->next;
}
}
I know its late but I also search for it but didn't get one so I make my own. maybe it will help someone.
I am using bubble sort (kind of sort algorithm) to sort data in a single linked list. It just swapping the data inside a node.
void sorting(){
Node* cur1 = head;
Node* cur2 = head;
for (int i = 0; i < getSize(); i++) {
for (int j = 0; j < getSize() - 1; j++) {
if (cur1->data < cur2->data) {
int temp = cur1->data;
cur1->data = cur2->data;
cur2->data = temp;
}
cur2 = cur2->next;
}
cur2 = head;
cur1 = head->next;
for (int k = 0; k < i; k++) {
cur1 = cur1->next;
}
}
}
Don't feel bad this is a lot harder than it sounds. If this were in an array it would be considerably easier. If the list were doubly linked it would be easier. Take a look at this code, it implements an insertion sort
struct Node {
int key;
Node *next;
} *NodePtr;
// do a simple selection sort http://en.wikipedia.org/wiki/Selection_sort
Node* sort_list(Node* head) {
Node *top = nullptr; // first Node we will return this value
Node *current = nullptr;
bool sorted = false;
while (sorted == false) {
// we are going to look for the lowest value in the list
Node *parent = head;
Node *lowparent = head; // we need this because list is only linked forward
Node *low = head; // this will end up with the lowest Node
sorted = true;
do {
// find the lowest valued key
Node* next = parent->next;
if (parent->key > next->key) {
lowparent = parent;
low = next;
sorted = false;
}
parent = parent->next;
} while (parent->next != nullptr);
if (current != nullptr) { // first time current == nullptr
current->next = low;
}
// remove the lowest item from the list and reconnect the list
// basically you are forming two lists, one with the sorted Nodes
// and one with the remaining unsorted Nodes
current = low;
if (current == head) { head = current->next; }
lowparent->next = low->next;
current->next = nullptr;
if (top == nullptr) {
top = current;
}
};
current->next = head;
return top;
}
int _tmain(int argc, _TCHAR* argv []) {
Node nodes[4];
nodes[0].key = 3;
nodes[1].key = 4;
nodes[2].key = 5;
nodes[3].key = 1;
nodes[0].next = &nodes[1];
nodes[1].next = &nodes[2];
nodes[2].next = &nodes[3];
nodes[3].next = nullptr;
auto sortedNodes = sort_list(&nodes[0]);
return 0;
}
Use a recursive approach as it is the easiest way of dealing with linked structures:
Pseudocode:
SORT(head)
if (head->next == null)
return
tempNode = head->next
SORT(tempNode)
if (tempNode->value < head->value)
SWAP(head, tempNode)
SORT(head)
return
so the let's say you have 5 4 3 2 1
1) 5 4 3 1 2
2) 5 4 1 3 2
3) 5 4 1 2 3
4) 5 1 4 2 3
5) 5 1 2 4 3
...
n) 1 2 3 4 5
Assume the Node like this:
struct Node
{
Node *next;
int key;
Node(int x) : key(x), next(NULL) {}
};
use insertion sort algorithm to sort the List:
Node* sort_list(Node* head)
{
Node dumy_node(0);
Node *cur_node = head;
while (cur_node)
{
Node *insert_cur_pos = dumy_node.next;
Node *insert_pre_pos = NULL;
while (insert_cur_pos)
{
if (insert_cur_pos->key > cur_node->key)
break;
insert_pre_pos = insert_cur_pos;
insert_cur_pos = insert_cur_pos->next;
}
if (!insert_pre_pos)
insert_pre_pos = &dumy_node;
Node *temp_node = cur_node->next;
cur_node->next = insert_pre_pos->next;
insert_pre_pos->next = cur_node;
cur_node = temp_node;
}
return dumy_node.next;
}
int swapNode( node * &first, node * &second)
{
//first we will declare the
//previous of the swaping nodes
node *firstprev=NULL;
node*secprev=NULL;
node*current=head;
//set previous first
while(current->next!=first)
{
current=current->next;
}
firstprev=current;
//seting 2nd previous
while(current->next!=second)
{
current=current->next;
}
// swap datas, assuming the payload is an int:
int tempdata = first->data;
first->data = second->data;
second->data = tempdata;
//swaping next of the nodes
firstprev->next=second;
secprev->next=first;
}
Here is my Merge sort realisation, with O(N*logN) time complexity and constant additional space. Uses C++11
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
typedef pair<ListNode*, ListNode*> PP;
class Solution {
public:
ListNode* sortList(ListNode* head) {
if (head==nullptr)return head;
if (head->next==nullptr) return head;
if (head->next->next==nullptr){
if (head->val<=head->next->val){
return head;
}
else {
ListNode* second=head->next;
second->next=head;
head->next=nullptr;
return second;
}
}else {
PP splitted=split(head);
return merge(sortList(splitted.first),sortList(splitted.second));
}
}
private:
ListNode* merge(ListNode* l1, ListNode* l2) {
ListNode * head=new ListNode(0);
ListNode * current=head;
if (l1==nullptr)return l2;
if (l2==nullptr)return l1;
do {
if (l1->val<=l2->val){
current->next=l1;
l1=l1->next;
}else{
current->next=l2;
l2=l2->next;
}
current=current->next;
}while (l1!=nullptr && l2!=nullptr);
if (l1==nullptr)current->next=l2;
else current->next=l1;
return head->next;
}
PP split(ListNode* node){
ListNode* slow=node;
ListNode* fast=node;
ListNode* prev;
while(fast!=nullptr){
if (fast->next!=nullptr){
prev=slow;
slow=slow->next;
fast=fast->next;
}else break;
if(fast->next!=nullptr){
fast=fast->next;
}
else break;
}
prev->next=nullptr;
return {node,slow};
}
};
Use std::list<T>::sort method. Or if you're being precocious, std::forward_list<T>::sort.
Why re-invent the wheel.
The code that I have made is this:
struct node
{
int value;
node *prev;
node *next;
};
void play()
{
node *head = NULL, *temp = NULL, *run = NULL;
for (int x = 1; x > 10; x++)
{
temp = new node(); //Make a new node
temp -> value = x; //Assign value of new node
temp -> prev = NULL; //Previous node (node before current node)
temp -> next = NULL; //Next node (node after current node)
}
if (head == NULL)
{
head = temp; //Head -> Temp
}
else
{
run = head; //Run -> Head
while (run -> next != NULL)
{
run = run -> next; //Go from node to node
}
run -> next = temp; //If next node is null, next node makes a new temp
temp -> prev = run;
}
run = head; //Play from start again
while (run != NULL) //Printing
{
printf("%d\n", run -> value);
run = run -> next;
}
}
int main()
{
play();
system ("pause");
return 0;
}
However, it is not working. There is no output (completely blank). How can I get this linked list to print properly? I want it to output:
1 2 3 4 5 6 7 8 9 10
Other options that I have is to make another separate function for the printing or move the whole thing to int main but I have already tried that and it still does not output anything.
For starters there is a typo in the condition of the first for-loop in the function
for (int x = 1; x > 10; x++)
^^^^^^
There must be
for (int x = 1; x <= 10; x++)
^^^^^^
Secondly the code that tries to add a new node to the list is outside the for-loop. So only the last allocated node will be added to the list. You have to place the code inside the loop.
Also if here is a double-linked list then it is desirable to have a tail node to which a new node will be appended.
And you should free all allocated memory before exiting the function.
The function can look the following way as it is shown in the demonstrative program.
#include <iostream>
#include <cstdlib>
struct node
{
int value;
node *prev;
node *next;
};
void play()
{
const int N = 10;
node *head = nullptr, *tail = nullptr;
for (int i = 0; i < N; i++)
{
node *temp = new node{ i + 1, tail, nullptr };
if (tail == nullptr)
{
head = tail = temp;
}
else
{
tail = tail->next = temp;
}
}
for (node *current = head; current != nullptr; current = current->next)
{
std::cout << current->value << ' ';
}
std::cout << std::endl;
while (head != nullptr)
{
node *temp = head;
head = head->next;
delete temp;
}
tail = head;
}
int main()
{
play();
// system("pause");
return 0;
}
The program output is
1 2 3 4 5 6 7 8 9 10
You could make the function more flexible by adding one parameter that specifies the number of nodes in the created list instead of using the magic number 10.
For example
void play( int n )
{
node *head = nullptr, *tail = nullptr;
for (int i = 0; i < n; i++)
{
node *temp = new node{ i + 1, tail, nullptr };
if (tail == nullptr)
{
head = tail = temp;
}
else
{
tail = tail->next = temp;
}
}
for (node *current = head; current != nullptr; current = current->next)
{
std::cout << current->value << ' ';
}
std::cout << std::endl;
while (head != nullptr)
{
node *temp = head;
head = head->next;
delete temp;
}
tail = head;
}
In this case the function can be called for example like
play( 10 );
or
play( 20 );
and so on.
When you run play(), you create 10 new nodes, but you store them nowhere before creating a new one. Thus, you "lose" all the nodes - except the last one, which is still in temp.
Instead, you should do something like:
for (int x = 1; x < 10; x++)
{
if (temp == nullptr) {
temp = new node();
temp -> value = x;
temp -> prev = nullptr;
temp -> next = nullptr;
head = temp;
} else {
temp -> next = new node();
temp -> next -> value = x;
temp -> next -> prev = temp;
temp -> next -> next = nullptr;
temp = temp -> next
}
}
Then, you can print your linked list as you already do:
run = head; //Play from start again
while (run != nullptr) //Printing
{
printf("%d\n", run -> value);
run = run -> next;
}
As noticed by #Vlad from Moscow, don't forget to free allocated memory before exiting the function.
Note that I use nullptr instead of NULL. It's a C++11 keyword that replaces NULL. Explications are here.
First your program never enters the for loop. Your loop is equivalent to:
int x=1;
while(x>10) { // always false
// do stuff
x++;
}
Therefore, temp is NULL, head is initialize to NULL and nothing happens.
Second, the initialization of your list is not in the loop, so at most only the head would be initialized. Move the closing bracket of the for loop at the end of your function (and adjust indentations etc).
In a second time, and if your compiler allows it, you might consider using more C++ idioms instead of C idioms (if your goal is to learn C++), using nullptr, cout, smart pointers... but it's an other story!
I was reading about Quicksort, and most of the codes I found were extremely complicated. So, I decided to make one on my own, wherein I considered the first element as pivot and then calling sort function recursively on the rest of the list.
I made the following code for Quicksort. It's as follows:
#include <iostream>
using namespace std;
class node
{
public:
int data;
node * next;
};
node * newnode (int x);
void quicksort(node ** begin, node ** end);
int main (void)
{
int foo,n,i,j,k;
node * temp;
node * head = NULL;
node * tail = NULL;
cout<<"How many nodes do you want to insert\n";
cin>>n;
cout<<"Enter data of linked list\n";
for ( i = 0; i < n; i++ )
{
cin>>foo;
node * bar;
if (head == NULL)
{
head = newnode(foo);
tail = head;
}
else
{
bar = newnode(foo);
tail->next = bar;
tail = bar;
}
}
cout<<"The linkedlist that you entered is as follows\n"; // Taking input
temp = head;
node * prev = NULL;
while (temp != NULL)
{
cout<<temp->data<<"\t";
prev = temp;
temp = temp->next;
}
cout<<"\n";
cout<<"Sorting the linked list now\n"; // Calling sort function
quicksort(&head,&prev);
temp = head;
while (temp != NULL) // Printing output
{
cout<<temp->data<<"\t";
temp = temp->next;
}
return 0;
}
node * newnode (int x) // for allocating a new node
{
node * foo = new node;
foo->data = x;
foo->next = NULL;
return foo;
}
void quicksort(node ** begin, node ** end) // actual sort function
{
if (*begin == *end)
return;
node * pivot = *begin;
node * temp = *begin;
temp = temp->next; // for pointing to next element
while (temp != *end)
{
if (temp->data < pivot->data)
{
node * temp1 = *begin; // swapping the two nodes if less than pivot
*begin = temp;
temp = temp->next;
(*begin)->next = temp1;
}
else
temp = temp->next; else moving to next
}
quicksort(begin,&pivot); // calling for remaining elements (first half)
quicksort(&(pivot->next),end); for second half
}
Howeever, when I run this, on input as 5 4 3 2 1, it sort of goes into an infinite loop. I tried running it through a debugger, but it get's extremely complicated to the extent that I lose my way in between. Can you point out the error where I might be going wrong? Thanks!
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);
}