How to move elements in doubly linked list? [closed] - c++

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 7 years ago.
Improve this question
I have custom list (doubly linked list and not std::list) implemented in my code. My requirement is to move the element by one left or right by updating the references. Is it possible?
class Elem
{
Elem *next;
Elem *prev;
}
.......
void move_element_left(Elem *e)
{
if(e->prev()==NULL)
return; //Left most ... so return
Elem *left = e->prev();
left->next() = e->next();
e->prev() = left->prev();
if (left->next())
left->next()->prev() = left;
if (e->prev())
e->prev()->next() = e;
e->next() = left;
left->prev() = e;
}
.......
int main()
{
ElemList ls;
...
...
move_element_left(e); //e of type Elem *
...
}
Above code works except for the 2nd object in the list which I want to move to left most (or to top most). (i.e. say if list(obj5, obj9, obj11, obj12,..), moving obj9 to the first in the list gives error)

See Bubble-sorting doubly linked list
I assume your Elem class does also contain data, so move the data or - if it's a simple data pointer - swap the pointers: C++ Swapping Pointers.
If that's not possible I would - from a "Don't Repeat Yourself" point of view - reuse those simple linked list functions you most probably already have:
void move_element_left(Elem *e)
{
Elem *left = e->prev();
if(left)
{
remove_element(e);
insert_element_before(e, left);
}
}

Works as designed ?
Following your code in a schema, shows that it works as designed:
void move_element_left(Elem *e)
{
if(e->prev()==NULL)
return; //ok ! Left most ... so return
Elem *left = e->prev(); // ok ! (1)
left->next() = e->next(); // ok ! (2)
e->prev() = left->prev(); // ok ! (3)
if (left->next()) // ok !
left->next()->prev() = left; // ok ! (4)
if (e->prev()) // ok ! e prev is left prev is null
e->prev()->next() = e;
e->next() = left; // ok ! (5)
left->prev() = e; // ok ! (6)
}
Here the schema (sorry for the childish aspect ;-) ):
So the list is in fact fine. The problem is that ElemList certainly contains a pointer to the head of the list . And this pointer still points to the old first and now second element. So the list is then no longer consitent.
How to fix it ?
One way out, would be to make move_element_left() a member function of ElemList. In this case you could take care of the special case where e->left becomes null, in which case you need to update ElemList's pointer to the first element.

Below is the updated code. You need to change the head pointer if the left pointer points to head of double linked list.
//**head is the address of pointer of head of double linked list
void move_element_left(Elem *e,Elem **head)
{
if(e->prev()==NULL)
return; //Left most ... so return
Elem *left = e->prev();
if(left==*head){
*head=e;
}
left->next() = e->next();
e->prev() = left->prev();
if (left->next())
left->next()->prev() = left;
if (e->prev())
e->prev()->next() = e;
e->next() = left;
left->prev() = e;
}

Related

