Algorithm to check a linked-list for loops - algorithm

I want to find an algorithm which checks a linked-list with n elements for consistency. The linked-list uses a dummy head (also known as sentinel-node). The algorithm needs to run in O(n) time and is allowed to use O(1) extra space apart from the space needed to iterate through the list. The size of the list is unknown. In addition it's forbidden to modify the list.
A list counts as inconsistent if there is a list item which points at a previous list item.
First I thought about storing the first element and then iterate through the list while comparing the current element with the first one.

Does the list provide a Size property that tells you how many elements it contains (n) without traversing it?
If it does then a simple solution that meets all your big-O requirements is to attempt to traverse the list, counting the elements as you go. If the count exceeds the expected number of elements in the list then it has a loop.
Pseudo-code would look something like this:
bool isConsistent (List list)
{
bool consistent = true;
Node node = list.Sentinel.Next;
int count = 0;
while (node != list.Sentinel && consistent)
{
count++;
if (count > list.Size)
consistent = false;
node = node.Next;
}
return consistent;
}
That completes in O(n) and uses O(1) storage.

Floyd's "Tortoise and Hare" algorithm does what you need and only needs a small modification to work with your dummy head/tail (sentinel) node.
Here is how I would write the pseudo-code:
bool IsConsistent (List list)
{
Node tortoise = list.Sentinel.Next;
Node hare = tortoise.Next;
while (tortoise != list.Sentinel && hare != list.Sentinel)
{
if (tortoise == hare)
return false;
tortoise = tortoise.Next;
hare = hare.Next.Next;
}
return true;
}

You will need some RAM for that if you don't have a Visited property on each item in the linked list.
If you have a Visited property you will first need to clear it before running the algorithm. This will probably not fit your big-O requirements.
It's not clear what you mean with "points at previous list item". Is equal by reference (object) or same value/set of property values (struct)? I assume reference. The code below can easily be modified to handle structs as well.
static void Main(string[] args)
{
var list = BuildALinkedListFromSomeData();
var isConsitent = IsConsistent(list);
}
static bool IsConsistent(LinkedList<Item> list)
{
var visited = new List<LinkedListNode<Item>>()
var runner = list.First;
while(runner != null)
{
if (visited.Contains(runner))
return false;
visited.Add(runner);
runner = runner.Next;
}
return true;
}
A O(n) solution that uses an existing numeric VisitCounter that already uses storage space (no additional storage needed):
static bool IsConsistent(LinkedList<Item> list)
{
var runner = list.First;
if (runner == null)
return false; // Assume consistent if empty
var consistent = true;
var runId = runner.Value.VisitCount;
while (runner != null)
{
// Does the traversed item match the current run id?
if(runner.Value.VisitCount > runId)
{
// No, Flag list as inconsistent. It must have been visited previously during this run
consistent = false;
// Reset the visit count (so that list is ok for next run)
runner.Value.VisitCount = runId;
}
// Increase visit count
runner.Value.VisitCount++;
// Visit next item in list
runner = runner.Next;
}
return consistent;
}
This makes changes to the content of an item in the list, but not the list itself. If you're not allowed to change the content of an item in the list, then of course this is not a solution either. Well, second-thought, this is not a possible solution at all. When inconsistent, your list is circular and the last algorithm will never finish :)
You will then have to traverse the list backwards from each visited item in your list and this will break your O(n+1) requirement.
Conclusion: Not so Mission Impossible if Count is available. See GrahamS' answer

Here is my solution for the second question.
IsConsistent(LinkedList<Item> list) :N
slow = List.Sentinel.next :Element
fast = slow.next :Element
isConsistent = true :boolean
while(fast != list.Sentinel && fast.next != list.Sentinel && isConsistent) do
if(slow == fast)
isConsistent = false
else
slow:= slow.next
fast:= fast.next.next
od
if(isConsistent)
return 0
else
position = 0 : N
slow:= list.Sentinel
while(slow != fast) do
slow:= slow.next
fast:= fast.next
position:= position + 1
od
return position

Basically, pointing a previous item means having a loop inside the list. In this case, loop check is seem appropriate.

At first I didn't thought about using list.Sentinel. Now I got a new idea.
IsConsistent(LinkedList<Item> list) :boolean
slow = List.Sentinel.next :Element
fast = slow.next :Element
while(slow != list.Sentinel && fast != list.Sentinel) do
if(slow == fast) return false
else
slow:= slow.next
fast:= fast.next.next
od
return true

