Python: Linked list: questions about node = node.next and node.next = node - linked-list

I am practicing Python, Linked List:
class LinkedList
class LinkedList:
def init(self):
self.head = None
def __repr__(self):
node = self.head
nodes = []
while node is not None:
nodes.append(node.data)
node = node.next
nodes.append('None')
print(nodes)
return ' -> '.join(nodes)
Question:
We all know that to point the 1st node to the 2nd node: first_node.next = second_node
However, in the class LinkedList above, we can see: node = node.next
1/ What is the difference between them?
2/ In the class LinkedList, where is the next method from?
Thanks for your advance.

node = node.next could better be described as current_node = node.next since it is not always the first node. In the __repr__ function, you're basically setting a node to the head. Then printing the data in that node (which is head). Then we set node to node.next which makes node set to the second node. If there were a third, fourth, ... node in the list, then node would eventually get set to them until the last node.
The code you sent is incomplete because it needs to also implement the node class along with the linked list class. This basically holds the data and a pointer to the next node.
class Node:
def __init__(self, data, next = None):
self.data = data
self.next = next
So next would not be a method but rather a member which holds the address to the next node.

Related

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...

jenkins pipeline array of nodes with label

I'm trying to run steps in jenkins pipeline parallel in nodes with specified label
I have a hardcoded define with node names "def deviceLabels = ['Node 1', 'Node 2']" and both of these have also label "Device" and that works fine
"return jenkins.model.Jenkins.instance.nodes.collect { node -> node.name }" returns all node names but how to get array of nodes containing label "Device" ?
This seems to return a list of the node names that contain a certain label:
labelToSelect = 'Device'
listOfNodeNames = jenkins.model.Jenkins.instance.nodes.collect {
node -> node.getLabelString().contains(labelToSelect) ? node.name : null
}
listOfNodeNames.removeAll(Collections.singleton(null))
listOfNodeNames
You can mess around with this sort of thing in your jenkins console (your.jenkins.url/script).
You can use this to get all nodes with common labels, this example will return a list with all nodes that have the label 'Device1' and 'JAVA'
//define what labels to select
labelToSelect = ['Device1','JAVA']
listOfNodeNames = []
//iterate over each label
labelToSelect.each { label ->
listOfLabelNodeNames = jenkins.model.Jenkins.instance.nodes.collect {
//for each label get the list of nodes that contain the label
node -> node.getLabelString().contains(label) ? node.name : null
}
// if it's the first list then just keep the first list
if(listOfNodeNames.size() == 0)
listOfNodeNames = listOfLabelNodeNames
else // do intersection with the next list of nodes that contain the next label
listOfNodeNames = listOfNodeNames.intersect(listOfLabelNodeNames)
}
//remove all instances of null in our collection
listOfNodeNames.removeAll(Collections.singleton(null))
listOfNodeNames

Cannot cast GraphObject to Node

I have a defined AbstractQuery as a Child of GraphObject :
class AbstractQuery(GraphObject):
__primarykey__ = "hash"
hash = Property()
projname = Property()
def __init__(self, hash):
self.hash = hash
self.projname = "" # TODO:initialize this
and iterate over all SQLQuery objects in my (already existing) graph and want to create a new AbstractQuery consisting of a hash. Any SQLQuery hashing to the hash determining the AbstractQuery should be connected:
def addAbstractionLayerSqlQueries(graph, logger=None):
abstractQueryTable = getAbstractQueries(graph, logger)
sqlqueries = graph.data("MATCH (n:SQLQuery) return n")
if logger is not None:
logger.info("abstracting {} queries".format(len(sqlqueries)))
counter = 1
for iterator in sqlqueries:
query = iterator['n']
if logger is not None:
logger.info("abstracting query {}/{}".format(counter,
len(sqlqueries)))
hash = sqlNormalizer.generate_normalized_query_hash(query['ts'])
if hash not in abstractQueryTable:
abstractQueryNode = al.AbstractQuery(hash)
abstractQueryTable[hash] = abstractQueryNode
graph.push(abstractQueryNode)
rel = Relationship(query, "ABSTRACTSTO", abstractQueryTable[hash])
graph.create(rel)
counter = counter + 1
Before I start this process I extract a table (using the hash as key) of all already existing AbstractQueries to prevent creating the same AbstractQuery twice.
However, when I run the method I end up with the exception:
TypeError: Cannot cast AbstractQuery to Node
Why is this and how can I fix this?
I previously entered multiple SQLQueries into my graph by using this representation:
class SQLQuery(GraphObject):
__primarykey__ = "uuid"
uuid = Property()
projname = Property()
session = Property()
user = Property()
seq = Property()
ts = Property()
sql = Property()
Statement = RelatedTo("SQLStatement")
AbstractsTo = RelatedTo("AbstractQuery")
def __init__(self, projname=None, session=None, user=None,
seq=None, ts=None, sql=None):
self.projname = projname
self.session = session
self.user = user
self.seq = seq
self.ts = ts
self.sql = sql
self.uuid = "{} [{} {}] {}.{}.{}".format(type(self).__name__,
seq, ts, projname,
session, user)
As I was able to use this representation to represent and enter Nodes I am quite flabbergasted on why py2neo rejects my AbstractQuery class as a node in my addAbstractionLayerSqlQueries function.
You're mixing two layers of API. The OGM layer sits above the regular py2neo API and a GraphObject does not directly correspond to a Node (it contains other stuff too). Therefore, you cannot build a Relationship to or from a GraphObject directly.
To access the core node behind your GraphObject, you can use my_object.__ogm__.node.
I fixed the problem by only using the Object Model and replacing the graph.data(...) query part:
def addAbstractionLayerSqlQueries(graph, logger=None):
abstractQueryTable = getAbstractQueries(graph, logger)
sqlqueries = list(adlsql.SQLQuery.select(graph))
print type(sqlqueries)
if logger is not None:
logger.info("abstracting {} queries".format(len(sqlqueries)))
counter = 1
for query in sqlqueries:
print type(query)
if logger is not None:
logger.info("abstracting query {}/{}".format(counter,
len(sqlqueries)))
hash = sqlNormalizer.generate_normalized_query_hash(query.ts)
if hash not in abstractQueryTable:
abstractQueryNode = al.AbstractQuery(hash)
abstractQueryTable[hash] = abstractQueryNode
graph.push(abstractQueryNode)
query.AbstractsTo.add(abstractQueryTable[hash])
graph.push(query)
counter = counter + 1
However, the actual reason for the error is still unknown and I'll accept any answer that explains this. This answer is only fixing the problem.