C++\C | Link | Queue | Hyperlink [closed]

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 3 months ago.
Improve this question
when i choose at Queue insert value ( example 1 ), then i call remove_Queue, and then i try to print_Queue, but in terminal i see value -572662307
code:
const int MAX_QUEUE = 10;
typedef int Item;
struct Queue {
Item value;
Queue* next;
};
Queue* front;
Queue* back;
Queue* tmp;
bool remove_Queue(Item& i,Queue* front, Queue* back)
{
if (front == NULL) return false;
i = front->value;
Queue* tmp = front;
front = front->next;
delete tmp;
if (x == 0) back = NULL // x-- in main, when i call this function
return true;
}
I hope someone can explain why i see this value when i delete just 1 value in my Queeu
You have global variables (that's bad), and you have local variables named the same as your global variables (that's worse) and you are expecting changes to local variables to be reflected outside of the local scope (that's plain wrong).
It's not completely clear what you are trying to do. I'm going to go down the global variable route (which is bad as I said above, but perhaps easier to understand).
I'm going to use the global variables as global variables, this means removing them as parameters to your remove_Queue function, but I'm going to change tmp to a local variable, which is what it should be.
const int MAX_QUEUE = 10;
typedef int Item;
struct Queue {
Item value;
Queue* next;
};
Queue* front;
Queue* back;
As you can see tmp has gone.
bool remove_Queue(Item& i)
{
if (front == NULL)
return false;
i = front->value;
Queue* tmp = front;
front = front->next;
delete tmp;
if (front == NULL) // is the queue empty?
back = NULL;
return true;
}
As you can see front and back are no longer parameters, so changes to them will affect the global variables declared above, instead of the local variables you had before. I also simplified this function, removing the parts I didn't understand. I also added a check for an empty queue, presumably then back should also be set to NULL.

Sort Ascending - Linked List [closed]

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 8 years ago.
Improve this question
I'm having a little trouble with getting my head around how this function would work and what I need to do. I have int number as my data type and node* next in my node class. I also have node pointers head, current and temp. My question is how would I go about getting my list of integers into order? Also how does ascending and decending work in a single linked list?
My header file:
#ifndef SDI_LL
#define SDI_LL
namespace SDI
{
class LinkedList
{
class Node
{
public:
int number; //data element
Node* next; //pointer to next, node inside each node
private:
};
private:
Node *head;
Node *current; //head, current and temp node pointers
Node *temp;
public:
LinkedList(); //constructor to access nodes from above
~LinkedList(); //destructor
void insert(int add);
void remove(int remove); //functions that access private data nodes above
void display();
void reverse();
void search(int searchNum);
void sortAscending();
void sortDecending();
void saveAll();
void restoreAll();
};
}
#endif
My ascending function so far where it starts from the beginning and searches through the list:
void LinkedList::sortAscending()
{
current = head;
for (current = head; current;)
{
temp = current;
current = current->next;
}
}
In general, you should use containers available in the standard libraries, which provide efficient sorting methods where applicable.
That said, if you want to do it for learning purposes - as you probably "should at least once" - then it is not too difficult to implement.
for (current = head; current;)
That's a funny for loop, personally I'd prefer:
current = head;
while(current) // or current != nullptr to be more explicit
Note also that you (unnecessarily, of course) assign head to current twice - immediately before the for loop, and in the initialisation of it.
A simple scheme (but not at all efficient!) might be to just swap 'out of order' elements as you iterate through the list, until no swaps were necessary:
bool changeMade;
do{
changeMade = false;
current = head;
while( current ){
temp = current;
current = current->next;
if( current && current->data < temp->data ){
changeMade = true;
swap( temp->data, current->data );
}
}
} while( changeMade );
This assumes a data field is the only other in the node - since it doesn't actually swap the nodes, just the data. (Doing the former is not really any more difficult - but without seeing your node type declaration I'd be making up names and risk confusing the issue.)
I don't see any declarations for current, head, and temp, but I assume they are pointers to node. Have you decided on a sort algorithm? Does the sort algorithm need to be efficient or is something with the performance of a bubble sort ok? With logic similar to a bubble sort, you can repeatedly move the node with the largest value to the end of the list. Or to save a bit of time, you could remove the node with the largest value from the original list and insert it into the front of a new list that would end up in sorted order. More efficient algorithms use logic based on merge sort.
To remove or swap nodes, using a pointer to pointer can avoid special handling for the first node of a list (the one pointed to by pList in this example):
NODE * SortList(NODE * pList)
{
NODE * pNew = NULL; /* sorted list */
NODE **ppNode; /* ptr to ptr to node */
NODE **ppLargest; /* ptr to ptr to largest node */
NODE * pLargest; /* ptr to largest node */
while(pList != NULL){ /* while list not empty */
ppLargest = &pList; /* find largest node */
ppNode = &((*ppLargest)->next);
while(NULL != *ppNode){
if((*ppNode)->data > (*ppLargest)->data)
ppLargest = ppNode;
ppNode = &((*ppNode)->next);
}
pLargest = *ppLargest; /* move node to new */
*ppLargest = pLargest->next;
pLargest->next = pNew;
pNew = pLargest;
}
return(pNew);
}

