what does node=node->next mean in linked list (data structures) - data-structures

The following is the structure
struct list *node
{
int data;
struct list *next;
}
What does node=node->next exactly do while traversing the linked list and isn't the next element pointer to pointer in the node variable?

Imagine incrementing a variable with a while loop.
int i = 0;
while (i < 6) {
// this loop will run forever without the line below
i++; // adds one to i so the loop will not run infinitely
}
The concept is the same with linked lists:
while (node != NULL) {
//need to make sure this loop doesn't run forever
node = node->next // kind of like incrementing i
}
Now the while loop will run until the end of the list is reached.

node = node->next makes node point towards next pointer in linked list.
As the value stored in next is pointer to next element in the list.
So making node as node->next and then calling the function again or iterating in the for loop makes you go forward.
Hope that helps

Related

Find the maximum sum of first and last element of a linked list

Given a singly linked list where each element contains a number and a pointer to the head of the list. Sum the first and last data and remove these nodes. Then sum the first and last data of the resulting linked list and remove these two nodes.
Keep doing this till the list becomes empty.
we have to find the maximum sum obtained from the resulting sum in O(1) space complexity.
The list is a singly linked list with even nodes.
My Thoughts:
One approach is to move the pointer to the last element at each iteration, remove the nodes, and keep a maxSum variable. This probably won't be an efficient solution.
If I understood correctly, a node in this linked list has two pointers: a pointer to the next node and one to the first node in the list.
There are several ways to solve this. Here is one:
Walk through the list and change the head pointer in each node to reference the previous node: this will give you a doubly linked list. Retain a pointer to the last node.
Now you can do a traversal in tandem starting at both ends of the list and walking towards each other.
Deleting nodes during that traversal is not really required. You could even restore the list to what it was originally in the second step.
It is even possible to do this without this extra head pointer in each node. In that case reverse the second half of the list.
Here is an implementation of the first idea, in JavaScript:
class Node {
constructor(data, head) {
this.data = data;
this.head = head || this; // default is node itself
this.next = null;
}
}
function createList(...values) {
if (!values) return null;
let head = new Node(values.shift()); // First value
let tail = head;
for (let value of values) { // Remaining values
tail.next = new Node(value, head);
tail = tail.next;
}
return tail.head;
}
function maxPairSum(head) {
if (!head) return -Infinity;
// Make doubly linked list, (ab)using node's head member
let tail;
for (tail = head; tail.next; tail = tail.next) {
tail.next.head = tail; // Next gets reference to previous
}
// Tandem walk, towards center
let maxSum = -Infinity;
for (let curr = head; curr != tail && curr != tail.next; curr = curr.next) {
maxSum = Math.max(maxSum, curr.data + tail.data);
tail = tail.head; // Is actually a reference to previous
}
// Restore head references (optional)
for (let curr = head; curr; curr = curr.next) {
curr.head = head;
}
return maxSum;
}
// Example run
let head = createList(2, 5, 1, 5, 4, 6);
let maxSum = maxPairSum(head);
console.log(maxSum); // 9
... And if you want to really remove the list, just clear the head reference. In JavaScript the garbage collector will free the unreachable memory; in some other languages (like C) you'll need to explicitly free the memory occupied by each node, before clearing the reference to the head node.
private static int max = 0, count = 0;
private static LinkedList top;
static int maximumPagesRec(LinkedList tail) {
if(tail.next==null)
max = max<top.data + tail.data ?top.data + tail.data: max;
else if(tail == top && count++ !=0){
max = max<top.data ?tail.data: max;
}
else if(top.next == tail && count++!=1)
max = max<top.data + tail.data ?top.data + tail.data: max;
else {
maximumPagesRec(tail.next);
}
top = top.next;
return max;
}
static int maximumPages(LinkedList head)
{ top = head;
return maximumPagesRec(head);
}
how about pushing all linked list value element to a stack, take 1->2->3->4 for example, and the stack will be 1234.
after that, we sum one by one and delete each linked list, store maximum value we got.

Singly linked list Tail

