Full disclosure: this is for an assignment, so please don't post actual code solutions!
I have an assignment that requires me to take a string from the user and pass it into a stack and a queue, then use those two to compare the chars to determine if the string is a palindrome. I have the program written, but there appears to be some logic error somewhere. Here's the relevant code:
public static void main(String[] args) {
UserInterface ui = new UserInterface();
Stack stack = new Stack();
Queue queue = new Queue();
String cleaned = new String();
boolean palindrome = true;
ui.setString("Please give me a palindrome.");
cleaned = ui.cleanString(ui.getString());
for (int i = 0; i < cleaned.length(); ++i) {
stack.push(cleaned.charAt(i));
queue.enqueue(cleaned.charAt(i));
}
while (!stack.isEmpty() && !queue.isEmpty()) {
if (stack.pop() != queue.dequeue()) {
palindrome = false;
}
}
if (palindrome) {
System.out.printf("%s is a palindrome!", ui.getString());
} else
System.out.printf("%s is not a palindrome :(", ui.getString());
stack.dump();
queue.clear();
}
public class Stack {
public void push(char c) {
c = Character.toUpperCase(c);
Node oldNode = header;
header = new Node();
header.setData(c);
header.setNext(oldNode);
}
public char pop() {
Node temp = new Node();
char data;
if (isEmpty()) {
System.out.printf("Stack Underflow (pop)\n");
System.exit(0);
}
temp = header;
data = temp.getData();
header = header.getNext();
return data;
}
}
public class Queue {
public void enqueue(char c) {
c = Character.toUpperCase(c);
Node n = last;
last = new Node();
last.setData(c);
last.setNext(null);
if (isEmpty()) {
first = last;
} else n.setNext(last);
}
public char dequeue() {
char data;
data = first.getData();
first = first.getNext();
return data;
}
}
public String cleanString(String s) {
return s.replaceAll("[^A-Za-z0-9]", "");
}
Basically, when running my code through the debugger in Eclipse, my pop and dequeue methods appear to only select certain alphanumerics. I am using replaceAll("[^A-Za-z0-9]", "") to "clean" the user's string of any nonalphanumeric chars (!, ?, &, etc.). When I say it only selects certain chars, there doesn't seem to be any pattern that I can discern. Any ideas?
Your general algorithm works properly, assuming your queue and stack are correct (i tried this using the Deque implementations found in the jdk). Since your assignment involves the datastructures, i've pretty much just took your main logic and replaced the datastructures with ArrayDequeue, so I don't feel like i'm answering this for you.
String word = "ooffoo";
word = word.replaceAll("[^A-Za-z0-9]", "");
Deque<Character> stack = new ArrayDeque<Character>(word.length());
Deque<Character> queue = new ArrayDeque<Character>(word.length());
for (char c : word.toCharArray()) {
stack.push(c);
queue.add(c);
}
boolean pal = true;
while (! stack.isEmpty() && pal == true) {
if (! stack.pop().equals(queue.remove())) {
pal = false;
}
}
System.out.println(pal);
I'd recommend using a debugger to see exactly what was being compared, or at the very least spit out some print lines:
while (!stack.isEmpty() && !queue.isEmpty()) {
Character sc = stack.pop();
Character qc = queue.dequeue();
System.out.println(sc + ":" + qc);
if (sc != qc) {
palindrome = false;
}
}
Related
I'm trying to implement an inorder, preorder, and postorder traversal algorithm for my BST. It seems that the inorder algorithm is working so far, but it's only returning the first character of the word. I realize that I'm returning char c, but I'm confused on how I would make it return the entire word. Any help would be highly appreciated!
package main;
import java.io.*;
import java.util.*;
// Node class
class Node
{
char c;
boolean end;
Node left, right;
public Node(char c)
{
this.c = c;
this.end = false;
this.left = null;
this.right = null;
}
}
class BinarySearchTree
{
private Node root;
public BinarySearchTree()
{
root = null;
}
public void addValue(String s)
{
root = addValue(root, s, 0);
}
private Node addValue(Node x, String s, int d)
{
char c = s.charAt(d);
if (x == null)
x = new Node(c);
if (c < x.c)
x.left = addValue(x.left, s, d);
else if (c > x.c)
x.right = addValue(x.right, s, d);
else x.end = true;
return x;
}
public boolean search(String s)
{
return search(root, s, 0);
}
private boolean search(Node x, String s, int d)
{
if (x == null)
return false;
char c = s.charAt(d);
if (c < x.c)
return search(x.left, s, d);
else if (c > x.c)
return search(x.right, s, d);
else
return x.end;
}
public void inorder(){
inorder(root);
}
private void inorder(Node r){
if (r != null){
inorder(r.left);
System.out.print(r.c);
inorder(r.right);
}
}
}
public class Project2
{
public static void main(String[] args) throws Exception
{
BinarySearchTree tree = new BinarySearchTree(); // Make new BST object
// Variable for scanned word
String token = "";
// Use scanner for input file
Scanner scan = new Scanner(new File("10words.txt")).useDelimiter("\\s+");
//Check for next line in text file
while (scan.hasNext())
{
token = scan.next();
tree.addValue(token);
}
scan.close();
tree.inorder();
Scanner inputWord = new Scanner(System.in);
System.out.print("\nEnter a word to search: ");
String word = inputWord.next().toLowerCase();
if(tree.search(word) == false){
System.out.println("Word NOT Found!");
} else{
System.out.println("Word Found!");
}
inputWord.close();
}
}
I did not look at your inorder code but you said it works so I'll believe you.
However I did take a look at your addValue code and you only save the first character here. No wonder you can't get the entire word back, you just don't save it :P
Instead, you should change your Node class to accept a String instead of a character. You won't need the d parameter in your addValue method then either.
The Java String class provides the .compareTo () method in order to lexicographically compare Strings. You can use it with string.compareTo(otherString)
This method will return a value < 0, equal to 0 or > 0.
< 0 means string is lexicographically smaller than otherString (for example: "Apple" would be smaller than "Banana")
= 0 means it's the exact same word
> 0 means string is bigger than otherString (for example: "Banana" would be bigger than "Apple")
your addValue method looks like it is incorrect. it only modifies the root, then character will be equal, so it returns. In particular d is never modified.
On a more fondamental level, a BST would be appropriate to look for a character in a tree, not for looking for a String. If you want to look for a word, you can use a Trie instead (which is not a binary tree).
I'm writing a program that asks the user for a postfix expression, and then outputs the result to the expression. I am attempting to do this using a Singly Linked List, and using the Adapter Pattern to create a stack.
The code for the SinglyLinkedList class, the LinkedStack class, and the Stack implementation are all straight out of a Data Structures book that I own. So the SinglyLinkedListTest class is the only one that has my own code in it (and has errors).
I've written a program that simply uses a stack to evaluate a postfix expression before, but I'm getting confused this time with the extra classes included.
I'm sure I have a ton of errors, but the most obvious ones to me are in my SinglyLinkedListTest class, every time I push a value onto the stack. I know the issue is that I am attempting to push Objects and characters onto the stack instead of the arguments that match push(E e), but I don't know how to alter my code to make this work.
Any suggestions or input would be greatly appreciated.
Here is my Stack Implementation:
package PostFix;
public interface Stack<E>
{
int size();
boolean isEmpty();
void push(E e);
E pop();
}
Here is my LinkedStack class:
package PostFix;
public class LinkedStack <E> implements Stack<E>
{
private SinglyLinkedList<E> list = new SinglyLinkedList<>();
public LinkedStack()
{
}
public int size()
{
return list.size();
}
public boolean isEmpty()
{
return list.isEmpty();
}
public void push(E e)
{
list.addFirst(e);
}
public E pop()
{
return list.removeFirst();
}
}
Here is my SinglyLinkedList class:
package PostFix;
public class SinglyLinkedList<E>
{
private static class Node<E>
{
private E element;
private Node<E> next;
public Node(E e, Node<E> n)
{
element = e;
next = n;
}
public E getElement()
{
return element;
}
public Node<E> getNext()
{
return next;
}
}
private Node<E> head = null;
private Node<E> tail = null;
private int size = 0;
public SinglyLinkedList()
{
}
public int size()
{
return size;
}
public boolean isEmpty()
{
return size == 0;
}
public void addFirst(E e)
{
head = new Node<>(e, head);
if (size == 0)
{
tail = head;
}
size++;
}
public E removeFirst()
{
if (isEmpty())
{
return null;
}
E answer = head.getElement();
head = head.getNext();
size--;
if (size == 0)
{
tail = null;
}
return answer;
}
}
Here is my final SinglyLinkedListTest class:
package PostFix;
import java.util.Scanner;
public class SinglyLinkedListTest
{
public static void main(String[] args)
{
Double num1, num2, answer;
char c;
Stack<Double> stack = new LinkedStack<>();
Scanner input = new Scanner(System.in);
System.out.println("Enter the expression you would like to evaluate: ");
String someString = input.nextLine();
for (int index = 0; index < someString.length(); index++)
{
c = someString.charAt(index);
if (Character.isDigit(c))
{
stack.push((double)Character.digit(c, 10));
}
else if (c == '+')
{
num2 = stack.pop();
num1 = stack.pop();
answer = num1+num2;
stack.push(answer);
}
else if (c == '-')
{
num2 = stack.pop();
num1 = stack.pop();
answer = num1-num2;
stack.push(answer);
}
else if (c == '*')
{
num2 = stack.pop();
num1 = stack.pop();
answer = num1*num2;
stack.push(answer);
}
else if (c == '/')
{
num2 = stack.pop();
num1 = stack.pop();
answer = num1/num2;
stack.push(answer);
}
}
System.out.println("The result is: " + stack.pop());
}
}
Stack<String> buffer = new LinkedStack<>();
Poor name: call it stack.
You've declared it as Stack<String> but you're pushing chars:
buffer.push(someString.charAt(index));
and Objects:
buffer.push(answer);
and popping ints:
num1 = buffer.pop();
You are never either pushing or popping strings.
Just make up your mind. You should be pushing and popping ints, or longs, or doubles, or BigDecimals, depending on what precision you need.
EDIT
buffer.push((double)c);
is invalid. You're pushing the ASCII value, not the numeric value it corresponds to. You need
buffer.push((double)Character.digit(c, 10));
You also need an else after each if block: if the character is a digit, it won't be a +, and if it's a + it won't be a -, etc.
I have a method that's supposed to validate accurate opening and closing parenthesis in a string using java. This method will be used to parse mathematical expressions so it's important for the parenthesis to be balanced. For some reason, it is returning false in both of these runs:
System.out.println(parChecker("(()")); // returns false :-)
System.out.println(parChecker("((()))")); // returns false :-( WHY??
Here is the method that uses a stack to solve the problem. Something is wrong here becuase it's returning false for a balanced set of parenthesis as well. What's the problem? Thank you in advance.
public static boolean parChecker(String str) {
String[] tokens = str.split("");
int size = tokens.length;
Stack theStack = new Stack(size);
int index = 0;
boolean balanced = true;
while ((index < size) && balanced) {
String symbol = tokens[index];
if (symbol.equals("(")) {
theStack.push(symbol);
} else {
if (theStack.isEmpty()) {
balanced = false;
} else {
theStack.pop();
}
}
index++;
}
if (balanced && theStack.isEmpty()) {
return true;
} else {
return false;
}
}
Here is my stack class that I'm using:
public class Stack {
private Object [] stack;
private int maxSize = 0;
private int top;
public Stack(int size){
maxSize = size;
stack = new Object[maxSize];
top = -1;
}
public void push(Object obj){
top++;
stack[top] = obj;
}
public Object pop(){
return stack[top--];
}
public Object peek(){
return stack[top];
}
public boolean isEmpty(){
return (top == -1);
}
public boolean isFull(){
return (top == maxSize -1);
}
}
The immediate problem is this
String[] tokens = str.split("");
Gives you first char = "" if you use java 1.7 or less, so you will exit your loop since stack is empty...
Note: this has been changed in java 1.8 split difference between java 1.7 and 1.8
change to:
char[] tokens = str.toCharArray();
I guess however that you need to consider the fact that there can be chars before your first ( and that you may have other chars then ( and )
As far as I can tell, there is no problem with the code (turns out it's a Java 7 specific issue..).
I would like to offer a replacement method though, for educational purposes, that is shorter, and and is tolerant of other characters being present:
public static boolean parChecker(String str) {
Stack stack = new Stack(str.length());
for (char c : str.toCharArray())
switch (c) {
case '(':
stack.push(c);
break;
case ')':
if (stack.isEmpty() || stack.pop() != Character.valueOf('('))
return false;
}
return stack.isEmpty();
}
As requested, here's another solution that doesn't use a stack:
public static boolean parChecker(String str) {
str = str.replaceAll("[^()]", "");
while (str.contains("()"))
str = str.replace("()", "");
return str.isEmpty();
}
And one more for the road: #FredK's algorithm:
public static boolean parChecker(String str) {
int depth = 0;
for ( char c : str.toCharArray() )
if ( ( depth += c == '(' ? 1 : c == ')' ? -1 : 0 ) < 0 )
return false;
return depth == 0;
}
Im looking at a way of doing a partial match using a binary search. Here is my code:
public void checkCardIndexForMatches(List<String> wordsToCheck) throws IOException {
String[] cardIndexCache = cardIndexCreator.getCardIndexCache();
for (String text: wordsToCheck){
int i = Arrays.binarySearch(cardIndexCache, text.getText().toLowerCase().trim());
if (i > 0){
text.setCardIndexMatch(true);
}
//check if partial match
// else if
}
}
So its pretty simple stuff so far - there is basically an external file which gets fed in, each line in the file is stored as an array in the cardIndexCache. The problem comes when the user wants to be able to match a 'phrase' in the array (a phrase being more than one word e.g. Mohammed Ali). The words in the wordsToCheck parameter are only passed in as individual words. So the first word will be Mohammed but the binary search fails as it doesnt know what the second word is. I cant think of a simple way of getting the binary search to indicate that a word has the potential to be a match (first part matches, just append the next word and see if that matches).
Any ideas much appreciated!
Here's a Trie I've written along with a search function that basically finds maximum common prefix, a similarity-search is possible but will be costly ..
class TNode
{
public MapList<Char,TNode> next;
public TNode ()
{
next = new MapList<Char,TNode>();
}
}
class Trie
{
TNode head;
public Trie ()
{
head = new TNode();
}
public void insert (String t)
{
TNode cur = head;
for (Char c : t.toCharArray())
{
if (!cur.next.containsKey(c))
{
cur.next.put(c,new TNode());
}
cur = cur.next.get(c);
}
}
public boolean remove (String t)
{
Stack<Pair<Char,TNode>> path = new Stack<Pair<Char,TNode>>();
TNode cur = head;
Pair<Char,TNode> n = null;
for (Char c : t.toCharArray())
{
if (!cur.next.containsKey(c))
{
return false;
}
path.push(c,cur);
cur = cur.next.get(c);
}
while (path.size() > 0)
{
n = path.pop();
if (n.getSecond().next.get(n.getFirst()).next.size() > 1)
{
break;
}
else
{
n.getSecond().next.remove(n.getFirst());
}
}
}
public boolean search (String t)
{
TNode cur = head;
for (Char c : t.toCharArray())
{
if (!cur.next.containsKey(c))
{
return false;
}
cur = cur.next.get(c);
}
return true;
}
public String searchMaxPrefix (String t)
{
TNode cur = head;
String match = "";
for (Char c : t.toCharArray())
{
if (cur.next.containsKey(c))
{
match += c;
}
else
{
break;
}
}
return match;
}
}
public boolean isPalindrome()
{
Stack myStack = new Stack();
for(Node current = head; current!=null; current = current.next)
{
if(!myStack.isEmpty())
{
if(myStack.peek()==current.data)
{
myStack.pop();
}else if(current.next!=null&&myStack.peek()==current.next.data)
{
continue;
}
else
{
myStack.push(current.data);
}
}else
{
myStack.push(current.data);
}
}
return myStack.isEmpty();
}
What I am doing here is using a stack to check whether a linked list is a palindrome. It works as expected only thing is I wanted to get rid of code duplication where the else condition has a push of the data onto the stack.
The algorithm is unfortunately not correct. For "abbaaa" it would report that that is a palindrome, although it isn't. Checking for palindromes without using the length is difficult.
abbaaa () -> push a
bbaaa (a) -> push b
baaa (ba) -> pop b
aaa (a) -> pop a
aa () -> push a
a (a) -> pop a
() -> palindrome
This is a somewhat classic problem. There are many ways to solve it in java. One of the easiest is this one:
boolean isPalindrome(String s) {
for (int i=0, len=s.length(); i<len/2; i++) {
if (s.charAt(i) != s.charAt(len-i-1)) return false;
}
return true;
}
(Strictly speaking, this is a rewrite rather than a refactoring; however, any rewrite that preserves method signatures can be seen as a refactoring... and it is certainly more efficient)
If all you want to do is remove the code duplication between the two else conditions then remove them entirely.
public boolean isPalindrome()
{
Stack myStack = new Stack();
for(Node current = head; current!=null; current = current.next)
{
if(!myStack.isEmpty())
{
if(myStack.peek()==current.data)
{
myStack.pop();
continue;
}else if(current.next!=null&&myStack.peek()==current.next.data)
{
continue;
}
}
myStack.push(current.data);
}
return myStack.isEmpty();
}
A simplification of functionality;
boolean isPalinDrome(String testString) {
return new StringBuffer(testString).reverse().toString().equals(testString);
}
This should provide same functionality without repeat. It is pointed out however that your algorithm doesn't seem to be correct.
public boolean isPalindrome()
{
Stack myStack = new Stack();
boolean doPush;
for(Node current = head; current!=null; current = current.next)
{
doPush = true;
if(!myStack.isEmpty())
{
if(myStack.peek()==current.data)
{
doPush = false;
myStack.pop();
}else if(current.next!=null&&myStack.peek()==current.next.data)
{
doPush = false;
continue;
}
}
if(doPush){
myStack.push(current.data);
}
}
return myStack.isEmpty();
}