Adding to SortedLinkedList using nodes

im making a SortedLinkedList, I'm trying to add lets say 10 integers of different value so I can run some asssert tests. But I'm having a problem adding them so they are already sorted when they arrive to the LinkedList, I tried using the curr.info.compareTo(x) > 0 for instance, but I'm having trouble making the correct else/if statements so it sorts them when they are added.
This code has 4 classes, I can provide more if its unclear.
Thank you for your help in advance.
Best regards,
Victor
public class SortedLinkedList<T extends Comparable<T>> implements Iterable<T> {
/* Easy operations for a linked list
add(x): Searching for the place where the element x is to be added must
take place in the calling routine. This must set previous to
point to the node AFTER which the new element is to be inserted.
curr is set to point to the new element.
remove(): The curr element is removed from the list. Searching for this
element must take place in the calling routine. This must set
curr to point to the element to be removed. After removal curr
points to the element following the removed one.
isEmpty(): checks for an empty list
endOfList(): checks whether curr has reached and passed the end of the list
retrievecurr(): return the info part of the curr element.
reset(): resets the list so that curr points to the first element
succ(): an iterator, moves curr one step forward
Note that when a class implements the interface Iterable<T> then
it can be the target of the "foreach" statement. See IterationExample.java */
private Node start, curr, prev;
public SortedLinkedList() {
curr = null; // the curr position in the list
start = null; // the first element
prev = null; // the node before curr
}
public void add(T x) {
if (start == null) { // if start == null, insert a first element into an empty list
Node newNode = new Node(); // create the new element, info and link are set to null.
newNode.info = x; // and assign the data given as parameter. The link is left as null
start = newNode; // start is updated to point to the new element
curr = start; // curr is updated to point to the new first (and only) element
} else if (prev == null) { // a new first element is inserterd into a non-empty list
Node newNode = new Node(); // a new node is created ...
newNode.info = x; // and assigned the data given as parameter
newNode.link = start; // and linked before the old first element
start = newNode; // start is updated to point to the new first element
curr = newNode; // curr is updated to point to the new first element
} else { // a new element is inserted last (if prev.link == null) or between prev and curr
Node newNode = new Node(); // create a new node
newNode.info = x; // assign it the data given as parameter
newNode.link = prev.link; // link it before curr ...
prev.link = newNode; // ... and after previous
curr = newNode; // update curr to point to newNode
}
} // add*
}

#Neo4j Deleting nodes/relationship while traversing using java API

I have a requirement to traverse all the nodes and delete all the nodes (and its relationships and connected nodes) based on certain criteria. For testing purpose (to make sure I can delete the nodes while traversing), i'm trying to just delete one node in the middle of the traverse and using another traversal to delete all the nodes and relationships attached to that node. I'm able to delete all the nodes and relationships but after that i'm getting IllegalStateException (Node has been deleted) when the loop is back to the 1st traversal. Is it possible to delete the nodes/relationships while traversing? If so, what is the effective way to traverse all nodes and delete some nodes along the way. Thanks in advance!
private void traverseGivenNode(Node node, TraversalDescription friendsTraversal) {
for ( Node currentNode : friendsTraversal.traverse(node).nodes() )
{
if (currentNode.getProperty("name").equals("AAA")) {
deleteNodeAndItsConnections(currentNode);
}
}
}
private void deleteNodeAndItsConnections(Node currentNode) {
TraversalDescription traversal = graphDb.traversalDescription()
.breadthFirst()
.uniqueness( Uniqueness.NODE_PATH ).evaluator(Evaluators.excludeStartPosition() ).relationships( RelTypes.KNOWS, Direction.OUTGOING );
for ( Node node : traversal.traverse(currentNode).nodes() )
{
deleteNode(node);
}
deleteNode(currentNode);
}
private void deleteNode(Node node) {
Iterable<Relationship> allRelationships = node.getRelationships();
for (Relationship relationship : allRelationships) {
relationship.delete();
}
node.delete();
}
One way to solve this would be to not delete anything until the traversals are complete. Instead, during the traversals, just add each node and relationship to be deleted to the corresponding HashSet. Afterwards, call Relationship.delete() on everything in the relationship Set, followed by Node.delete() on everything in the Node set.
Create set for relationships to be added and deleted.
Set<Relationship> removableRelations = new HashSet<Relationship>();
Set<Node> removableNodes = new HashSet<Node>();
Add nodes and relationships to be deleted in removableRelations and removableNodes
then write below code for removing these:
for(Relationship removableRel:removableRelations){
removableRel.delete();
}
for(Node remNode:removableNodes){
remNode.delete();
}

Resources