if you want create a singly linked list like this:
struct Node {
int data;
Node *next;
};
struct List{
Node *head;
// Node *tail; --> necessary?
Node *last;
};
And this list has the methods "append", "remove", "printList" and "findElement".
Is it necessary to have a tail? Because with "last" you can address the last node.
So when it is necessary to have all three Nodes "head", "tail" and "last"? When you want to insert the node sorted into the list for example?
No, it's not necessary. The tail is equal to head->next and thus it would be redundant and add bookkeeping overhead to keep this field updated.
Also note that the field last is kind of unusual. In most use cases, you add elements to the head of a singly linked list and use a different data structure when you really need to add to the end.
Actually, you can implement enqueue (append at tail), push (prepend at head), dequeue (remove from head), and of course find and print with with a one-pointer header. The trick is to make the list circular and have the header point to the tail. Then tail->next is the head.
#include <stdio.h>
#include <stdlib.h>
typedef struct node_s {
struct node_s *next;
int data;
} Node;
typedef struct list_s {
Node *tail;
} List;
Node *new_node(int data) {
Node *node = malloc(sizeof *node);
node->data = data;
node->next = node;
return node;
}
void init_list(List *list) {
list->tail = NULL;
}
int is_empty(List *list) {
return list->tail == NULL;
}
void enqueue(List *list, Node *node) {
if (list->tail) {
Node *head = list->tail->next;
node->next = head;
list->tail->next = node;
list->tail = node;
} else list->tail = node->next = node;
}
void push(List *list, Node *node) {
if (list->tail) {
Node *head = list->tail->next;
node->next = head;
list->tail->next = node;
} else list->tail = node->next = node;
}
Node *dequeue(List *list) {
Node *head = list->tail->next;
if (head == list->tail)
list->tail = NULL;
else
list->tail->next = head->next;
return head;
}
void print_list(List *list) {
printf("The list:\n");
if (list->tail) {
Node *head = list->tail->next;
Node *p = head;
do {
printf("%d\n", p->data);
p = p->next;
} while (p != head);
}
}
int main(int argc, char *argv[]) {
List list[1];
init_list(list);
// Build the list in order and print it.
for (int i = 0; i < 4; i++) enqueue(list, new_node(i));
print_list(list);
// Remove elements from head until empty.
printf("Dequeueing:\n");
while (!is_empty(list)) {
Node *node = dequeue(list);
printf("%d\n", node->data);
free(node);
}
// Build the list in reverse order and print it.
for (int i = 0; i < 4; i++) push(list, new_node(i));
print_list(list);
return 0;
}
I think it depends on what operations you want to use.
Assuming you want to insert and delete nodes at the tail of a list, it is certainly a wise choice to keep a last node in your list.
Otherwise, if you want to do operations at the beginning of the list, a last node is unnecessary.
It's not necessary but a tail can be useful if you're working with the linked list in a queue-like FIFO fashion rather than a stack-like LIFO fashion or want to be able to transfer entire lists of elements from one head to another's tail without disrupting the relative order of the elements.
Note that I'm referring to 'tail' as a reference to the last node in the list which I believe is safe to assume that the question is about.
A lot of very micro-optimized SLL implementations often are tail-less and work like a stack while backed by an efficient fixed allocator for locality of reference (cache-friendliness) and faster node allocations/deallocations. There the primary benefit of the SLL over a variable-sized array-based sequence is the ability to start moving things around by just changing the value of the next pointer/reference and the lack of invalidation on inserting/removing elements if you're working in native, lower-level languages that involve pointers. The lack of a tail can boost performance quite a bit by reducing the amount of branching instructions required in operations to push and pop from the stack.
For the needs you listed, whether the tail is going to help or just add unnecessary complexity and overhead is if your append and remove operations can work strictly from the front in a LIFO stack fashion or if you want to be able to append to the back but remove from the front in a FIFO fashion without any iteration involved, e.g. If you don't have a tail in the latter case, one of these operations are going to go from constant-time complexity to linear-time complexity, and you might improve your use cases by exchanging that linear-time algorithmic complexity for the relatively smaller micro-level overhead of maintaining a tail.

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)?

how to find lowest common ancestor of a nary tree?

