How exactly does a XOR Linked list work? - algorithm

The following link explains it. The implementation is said to work by storing the XOR of the previous and next address(say nxp), instead of storing both(previous and next address) separately.However, further along the implementation is said to work by xor-ing the previous address and nxp, in order to get the next address.
But isnt this practically using the same space as having previous and next pointers?

In a doubly linked list, you store two pointers per node: prev and next. In an XOR linked list, you store one 'pointer' per node, which is the XOR of prev and next (or if one of them is absent, just the other (the same as XORing with 0)). The reason why you can still traverse an XOR linked list in both directions relies on the properties of XOR and the redundancy of information inherent in a double linked list.
Imagine you have three nodes in your XOR linked list.
A is the head, and has an unobfuscated pointer to B (B XOR 0, next only)
B is the middle element, and has the XOR of pointers to A and to C.
C is the tail, and an unobfuscated pointer to B (0 XOR B, prev only)
When I am iterating over this list, I start at A. I note A's position in memory as I travel to B. When I wish to travel to C, I XOR B's pointer with A, granting me the pointer to C. I then note B's position in memory and travel to C.
This works because XOR has the property of undoing itself if applied twice: C XOR A XOR A == C. Another way to think about it is, the doubly linked list stores no extra information a singly linked list does not (since it's just storing all the previous pointers as copies of next pointers somewhere else in memory), so by exploiting this redundancy we can have doubly linked list properties with only as many links as are needed. However, This only works if we start our XOR linked list traversal from the start or end — as if we just jump into a random node in the middle, we do not have the information necessary to start traversing.
While an XOR linked list has the advantage of smaller memory usage, it has disadvantages — it will confuse the compiler, debugging and static analysis tools as your XOR of two pointers will not be correctly recognized by a pointer by anything except your code. It also slows down pointer access to have to do the XOR operation to recover the true pointer first. It also can't be used in managed code — XOR obfuscated pointers won't be recognized by the garbage collector.

Let us consider the following XOR list
A->B->C->D
suppose you created nodes in this format below
Key|Link|
A|0^addr(B)| -> B|addr(A)^addr(C)| -> C|addr(B)^addr(D)| -> D|addr(C)^0|
CASE #1:[Forward Traversal] Now Suppose you are in B (current_node=>B) want visit C , so you need Address of C . How you will get ?
Addressof(Next_node) = addressof(Prev_node) ^ Current_node(Link)
addr(A)^ ( addr(A)^ addr(C) )
=>(addr(A) ^ addr(A)) ^ addr(C)
=> 0 ^ addr(C)
=>addr(C)
CASE #2: [Backward traversal] Now Suppose you are in C (current_node=> C) want visit B , so you need Address of B . How you will get ?
Addressof(Prev_node) = addressof(Next_node) ^ Current_node(Link)
addr(D) ^ ((addr(B) ^ addr(D))
=> (addr(D)^ addr(D)) ^ addr(B)
=> 0^addr(B)
=> addr(B)
Traversing:
To traverse whole list ,You will need 3 pointers prevPtr , currPtr , nextPtr to store relative current, previous and next node's address starting with head.
Then in each iteration these pointers need be move to one position ahead.
struct Node *currPtr = head;
struct Node *prevPtr = NULL;
struct Node *nextPtr;
printf ("Following are the nodes of Linked List: \n");
while (currPtr != NULL)
{
// print current node
printf ("%d ", currPtr->key);
// Save the address of next node
nextPtr = XOR (prevPtr, currPtr->link);
//move prevPtr and currPtr one position for next iteration
prevPtr = currPtr;
currPtr = nextPtr;
}

But isnt this practically using the same space as having previous and
next pointers?
No - it uses about half the space, as the size of the result of XOR-ing the "prev" and "next" is equal to the size of the larger of the two.

XOR has a very special property about it, namely, given a XOR b = c, only two (any two) of the variable are required to compute the the third, with some restrictions. See the XOR swap algorithm for why this works.
In this case the previous (or next) pointer must still be carried, but only through traversal calculations and not as a seperate member.

Double linked list needs 2*N pointers stored for N nodes, plus at least one additional pointer(head, or perhaps head and tail).
XOR linked list needs N pointers stored for N nodes, plus at least two additional pointers (head and last visited node, or perhaps head and tail and last visited node). While traversing, you store one node (the last visited node), but when you go to the next node, you rewrite that with the now-previous node's address.

Related

Linked List - Remove numbers from a specified range

I have a linked list that contains numbers from 0 to 1 and my task is to remove numbers from a given range (x, y) from this list. Do you have any idea how to solve that problem in a reasonable complexity?
Let's first think about how a LinkedList is structured. Lets take a look at the following image:
Each element in a (doubly) linked list has a pointer to the next (and the previous) element. The Java class LinkedList is for example a doubly-linked list.
In such a list there is no direct access to "give me the index of element B". We just have a head reference (pointing at the start of the list) and a tail reference (pointing at the end). To find the element B, we need to start at head (or tail) and completely walk through the entire list, following the next (or prev) pointer of the elements until we found element B.
So, back to your question, there is no efficient way to remove elements of range(x, y) from a LinkedList. This can only be done efficient in sorted structures like PriorityQueue or a sorted ArrayList (binary search yields O(log(n)) or one with direct access to elements like HashSet for example.
Here is a code snippet in Java that solves your task for LinkedList, however, as stated, it is not efficient and has a running time of O(n) (we need to take a look at each element in order to find out which elements need to be deleted):
LinkedList<Integer> list = ...
// Inclusive lower bound
int lowerBound = ...
// Exclusive upper bound
int upperBound = ...
ListIterator<Integer> listIter = list.listIterator();
while (listIter.hasNext()) {
int value = listIter.next();
// Check if the value is inside bounds
if (value >= lowerBound || value < upperBound) {
// Remove the element from the list using the iterator
// which prevents ConcurrentModificationException
listIter.remove();
}
}
If you think about it, linkedlist has no method getAtIndex. You can only start from Head and work your way to the tail or vice versa. The complexity of this would be O(n)

If the head of a linked list is pointing to kth element, then how will you get the elements before kth element?

I search this question over web and get the ans that it can be implemented using XOR linked list or the linked list in the question has to be doubly linked list.
But I'm thinking the question is not complete in itself because for implementing XOR linked list function, the next pointer of the node must be in the suitable form i.e (next pointer) xor (previous pointer). But nothing is given.
Provide me some good solution.
You cannot get the elements before the position k unless the list is a doubly linked list. If each node points to its following node, and thats the only connection it carries, how is it supposed to access the previous node? Think of it like an iteration: you cannot go back once you call upon the next value.
If it is necessary to access the values before k, you may either 1) save the elements when you come across them (probably not a good idea) or 2) should consider using another data structure, depending on the implementation.
XOR linked list or Memory efficient linked list can be used.
let's say you have LL: 1->2->***3***->4 and your head is pointing on the 3rd node.
Using the XOR ll we know that :
1 -> NULL ^ 2
2-> 1 ^ 3
3-> 2 ^ 4
4-> 3^ NULL
So here in order to find the address of 2 and 1, we use the equation 3 -> 2 ^ 4
we know the address of 3 (as it is head) and the address of 4( head. next) so if we XOR 4 on both the side we get:
3^4 -> 2 ^ 4 ^ 4 (using the XOR property : 0 ^ 0 -> 0)
we get : 3 ^ 4 -> 2
this means that the prev element is the XOR of the head and the next of the head element.
So, this is how XOR can be used to find the prev element when the kth element is given as head.
It is not possible to navigate from any random (kth) element to its neighbour. You need the predecessor to navigate to the successor.
You need the successor to navigate to the predecessor.
In order to fulfill this requirement you can store a pointer to the kth and (k+1)th element in the header.
If you can´t store the (k+1)th element, the only way to find the predecessor is to loop through the list from the beginning (or end) until you find the kth element - then you can go backwards.
Hope this helps. I never worked with xor-linked lists. But this is what I found out here.
If the head of a linked list is pointing to kth element
then, where is the first element?
If it is a single linked list, and the given "head" is not actually the first element, but somewhere in the middle, then without the real head, I think elements before it can't be reached.
May I ask is it a leetcode problem? If yes, it is reasonable. Problems are often not clearly described in the site.
Here it is written that head is pointing to some kth element.
we know in XOR linked list the pointer of head contains xor of NULL and address of second element,so in this case xor of NULL and second element is same as the address of some k th element;
i will save the pointer of head in some pointer p,and keep traversing the XOR linked list till the address of p matches with the current node.
node* p = head->ptr;
node* prev = NULL;
node* curr = head;
node* next = NULL;
while(curr!=p && p)
{
next = xor(prev,curr->ptr);
print(curr->data);
prev = curr;
curr = next;
}
We can use XOR linked list (memory efficient linked list) for this.
XOR linked list is a linked list of which next pointer contains the address as XOR of Previous and Next node address. So, that whenever we need to access next element just XOR it with previous and vice versa for previous element.

dynamic-set operation UNION takes two disjoint sets S1 and S2 as input

This is my homework question i have tried to solve it just need someone to look and tell me if i am doing it right or worng..
The dynamic-set operation UNION takes two disjoint sets S1 and S2 as input, and it returns a set S = S1 U S2 consisting of all the elements of S1 and S2. The sets S1 and S2 are usually destroyed by the operation. Show how to support UNION in O(1) time using a suitable list data structure
I am thinking of having two linked lists which can be done in constant time but for that we need to remember a pointer to both first(head) and last(tail) element of list.
struct node{
char* word;
struct node* next;
}
struct Set{
struct node* head;
struct node* tail;
}
For every list beside with the head pointer we'll also keep a tail pointer.
Supporting union operation in O(1) time: Suppose we've two Sets S1 and S2.
PSEUDO-CODE:
node* Union(Set S1,Set S2){
S1.tail->next = S2.head;
S1.tail = S2.tail;
Remove S2 from the list of sets;
return S1;
}
is my approach going in right direction?
Just in case we don't have the tail pointer at hand (actually a common case for linked lists...), we cannot UNION the two lists in O(1), since we have to traverse one of the list to get its tail pointer, which takes O(n).
In this case, with only two head pointers at hand, the "suitable list data structure" has to be a doubly circular linked list. We disconnect the link between the head element of LIST_1 and its next element, and disconnect the link between the head element of LIST_2 and its prev element. Then we connect the two head elements and connect the other two elements. Thus, we get another doubly circular linked list, and the "pointer flow" is kept (which is why we shouldn't disconnect the head element of LIST_2 with its next element).
Yea, that's the same approach I'd take.
S1:
A1->A2->A3
S2:
B1->B2->B3
Tail node of S1 (A3) linked to head node of S2 (B1)
S1US2:
A1->A2->A3*->*B1->B2->B3
In the question that you mentioned it's written that we can use any suitable list data structure ( the answer that you have given considers a pointer to tail as well, which is not necessary unless you want to do it using a singly linked list in O(1) and generally we consider only the concept of head node when we talk about linked lists ) thus we will use doubly circular linked list. Now we have to join the 2 sets so we can do the following operations to achieve it in O(1)
(headS1->prev)->next = headS2;
temp = headS1->prev;
(headS2->prev)->next = headS1 ;
headS1->prev = headS2->prev ;
headS2->prev = temp;

How to "sort" elements of 2 possible values in place in linear time? [duplicate]

This question already has answers here:
Stable separation for two classes of elements in an array
(3 answers)
Closed 9 years ago.
Suppose I have a function f and array of elements.
The function returns A or B for any element; you could visualize the elements this way ABBAABABAA.
I need to sort the elements according to the function, so the result is: AAAAAABBBB
The number of A values doesn't have to equal the number of B values. The total number of elements can be arbitrary (not fixed). Note that you don't sort chars, you sort objects that have a single char representation.
Few more things:
the sort should take linear time - O(n),
it should be performed in place,
it should be a stable sort.
Any ideas?
Note: if the above is not possible, do you have ideas for algorithms sacrificing one of the above requirements?
If it has to be linear and in-place, you could do a semi-stable version. By semi-stable I mean that A or B could be stable, but not both. Similar to Dukeling's answer, but you move both iterators from the same side:
a = first A
b = first B
loop while next A exists
if b < a
swap a,b elements
b = next B
a = next A
else
a = next A
With the sample string ABBAABABAA, you get:
ABBAABABAA
AABBABABAA
AAABBBABAA
AAAABBBBAA
AAAAABBBBA
AAAAAABBBB
on each turn, if you make a swap you move both, if not you just move a. This will keep A stable, but B will lose its ordering. To keep B stable instead, start from the end and work your way left.
It may be possible to do it with full stability, but I don't see how.
A stable sort might not be possible with the other given constraints, so here's an unstable sort that's similar to the partition step of quick-sort.
Have 2 iterators, one starting on the left, one starting on the right.
While there's a B at the right iterator, decrement the iterator.
While there's an A at the left iterator, increment the iterator.
If the iterators haven't crossed each other, swap their elements and repeat from 2.
Lets say,
Object_Array[1...N]
Type_A objs are A1,A2,...Ai
Type_B objs are B1,B2,...Bj
i+j = N
FOR i=1 :N
if Object_Array[i] is of Type_A
obj_A_count=obj_A_count+1
else
obj_B_count=obj_B_count+1
LOOP
Fill the resultant array with obj_A and obj_B with their respective counts depending on obj_A > obj_B
The following should work in linear time for a doubly-linked list. Because up to N insertion/deletions are involved that may cause quadratic time for arrays though.
Find the location where the first B should be after "sorting". This can be done in linear time by counting As.
Start with 3 iterators: iterA starts from the beginning of the container, and iterB starts from the above location where As and Bs should meet, and iterMiddle starts one element prior to iterB.
With iterA skip over As, find the 1st B, and move the object from iterA to iterB->previous position. Now iterA points to the next element after where the moved element used to be, and the moved element is now just before iterB.
Continue with step 3 until you reach iterMiddle. After that all elements between first() and iterB-1 are As.
Now set iterA to iterB-1.
Skip over Bs with iterB. When A is found move it to just after iterA and increment iterA.
Continue step 6 until iterB reaches end().
This would work as a stable sort for any container. The algorithm includes O(N) insertion/deletion, which is linear time for containers with O(1) insertions/deletions, but, alas, O(N^2) for arrays. Applicability in you case depends on whether the container is an array rather than a list.
If your data structure is a linked list instead of an array, you should be able to meet all three of your constraints. You just skim through the list and accumulating and moving the "B"s will be trivial pointer changes. Pseudo code below:
sort(list) {
node = list.head, blast = null, bhead = null
while(node != null) {
nextnode = node.next
if(node.val == "a") {
if(blast != null){
//move the 'a' to the front of the 'B' list
bhead.prev.next = node, node.prev = bhead.prev
blast.next = node.next, node.next.prev = blast
node.next = bhead, bhead.prev = node
}
}
else if(node.val == "b") {
if(blast == null)
bhead = blast = node
else //accumulate the "b"s..
blast = node
}
3
node = nextnode
}
}
So, you can do this in an array, but the memcopies, that emulate the list swap, will make it quiet slow for large arrays.
Firstly, assuming the array of A's and B's is either generated or read-in, I wonder why not avoid this question entirely by simply applying f as the list is being accumulated into memory into two lists that would subsequently be merged.
Otherwise, we can posit an alternative solution in O(n) time and O(1) space that may be sufficient depending on Sir Bohumil's ultimate needs:
Traverse the list and sort each segment of 1,000,000 elements in-place using the permutation cycles of the segment (once this step is done, the list could technically be sorted in-place by recursively swapping the inner-blocks, e.g., ABB AAB -> AAABBB, but that may be too time-consuming without extra space). Traverse the list again and use the same constant space to store, in two interval trees, the pointers to each block of A's and B's. For example, segments of 4,
ABBAABABAA => AABB AABB AA + pointers to blocks of A's and B's
Sequential access to A's or B's would be immediately available, and random access would come from using the interval tree to locate a specific A or B. One option could be to have the intervals number the A's and B's; e.g., to find the 4th A, look for the interval containing 4.
For sorting, an array of 1,000,000 four-byte elements (3.8MB) would suffice to store the indexes, using one bit in each element for recording visited indexes during the swaps; and two temporary variables the size of the largest A or B. For a list of one billion elements, the maximum combined interval trees would number 4000 intervals. Using 128 bits per interval, we can easily store numbered intervals for the A's and B's, and we can use the unused bits as pointers to the block index (10 bits) and offset in the case of B (20 bits). 4000*16 bytes = 62.5KB. We can store an additional array with only the B blocks' offsets in 4KB. Total space under 5MB for a list of one billion elements. (Space is in fact dependent on n but because it is extremely small in relation to n, for all practical purposes, we may consider it O(1).)
Time for sorting the million-element segments would be - one pass to count and index (here we can also accumulate the intervals and B offsets) and one pass to sort. Constructing the interval tree is O(nlogn) but n here is only 4000 (0.00005 of the one-billion list count). Total time O(2n) = O(n)
This should be possible with a bit of dynamic programming.
It works a bit like counting sort, but with a key difference. Make arrays of size n for both a and b count_a[n] and count_b[n]. Fill these arrays with how many As or Bs there has been before index i.
After just one loop, we can use these arrays to look up the correct index for any element in O(1). Like this:
int final_index(char id, int pos){
if(id == 'A')
return count_a[pos];
else
return count_a[n-1] + count_b[pos];
}
Finally, to meet the total O(n) requirement, the swapping needs to be done in a smart order. One simple option is to have recursive swapping procedure that doesn't actually perform any swapping until both elements would be placed in correct final positions. EDIT: This is actually not true. Even naive swapping will have O(n) swaps. But doing this recursive strategy will give you absolute minimum required swaps.
Note that in general case this would be very bad sorting algorithm since it has memory requirement of O(n * element value range).

How to check if a circular single linked list is pallindrome or not?

Question: I have a single linked list (i.e. a list with only pointer to the next node). Additionally this is a circular linked list (in this example, the last node has a pointer to the first node). Every node in the list contains a char.
An example of such a list can be: a->b->c->b->a
Now how can I verify if this list is a pallindrome?
I have thought of the following solution:
Start from the head of list. Find the length of the list and then the mid node. Now start again from the head of the list and keep pushing elements in stack until the mid. Now traverse the list from the mid and pop element. If the value of the popped element is equal to the value of the current node. if not, return false. otherwise, continue until the stack is empty and we've verified all chars. CONS: uses extra stack space :(
Start from the head of list. Find the length of the list and then the mid node. now reverse the 2nd half of this list. and then using 2 pointers (one pointing to start and the other pointing to the mid+1'th element), check if the values are same. if not, return false. else continue until we reach the start node again. CONS: Changing original data structure.
Is there a more elegant way to approach this problem (which hopefully does not use O(n) extra space or changes original list)? I'm interested in the algorithm rather than any specific implementation.
Thanks
Since you're dealing with a single linked list, you must use a little extra space or a lot more extra time.
Your first approach sounds reasonable, but you can determine the length of the list and palindrome-ness in a single run.
We modify the so-called Floyd's Cycle-Finding Algorithm:
two pointers, "slow" and "fast", both start at the list head; the slow pointer advances one list element per iteration, the fast pointer two elements
in each step, the slow pointer pushes the current element on the stack
if the fast pointer reaches the end of the list, the slow pointer points to the middle of the list, so now:
the slow pointer advances to the end of the list, and in each step:
it pops one element from the stack and compares it to the current list element (if they are not equal, return false)
if the slow pointer reaches the end of the list, it is a palindrome
A little extra work is required for lists with an odd number of elements.
This is in pseudo-Haskell (I can't remember the exact syntax these days) and I've written for the non-circular case -- to fix that, just replace the clause matching against [] with whatever condition you use to identify you've come full circle.
p(xs) = q(xs, Just(xs)) != Nothing
q([], maybeYs) = maybeYs
q(x : xs, Nothing) = Nothing
q(x : xs, maybeYs) =
let maybeZs = q(xs, maybeYs) in
case maybeZs of
Nothing -> Nothing
Just (x :: zs) -> Just(zs)
otherwise -> Nothing
Since you know the Linked List does make a cycle, and you are only looking for palindromes starting at head, you can make this easier on yourself.
A -> B -> C -> B -> A
In this case, start with a pointer at head (call it H), and a pointer at head.Left() (call it T).
Now keep moving the head pointer H to the right, and the tail pointer T to the left.
As you walk the list, verify that the values of those elements are equal (i.e. a palindrome).
Your stopping condition however take a bit more. There are two cases:
Both pointers end point at the same element (i.e. odd number of elements)
The H pointer is pointing at the element just to the right of T.
So, you stop if H==T or if H==(T.Right()).
Using this approach (or similar) you visit each element just once.
Use the Tortoise and Hare approach as in the other solutions if you don't know if the linked list is cyclic.
Just paste my implementation so we could compare with each others, full test here:
/**
* Given a circular single linked list and the start pointer, check if it is a palindrome
* use a slow/fast pointer + stack is an elegant way
* tip: wheneve there is a circular linked list, think about using slow/fast pointer
*/
#include <iostream>
#include <stack>
using namespace std;
struct Node
{
char c;
Node* next;
Node(char c) {this->c = c;}
Node* chainNode(char c)
{
Node* p = new Node(c);
p->next = NULL;
this->next = p;
return p;
}
};
bool isPalindrome(Node* pStart)
{
Node* pSlow = pStart;
Node* pFast = pStart;
stack<Node*> s;
bool bEven = false;
while(true)
{
// BUG1: check fast pointer first
pFast = pFast->next;
if(pFast == pStart)
{
bEven = false;
break;
}
else
{
pFast = pFast->next;
if(pFast == pStart)
{
bEven = true;
break;
}
}
pSlow = pSlow->next;
s.push(pSlow);
}
if(s.empty()) return true; // BUG2: a, a->b->a
if(bEven) pSlow = pSlow->next; // BUG3: a->b->c->b->a, a->b->c->d->c->b->a: jump over the center pointer
while(!s.empty())
{
// pop stack and advance linked list
Node* topNode = s.top();
s.pop();
pSlow = pSlow->next;
// check
if(topNode->c != pSlow->c)
{
return false;
}
else
{
if(s.empty()) return true;
}
}
return false;
}
I think we dont need an extra space for this. And this can be done with O(n) complexity.
Modifying Philip's solution:
We modify the so-called Floyd's Cycle-Finding Algorithm:
Two pointers, "slow" and "fast", both start at the list head; the slow pointer advances one list element per iteration, the fast pointer two elements
in each step, the slow pointer pushes the current element on the stack
if the fast pointer reaches the end of the list, the slow pointer points to the middle of the list, so now:
Have another pointer at the start of the linked-list (start pointre) and now -
move the start pointer and the slow pointer one by one and compare them - if they are not equal, return false
- if the slow pointer reaches the end of the list, it is a palindrome
This is O(n) time complexity and no extra space is required.

Resources