I've been struggling with this last function (list_copy_front). The function is for a linked list, it is supposed to return the value of the head pointer for a new list that contains copies of the first n nodes that the source pointer points to. Also if there is less than n nodes in the source then just copy all. Currently, when I run it as is I get a nasty Segmentation Fault SIGSEGV error. The debugger says the error happens at "Node *cursor = source_ptr-> link; Any help would be greatly appreciated, thank you.
Here is some relevant info,
struct Node
{
typedef int Item;
Item data;
Node *link;
};
void list_tail_attach(Node*& head_ptr, const Node::Item& entry);
Node* list_copy_front(Node* source_ptr, size_t n);
void list_tail_attach(Node*& head_ptr, const Node::Item& entry)
{
Node *last = new Node;
last->data = entry;
last->link = NULL;
if(head_ptr == NULL)
{
head_ptr = last;
}
else
{
Node *temp = new Node;
temp = head_ptr;
while(temp->link != NULL)
{
temp = temp->link;
}
temp->link = last;
}
}
Node* list_copy_front(Node* source_ptr, size_t n)
{
Node *new_head_ptr = new Node;
Node *cursor = source_ptr->link;
size_t i = 0;
for(i = 0; i < n; i++)
{
list_tail_attach(new_head_ptr, cursor->data);
cursor = cursor->link;
}
return new_head_ptr;
}
Here's the Main test for the function
int test4()
{
Node* list = NULL; // an empty list
Node* copy = NULL;
copy = list_copy_front(list, 3);
if(copy != NULL)
{
cout << "list_copy_front function doesn't work for copying empty list\n";
return 0;
}
for(int i = 1; i <= 4; i++)
list_tail_attach(list, i);
// list contains 1, 2, 3, 4
copy = list_copy_front(list, 3);
if(list_length(copy) != 3 || copy->data != 1 || copy->link->data != 2 || copy->link->link->data != 3 )
{
cout << "list_copy_front function doesn't work\n";
return 0;
}
copy->link->data = 100;
if(list->link->data == 100)
{
cout << "list_copy_front function doesn't work.\n";
return 0;
}
list_clear(copy);
copy = list_copy_front(list, 6);
if(list_length(copy) != 4)
{
cout << "list_copy_front function doesn't work\n";
return 0;
}
cout << "list_copy_front passes the test\n";
list_clear(list);
for(int i = 1; i <= 3; i++)
list_head_insert(list, i);
// list contains 3, 2, 1
list_copy(list, copy);
if(list_length(copy) != 3 || copy->data != 3 || copy->link->data != 2 || copy->link->link->data != 1 )
{
cout << "list_copy function doesn't work\n";
return 0;
}
cout << "list_copy function passes the test\n";
return 2;
}
Edit 3
So far here's what I'm working with I appreciate the comments so far it's just not quite working out. Which is probably my fault for not explaining better.
void list_tail_attach(Node*& head_ptr, const Node::Item& entry)
{
Node *last = new Node; // Creates new Node
last->data = entry; // Points last to data
last->link = NULL;
if(last == NULL)
{
return;
}
if(head_ptr == NULL)
{
head_ptr = last;
}
else
{
Node *temp = head_ptr;
while(temp->link != NULL)
{
temp = temp->link;
}
temp->link = last;
}
}
Node* list_copy_front(Node* source_ptr, size_t n)
{
if(source_ptr == NULL)
{
return NULL;
}
Node *new_head_ptr = new Node;
Node *cursor = source_ptr;
size_t i = 0;
while(cursor!= NULL && i < n)
{
list_tail_attach(new_head_ptr, cursor->data);
cursor = cursor->link;
i++;
}
return new_head_ptr;
}
I am not allowed to change the way the function takes it's input so, that's why I left Node *last.
I left list_tail_attach(new_head_ptr, cursor->data) because without it I get an invalid conversion error. However when I run the above code I still receive an SIGSEGV error for while(temp->link != NULL) in list_tail_attach and on list_tail_attach(new_head_ptr, cursor->data); in list_copy_front.
Thank you if you are able to comment further
The first test case
Node* list = NULL; // an empty list
Node* copy = NULL;
copy = list_copy_front(list, 3);
gives Node* source_ptr == NULL and expects your function to handle it gracefully.
The function code soon tries to dereference NULL
Node *cursor = source_ptr->link;
The result is a segfault.
First is list_tail_attach, this function I assumed to be attaching an existing Node into a linked list. If the linked list is null then the Node become the head
void list_tail_attach(Node *& head_ptr, Node *& entry)
{
if (entry == NULL) {
return;
}
if (head_ptr == NULL)
{
head_ptr = entry;
}
else
{
Node *temp = head_ptr;
while (temp->link != NULL)
{
temp = temp->link;
}
temp->link = entry;
}
}
I changed the entry into a reference to a pointer to made it easier.
Ok, now move on to the list_copy_front
Node * list_copy_front(Node* source_ptr, size_t n)
{
if (source_ptr == NULL) {
return NULL;
}
Node * new_head_ptr = new Node;
Node * cursor = source_ptr;
size_t i = 0;
while(cursor != NULL && i < n){
list_tail_attach(new_head_ptr, cursor);
cursor = cursor->link;
i++;
}
return new_head_ptr;
}
You have to guard the source_ptr in case it is null.
To attach a new Node
for (int x = 0; x < 5; x++) {
Node * tmp = new Node();
tmp->data = x;
tmp->link = NULL;
list_tail_attach(list, tmp);
}
My professor helped me out with the correct solution. For anyone who views this in the future...
Node* list_copy_front(Node* source_ptr, size_t n)
{
if(source_ptr == NULL) // Takes care of NULL case
{
return NULL;
}
Node *new_head_ptr = NULL; // Creates new head and ensures NULL
Node *cursor = source_ptr; // Sets temp Node = to source
size_t i = 0; // Initializes temp variable
while(cursor!= NULL && i < n) // Loop that continues while n is bigger than i and it is not NULL
{
list_tail_attach(new_head_ptr, cursor->data);
cursor = cursor->link; // Attaches to new list
i++; // Increases count
}
return new_head_ptr;
}
The line that needed to be changed was
Node * new_head_ptr = new Node;
to
Node * new_head_ptr = NULL;
Related
Please help me find what is wrong with my code
(1).
You are given a Singly Linked List with N nodes where each node next pointing to its next node. You are also given M random pointers , where you will be given M number of pairs denoting two nodes a and b i.e. a->arb = b.
The task is to complete the function copyList() which takes one argument the head of the linked list to be cloned and should return the head of the cloned linked list.
NOTE : If their is any node whose arbitrary pointer is not given then its by default null.
I tried to write code for the above problem..but it is not working
// { Driver Code Starts
#include <bits/stdc++.h>
using namespace std;
struct Node {
int data;
Node *next;
Node *arb;
Node(int x) {
data = x;
next = NULL;
arb = NULL;
}
};
void print(Node *root) {
Node *temp = root;
while (temp != NULL) {
int k;
if (temp->arb == NULL)
k = -1;
else
k = temp->arb->data;
cout << temp->data << " " << k << " ";
temp = temp->next;
}
}
Node *copyList(Node *head);
void append(Node **head_ref, Node **tail_ref, int new_data) {
Node *new_node = new Node(new_data);
if (*head_ref == NULL) {
*head_ref = new_node;
} else
(*tail_ref)->next = new_node;
*tail_ref = new_node;
}
bool validation(Node *head, Node *res, Node *cloned_addr,
Node *generated_addr) {
if (generated_addr == cloned_addr) return false;
Node *temp1 = head;
Node *temp2 = res;
int len1 = 0, len2 = 0;
while (temp1 != NULL) {
len1++;
temp1 = temp1->next;
}
while (temp2 != NULL) {
len2++;
temp2 = temp2->next;
}
/*if lengths not equal */
if (len1 != len2) return false;
temp1 = head;
temp2 = res;
while (temp1 != NULL) {
if (temp1->data != temp2->data) return false;
if (temp1->arb != NULL and temp2->arb != NULL) {
if (temp1->arb->data != temp2->arb->data) return false;
} else if (temp1->arb != NULL and temp2->arb == NULL)
return false;
else if (temp1->arb == NULL and temp2->arb != NULL)
return false;
temp1 = temp1->next;
temp2 = temp2->next;
}
return true;
}
/* Driver program to test above function*/
int main() {
int T, i, n, l, k;
Node *generated_addr = NULL;
/*reading input stuff*/
cin >> T;
while (T--) {
generated_addr = NULL;
struct Node *head = NULL, *tail = NULL;
cin >> n >> k;
for (i = 1; i <= n; i++) {
cin >> l;
append(&head, &tail, l);
}
for (int i = 0; i < k; i++) {
int a, b;
cin >> a >> b;
Node *tempA = head;
int count = -1;
while (tempA != NULL) {
count++;
if (count == a - 1) break;
tempA = tempA->next;
}
Node *tempB = head;
count = -1;
while (tempB != NULL) {
count++;
if (count == b - 1) break;
tempB = tempB->next;
}
// when both a is greater than N
if (a <= n) tempA->arb = tempB;
}
/*read finished*/
generated_addr = head;
Node *res = copyList(head);
Node *cloned_addr = res;
cout << validation(head, res, cloned_addr, generated_addr) << endl;
}
return 0;
}
// } Driver Code Ends
/* the node structure is as follows
struct Node {
int data;
Node *next;
Node *arb;
Node(int x) {
data = x;
next = NULL;
arb = NULL;
}
};
*/
// Should return the head of the copied linked list the
// output will be 1 if successfully copied
Node *copyList(Node *head) {
if(!head)
return nullptr;
Node*q=head;
Node*clone=new Node(q->data);
clone->next=0;
clone->arb=q->arb;
Node*p=clone;
Node*r=q;
q=q->next;
while(q)
{
r->next=p;
p->next=new Node(q->data);
p=p->next;
p->next=0;
p->arb=q->arb;
r=q;
q=q->next;
}
r->next=p;
p=clone;
while(p)
{
if(p->arb)
p->arb=p->arb->next;
p=p->next;
}
return clone;
}
The pointers inside the list cannot be assigned until you have constructed the cloned list itself, because until then the nodes to point will not exist.
Therefore, you need two iterations: the first one to clone the list and make a dictionary that associates the original node with the clone, and the second one to update the pointers. The code would look like this:
Node *copyList(Node *head) {
if(!head)
return nullptr;
Node* it1 = head;
Node* clone = new Node;
Node* it2 = clone;
std::map<Node*, Node*> nodeDict;
nodeDict[nullptr] = nullptr;
// first iteration: create the list and the values
while(it1){
it2->data = it1->data;
nodeDict[it1] = it2;
it1 = it1->next;
it2->next = it1 ? new Node: nullptr;
it2 = it2->next;
}
// second iteration: connect the nodes
it1 = head;
it2 = clone;
while(it1){
it2->arb = nodeDict[it1->arb];
it1 = it1->next;
it2 = it2->next;
}
return clone;
}
I am writing a program that modifies a linked list. The problem I am having is when inserting nodes into the linked list. The first few nodes are inserted and moved properly, but when reaching the end of the linked list some nodes are either removed or not displayed.
Function for inserting
void LinkedList::insert(int num, int pos)
{
Node *temp1 = new Node;
temp1->data = num;
temp1->next = NULL;
if(pos == 0)
{
temp1->next = head;
head = temp1;
return;
}
Node *temp2 = head;
for(int i = 0; i < pos-1; i++)
{
temp2 = temp2->next;
}
temp1->next = temp2->next;
temp2->next = temp1;
}
Node structure
struct Node
{
int data;
Node *next;
};
int size;
Node *head, *tail;
Driver code
nums.insert(1, 0); // 1 in location 0
nums.insert(5, 4); // 5 in location 4
nums.insert(3, 7); // 3 in location 7
List before insert
8 6 7 8 0 9
List after insert
1 8 6 7 5 8
Expected after insert
1 8 6 7 5 8 0 9 3
Would the values excluded from being display needed to be stored and inserted afterwards? Or is the inserting itself not being coded properly/missing elements?
Thanks for your help.
Full code
#include "linkedlist.h"
LinkedList::LinkedList()
{
head = nullptr;
tail = nullptr;
size = 0;
}
LinkedList::~LinkedList()
{
if(head != nullptr)
{
Node *temp;
while(head != nullptr)
{
temp = head->next;
// deletes head
delete head;
// goes to next element
head = temp;
}
}
}
void LinkedList::display()
{
Node *temp = head;
for(int i = 0; i < size; i++)
{
cout << temp->data << "\t";
temp = temp->next;
}
cout << endl;
}
void LinkedList::append(int num)
{
// list is empty
if(head == nullptr)
{
head = new Node;
head->data = num;
head->next = nullptr;
// sets tail to head
tail = head;
}
else
{
// creates new node
Node *temp = new Node;
// sets new node data
temp->data = num;
temp->next = nullptr;
// sets previous tail link to new node
tail->next = temp;
// sets this node to new tail
tail = temp;
}
// increments size
size++;
}
void LinkedList::pop()
{
if(size > 1)
{
Node *temp = head;
// loops to node before tail
while(temp->next->next != nullptr)
{
temp = temp->next;
}
// deletes tail
delete tail;
// sets new tail
tail = temp;
tail->next = nullptr;
}
// if there's only one item
else if(size == 1)
{
Node *temp = tail;
// head and tail are now null
head = nullptr;
tail = nullptr;
// deletes node
delete temp;
}
size--;
}
int LinkedList::min()
{
int min = head->data;
struct Node *temp = head;
while(temp != nullptr)
{
if(min > temp->data)
{
min = temp->data;
}
temp = temp->next;
}
return min;
}
int LinkedList::max()
{
int max = head->data;
struct Node *temp = head;
while(temp != nullptr)
{
if(max < temp->data)
{
max = temp->data;
}
temp = temp->next;
}
return max;
}
int LinkedList::mean()
{
int sum = 0;
int average = 0;
struct Node *temp = head;
while(temp != nullptr)
{
sum += temp->data;
temp = temp->next;
}
average = sum / size;
return average;
}
void LinkedList::sort()
{
Node *current1 = head;
Node *current2 = head;
for(int i = 0; i < size; i++)
{
for(int j = 0; j < size - 1; j++)
{
if(current1->data < current2->data)
{
int temp = current1->data;
current1->data = current2->data;
current2->data = temp;
}
current2 = current2->next;
}
current2 = head;
current1 = head->next;
for(int p = 0; p < i; p++)
{
current1 = current1->next;
}
}
}
void LinkedList::reverse()
{
Node *current1 = head;
Node *current2 = head;
for(int i = 0; i < size; i++)
{
for(int j = 0; j < size - 1; j++)
{
if(current1->data > current2->data)
{
int temp = current1->data;
current1->data = current2->data;
current2->data = temp;
}
current2 = current2->next;
}
current2 = head;
current1 = head->next;
for(int p = 0; p < i; p++)
{
current1 = current1->next;
}
}
}
int LinkedList::linearSearch(int key)
{
Node *search = nullptr;
Node *temp = head;
Node *current = head;
int count = 0;
while(current != NULL && current->data != key)
{
count++;
temp = current;
current = current->next;
}
if(current != NULL)
{
search = current;
current = current->next;
}
key = count;
return key;
}
void LinkedList::insert(int num, int pos)
{
Node *temp1 = new Node;
temp1->data = num;
temp1->next = NULL;
if(pos == 0)
{
temp1->next = head;
head = temp1;
return;
}
Node *temp2 = head;
for(int i = 0; i < pos-1; i++)
{
temp2 = temp2->next;
}
temp1->next = temp2->next;
temp2->next = temp1;
}
You have a size member that your display function uses, but you never increment it in insert. So while the element gets added, you don't increase the size of the list.
Reading your whole code and getting to the solution may consume lot of time but if you want i have a code ready which is properly working. If you wanted to use this. Please go for it and also, please feel free to ask my anything though this link
#include <iostream>
using namespace std;
struct node
{
int data;
node *next;
};
class linked_list
{
private:
node *head,*tail;
public:
linked_list()
{
head = NULL;
tail = NULL;
}
void add_node(int n)
{
node *tmp = new node;
tmp->data = n;
tmp->next = NULL;
if(head == NULL)
{
head = tmp;
tail = tmp;
}
else
{
tail->next = tmp;
tail = tail->next;
}
}
node* gethead()
{
return head;
}
static void display(node *head)
{
if(head == NULL)
{
cout << "NULL" << endl;
}
else
{
cout << head->data << endl;
display(head->next);
}
}
static void concatenate(node *a,node *b)
{
if( a != NULL && b!= NULL )
{
if (a->next == NULL)
a->next = b;
else
concatenate(a->next,b);
}
else
{
cout << "Either a or b is NULL\n";
}
}
};
int main()
{
linked_list a;
a.add_node(1);
a.add_node(2);
linked_list b;
b.add_node(3);
b.add_node(4);
linked_list::concatenate(a.gethead(),b.gethead());
linked_list::display(a.gethead());
return 0;
}
Update. its working for 65,519 in the FOR LOOP. If i increase it to 65,520, it fails. Completely strange.
This program is not working for large inputs. It is perfect for small inputs. I am getting an exception on Xcode.
Thread 1 : EXC_BAD_ACCESS (code=2, address = 0x7fff5f3fffb8).
Kindly let me know how I can bypass this strange error.
#include <stdio.h>
#include <stdlib.h>
#include <iostream>
using namespace std;
typedef struct Node * nodePtr;
struct Node{
int data;
nodePtr next;
};
nodePtr globalHead;
void partition(nodePtr head, nodePtr *front, nodePtr *back){
nodePtr fast;
nodePtr slow;
if (head == NULL || head->next == NULL){
*front = head; // &a
*back = NULL; // &b
}else{
slow = head;
fast = head->next;
while(fast != NULL){
fast = fast->next;
if(fast != NULL){
slow = slow->next;
fast = fast->next;
}
}
*front = head; // a
*back = slow->next; // b
slow->next = NULL;
//printList(*front);
//printList(*back);
}
}
nodePtr mergeLists(nodePtr a, nodePtr b){
nodePtr mergedList = NULL;
if (a == NULL){
return b;
}else if (b == NULL){
return a;
}
try {
if (a->data <= b->data){
mergedList = a;
mergedList->next = mergeLists(a->next, b);
}else{
mergedList = b;
mergedList->next = mergeLists(a, b->next);
}
}
catch (int e) {
cout << "Error is . . " << e << endl;
}
return mergedList;
}
void mergeSort(nodePtr *source){
nodePtr head = *source;
nodePtr a = NULL;
nodePtr b = NULL;
if(head == NULL || head->next == NULL){
return;
}
partition(head, &a, &b);
mergeSort(&a);
mergeSort(&b);
*source = mergeLists(a, b);
}
void push(nodePtr *head, int data){
nodePtr newNode = (nodePtr) malloc(sizeof(struct Node));
newNode->data = data;
newNode->next = NULL;
if ((*head) == NULL){
*head = newNode;
globalHead = *head;
}else{
(*head)->next = newNode;
*head = newNode;
}
}
void printList(nodePtr head){
nodePtr current = head;
while(current != NULL){
printf("%d ",current->data);
current = current->next;
}
printf("\n");
}
// *head = head in the main function,
// it is only there to connect the two and
// not let make the function return anything
// passed by reference
// globalHead points to the start of the linked list
// if you are passing the address over here you have to
// make a double pointer over there in the function
int main(void)
{
nodePtr head = NULL;
// linked list is formed from top to bottom fashion
// push is done in constant time O(1)
long long int i;
//Pushing 200,000 Elements to the Linked List.
for(i=1 ; i<=200000 ; i++) {
push(&head, rand()%200000);
}
printList(globalHead);
mergeSort(&globalHead);
cout << "After Sorting . . \n";
printList(globalHead);
return 0;
}
Using recursion mergeLists() is the issue, it will call itself for every node on the list. Try changing the code so that the code loops and appends nodes to the initially empty mergeList, using a second pointer to node, or optionally a pointer to pointer to node which is initially set to &mergeList. For example, using the name pMerge instead of mergeList:
Node * mergeLists(Node *a, Node *b)
{
Node *pMerge = NULL; // ptr to merged list
Node **ppMerge = &pMerge; // ptr to pMerge or prev->next
if(a == NULL)
return b;
if(b == NULL)
return a;
while(1){
if(a->data <= b->data){ // if a <= b
*ppMerge = a;
a = *(ppMerge = &(a->next));
if(a == NULL){
*ppMerge = b;
break;
}
} else { // b <= a
*ppMerge = b;
b = *(ppMerge = &(b->next));
if(b == NULL){
*ppMerge = a;
break;
}
}
}
return pMerge;
}
Here is example code of a fast method to sort a linked list using an array of pointers to lists aList[], where aList[i] points to a list of size 2 to the power i, that makes use of mergeLists().
#define NUMLISTS 32 // size of aList
Node * mergeSort(NODE *pList)
{
Node * aList[NUMLISTS]; // array of pointers to lists
Node * pNode;
Node * pNext;
int i;
if(pList == NULL) // check for empty list
return NULL;
for(i = 0; i < NUMLISTS; i++) // zero array
aList[i] = NULL;
pNode = pList; // merge nodes into array
while(pNode != NULL){
pNext = pNode->next;
pNode->next = NULL;
for(i = 0; (i < NUMLISTS) && (aList[i] != NULL); i++){
pNode = mergeLists(aList[i], pNode);
aList[i] = NULL;
}
if(i == NUMLISTS)
i--;
aList[i] = pNode;
pNode = pNext;
}
pNode = NULL; // merge array into one list
for(i = 0; i < NUMLISTS; i++)
pNode = mergeLists(aList[i], pNode);
return pNode;
}
I've been trying to add an item to the end of a linked list. I think I have a handle on the concept but i'm having difficulty implementing the code. In particular, being able to traverse a linked list and find the tail. Here is what i have so far. I've been at this for a while trying different things. Any help would be appreciated.
##include <iostream>
using namespace std;
class node
{
public:
int data;
node *next;
};
class linkedList
{
private:
node* ptrHead;
node* ptrTail;
int size;
public:
linkedList(); //default constructor
void display();
void addFront(int);
void removeFront();
void addBack(int);
void removeBack();
};
//default constructor
linkedList::linkedList(){
size = 0;
ptrHead = ptrTail = NULL;
}
//display linked list
void linkedList::display(){
node* current = ptrHead;
while (current != NULL) {
cout << current->data << " "; //display current item
current = current->next; //move to next item
}
cout << size;
}
//add item to front of linked list
void linkedList::addFront(int addData){
node* n = new node;
n->next = ptrHead;
n->data = addData;
ptrHead = n;
size++;
}
//remove item from front of linked list
void linkedList::removeFront(){
node* n = ptrHead;
ptrHead = ptrHead->next;
delete n;
size--;
}
void linkedList::addBack(int addData){ ////work in progress
node* n = new node; //create new node
n->data = addData; //input data
n->next = NULL; //set node to point to NULL
if ( ptrTail == NULL ) // or if ( ptrTail == nullptr )
{
ptrHead = n;
ptrTail = n;
}
else
{
ptrTail->next = n;
ptrTail = n;
}
size++;
}
//this is the test code from my main function
int main()
{
//test code
linkedList list;
list.addFront(40);
list.addFront(30);
list.addFront(20);
list.addFront(10);
list.addFront(0);
list.addBack(50);
list.addBack(60);
list.display(); //50 60 7 (the 7 is the count/size of the linked list)
cout << endl;
}
for(int i=1; i<size; i++)
pCurrent = pCurrent->next;
pCurrent = n;
This will work. But you have to keep the size variable as real size of the Linked List.
Or If you want to add element in the end always, you can follows the below steps.
Keep a extra node tail and add the element to that.
if(head == NULL)
{
head = n;
tail = n;
}
else
{
tail->next = n;
tail = tail->next;
}
You did not show the definition of your linkedList.
So I can only suppose that it has data members ptrTail and ptrHead. In this case the function will look the following way
void linkedList::addBack(int addData)
{
node* n = new node; //create new node
n->data = addData; //input data
n->next = NULL; //set node to point to NULL
if ( ptrTail == NULL ) // or if ( ptrTail == nullptr )
{
ptrHead = n;
}
else
{
ptrTail->next = n;
}
ptrTail = n;
size++;
}
Function addFront can be defined the similar way
void linkedList::addFront(int addData)
{
node* n = new node; //create new node
n->data = addData; //input data
if ( ptrHead == NULL ) // or if ( ptrHead == nullptr )
{
ptrTail = n;
}
n->next = ptrHead;
ptrHead = n;
size++;
}
One more function
void linkedList::removeFront()
{
if ( ptrHead != NULL )
{
if ( ptrTail == ptrHead ) ptrTail = NULL;
node* n = ptrHead;
ptrHead = ptrHead->next;
delete n;
size--;
}
}
Try this
node* pCurrent = ptrHead;
if( pCurrent != NULL ){
//find tail
while (pCurrent->next != NULL)
pCurrent = pCurrent->next;
// add new node at end of tail
pCurrent->next = n;
} else {
pCurrent = n;
}
}
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);
}