Is there a way without using extra space to find LCA of nary tree.
I did it using a string saving the preorder of both the nodes and finding common prefix
If nodes "know" their depth - or you're willing to allow the space to compute the depth of your nodes, you can back up from the lower node to the same depth of the higher node, and then go up one level at a time until they meet.
Depends on what "extra space" means in this context. You can do it with one integer - the difference in depths of the two nodes. Is that too much space?
Another possibility is given you don't have a parent pointer, you can use pointer reversal - every time you traverse a pointer, remember the location from which you came, remember the pointer you will next traverse, and then just before the next pointer traversal, replace that pointer with the back pointer. You have to reverse this when going up the tree to restore it. This takes the space of one pointer as a temporary. And another integer to keep the depth as you work your way down and up. Do this synchronously for the two nodes you seek, so that you can work your way back up from the lower one until you're at the same height in both traversals, and then work back up from both until you're at the common node. This takes three extra pieces of memory - one for each of the current depths, one for the temporary used during a pointer reversal. Very space efficient. Is it worth it?
Go back and do it for a binary tree. If you can do it for a binary tree you can do it for an n-ary tree.
Here's a link to LCA in a binary tree:
And here's how it looks after converting it to a n-ary tree LCA:
public class LCA {
public static <V> Node<V>
lowestCommonAncestor(Node<V> argRoot, Node<V> a, Node<V> b) {
if (argRoot == null) {
return null;
}
if (argRoot.equals(a) || argRoot.equals(b)) {
// if at least one matched, no need to continue
// this is the LCA for this root
return argRoot;
}
Iterator<Node<V>> it = argRoot.childIterator();
// nr of branches that a or b are on,
// could be max 2 (considering unique nodes)
int i = 0;
Node<V> lastFoundLCA = null;
while (it.hasNext()) {
Node<V> node = lowestCommonAncestor(it.next(), a, b);
if (node != null) {
lastFoundLCA = node;
i++ ;
}
if (i >= 2) {
return argRoot;
}
}
return lastFoundLCA;
}
}
Do a synchronous walk to both the nodes.
Start with LCA=root;
loop:
find the step to take for A and the step for B
if these are equal { LCA= the step; decend A; descend B; goto loop; }
done: LCA now contains the lca for A and B
Pseudocode in C:
struct node {
struct node *offspring[1234];
int payload;
};
/* compare function returning the slot in which this should be found/placed */
int find_index (struct node *par, struct node *this);
struct node *lca(struct node *root, struct node *one, struct node *two)
{
struct node *lca;
int idx1,idx2;
for (lca=root; lca; lca=lca->offspring[idx1] ) {
idx1 = find_index(lca, one);
idx2 = find_index(lca, two);
if (idx1 != idx2 || idx1 < 0) break;
if (lca->offspring[idx1] == NULL) break;
}
return lca;
}

Does the singularly LinkedList give output In LIFO?

I was working on a singularly-linked list. While creating my own linked list I got confused on printing the collection of nodes in my custom linked list.
I want to know, does a singularly-linked list display its collection in a LIFO manner like a stack?
below is my Own LinkedList AND node is A Class can anyone tell me Does Singular LinkedList Prints The Collection In Lifo Manner.
class MYlinklist
{
Node header;
public void Add(int a)
{
Node n = new Node();
n.element = a;
n.Next = header;
header = n;
}
public void Print()
{
Node n = new Node();
n = header;
while (n != null)
{
Console.WriteLine(n.element.ToString());
n = n.Next;
}
}
}
If you are referring to LinkedList<T>, the answer depends on how you add new members.
If you want to make the linked list iterate in LIFO, you can do so by always using AddFirst to add, and RemoveFirst to remove. This will cause it behave very much like a stack.
The nice thing about LinkedList<T>, however, is that you can add anywhere inside of the list as an O(1) operation.
Edit:
If you want this to be FIFO instead, you'll need to change how to add your nodes, and add them at the end of the list, not the start:
class MyLinkedList
{
Node header;
Node last;
public void Add(int a)
{
Node n = new Node();
n.element = a;
n.Next = null; // We'll put this at the end...
if (last == null)
{
header = n;
last = n;
}
else
{
last.Next = n;
last = n;
}
}
public void Print()
{
Node n = new Node();
n = header;
while (n != null)
{
Console.WriteLine(n.element.ToString());
n = n.Next;
}
}
}
You're adding nodes at the head of the list (note how you are always setting node.Next to the head of the list).
Then you're iterating through from the head (which is the last element inserted) to the tail.
If you want to iterate in FIFO order, you should do the following:
Maintain a reference to the tail of the list (as well as the head, which you've put in header).
When you add a node, set tail.Next to the new node, and then set tail to point to the new node.
Your iteration function can be unchanged.
Your other option is, instead of maintaining a reference to the tail, just do an iteration through the list each time. But this comes with the tradeoff of needing to go through n-1 elements to add the nth element every time, which means adding many elements is an O(n^2) operation. I would not recommend doing this, but it might be fine for a beginning if you're learning the basics and you're not sure about the tail reference manipulation. In production code, though, you should always have a head and a tail reference for linked lists.

Resources