DFS and BFS on a Trie in Java - java

I have a Trie which looks like this:
Root
/ \
b c
/ / \
a a h
/ / / \
t t a e
/ /
t e
/ \
r s
/ \
s e
I'm trying to implement a DFS, and BFS. The BFS works fine, using a queue:
public String breadthFirstSearch() {
//FIFO Queue to hold nodes
Queue<TrieNode> nodeQueue = new LinkedList<TrieNode>();
//Output array
ArrayList<Integer> out = new ArrayList<Integer>();
//Start from root
nodeQueue.add(this.root);
//While queue is not empty
while (nodeQueue.isEmpty() == false) {
//Remove and return first queue element
TrieNode current = nodeQueue.poll();
//For node's children
for (int i=0; i<26; i++) {
//If not null
if (current.offspring[i] != null) {
//Add node to queue
nodeQueue.add(current.offspring[i]);
//Add node's index (char) to output array
out.add(i);
}
}
}
//Return result
return indexArrayToString(out);
}
Output:
b,c,a,a,h,t,t,a,e,t,e,r,s,s,e
Now, I'm trying to implement the DFS (same algorithm, but using a stack) however the output isn't correct:
public String depthFirstSearch() {
//LIFO Stack to hold nodes
Stack<TrieNode> nodeStack = new Stack<TrieNode>();
//Output array
ArrayList<Integer> out = new ArrayList<Integer>();
//Start from root
nodeStack.push(this.root);
//While stack is not empty
while (nodeStack.isEmpty() == false) {
//Remove and return first stack element
TrieNode current = nodeStack.pop();
//For node's children
for (int i=0; i<26; i++) {
//If not null
if (current.offspring[i] != null) {
//Add node to stack
nodeStack.push(current.offspring[i]);
//Add node's index (char) to output array
out.add(i);
}
}
}
//Return result
return indexArrayToString(out);
}
This gives:
b,c,a,h,a,e,e,r,s,e,s,t,t,a,t
When I want it to give:
t,a,b,t,a,t,a,s,r,e,s,e,e,h,c
I can't figure out what's going wrong.

I have implemented the map-based approach that I mentioned in my comment, i.e. without modifying the original TrieNode class:
public String depthFirstSearch() {
//LIFO Stack to hold nodes
Stack<TrieNode> nodeStack = new Stack<TrieNode>();
//keep set of processed nodes (processed node is a node whose children were already pushed into the stack)
Set<TrieNode> processed = new HashSet<TrieNode>();
//boolean for checking presence of at least one child
boolean hasChild=false;
//map for trienode->char
Map<TrieNode, Integer> map = new HashMap<TrieNode, Integer>();
//Output array
List<Integer> out = new ArrayList<Integer>();
//Start from root
nodeStack.push(this.root);
//While stack is not empty
while (nodeStack.isEmpty() == false) {
//Peek at the top of stack
TrieNode topNode = nodeStack.peek();
//if it is not processed AND if it has at least one child, push its children into the stack from right to left. otherwise pop the stack
hasChild=false;
if(!processed.contains(topNode))
{
for (int i=25; i>=0; i--)
{
//If not null
if (topNode.offspring[i] != null)
{
//Add node to stack and map
nodeStack.push(topNode.offspring[i]);
map.put(topNode.offspring[i], i);
hasChild=true;
}
}//end for
processed.add(topNode); //after discovering all children, put the top into set of processed nodes
if(!hasChild) //top node has no children so we pop it and put into the list
{
TrieNode popNode = nodeStack.pop();
if(map.get(popNode)!=null)
out.add(map.get(popNode));
}
}
else //the node has been processed already so we pop it and put into the list
{
TrieNode popNode = nodeStack.pop();
if(map.get(popNode)!=null)
out.add(map.get(popNode));
}
}//end while stack not empty
//Return result
return indexArrayToString(out);
}//end method