Related

find out which sorting alogorithm used in this function

Hi can someone help me out which sorting algorithm used in this function
public void sortList() {
Node current = null, index = null;
int temp;
//Check whether list is empty
if(head == null) {
return;
}
else {
//Current will point to head
for(current = head; current.next != null; current = current.next) {
//Index will point to node next to current
for(index = current.next; index != null; index = index.next) {
//If current's data is greater than index's data, swap the data of current and index
if(current.data > index.data) {
temp = current.data;
current.data = index.data;
index.data = temp;
}
}
}
}
}
By the way it is Doubly Link List
The current node is fixed and then iteration is done from next node to the end(via index variable), at the end of one iteration of outer loop the node pointed to by current has correct value, then the current is progressed to next node.
This is Selection Sort, the most elementary sort
Fun fact : although slow because of complexity O(n^2) selection sort can be used when the write operation is expensive because it only swaps max n times for a list of size n

Linked list addition (of total size n) and reversion of last k nods at order of n

I am looking at this challenge:
Given are numbers m and p, which both may be as large as 250000. The next m lines have one of the following commands:
APPEND y, which adds y to the end of our list (queue)
ROTATE, which reverses the p last elements of the list. If the list has fewer than p elements, it reverses all of the elements of the list.
Our job is to print the list after all commands have been executed.
A brute force approach is to reverse the array manually, which would have a complexity of O(pm), but you are required to implement it with a complexity of O(m).
I have thought about using a doubly linked list, and I am quite sure it would work, but I could not complete my answer.
Example
Input
8 3
APPEND 1
APPEND 2
APPEND 3
APPEND 4
ROTATE
APPEND 5
APPEND 6
ROTATE
Output
1 4 3 6 5 2
The idea of a doubly linked list is correct. To make it work you need to step away from prev/next notions, but just keep track of the potential 2 neighbours a node may have, without any indication of direction (prev/next).
Your doubly linked list will have a head and a tail -- that must stay. And you are right to also maintain a reference to the node that is currently the start node of the "k last elements" (or fewer when there are not that many elements in the list). Keep that updated whenever you add a node. In order to know in which direction to move that reference, also maintain a reference to the node that precedes it.
Then, when a reversal needs to be performed, it is a matter of swapping the references (and back-references) to the head and tail of that "k last element" sublist. Don't go over the whole sublist to change links between each pair of consecutive nodes. By removing the idea of prev/next, you can just leave those "internal" links as they are. Whenever you need to iterate through the list, you will always know which side you are coming from (i.e. what the "previous" node was), and so you can derive which of the neighbours must be the "next" one.
Here is an implementation of that idea in JavaScript. At the end of the code the algorithm is executed for the example input you have given:
class Node {
constructor(x, neighbor1=null, neighbor2=null) {
this.x = x;
this.neighbors = [neighbor1, neighbor2]; // No specific order...
}
opposite(neighbor) {
// Return the neighbor that is on the other side of the argument-neighbor
return this.neighbors[1 - this.neighbors.indexOf(neighbor)];
}
replaceNeighbor(find, repl) {
let i = this.neighbors.indexOf(find);
this.neighbors[i] = repl;
}
}
class List {
constructor(k) {
this.nodeCount = 0;
this.k = k;
// All node references are null:
this.head = this.tail = this.tailBeforeLastK = this.headOfLastK = null;
}
add(x) {
this.nodeCount++;
let node = new Node(x, this.tail, null);
if (this.head === null) {
this.headOfLastK = this.head = this.tail = node;
return;
}
this.tail.replaceNeighbor(null, node);
this.tail = node;
if (this.nodeCount > this.k) { // Move the head of the "last K" sublist
[this.tailBeforeLastK, this.headOfLastK] =
[this.headOfLastK, this.headOfLastK.opposite(this.tailBeforeLastK)];
}
}
reverse() {
if (this.nodeCount < 2 || this.k < 2) return;
// Exchange the links to the start/end of the K-last sublist
this.tail.replaceNeighbor(null, this.tailBeforeLastK);
if (this.tailBeforeLastK) {
this.tailBeforeLastK.replaceNeighbor(this.headOfLastK, this.tail);
this.headOfLastK.replaceNeighbor(this.tailBeforeLastK, null);
}
else this.head = this.tail;
// Swap
[this.tail, this.headOfLastK] = [this.headOfLastK, this.tail];
}
toArray() {
let result = [];
for (let prev = null, node = this.head; node; [prev, node] =
[node, node.opposite(prev)]) {
result.push(node.x);
}
return result;
}
}
// Example
let k = 3;
// null means: REVERSE, a number means: ADD <number>:
let actions = [1, 2, 3, 4, null, 5, 6, null];
let list = new List(k);
for (let action of actions) {
if (action === null) list.reverse();
else list.add(action);
}
console.log(list.toArray());

