Big-O for while loop? - linked-list

How do I solve the Big-O for this problem containing a while loop that goes through the nodes and increment the length as long as it does not equal to null? Would this just be O(N) because it goes through N nodes? Also, the statements within the while loop would just be O(1), correct?
/**
*#param head the first node of the linked list
*#return the length of the linked list
*/
public static <E> int getLength(Node<E> head) {
int length = 0;
Node<E> node = head;
while (node!=null) {
length++;
node = node.next;
}
return length;
}

As you said the traversal of a linked list takes O(N) since you need to go over each node once.
The assignment operator is O(1), since you need to do this just once, every time.

Related

How to fill a list with null values so it is a specific length?

I have a situation where I have a list that can be at most 4 elements.
However, if I have only 1-3 elements to put in that list, how can I fill the remainder with null values?
For example, a List<int?> of length 4 with 2 given elements, should result in:
[1,3] -> [1,3,null,null]
Here's what I'm doing, but maybe there is a better way
List.generate(4, (index) {
try {
final id = given.elementAt(index);
return id;
} catch (error) {
return null;
}
});
The simplest version would probably be:
[for (var i = 0; i < 4; i++) i < given.length ? given[i] : null]
You can use List.generate, but in this case, the function is simple enough that a list literal can do the same thing more efficiently.
(Or, as #jamesdlin says, if you want a fixed-length list, use List.generate).
A more indirect variant could be:
List<GivenType?>.filled(4, null)..setAll(0, given)
where you create a list of four nulls first, then write the given list into it. It's probably just more complicated and less efficient.

LinkedList pointer explanation

So I get a little idea of how a linked list work and how the head node points to another node that contains data and also the address of the next node. I've also looked at examples. I've been looking at this code I found for the past five hours confused on how under the display() method that current = head points to the next node. I keep thinking head.next = null and doesn't point at the next node. Can someone explain to me how head.next is pointing to the next node or when did it acquired the address because I can't find when in the code it does.
public class SinglyLinkedList {
//Represent a node of the singly linked list
class Node{
int data;
Node next;
public Node(int data) {
this.data = data;
this.next = null;
}
}
//Represent the head and tail of the singly linked list
public Node head = null;
public Node tail = null;
//addNode() will add a new node to the list
public void addNode(int data) {
//Create a new node
Node newNode = new Node(data);
//Checks if the list is empty
if(head == null) {
//If list is empty, both head and tail will point to new node
head = newNode;
tail = newNode;
}
else {
//newNode will be added after tail such that tail's next will point to newNode
tail.next = newNode;
//newNode will become new tail of the list
tail = newNode;
}
}
//display() will display all the nodes present in the list
public void display() {
//Node current will point to head
Node current = head;
if(head == null) {
System.out.println("List is empty");
return;
}
System.out.println("Nodes of singly linked list: ");
while(current != null) {
//Prints each node by incrementing pointer
System.out.print(current.data + " ");
current = current.next;
}
System.out.println();
}
public static void main(String[] args) {
SinglyLinkedList sList = new SinglyLinkedList();
//Add nodes to the list
sList.addNode(1);
sList.addNode(2);
sList.addNode(3);
sList.addNode(4);
//Displays the nodes present in the list
sList.display();
}
}
When you iterate through the linked list the first time, head points to the firstNode. Then as the while loop runs, the code updates the pointer("Current") to point to the next Node. This is shown where you see current = current.next; The loops keep running until current points to null, after which it ends. Hope you understand better.
You are right that head.next is not directly assigned. However, tail.next is. Let's see what happens in addNode() for two cases:
When the list is empty and you add a node, both head and tail are set to the newNode. Keep in mind that (this being Java) head and tail are references to the object newNode, that is, they reference the same object.
When there is already 1 element in the list, and you add a new node (the second one) you set tail.next = newNode. Now remember that head and tail are references to the same object (the first one added so far). They are basically two names for the same thing at this moment. So what really happens is that the object referenced by head and tail gets its next member set to newNode - and now both head.next and tail.next point to newNode. After that tail itself is made to reference tne newNode and at this moment head and tail start to reference different objects - head still referencing the first element, and tail now referencing the second (and so far last) element.
Now when you get to display(), you see that head is really a reference to the first element of the list, its next points to the second one and so on...

duplicate unsorted linked list

I've found this function to remove duplicate values in linked list:
public static void deleteDups (LinkedListNode n){
Hashtable table = new Hashtable();
LinkedListNode previous = null;
while(n!=null){
if(table.containsKey(n.data)){
previous.next = n.next;
} else {
table.put(n.data, true);
previous = n;
}
n = n.next;
}
}
Why is better copy the element in an hash table and not to another structure like a different linked list?
Thanks
Because checking for the existence of an item is an O(N) operation in a linked-list, however it is O(1) for the hash-table. Performance is the reason.
if(table.containsKey(n.data))
this is where the current item is checked if it is seen before (a duplicate) and that operation would be costly when implemented via a linked-list.

How do I join two linked lists in C?

I'm wanting to complete two linked lists in preparation for an exam
here is what I have so far
1 - reverse the elements in a linked list
2 - append list2 to the end of list one
I got help with the reverse function off someone in my course and have tried to comment out each step to understand what is going on but I am struggling. If you could also help me out with that it would be fantasticcaalll
In the combine function I am just confused overall
When do I use '&' and when do I use '*'?
typedef struct node *list;
typedef struct node {
int value;
list whateverNextIsCalled;
} node;
// Reverse list
list reverse (list inputList){
list outputList = NULL;
while (inputList != NULL) {
/*
nodePtr points to the first element in the inputList
*/
node *nodePtr = inputList;
/*
Make the head pointer of inputList point to the next element
*/
inputList = inputList->whateverNextIsCalled;
/*
???? help point 1
*/
nodePtr->whateverNextIsCalled = outputList;
/*
???? help point 2
*/
outputList = nodePtr;
}
return outputList;
}
// Add one list to the end of another
void combine (list list1, list list2){
/*
Point to the first value of list1
*/
node *current = list1;
/*
Find the last node of list1
*/
while(current->whateverNextIsCalled != NULL) {
current = current->whateverNextIsCalled;
}
//connect the last node of toList and the first node of fromList
current->whateverNextIsCalled = &list2;
list1 = current;
}
you can just reach to the last of the first linked list and in its next where there will be null just put the start of next linked list
i dint understand why you have reversed the list

Simulating a Markov Chain with Neo4J

A Markov chain is composed of a set of states which can transition to other states with a certain probability.
A Markov chain can be easily represented in Neo4J by creating a node for each state, a relationship for each transition, and then annotating the transition relationships with the appropriate probability.
BUT, can you simulate the Markov chain using Neo4J? For instance, can Neo4J be coerced to start in a certain state and then make transitions to the next state and the next state based upon probabilities? Can Neo4J return with a printout of the path that it took through this state space?
Perhaps this is easier to understand with a simple example. Let's say I want to make a 2-gram model of English based upon the text of my company's tech blog. I spin up a script which does the following:
It pulls down the text of the blog.
It iterates over every pair of adjacent letters and creates a node in Neo4J.
It iterates again over every 3-tuple of adjacent letters and then creates a Neo4J directed relationship between the node represented by the first two letters and the node represented by the last two letters. It initializes a counter on this relationship to 1. If the relationship already exists, then the counter is incremented.
Finally, it iterates through each node, counts how many total outgoing transitions have occurred, and then creates a new annotation on each relationship of a particular node equal to count/totalcount. This is the transition probability.
Now that the Neo4J graph is complete, how do I make it create a "sentence" from my 2-gram model of English? Here is what the output might look like:
IN NO IST LAT WHEY CRATICT FROURE BIRS GROCID PONDENOME OF DEMONSTURES OF THE REPTAGIN IS REGOACTIONA OF CRE.
Neo4j doesn't provide the functionality you're asking for out of the box, but since you've already come as far as correctly populating your database, the traversal that you need is just a few lines of code.
I've recreated your experiment here, with a few modifications. First of all, I populate the database with a single pass through the text (steps 2 and 3), but that's a minor. More importantly, I only store the number of occurrences on each relationship and the total number on the node (step 4), as I don't think there is a need to pre-calculate probabilities.
The code that you're asking for then looks something like this:
/**
* A component that creates a random sentence by a random walk on a Markov Chain stored in Neo4j, produced by
* {#link NGramDatabasePopulator}.
*/
public class RandomSentenceCreator {
private final Random random = new Random(System.currentTimeMillis());
/**
* Create a random sentence from the underlying n-gram model. Starts at a random node an follows random outgoing
* relationships of type {#link Constants#REL} with a probability proportional to that transition occurrence in the
* text that was processed to form the model. This happens until the desired length is achieved. In case a node with
* no outgoing relationships it reached, the walk is re-started from a random node.
*
* #param database storing the n-gram model.
* #param length desired number of characters in the random sentence.
* #return random sentence.
*/
public String createRandomSentence(GraphDatabaseService database, int length) {
Node startNode = randomNode(database);
return walk(startNode, length, 0);
}
private String walk(Node startNode, int maxLength, int currentLength) {
if (currentLength >= maxLength) {
return (String) startNode.getProperty(NAME);
}
int totalRelationships = (int) startNode.getProperty(TOTAL, 0);
if (totalRelationships == 0) {
//terminal node, restart from random
return walk(randomNode(startNode.getGraphDatabase()), maxLength, currentLength);
}
int choice = random.nextInt(totalRelationships) + 1;
int total = 0;
Iterator<Relationship> relationshipIterator = startNode.getRelationships(OUTGOING, REL).iterator();
Relationship toFollow = null;
while (total < choice && relationshipIterator.hasNext()) {
toFollow = relationshipIterator.next();
total += (int) toFollow.getProperty(PROBABILITY);
}
Node nextNode;
if (toFollow == null) {
//no relationship to follow => stay on the same node and try again
nextNode = startNode;
} else {
nextNode = toFollow.getEndNode();
}
return ((String) nextNode.getProperty(NAME)).substring(0, 1) + walk(nextNode, maxLength, currentLength + 1);
}
private Node randomNode(GraphDatabaseService database) {
return random(GlobalGraphOperations.at(database).getAllNodes());
}
}

Resources