To get the output that you wanted, you need to think about when a node is added to the out list. In your code, you start at the root and iterate throught it's offspring in a kind-of recursive style while adding them directly to your output. Therefore your output has more in common with a BFS than a DFS.
Although there are very simple DFS implementations like
DFS(TrieNode current){
for(int i = 26; i >= 0; i--){
if(current.offspring[i] != null){
DFS(current.offspring[i]);
}
}
out.add(current);
}
if you want to keep most of your code for any reason, you could create a second stack that keeps track for you where in the tree you are and when which node is supposed to be added to the output.
Explicitly, this could look something like this:
public String depthFirstSearch() {
//LIFO Stack to hold nodes
Stack<TrieNode> nodeStack = new Stack<TrieNode>();
//Second stack that keeps track of visited nodes
Stack<TrieNode> helpStack = new Stack<TrieNode>();
//Output array
ArrayList<Integer> out = new ArrayList<Integer>();
//Start from root
nodeStack.push(this.root);
//While stack is not empty
while (nodeStack.isEmpty() == false) {
//Remove and return first stack element
TrieNode current = nodeStack.peek();
//We visited this node -> push it on the second stack
helpStack.push(current);
//We want to add nodes to the output once we reach a leaf node, so we need a
//helper variable
boolean hasOffspring = false;
//For node's children - since we want to go the left path first we push the
//children in right-to-left fashion on the stack. Can vary with implementation.
for (int i=25; i>=0; i--) {
//If not null
if (current.offspring[i] != null) {
//Add node to stack
nodeStack.push(current.offspring[i]);
//not a leaf
hasOffspring = true;
}
}
//if we reached a leaf node add it and all previous nodes to the output until
//we reach a fork where we didn't already fo the other path
if(!hasOffspring){
TrieNode node1 = nodeStack.peek();
TrieNode node2 = helpStack.peek();
while(node1.equals(node2)){
nodeStack.pop();
helpStack.pop();
//Add node's index (char) to output array
out.add(node1);
//we are back at the root and completed the DFS
if(nodeStack.isEmpty() || helpStack.isEmpty()) break;
node1 = nodeStack.peek();
node2 = nodeStack.peek();
}
}
}
//Return result
return indexArrayToString(out);
}

Related

DFS is not working properly for undirected graph

I want to use DFS to find all possible paths from one source vertex to a destination vertex. Being new to recursion, I am just completely lost in how I would have my recursive method perform such a function.
The code I have right now only finds one path and exits the method after the vertex had been found.
The code I have:
public Node DFSTime(Node node) {
// Boolean to check if the destination airport is found and then exit the
// recursive method
boolean ifreached = false;
// Check if the node is the destination airport
if (node.element.equals(destinationAirport)) {
stack.push(node);
return null;
} else {
int index = 0;
stack.push(node);
// Find the exact index of the node in the adjacency list
for (int i = 0; i < adjList.adjMatrix.size(); i++) {
if (adjList.adjMatrix.get(i).head.element.equals(node.element) == true) {
index = i;
break;
}
}
// Check if the node is already visited
if (visited.contains(node.element.toString()) == false) {
visited.add(node.element.toString());
}
Node currentNode = adjList.adjMatrix.get(index).head.nextNode;
// counter to keep track of the number of neighbors visited
int counter = 0;
// Iterating through the linked list at adjMatrix[index]
while (currentNode != null) {
// If visited then skip
if (visited.contains(currentNode.element) == false) {
previousAirport = node.element.toString();
Node temp = DFSTime(currentNode);
//If the destination airport is found then exit the recursive method
if (temp == null) {
ifreached = true;
break;
}
}
//Iterate to the next neighbor
currentNode = currentNode.nextNode;
counter++;
}
// If the destination airport is not found after iterating through the neighbors
// then pop the stack
if (counter == adjList.adjMatrix.get(index).size - 1) {
Node temp = stack.pop();
previousAirport = temp.element.toString();
visited.remove(temp.element.toString());
return temp;
}
}
// If the destination airport is found then return null
if (ifreached == true) {
return null;
}
return node;
}
This question is similar to another question I asked, and so I basically tried to change a few things from that question for my recursive method.
The Stack is a linked list stack I implemented. And the adjacency list is an ArrayList of Linked Lists.

How to perform different basic traversals of graphs?