How to find the total number of items in linked list?

I have a linked list which is cyclic and I want to find out the total number of elements in this list. How to achieve this?
One solution that I can think of is maintaining two pointers. First pointer (*start) will always point to the starting node, say Node A.
The other pointer (*current) will be initialized as: current = start->next.
Now, just iterate each node with current -> next until it points to start.
And keep incrementing a counter: numberOfNodes++;
The code will look like:
public int countNumberOfItems(Node* start){
Node* current = start -> next;
int numberOfNodes = 1; //Atleast the starting node is there.
while(current->next != start){
numberOfNodes++;
current = current->next;
}
return numberOfNodes;
}
Let's say the list has x nodes before the loop and y nodes in the loop. Run the Floyd cycle detection counting the number of slow steps, s. Once you detect a meet point, run around the loop once more to get y.
Now, starting from the list head, make s - y steps, getting to the node N. Finally, run two slow pointers from N and M until they meet, for t steps. Convince yourself (or better prove) that they meet where the initial part of the list enters the loop.
Therefore, the initial part has s - y + t + 1 nodes, and the loop is formed by y nodes, giving s + t + 1 total.
You just want to count the nodes in your linked list right? I've put an example below. But in your case there is a cycle so you also need to detect that in order not to count some of the nodes multiple times.
I've corrected my answer there is now an ordinary count and count in loop (with a fast and slow pointer).
static int count( Node n)
{
int res = 1;
Node temp = n;
while (temp.next != n)
{
res++;
temp = temp.next;
}
return res;
}
static int countInLoop( Node list)
{
Node s_pointer = list, f_pointer = list;
while (s_pointer !=null && f_pointer!=null && f_pointer.next!=null)
{
s_pointer = s_pointer.next;
f_pointer = f_pointer.next.next;
if (s_pointer == f_pointer)
return count(s_pointer);
}
return 0;
}
First find the cycle using Floyd Cycle Detection algorithm and also maintain count when you checking cycle once found loop then print count for the same.
function LinkedList() {
let length = 0;
let head = null;
let Node = function(element) {
this.element = element;
this.next = null;
}
this.head = function() {
return head;
};
this.add = function(element) {
let node = new Node(element);
if(head === null){
head = node;
} else {
let currentNode = head;
while(currentNode.next) {
currentNode = currentNode.next;
}
currentNode.next = node;
}
};
this.detectLoopWithCount = function() {
head.next.next.next.next.next.next.next.next = head; // make cycle
let fastPtr = head;
let slowPtr = head;
let count = 0;
while(slowPtr && fastPtr && fastPtr.next) {
count++;
slowPtr = slowPtr.next;
fastPtr = fastPtr.next.next;
if (slowPtr == fastPtr) {
console.log("\n Bingo :-) Cycle found ..!! \n ");
console.log('Total no. of elements = ', count);
return;
}
}
}
}
let mylist = new LinkedList();
mylist.add('list1');
mylist.add('list2');
mylist.add('list3');
mylist.add('list4');
mylist.add('list5');
mylist.add('list6');
mylist.add('list7');
mylist.add('list8');
mylist.detectLoopWithCount();
There is a "slow" pointer which moves one node at a time. There is a "fast" pointer which moves twice as fast, two nodes at a time.
A visualization as slow and fast pointers move through linked list with 10 nodes:
1: |sf--------|
2: |-s-f------|
3: |--s--f----|
4: |---s---f--|
5: |----s----f|
At this point one of two things are true: 1) the linked list does not loop (checked with fast != null && fast.next != null) or 2) it does loop. Let's continue visualization assuming it does loop:
6: |-f----s---|
7: |---f---s--|
8: |-----f--s-|
9: |-------f-s|
10: s == f
If the linked list is not looped, the fast pointer finishes the race at O(n/2) time; we can remove the constant and call it O(n). If the linked list does loop, the slow pointer moves through the whole linked list and eventually equals the faster pointer at O(n) time.