Union of two linked lists [closed]

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 9 years ago.
Improve this question
I am trying to develop a friend function for the union of two link lists. Compiler keeps giving me an error saying that Node was not declared in this scope, as well as p,q not declared in this scope. So I added List::Node, but it is not performing the union still
const List getunion(const List&a, const List&b) {
List::Node * p=a.list;
List::Node* q=b.list;
List result;
while (q!=NULL && p!=NULL) {
if(q->value==p->value) {
result.insert(q->value);
q=q->next;
p=p->next;
}
q=q->next;
p=p->next;
}
return result;
}
void insert(int x) {
Node* tmp=new Node;
tmp->value=x;
if(list==NULL || list->value >x){
tmp->next=list;
list=tmp;
}
else {
Node *curr=list;
while (curr->next !=NULL && curr->next->value < x) {
curr=curr->next;
}
tmp->next=curr->next;
curr->next=tmp;
}
Note my insert function adds Nodes in ascending order, and I have tried it out and it does work on test cases, it's when i implement the union function that things go astray...
I take it that you fixed the compile error and now you are wondering why it doesn't work.
You're not merging these two lists correctly. The issues are:
You only insert an item if it's in both lists - that's intersection, not union.
You are advancing both pointers simultaneously.
You need to merge one or the other:
while ( q && p ) {
if( q->value < p->value ) {
result.insert(q->value);
q = q->next;
} else if( q->value > p->value ) {
result.insert(p->value);
p = p->next;
} else {
result.insert(q->value);
q = q->next;
p = p->next;
}
}
Now, once either of those list pointers reaches the end, you still need to add the remaining elements from the other. This will do the trick:
for(; q; q = q->next) result.insert(q->value);
for(; p; p = p->next) result.insert(p->value);
Make sure, also, that you have defined a copy constructor for List. It looks like you're doing your own memory allocation in there, so you must follow the Rule of Three.
Firstly, I am not sure what you code is intended to be doing.
It seems you expect the input to be 2 lists, which you step thru in parallel, constructing a third list if the corresponding values are matching.
This is more like an intersection than a union, tho its harsher than that, since it cares about position.
The insert seems to be a sorted insert.
Anyway, this part is certainly wrong:
if(q->value==p->value) {
result.insert(q->value);
q=q->next;
p=p->next;
}
Remove these q=q->next and p=p->next.
These are causing a double step, since its done inside the if statement, and outside.
Double stepping is bad, since it can take you past the end of a list, causing crashes.

Deep Copy Linked List - O(n)

I'm trying to deep copy a linked list . I need an algorithm that executes in Linear Time O(n). This is what i have for now , but i'm not able to figure out what's going wrong with it. My application crashes and i'm suspecting a memory leak that i've not been able to figure out yet. This is what i have right now
struct node {
struct node *next;
struct node *ref;
};
struct node *copy(struct node *root) {
struct node *i, *j, *new_root = NULL;
for (i = root, j = NULL; i; j = i, i = i->next) {
struct node *new_node;
if (!new_node)
{
abort();
}
if (j)
{
j->next = new_node;
}
else
{
new_root = new_node;
}
new_node->ref = i->ref;
i->ref = new_node;
}
if (j)
{
j->next = NULL;
}
for (i = root, j = new_root; i; i = i->next, j = j->next)
j->ref =i->next->ref;
return new_root;
}
Can anyone point out where i'm going wrong with this ??
This piece alone:
struct node *new_node;
if (!new_node)
{
abort();
}
Seems good for a random abort() happening. new_node is not assigned and will contain a random value. The !new_node expression could already be fatal (on some systems).
As a general hint, you should only require 1 for-loop. Some code upfront to establish the new_root.
But atruly deep copy would also require cloning whatever ref is pointing to. It seems to me the second loop assigns something from the original into the copy. But I'm not sure, what is ref ?
One thing I immediately noticed was that you never allocate space for new_node. Since auto variables are not guaranteed to be initialized, new_node will be set to whatever value was in that memory before. You should probably start with something like:
struct node *new_node = (new_node *) malloc(sizeof(struct node));
in C, or if you're using C++:
node* new_node = new node;
Copying the list is simple enough to do. However, the requirement that the ref pointers point to the same nodes in the new list relative to the source list is going to be difficult to do in any sort of efficient manner. First, you need some way to identify which node relative to the source list they point to. You could put some kind of identifier in each node, say an int which is set to 0 in the first node, 1 in the second, etc. Then after you've copied the list you could make another pass over the list to set up the ref pointers. The problem with this approach (other that adding another variable to each node) is that it will make the time complexity of the algorithm jump from O(n) to O(n^2).
This is possible, but it takes some work. I'll assume C++, and omit the struct keyword in struct node.
You will need to do some bookkeeping to keep track of the "ref" pointers. Here, I'm converting them to numerical indices into the original list and then back to pointers into the new list.
node *copy_list(node const *head)
{
// maps "ref" pointers in old list to indices
std::map<node const *, size_t> ptr_index;
// maps indices into new list to pointers
std::map<size_t, node *> index_ptr;
size_t length = 0;
node *curn; // ptr into new list
node const *curo; // ptr into old list
node *copy = NULL;
for (curo = head; curo != NULL; curo = curo->next) {
ptr_index[curo] = length;
length++;
// construct copy, disregarding ref for now
curn = new node;
curn->next = copy;
copy = curn;
}
curn = copy;
for (size_t i=0; i < length; i++, curn = curn->next)
index_ptr[i] = curn;
// set ref pointers in copy
for (curo = head, curn = copy; curo != NULL; ) {
curn->ref = index_ptr[ptr_index[curo->ref]];
curo = curo->next;
curn = curn->next;
}
return copy;
}
This algorithm runs in O(n lg n) because it stores all n list elements in an std::map, which has O(lg n) insert and retrieval complexity. It can be made linear by using a hash table instead.
NOTE: not tested, may contain bugs.

What is the pointer-to-pointer technique for the simpler traversal of linked lists? [duplicate]

This question already has answers here:
An interesting C linked list idiom
(11 answers)
Closed 5 years ago.
Ten years ago, I was shown a technique for traversing a linked list: instead of using a single pointer, you used a double pointer (pointer-to-pointer).
The technique yielded smaller, more elegant code by eliminating the need to check for certain boundary/edge cases.
Does anyone know what this technique actually is?
I think you mean double pointer as in "pointer to a pointer" which is very efficient for inserting at the end of a singly linked list or a tree structure. The idea is that you don't need a special case or a "trailing pointer" to follow your traversal pointer once you find the end (a NULL pointer). Since you can just dereference your pointer to a pointer (it points to the last node's next pointer!) to insert. Something like this:
T **p = &list_start;
while (*p) {
p = &(*p)->next;
}
*p = new T;
instead of something like this:
T *p = list_start;
if (p == NULL) {
list_start = new T;
} else {
while (p->next) {
p = p->next;
}
p->next = new T;
}
NOTE: It is also useful for making efficient removal code for a singly linked list. At any point doing *p = (*p)->next will remove the node you are "looking at" (of course you still need to clean up the node's storage).
By "double-pointer", I think you mean "pointer-to-pointer". This is useful because it allows you to eliminate special cases for either the head or tail pointers. For example, given this list:
struct node {
struct node *next;
int key;
/* ... */
};
struct node *head;
If you want to search for a node and remove it from the list, the single-pointer method would look like:
if (head->key == search_key)
{
removed = head;
head = head->next;
}
else
{
struct node *cur;
for (cur = head; cur->next != NULL; cur = cur->next)
{
if (cur->next->key == search_key)
{
removed = cur->next;
cur->next = cur->next->next;
break;
}
}
}
Whereas the pointer-to-pointer method is much simpler:
struct node **cur;
for (cur = &head; *cur != NULL; cur = &(*cur)->next)
{
if ((*cur)->key == search_key)
{
removed = *cur;
*cur = (*cur)->next;
break;
}
}
I think you mean doubly-linked lists where a node is something like:
struct Node {
(..) data // The data being stored in the node, it can be of any data type
Node *next; // A pointer to the next node; null for last node
Node *prev; // A pointer to the previous node; null for first node
}
I agree with the comments about using the STL containers for handling your list dirty work. However, this being Stack Overflow, we're all here to learn something.
Here's how you would normally insert into a list:
typedef struct _Node {
void * data;
Node * next;
} Node;
Node * insert( Node * root, void * data ) {
Node * list = root;
Node * listSave = root;
while ( list != null ) {
if ( data < list->data ) {
break;
}
listSave = list;
list = list->next;
}
Node * newNode = (Node*)malloc( sizeof(Node) );
newNode->data = data;
/* Insert at the beginning of the list */
if ( listSave == list ) {
newNode->next = list;
list = newNode;
}
/* Insert at the end of the list */
else if ( list == null ) {
listSave->next = newNode;
newNode->next = null;
list = root;
}
/* Insert at the middle of the list */
else {
listSave->next = newNode;
newNode->next = list;
list = root;
}
return list;
}
Notice all the extra checking you have to do depending on whether the insertion occurs at the beginning, end or middle of the list. Contrast this with the double pointer method:
void insert( Node ** proot, void * data ) {
Node ** plist = proot;
while ( *plist != null ) {
if ( data < (*plist)->data ) {
break;
}
plist = &(*plist)->next;
}
Node * newNode = (Node *)malloc( sizeof(Node) );
newNode->data = data;
newNode->next = *plist;
*plist = newNode;
}
As Evan Teran indicated, this works well for singly linked lists, but when it's doubly linked, you end up going through just as many if not more manipulations as the single pointer case. The other draw back is that you're going through two pointer dereferences for each traversal. While the code looks cleaner, it probably doesn't run as quickly as the single pointer code.
You probably mean a doubly-linked list, with one of the pointers going forward and the other going backward. This allows you to get to the next and previous nodes for a given node without having to remember the last one or two nodes encountered (as in a singly-linked list).
But the one thing I discovered which made the code even more elegant was to always have two dummy elements in the list at all times, the first and the last. This gets rid of the edge cases for insertion and deletion since you're always acting on a node in the middle of the list.
For example, an empty list is created:
first = new node
last = new node
first.next = last
first.prev = null
last.next = null
last.prev = first
// null <- first <-> last -> null
Obviously, traversing the list is slightly modified (forward version shown only):
curr = first.next
while curr <> last:
do something with curr
curr = curr.next
The insertions are much simpler since you don't have to concern yourself with whether you're inserting at the start or end of the list. To insert before the current point:
if curr = first:
raise error
add = new node
add.next = curr
add.prev = curr.prev
curr.prev.next = add
curr.prev = add
Deletions are also simpler, avoiding the edge cases:
if curr = first or curr = last:
raise error
curr.prev.next = curr.next
curr.next.prev = curr.prev
delete curr
All very much cleaner code and at the cost of only having to maintain two extra nodes per list, not a great burden in today's huge memory space environments.
Caveat 1: If you're doing embedded programming where space still might matter, this may not be a viable solution (though some embedded environments are also pretty grunty these days).
Caveat 2: If you're using a language that already provides linked list capabilities, it's probably better to do that rather than roll your own (other than for very specific circumstances).