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
}
}
Related
I am attempting to take a user inputted word, ad it to a stack and then check to see if that word is a palindrome. I am attempting to pop everything off the stack and onto a new string and then compare the strings. I believe my current issue is that my pop() function doesn't actually return a value. It actually just cuts off the tail node and then reprints the string without the tail node. I guess my question is, how do I write my pop() function so that it returns the "popped" value?
Here is my main method
Scanner input = new Scanner(System.in);
Stack_Scott_Robinson<Character> myList = new Stack_Scott_Robinson<Character>(); //create a list object
System.out.println("Enter a string: ");
String s = input.next();
for (int i = 0; i < s.length(); i++){
myList.push(s.charAt(i));
}
String reverseInput = "";
while (!myList.isEmpty()){
reverseInput = reverseInput + myList.Pop();
}
if (s.equals(reverseInput)){
System.out.println("This is a palindrome");
}else{
System.out.println("This is not a palidrome");
System.out.print("Would you like to re-run code with different input string(y/n)?");
another = input.next();
}
Here is my pop() method
public void Pop()
{
Node countList = end; //set "count" node at the front of the list
int size = 0; //initialize the size variable
//moves the count node down the list and increments the size variable
while (countList != null)
{
countList = countList.next;
size++;
}
if (size == 0){ //empty list
System.out.println("error: empty list");
}else if (size == 1) //one node list
{
top = null;
end = null;
System.out.println("list is now empty");
}
else{
Node current = end;//set a current node at the front of the list
for (int i = 0; i<size-2; i++)//-2 because the list starts at 0 and we want the second to last position
{
current = current.next;//moves the current node down the list until it is
}
Node temporary = current.next; //the second to last position
Node temp = top;//create a new node space
top = current;//set the new node equal to the second to last position
top.next = null;//sets the node as the tail
}
}
Here is how java.util.Vector does it (java.util.Stack extends Vector)
public synchronized E pop() {
E obj;
int len = size();
obj = peek();
removeElementAt(len - 1);
return obj;
}
and
public synchronized void removeElementAt(int index) {
if (index >= elementCount) {
throw new ArrayIndexOutOfBoundsException(index + " >= " +
elementCount);
}
else if (index < 0) {
throw new ArrayIndexOutOfBoundsException(index);
}
int j = elementCount - index - 1;
if (j > 0) {
System.arraycopy(elementData, index + 1, elementData, index, j);
}
modCount++;
elementCount--;
elementData[elementCount] = null; /* to let gc do its work */
}
In the pop method, you can see that we know what object to remove because they get it using peek(); Then they just remove the element at the end of the vector. Hopefully this helps. I'm not sure how you are representing your Stack under the hood, so I can't really give you a better answer without that.
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);
}
This is my code so far to find all of the nodes represented by char characters. I've been able to code how to get the root node's "(" and ")" using the helper method. However, i'm having a mind block when trying to integrate the helper method into the treeProcessor. In the treeProcessor method i'm trying to further delve into binary tree so that the end goal is to just print out the root node and sub trees.
public static ArrayList<String> paths = new ArrayList<>();
public static void main(String[] args)
{
String tree = "(a(b()())(c()()))";
//replace this line with a call to the treeProcessor
System.out.println(Arrays.toString(treeBreakdownHelper(tree)));//a, (b()()), (c()())
System.out.println();
System.out.println(paths);//prints every path found
}
//recursive method
public static void treeProcessor(String tree, String path)
{
//breakdown tree
//update path
//check if current element is leaf/last element
//if it is, add to ArrayList
//if not last element, run processor again on subtrees that are not empty
}
//valid tree:
//(a()())
//(a(b()())(c()()))
//helper method
public static String[] treeBreakdownHelper(String tree)
{
String[] temp = new String[3];
//0 = root
//1 = left tree
//2 = right tree
tree = tree.substring(1, tree.length()-1);
//System.out.println(tree);//test removal of outer parens
temp[0] = "" + tree.charAt(0);
tree = tree.substring(1);
//System.out.println(tree);//test removal of root node
int openCount = 0;
int middle = 0;
for(int i = 0; i < tree.length(); i++)
{
//System.out.println(openCount);
if(tree.charAt(i) == '(')
{
openCount++;
}
else if(tree.charAt(i) == ')')
{
openCount--;
}
if(openCount == 0)
{
middle = i;
break;
}
}
//System.out.println(middle);
//System.out.println(tree.substring(0,middle+1));
temp[1] = tree.substring(0,middle+1);
//System.out.println(tree.substring(middle+1));
temp[2] = tree.substring(middle+1);
return temp;
}
}
I'm trying to create a balanced tree with a string of letters. If you put "ABCDE" for string, your code is expected to give an output something like this.
INPUT : "ABCDE"
OUTPUT :
.......................................................
+
+ E
+ + -- --
A B C D -- -- -- --
.......................................................
The book suggests me to first create an array of one-node tree whose root will be each character of the string. Then, make a three-node tree out of each pair of one-node trees, making a new + node for the root which will result in a forest of three - node trees.
I know this problem is a stepping-stone to ultimately write the Huffman tree.
I'm having trouble putting the three-node tree back into the array with one-node trees and then make a 7-node tree by combining the two three-node trees and so on.
Below is my code,
import java.util.*; // for Stack class
class StringNode {
public char iData; // data item (key)
public StringNode leftChild; // this node's left child
public StringNode rightChild; // this node's right child
StringNode(char d) {
iData = d;
}
public void displayNode() // display ourself
{
System.out.print('{');
System.out.print(iData);
System.out.print("} ");
}
} // end class Node
class STree {
private StringNode root; // first node of tree
public String sequence;
// -------------------------------------------------------------
public STree() // constructor
{
root = null;
} // no nodes in tree yet
public void makeBalanceTree() // creating a balanced tree
{
StringNode array[] = new StringNode[sequence.length()];
for (int i = 0; i < sequence.length(); i++)
array[i] =
new StringNode(sequence.charAt(i)); //fill array with node holding each character as key
STree forest[] = new STree[array.length]; //make a forest of trees
for (int j = 0; j < array.length; j++) { //store each node as the root of the tree
forest[j] = new STree();
forest[j].root = array[j];
}
int count = sequence.length();
while (count == 0) {}
}
public void displayTree() {
Stack globalStack = new Stack();
globalStack.push(root);
int nBlanks = 32;
boolean isRowEmpty = false;
System.out.println("......................................................");
while (isRowEmpty == false) {
Stack localStack = new Stack();
isRowEmpty = true;
for (int j = 0; j < nBlanks; j++) System.out.print(' ');
while (globalStack.isEmpty() == false) {
StringNode temp = (StringNode) globalStack.pop();
if (temp != null) {
System.out.print(temp.iData);
localStack.push(temp.leftChild);
localStack.push(temp.rightChild);
if (temp.leftChild != null || temp.rightChild != null) isRowEmpty = false;
} else {
System.out.print("--");
localStack.push(null);
localStack.push(null);
}
for (int j = 0; j < nBlanks * 2 - 2; j++) System.out.print(' ');
} // end while globalStack not empty
System.out.println();
nBlanks /= 2;
while (localStack.isEmpty() == false) globalStack.push(localStack.pop());
} // end while isRowEmpty is false
System.out.println("......................................................");
} // end displayTree()
} // end class Tree
public class StringTreeApp {
public static void main(String[] args) {
int value;
STree theTree = new STree();
theTree.sequence = "ABCDE";
theTree.makeBalanceTree();
theTree.displayTree();
} // end main()
} // end class TreeApp
I think that the book is making it harder for you than necessary by recommending creating an array of StringNodes up front.
If you have a String, you know that the "middle" character is going to be the iData; the characters preceding it are going to be in the left tree; the characters following it are going to be in the right tree.
As such, you should be able to construct a StringNode as follows:
StringNode buildStringNode(String sequence) {
if (sequence.isEmpty()) return null;
int middlePos = (sequence.length() + 1) / 2;
char iData = sequence.charAt(middlePos);
StringNode result = new StringNode(iData);
result.leftChild = buildStringNode(sequence.substring(0, middlePos));
result.rightChild = buildStringNode(sequence.substring(middlePos + 1));
return result;
}
This "automatically" combines the child trees with the parent tree. Your makeBalanceTree() method is then simply:
void makeBalanceTree() {
root = buildStringNode(sequence);
}
I have a question, I've looked around on the internet but couldn't find an example. But making a String trim() method in java (remove lead/trailing whitespace), I know the basic code for this is:
public LString trim(){
int i = this.size;
int j = 0;
int k = this.offset;
char[] arrayOfChar = this.data;
while ((j < i) && (arrayOfChar[(k + j)] <= ' '))
++j;
while ((j < i) && (arrayOfChar[(k + i - 1)] <= ' '))
--i;
return (((j > 0) || (i < this.size)) ? substring(j, i) : this);
}
But, how would you write this same method, but applied to a linked list? More specifically, a linked list that uses a Node class.
Here is what I did....correct me if this is wrong...I'll include relevant class information that pertains to the question.
public class LString{
private Node front = null; //first val in list
private Node back; //last val in list
private int size = 0;
private int i;
private int offset;
public LString(){
//construct empty list
Node LString = new Node();
front = null;
}
.......//skip down some methods to this one
//returns new lstring that is slice of lstring
//contains an endIndex as well
public LString substring(int beginIndex, int endIndex){
Node current = this.front;
int size = 0;
while(current != null && size < beginIndex){
size++;
current = current.getNext();
}
front = new Node();
front.setData(current.getData());
Node ocurrent = front;
while(current != null && size < endIndex){
current = current.getNext();
Node curr2 = new Node();
curr2.setData(current.getData());
ocurrent.setNext(curr2);
ocurrent = curr2;
size++;
}
ocurrent.setNext(null); //set next val to null to term string
return this;
}
public LString trim(){
String lstr;
int i = this.size;
int m = this.offset;
int k = charAt(m);
Node current = front;
while(current != null){
current = current.getNext();
if(current.data > '\u0020'){
return this;
} else if(current.data < '\u0020'){
LString lstring = new LString(); //this worked!?
return lstring;
}
}
return this.substring(k, m+1);
}
...............................................................
//My Node class:
public class Node{
public char data;
public Node next;
//constructors from page 956
public Node()
{
this('\0',null); //'\0' is null char for java
}
public Node(char initialData, Node initialNext)
{
data = initialData;
next = initialNext;
}
}
(If you are unfamiliar with the node class, it basically just creates a singly linked node to use as your links between data in your linked list class)
I've never seen an example or anything, so I thought I'd ask the community.
Assuming that
by trimming the list you want to remove leading and trailing elements that are null
and under "linked list that uses a Node class" you mean java.util.LinkedList
You should keep in mind that in java internal implementation of LinkedList is not exposed (note: java.util.LinkedList.Node has private access modifier), all modifications are performed through methods of iterator and LinkedList itself.
Implementation would be:
public static void trim (LinkedList list){
if (list == null || list.size() == 0) return;
Object element = null;
ListIterator i = list.listIterator();
while (i.hasNext() && element == null) {
element = i.next();
if (element == null) {
i.remove();
}
}
element = null;
i = list.listIterator(list.size());
while (i.hasPrevious() && element == null) {
element = i.previous();
if (element == null) {
i.remove();
}
}
}
However if you are reimplementing mutable strings via linked list as an exercise
(if not as an exercise then stop right there and use StringBuilder or StringBuffer), then, assuming that you implement it with doubly linked list, it will go like this:
EDIT: my bad, you can iterate to the first non-empty element and set reference directly to it, updated algorithm
Fetch first element
While fetched element is empty fetch next
Set head reference to the last fetched element, set last fetched element's prev reference to null
Fetch last element
While fetched element is empty fetch previous
Set tail reference to the last fetched element, set last fetched element's next reference to null
UPDATE With code you provided try something like this (since you are using singly-linked list, it is slightly different then the one described above):
public void trim(){
//early out if empty
if (front == null || back==null) return;
Node current = front;
//looking for the first non-empty element
while(current != null && current.data<'\u0020' ){
current = current.next;
}
//left trim
this.front = current;
//looking for last non-empty element
while (current!=null&¤t.next!=null&¤t.next.data>'\u0020'){
current = current.next;
}
//right trim
this.back = current;
if (current!=null){
current.next = null;
}
}
Assuming you just want to trim each String in a LinkedList, why not just iterate over each item?
LinkedList<String> myNodes = new LinkedList<String>();
myNodes.add('This is a node ');
myNodes.add(' another node '));
for (String s : myNodes){
s.trim();
}