Find duplicates values in the linked list (Simple convert into difficult)

This seems to be a very simple question. I had been asked by the interviewer to find the duplicate element in the linked list, and then he told me Some of the constraints that made the question difficult for me. the constraint is you have to traverse the linked list only one time.
Resources
The only resource I have available is another linked list.
BONUS
Remove that Element if you can traverse it only one time,
The time should be O(N)
Q1: I can't find the Answer, I don't know if the solution exists or not or he was just confusing me... if yes, how can that be possible?
You could use a HashMap, If this were to be implemented in Java we could use Map datastructure
The Map stores Key-Value Pairs and the elements can be accessed almost O(1), therefore this snippet runs in O(n)
private void removeDuplicates(final Node node) {
Map<Integer, Boolean> map = new HashMap<Integer, Boolean>();
Node n = node;
Node prev = null;
while (n != null) {
if (map.get(n.data) == null) {
map.put(n.data, true);
}
else {
System.out.println("Found Duplicate of: "+n.data);
/*To remove duplicates. do this
if (n.next != null) {
n.data = n.next.data;
n.next = n.next.next;
continue;
}
if (prev != null) {
prev.next = n.next;
}
*/
}
prev = n;
n = n.next;
}
}

working with pointers and linkedLists: how to iterate over a linked list, change and compare keys

I am asked to implement an algorithm based upon the data structure of a linkedList in the form of pseudocode.
Unfortunately I have a Python/Java background and thus no experience with pointers.
Could someone explain me how I would iterate over a doublyLinkedList, change and compare values of elements.
From what I have understood so far, i would do something like this.: to have an iteration over each element.
for L.head to L.tail
But how would I then access the current object in the list analogous to A[i] for i to L.length?
As the order of a linkedList is determined by pointers rather than indices in a linkedList can I simply do things like currentObj.prev.key = someVal or currentObj.key < currentObj.prev.key or is there some other wokflow to work with individual elements?
Again, I am obviously stuck as I lack an basic understanding on how to deal with pointers.
Cheers,
Andrew
So basically the data structures are:
Node:
node {
node next;//"single link"
node prev;//for "doubly"...
}
and List:
list {
node head;//for singly linked, this'd be enough
node tail;//..for "doubly" you "point" also to "tail"
int/*long*/ size; //can be of practical use
}
The (common) operations of a list:
Creation/Initialization:
list:list() {
head = null;
tail = null;
size = 0;
}
Add a node at the first position:
void:addFirst(node) {
if(isEmpty()) {
head = node;
tail = node;
size = 1;
} else {
head.prev = node;
node.next = head;
head = node;
size++;
}
}
// ..."add last" is quite analogous...
"is empty", can be implemented in different ways..as long as you keep the invariant
bool:isEmpty() {
return size==0;
//or return head==null ... or tail==null
}
"add a node at position i":
void:add(i, node) {
assert(i>=0 && i <=size);//!
if(isEmpty() || i == 0) {
addFirst(node);
} else if (i == size) {
addLast(node);
} else {//here we could decide, whether i is closer to head or tail, but for simplicity, we iterate "from head to tail".
int j = 1;
node cur = head.next; //<- a "cursor" node, we insert "before" it ;)
while(j < i) {//1 .. i-1
cur = cur.next;// move the cursor
j++;//count
}
//j == i, cur.next is not null, curr.prev is not null, cur is the node at currently i/j position
node.prev = cur.prev;
cur.prev.next = node;
cur.prev = node;
node.next = cur;
}
//don't forget the size:
size++;
}
Delete(node) is easy!
"Delete at position", "find node", "get node by position", etc. should use a similar loop (as add(i, node))...to find the correct index or node.
The strength/advantage of a doubly (comparing to a singly) linked list, is that it can iterate as "forth" as "back". To use this advantage (it is only advantageous on index-based operations, for "find(node)" e.g. you still don't know where to start/iterate best), you determine whether pos is closer to head(0) or to tail(size-1), and start&route your iteration accordingly.
...What else operations are you intereseted in (detail)?

Resources