I am trying to perform an iterative breadth first traversal, iterative depth first traversal, and recursive depth first traversal of a given graph (using an adjacency matrix).
In its current state, my program outputs various wrong answers.
Here's some examples.
I am expecting
From Node A
DFS (iterative): A B H C D E I F G
DFS (recursive): A B H C D E I F G
BFS (iterative): A B D I H C E F G
but am instead getting
From Node A
DFS (iterative): A I D B H C F G E
DFS (recursive): A B H C F D E I G
BFS (iterative): A B D I H C E F G
I'm unsure if the problem with my program lies within the implementation of the traversals, or my implementation of some other part of the program. To be more specific, I'm not sure if my implementation connectNode or getNeighbors method is what is causing the incorrect output, or if it is my implementation of the traversals.
EDIT: Neighbors are supposed to be chosen in ascending order, if that's important. Perhaps this is part of the problem?
EDIT2: I added the new line of code, thanks to #HylianPikachu's suggestion. I now get full answers, but they are still not in the correct order.
EDIT3: I added the code to make it so the root node is checked as visited for bfs and recursive dfs. I think. I should also note that I was given parts of this code and told to fill in the rest. The use of the stack and queue are what I was told to use, even though there might be better options.
EDIT4: Added what was suggested, and now, the Iterative BFS works and gets the correct result. However, both DSF searches still do not work. I modified the results of the program above, to show this.
import java.util.*;
public class GraphM {
public Node rootNode;
public List<Node> nodes = new ArrayList<Node>(); // nodes in graph
public int[][] adjMatrix; // adjacency Matrix
public void setRootNode(Node n) {
rootNode = n;
}
public Node getRootNode() {
return rootNode;
}
public void addNode(Node n) {
nodes.add(n);
}
// This method connects two nodes
public void connectNode(Node src, Node dst) {
if(adjMatrix == null) {
adjMatrix = new int[nodes.size()][nodes.size()];
}
adjMatrix[nodes.indexOf(src)][nodes.indexOf(dst)] = 1;
adjMatrix[nodes.indexOf(dst)][nodes.indexOf(src)] = 1;
}
// Helper method to get one unvisited node from a given node n.
private Node getUnvisitedChildNode(Node n) {
int index = nodes.indexOf(n);
int size = adjMatrix.length;
for (int j = 0; j < size; j++)
if (adjMatrix[index][j] == 1 && ((Node) nodes.get(j)).visited == false)
return nodes.get(j);
return null;
}
// get all neighboring nodes of node n.
public List<Node> getNeighbors(Node n) {
List<Node> neighbors = new ArrayList<Node>();
for(int i = 0; i < nodes.size(); i ++) {
if (adjMatrix[nodes.indexOf(n)][i] == 1) {
neighbors.add(nodes.get(i));
}
Collections.sort(neighbors);
}
return neighbors;
}
// Helper methods for clearing visited property of node
private void reset() {
for (Node n : nodes)
n.visited = false;
}
// Helper methods for printing the node label
private void printNode(Node n) {
System.out.print(n.label + " ");
}
// BFS traversal (iterative version)
public void bfs() {
Queue<Node> queue = new LinkedList<Node>();
queue.add(rootNode);
while(!queue.isEmpty()) {
Node node = queue.poll();
printNode(node);
node.visited = true;
List<Node> neighbors = getNeighbors(node);
for ( int i = 0; i < neighbors.size(); i ++) {
Node n = neighbors.get(i);
if (n != null && n.visited != true) {
queue.add(n);
n.visited = true;
}
}
}
}
// DFS traversal (iterative version)
public void dfs() {
Stack<Node> stack = new Stack<Node>();
stack.add(rootNode);
while(!stack.isEmpty()){
Node node = stack.pop();
if(node.visited != true) {
printNode(node);
node.visited = true;
}
List<Node> neighbors = getNeighbors(node);
for (int i = 0; i < neighbors.size(); i++) {
Node n = neighbors.get(i);
if(n != null && n.visited != true) {
stack.add(n);
}
}
}
}
// DFS traversal (recursive version)
public void dfs(Node n) {
printNode(n);
n.visited = true;
List<Node> neighbors = getNeighbors(n);
for (int i = 0; i < neighbors.size(); i ++) {
Node node = neighbors.get(i);
if(node != null && node.visited != true) {
dfs(node);
}
}
}
// A simple Node class
static class Node implements Comparable<Node> {
public char label;
public boolean visited = false;
public Node(char label) {
this.label = label;
}
public int compareTo(Node node) {
return Character.compare(this.label, node.label);
}
}
// Test everything
public static void main(String[] args) {
Node n0 = new Node('A');
Node n1 = new Node('B');
Node n2 = new Node('C');
Node n3 = new Node('D');
Node n4 = new Node('E');
Node n5 = new Node('F');
Node n6 = new Node('G');
Node n7 = new Node('H');
Node n8 = new Node('I');
// Create the graph (by adding nodes and edges between nodes)
GraphM g = new GraphM();
g.addNode(n0);
g.addNode(n1);
g.addNode(n2);
g.addNode(n3);
g.addNode(n4);
g.addNode(n5);
g.addNode(n6);
g.addNode(n7);
g.addNode(n8);
g.connectNode(n0, n1);
g.connectNode(n0, n3);
g.connectNode(n0, n8);
g.connectNode(n1, n7);
g.connectNode(n2, n7);
g.connectNode(n2, n3);
g.connectNode(n3, n4);
g.connectNode(n4, n8);
g.connectNode(n5, n6);
g.connectNode(n5, n2);
// Perform the DFS and BFS traversal of the graph
for (Node n : g.nodes) {
g.setRootNode(n);
System.out.print("From node ");
g.printNode(n);
System.out.print("\nDFS (iterative): ");
g.dfs();
g.reset();
System.out.print("\nDFS (recursive): ");
g.dfs(g.getRootNode());
g.reset();
System.out.print("\nBFS (iterative): ");
g.bfs();
g.reset();
System.out.println("\n");
}
}
}
So, we already covered the first part of your question, but I'll restate it here for those who follow. Whenever working with graphs and an adjacency matrix, probably the best way to initialize elements in the array is "both ways."
Instead of just using the following, which would require a specific vertex be listed first in order to find the neighbors:
adjMatrix[nodes.indexOf(src)][nodes.indexOf(dst)] = 1;
Use this, which leads to searches that are agnostic of the vertex order:
adjMatrix[nodes.indexOf(src)][nodes.indexOf(dst)] = 1;
adjMatrix[nodes.indexOf(dst)][nodes.indexOf(src)] = 1;
Now, for ordering. You want the vertices to be outputted in order from "least" letter to "greatest" letter. We'll address each one of your data structures individually.
In BFS (iterative), you use a Queue. Queues are "first in, first out." In other words, the element that was least recently added to the Queue will be outputted first whenever you call queue.poll(). Thus, you need to add your nodes from least to greatest.
In DFS (iterative), you use a Stack. Stacks are "last in, first out." In other words, the element that was most recently added to the Stack will be outputted first whenever you call stack.pop(). Thus, you need to add your nodes from greatest to least.
In DFS (recursive), you use a List. Lists have no "in-out" ordering per se, as we can poll them in whatever order we want, but the easiest thing to do would just be to sort the List from least to greatest and output them in order.
With this in mind, we need to introduce protocol for sorting the graph. All three protocols use getNeighbors(), so we'll sort the outputted List immediately after we call that function. Lists can be ordered with the function Collections.sort(List l) from java.utils.Collections, but we first need to modify your nodes class so Java knows how to sort the Nodes. For further reading about the details of what I'm doing, you can look here, but this post is getting way longer than I intended already, so I'm going to just show the code here and let the interested explore the link themselves.
You would first tweak your Node class by implementing Comparable<Node> and adding the compareTo() function.
static class Node implements Comparable<Node>{
public char label;
public boolean visited = false;
public Node(char label) {
this.label = label;
}
#Override
public int compareTo(Node that) {
return Character.compare(this.label, that.label);
}
}
Then, in the cases in which we want to order the List from least to greatest, we can use Collections.sort(neighbors). When we want it from greatest to least, we can use Collections.sort(neighbors, Collections.reverseOrder()). Our final code will look like this:
// BFS traversal (iterative version)
public void bfs() {
Queue<Node> queue = new LinkedList<Node>();
queue.add(rootNode);
while(!queue.isEmpty()) {
Node node = queue.poll();
printNode(node);
node.visited = true;
List<Node> neighbors = getNeighbors(node);
//NEW CODE: Sort our neighbors List!
Collections.sort(neighbors);
for ( int i = 0; i < neighbors.size(); i ++) {
Node n = neighbors.get(i);
if (n != null && n.visited != true) {
queue.add(n);
n.visited = true;
}
}
}
}
// DFS traversal (iterative version)
public void dfs() {
Stack<Node> stack = new Stack<Node>();
stack.add(rootNode);
while(!stack.isEmpty()){
Node node = stack.pop();
if(node.visited != true) {
printNode(node);
node.visited = true;
}
List<Node> neighbors = getNeighbors(node);
//NEW CODE: Sort our neighbors List in reverse order!
Collections.sort(neighbors, Collections.reverseOrder());
for (int i = 0; i < neighbors.size(); i++) {
Node n = neighbors.get(i);
if(n != null && n.visited != true) {
stack.add(n);
}
}
}
}
// DFS traversal (recursive version)
public void dfs(Node n) {
printNode(n);
n.visited = true;
List<Node> neighbors = getNeighbors(n);
//NEW CODE: Sort our neighbors List!
Collections.sort(neighbors);
for (int i = 0; i < neighbors.size(); i ++) {
Node node = neighbors.get(i);
if(node != null && node.visited != true) {
dfs(node);
}
}
}
I would suggest splitting up your problem into smaller parts.
If you want to write a class for an undirected graph, first do that and test it a bit.
If you want to look if you can implement traversal, make sure your graph works first. You can also use guava, which lets you use MutableGraph (and lots more). Here is how to install it in case you're using IntelliJ and here is how to use graphs from guava.
Also remember to use a debugger to find out were your code goes wrong.

Changing object reference in Java

I am trying to implement a suffix trie in Java. A trie has a root node and connected to it are edges. However, when implementing functions such as constructTrie(T) (constructs a trie given a String T) or substring(S,T) (checks whether S is a substring of T), I am keeping a current node cNode which changes throughout the code depending on which node I am considering.
I am not sure if I'm changing cNode's value correctly. The following is class Trie.
import java.util.*;
class Trie{
protected Node root = null;
public Trie(){
Node n = new Node();
root = n;
}
// Constructs a trie for a given string T
public void constructTrie(String T){
ArrayList<String> suffixArray = new ArrayList<String>();
T += "#"; // Terminator
int length = T.length();
// Creates suffix array and removes first letter with every iteration
for(int i=0; i<length; i++){
suffixArray.add(T);
T = T.substring(1);
}
// Goes through suffix array
for(int i=0; i<length; i++){
Node cNode = null;
cNode = root; // Current node
int j = 0;
// Goes through each letter of an entry in the suffix array
while(j < (suffixArray.get(i)).length()){
int index = cNode.findEdge((suffixArray.get(i)).charAt(j));
// If an edge is found at the root with the current letter, update cNode and remove the letter from word
if(index != -1){
cNode = cNode.getEdge(index).getNode(); // Gets node pointed at by edge and sets it as current node
String replace = (suffixArray.get(i)).substring(1);
suffixArray.set(0, replace); // Erases first letter of suffix
j++;
System.out.println(i + " " + j + " " + replace);
}
// If an edge is not found at the root, write the whole word
else{
for(int k=0; k<(suffixArray.get(i)).length(); k++){
Edge e = new Edge((suffixArray.get(i)).charAt(k)); // Creates edge with current letter of current entry of the suffix array
Node n = new Node(); // Creates node to be pointed at by edge
e.setNode(n);
cNode.newEdge(e);
cNode = n; // Updates current node
}
j = (suffixArray.get(i)).length(); // If the word is written, we break from the while and move on to the next suffix array entry
}
}
}
}
// Checks if S is a substring of T
public boolean substring(String S, String T){
constructTrie(T);
Node cNode = null;
cNode = root;
int index;
for(int i=0; i<S.length(); i++){
index = cNode.findEdge(S.charAt(i));
if(index == -1)
return false; // Substring was not found because a path was not followed
cNode = (cNode.getEdge(index)).getNode(); // Reset current node to the next node in the path
}
return true; // Substring was found
}
Specifically, am I allowed to set Node root = null as a class variable, initialise root when an object of type Trie is created and change cNode as shown in the methods? The code is compiled with no errors, however when tested it does not always output the correct response e.g. when tested, it outputs that 'es' is not a substring of 'pest'.
Updating fields in a method of a class makes a class not thread safe. Your methods have side effects that may not be what the user of the your class expects.
Consider:
Trie t = new Trie("My String");
boolean startsWithMy = t.substring("My");
boolean startsWithMyString = t.substring("My String");
If you're updating the root field in the substring method, then the 2nd call won't do what you might expect, since the first substring call changed the Trie.
If you want to make a reusable class that is easy to use with minimal side effects, then what I would do is write your class following this basic pattern:
public class Trie {
private final Node root;
public Trie(String input) {
// Construct the Trie here and assign it to root:
this.root = constructTry(input);
}
public boolean substring(String part) {
// Create a local Node variable:
Node currentNode = root;
// Navigate the Trie here using currentNode:
// ...
return result;
}
}
You can even add a method (if you desire) to return a subpart of the Trie:
public Trie subTrie(String part) {
// Find the Node here that matches the substring part, and return it.
// If nothing found, then throw NoSuchElementException or return null.
Node subNode = findNode(part);
if (subNode == null) {
throw new NoSuchElementException("No element starting with: " + part);
}
// Constructs a new Trie with a different root node using a 2nd constructor option
return new Trie(subNode);
}
You are changing the reference of your root node by adding garbage to it.
Let say you do this:
Trie trie = new Trie();
trie.substring("es", "pest"); // this returns true.
but if you do
Trie trie = new Trie();
trie.substring("es", "pest");
trie.substring("te", "Master");
You second call to Substring will pick up where your last call left. You root is already initialized and contains a tree for the word "pest" root(p, e, s, t, #). After the second call instead of having as expected root(M, a, s, t, e, r, #), you end up with root(p, e, s, t, #, M, a, r). Which is is a completely different word. As such te is not a substring of pest#Mar.
But if you implement it according to #john16384, you will be forced to do the following which eliminate the side effects:
Trie trie = new Trie("pest");
trie.substring("es"); // this returns true.
trie = new Trie("Master");
trie.substring("te") // this returns true.
Doing it this way alway forces you to start from a clean root. See the implementation below:
class Trie {
protected Node root = null;
public Trie(String T) {
root = constructTrie(T);
}
// Constructs a trie for a given string T
private Node constructTrie(String T) {
ArrayList<String> suffixArray = new ArrayList<String>();
T += "#"; // Terminator
int length = T.length();
// Creates suffix array and removes first letter with every iteration
for (int i = 0; i < length; i++) {
suffixArray.add(T);
T = T.substring(1);
}
Node localRoot = new Node();
// Goes through suffix array
for (int i = 0; i < length; i++) {
Node cNode = localRoot;
int j = 0;
// Goes through each letter of an entry in the suffix array
while (j < (suffixArray.get(i)).length()) {
int index = cNode.findEdge((suffixArray.get(i)).charAt(j));
// If an edge is found at the root with the current letter, update cNode and remove the letter from word
if (index != -1) {
cNode = cNode.getEdge(index).getNode(); // Gets node pointed at by edge and sets it as current node
String replace = (suffixArray.get(i)).substring(1);
suffixArray.set(0, replace); // Erases first letter of suffix
j++;
System.out.println(i + " " + j + " " + replace);
}
// If an edge is not found at the root, write the whole word
else {
for (int k = 0; k < (suffixArray.get(i)).length(); k++) {
Edge e = new Edge((suffixArray.get(i)).charAt(k)); // Creates edge with current letter of current entry of the suffix array
Node n = new Node(); // Creates node to be pointed at by edge
e.setNode(n);
cNode.newEdge(e);
cNode = n; // Updates current node
}
j = (suffixArray.get(i)).length(); // If the word is written, we break from the while and move on to the next suffix array entry
}
}
}
return localRoot;
}
// Checks if S is a substring of T
public boolean substring(String S) {
Node cNode = root;
int index;
for (int i = 0; i < S.length(); i++) {
index = cNode.findEdge(S.charAt(i));
if (index == -1)
return false; // Substring was not found because a path was not followed
cNode = (cNode.getEdge(index)).getNode(); // Reset current node to the next node in the path
}
return true; // Substring was found
}
}

How to insert an item at a given position in a linked list?

This how you would add an item:
public void insert (Object item)
{
Link add = new Link();
add.data = item;
add.next = head;
_head = add;
++_listsize;
}
But how do you add an item at a given position. So far this is what I got:
public void insert (Object item, int pos)
{
Link add = new Link();
int ix = pos - 1;
add.next = _head;
for (int i = _listsize - 1; i >= ix; --i)
add = add.next;
add.data = item;
_head = add;
++_listsize;
}
This will insert the item correctly if it is sequential, but let say I am given a position which is in the middle, what it will do it will insert the item but it will completely cut off (or delete the rest). For example:
insert at 1:
a
insert at 2:
b
a
insert at 3:
c
b
a
insert at 2:
d
a
You should do something like this:
public void insert (Object item, int pos)
{
Link add = new Link();
int ix = pos - 1;
Link cur = _head;
for (int i = 0; i < _list_size; i++) {
if(i == ix) {
add.next = cur.next;
cur.next = add;
}
cur = cur.next;
}
++_listsize;
}
It seems you have not correctly inserted the new Link into the list. When you do that, you need to find the Link at the given position as well as the Link at the previous position. Then only you can set the previous.next = add and add.next = position.
Below is the updated method that does the task.
public void insert (Object item)
{
Link add = new Link();
add.data = item;
add.next = _head;
_head = add;
++_listsize;
}
public void insert (Object item, int pos)
{
Link add = new Link();
add.data = item;
int ix = pos - 1;
add.next = _head;
Link previous = _head;
for (int i = _listsize - 1; i > ix; --i) {
previous = previous.next;
}
Link position = previous.next;
previous.next = add;
add.next = position;
++_listsize;
}
Use add( int index, E element), which insert the element at the specified index : http://docs.oracle.com/javase/7/docs/api/java/util/LinkedList.html#add(int, E)
EDIT : if you're using LinkedList, of course ; with your own class, you have to store prev/next pointers and simply update them (previous node next's pointer should point to the new element, and next node previous's pointer should point to the new element too)
It is definetly possible. But what would matter most is deciding at which position to insert new element because after each insertion the list would change and position of new element coming will have to be decided appropriately. You can try this
insertat=head;
for(i=0;i<pos;i++){
insertat=insertat.next;
}
add.next=insertat.next;
insertat.next=add;
listsize++;
You need a temporary variable that start from the head, traverse each node until the desired position or the end of the list, then insert the new node.
Since it is a homework exercise, I will only post pseudo code:
if pos < 0
//define what to do here...
return
end if
if pos == 0
//inserting at the beginning
insert(item)
return
end if
Link temp <- head
int index <- 0
while index < pos and temp->next != null
temp <- temp->next
index <- index + 1
end while
//now you're at your desired location or at the end of the list
Link newLink <- new Link
newLink->data <- item
newLink->next <- temp->next
temp->next <- newLink
After attempting alone the implementation of the concept, you can consider the open-source research. One of the best things you can do with open source is learn from it, study the implementation of java.util.LinkedList,
following the logic of the method add (int index, E element) { http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/6-b14/java/util/LinkedList.java#360 }, you can divide in;
1) Get where the element will be added, in your case "link"
http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/6-b14/java/util/LinkedList.java#380
2) and you can examine the code that links the elements following the logic "before adding" in the code snippet
http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/6-b14/java/util/LinkedList.java#794
So, you will understand the logic behind the algorithm and will be able to perform your own implementation
My solution is not as clean as it will be with recursion but if you are testing more than 50,000 elements on the list go with an iterative solution. or you can modify the JVM and change the stack size.
Because you can get a stack overflow just because you will pass the capacity of activation records in the stack. Think about the worst case scenario that you will do an insert at the end of the list.
/**
* Inserts the specified element at the specified position in this list.
*
* #param :index the desire position starting from 0 2,3,4,5
* #param :data the content of the new node
* #return Boolean: if the insertion was successfully return true otherwise false
*/
public boolean add(int index, T data) {
/*Add to the end of the list*/
if (index == size()) {
add(data);
return true;
}
/*Empty list and index bigger than 0*/
else if (this.front == null && index != 0) {
return false;
} else {
Node<T> tempNode = this.front;
while (tempNode != null && tempNode.next != null && --index != 0) {
tempNode = tempNode.next;
}
if (index != 0) {
return false;
} else {
Node<T> newNode = new Node<T>(data);
/*Empty list,and index is 0*/
if (tempNode == null) {
this.front = newNode;
} else {
newNode.next = tempNode.next;
tempNode.next = newNode;
}
}
}
return true;
}

Inserting a node into a linked list in constant-time?

I'm working on an assignment that is telling me to assume that I have a singly linked list with a header and tail nodes. It wants me to insert an item y before position p. Can anybody please look over my code and tell me if I'm on the right track? If not, can you provide me with any tips or pointers (no pun intended)?
tmp = new Node();
tmp.element = p.element;
tmp.next = p.next;
p.element = y;
p.next = tmp;
I think I may be wrong because I do not utilize the header and tail nodes at all even though they are specifically mentioned in the description of the problem. I was thinking of writing a while loop to traverse the list until it found p and tackle the problem that way but that wouldn't be constant-time, would it?
Just write it down if you get stuck with an algorithm:
// First we have a pointer to a node containing element (elm)
// with possible a next element.
// Graphically drawn as:
// p -> [elm] -> ???
tmp = new Node();
// A new node is created. Variable tmp points to the new node which
// currently has no value.
// p -> [elm] -> ???
// tmp -> [?]
tmp.element = p.element;
// The new node now has the same element as the original.
// p -> [elm] -> ???
// tmp -> [elm]
tmp.next = p.next;
// The new node now has the same next node as the original.
// p -> [elm] -> ???
// tmp -> [elm] -> ???
p.element = y;
// The original node now contains the element y.
// p -> [y] -> ???
// tmp -> [elm] -> ???
p.next = tmp;
// The new node is now the next node from the following.
// p -> [y] -> [elm] -> ???
// tmp -> [elm] -> ???
You have the required effect, but it can be more efficient and I bet you can now find out yourself.
It is more clear to write something like:
tmp = new Node();
tmp.element = y;
tmp.next = p;
p = tmp;
Which of course does not work if p is not mutable. But your algorithm fails if p == NULL.
But what I meant to say, is, if you have problems with an algorithm, just write the effects out. Especially with trees and linked lists, you need to be sure all pointers are pointing to the righ direction, else you get a big mess.
Hint: insertion into a linked list is only constant when position n = 0, or the head of the list. Otherwise, the worst-case complexity is O(n). That's not to say that you cannot create a reasonably efficient algorithm, but it will always have at least linear complexity.
The reason why the header and tail node is given in the question is to the update the header and tail reference if the the replacement node that your creating happens to become the header or tail. In other is words, the given previous node is either a header or tail.
What you are not doing is linking the element that was before p prior to insertion of y to y. So while y is inserted before p, no one is pointing to y now (at-least not in the code snipped you showed).
You can only insert in constant time if you know the positions of the elements between which you have to insert y. If you have to search for that position, then you can never have a constant time insertion in a single link list.
How about using code that is already there? LinkedHashMap, LinkedList, LinkedHashSet. You can also check out the code and learn from it.
create a node ptr
ptr->info = item //item is the element to be inserted...
ptr->next = NULL
if (start == NULL) //insertion at the end...
start = ptr
else
temp = ptr
while (temp->next != NULL)
temp = temp->next
end while
end if
if (start == NULL) //insertion at the beginning...
start = ptr
else
temp = start
ptr->info = item
ptr->next = start
start = ptr
end if
temp = start //insertion at specified location...
for (i = 1; i < pos-1; i++)
if (start == NULL)
start = ptr
else
t = temp
temp = temp->next
end if
end for
t->next = ptr->next
t->next = ptr
In a singly LinkedList only adding a Node to the beginning of the list or creating a List with only one Node would take O(1). OR as they have provided the TailNode also Inserting the Node at End of list would take O(1).
every other inserting operation will take O(n).
The whole explanation and the 2 codes are in Java... but its easy to translate it to any other language of your choice.
I do want to help you however I am a beginner myself...
Still I have used the logic, sharing it from the queues implementation...
I have pasted two codes one is in O(N) the other contains a method called append which is in O(1)
Now, the explanation
declare the tail node with head node in the class
now in the method append class in the 2nd code below just look at the tail pointer
CASE 1: when LL empty
usually people check if (head == null) if true then they point the head to the
new Node and return
whereas what I have done is I checked if (tail == null) and if it was true
then tail = head = newnode meaning that the tail and head both now point to
the new Node to be added.
CASE 2: when LL is not empty
wait, haha, hear me out first, I know you might be thinking that what if the
LL has just 1 node currently, then what? well... for that...
this case 2 handles it automatically, in case 1 it sets the head and tail
equal to the newnode right, so it now just changes and modifies the tail node
keeping the head node intact.
this way, the head keeps pointing to the first node and the tail keeps updating and pointing to the newnodes created with each append function call.
Hope this explanation helps...
PS. check from line 24 for O(N) and 102 for O(1) and every time a newnode is added to the LL by the append method call, the tail will point to the new node to be added.
import java.io.*;
import java.util.*;
public class Solution {
// class Solution is what should be called as the LINKEDLIST class but its ok
Node head; // declaring a head for the LL
class Node { // Node class
int data; // the .data variable
Node ref; // .ref aka .next
Node(int data) { // constructor for initializing the values
this.data = data;
this.ref = null;
}
}
public void append(int data) { // i call 'to join at the end' as append
// O(N)
Node newnode = new Node(data); // new node creation
if (head == null) { // checking is head is null aka None in Py
head = newnode;
return;
}
Node curr = head; // assigning head to a curr node ready for traversal
while (curr.ref != null) { // traversal begins
curr = curr.ref;
} // traversal ends
curr.ref = newnode; // this is the last node where the join happens
}
public void p() { // i name printing function as p()
if (head == null) { // if head is null then print empty
System.out.println("Empty");
return;
}
Node curr = head; // same thing - traversal begins here
while (curr != null) {
System.out.println(curr.data);
curr = curr.ref;
} // by now all data values have been printed out already
}
public static void main(String[] args) {
Scanner sc = new Scanner(System.in); // scanner class for input
Solution l = new Solution(); // object creating for LL as Solution class name
int numberOfNodes = sc.nextInt(); // input for number of NODEs in LL
for (int i = 0; i < numberOfNodes; i++) { // loop for .data values
int data = sc.nextInt();
l.append(data); // function append call for each (i)
}
l.p(); // finally print func call to display output LL
}
}
class PractGG {
Node head;
Node tail;
class Node {
int data;
Node ref;
Node(int data) {
this.data = data;
this.ref = null;
}
}
public void push(int data) {
Node newnode = new Node(data);
if (head == null) {
tail = head = newnode;
return;
}
newnode.ref = head;
head = newnode;
}
public void append(int data) {
// O(1)
Node newnode = new Node(data);
if (tail == null) {
tail = head = newnode;
return;
}
tail.ref = newnode;
tail = newnode;
}
public void p() {
if (head == null) {
System.out.println("Empty");
}
Node curr = head;
while (curr!=null) {
System.out.print(curr.data + "==>");
curr = curr.ref;
}
System.out.println();
}
public static void main(String[] args) {
PractGG l = new PractGG();
l.append(1);
l.append(2);
l.append(3);
l.p();
}
}

Categories

Resources