remove() not functioning correctly - java

In the following Main method why isn't the last word (clapping) removed?
public class Main {
public static void main(String[] args) {
HT ht = new HT();
ht.insert("airplane");
ht.insert("distilling");
ht.insert("speaks");
ht.insert("knit");
ht.insert("digitize");
ht.insert("Media");
ht.insert("canonicalized");
ht.insert("libraries");
ht.insert("clapping");
ht.insert("residues");
ht.insert("spoilers");
System.out.println(Arrays.toString(ht.set));
ht.remove("distilling");
ht.remove("knit");
ht.remove("canonicalized");
ht.remove("libraries");
ht.remove("clapping");
System.out.println(Arrays.toString(ht.set));
}
}
The output is
[Media, digitize, airplane, canonicalized, spoilers, distilling, clapping, knit, libraries, speaks, residues]
[Media, digitize, airplane, null, spoilers, null, clapping, null, null, speaks, residues]
clapping is not removed. Why?
HT.java
public class HT {
public String[] set;
public int size;
public HT() {
this.set = new String[11];
this.size = 0;
}
public void insert(String word) {
int hash1 = giveHash1( word );
int hash2 = giveHash2( word );
while (set[hash1] != null) {
hash1 += hash2;
hash1 %= set.length;
}
set[hash1] = word;
size++;
}
public void remove(String word) {
int hash1 = giveHash1(word);
int hash2 = giveHash2(word);
while (set[hash1] != null && !set[hash1].equals(word)) {
hash1 += hash2;
hash1 %= set.length;
}
set[hash1] = null;
size--;
}
public int giveHashCode(String s) {
int hash = 0, x = 31;
for(int i=0;i<s.length();i++) {
hash = x * hash + s.charAt(i);
}
return hash;
}
private int giveHash1(String s) {
return (giveHashCode(s) % set.length < 0)
? (giveHashCode(s) % set.length) + set.length
: giveHashCode(s) % set.length;
}
private int giveHash2(String s) {
return 3 - (((giveHashCode(s) % set.length < 0)
? (giveHashCode(s) % set.length) + set.length
: giveHashCode(s) % set.length) % 3);
}
}
Apart from the modifiers, is there anything wrong with the code? Probably with the hash functions or maybe with insert() or remove()?

The problem is most likely the terminating condition for the loop in the remove() method.
while (set[hash1] != null && !set[hash1].equals(word)) {
which terminates at the first null value it finds.
When inserting, you're updating hash1 if the position is already occupied, so the final position of a word depends on the existing inserted words i.e. the occupied positions.
However when you've already removed a few of the values, the loop in remove() may find empty positions (null values) much sooner, and terminate before actually reaching the position the word was originally inserted in.

Related

Java HashMap: Changing Bucket Implementation to Linear Probing method

In advance, I apologize for my lack of experience, these are advanced concepts that are difficult to wrap my head around. From what I understand, linear probing is circular, it won't stop until it finds an empty cell.
However I am not sure how to implement it. Some example on how to would be greatly appreciated. Sorry again for the inexperience, I'm not some vetted programmer, I'm picking this up very slowly.
public boolean ContainsElement(V element)
{
for(int i = 0; i < capacity; i++)
{
if(table[i] != null)
{
LinkedList<Entry<K, V>> bucketMethod = table[i];
for(Entry<K, V> entry : bucketMethod)
{
if(entry.getElement().equals(element))
{
return true;
}
}
}
}
return false;
}
Here's a working hash table based on the pseudocode examples found in the Wikipedia article for open addressing.
I think the main differences between the Wikipedia example and mine are:
Treating the hashCode() a little bit due to the way Java does modulo (%) with negative numbers.
Implemented simple resizing logic.
Changed the logic in the remove method a little bit because Java doesn't have goto.
Otherwise, it's more or less just a direct translation.
package mcve;
import java.util.*;
import java.util.stream.*;
public class OAHashTable {
private Entry[] table = new Entry[16]; // Must be >= 4. See findSlot.
private int size = 0;
public int size() {
return size;
}
private int hash(Object key) {
int hashCode = Objects.hashCode(key)
& 0x7F_FF_FF_FF; // <- This is like abs, but it works
// for Integer.MIN_VALUE. We do this
// so that hash(key) % table.length
// is never negative.
return hashCode;
}
private int findSlot(Object key) {
int i = hash(key) % table.length;
// Search until we either find the key, or find an empty slot.
//
// Note: this becomes an infinite loop if the key is not already
// in the table AND every element in the array is occupied.
// With the resizing logic (below), this will only happen
// if the table is smaller than length=4.
while ((table[i] != null) && !Objects.equals(table[i].key, key)) {
i = (i + 1) % table.length;
}
return i;
}
public Object get(Object key) {
int i = findSlot(key);
if (table[i] != null) { // Key is in table.
return table[i].value;
} else { // Key is not in table
return null;
}
}
private boolean tableIsThreeQuartersFull() {
return ((double) size / (double) table.length) >= 0.75;
}
private void resizeTableToTwiceAsLarge() {
Entry[] old = table;
table = new Entry[2 * old.length];
size = 0;
for (Entry e : old) {
if (e != null) {
put(e.key, e.value);
}
}
}
public void put(Object key, Object value) {
int i = findSlot(key);
if (table[i] != null) { // We found our key.
table[i].value = value;
return;
}
if (tableIsThreeQuartersFull()) {
resizeTableToTwiceAsLarge();
i = findSlot(key);
}
table[i] = new Entry(key, value);
++size;
}
public void remove(Object key) {
int i = findSlot(key);
if (table[i] == null) {
return; // Key is not in the table.
}
int j = i;
table[i] = null;
--size;
while (true) {
j = (j + 1) % table.length;
if (table[j] == null) {
break;
}
int k = hash(table[j].key) % table.length;
// Determine if k lies cyclically in (i,j]
// | i.k.j |
// |....j i.k.| or |.k..j i...|
if ( (i<=j) ? ((i<k)&&(k<=j)) : ((i<k)||(k<=j)) ) {
continue;
}
table[i] = table[j];
i = j;
table[i] = null;
}
}
public Stream<Entry> entries() {
return Arrays.stream(table).filter(Objects::nonNull);
}
#Override
public String toString() {
return entries().map(e -> e.key + "=" + e.value)
.collect(Collectors.joining(", ", "{", "}"));
}
public static class Entry {
private Object key;
private Object value;
private Entry(Object key, Object value) {
this.key = key;
this.value = value;
}
public Object getKey() { return key; }
public Object getValue() { return value; }
}
public static void main(String[] args) {
OAHashTable t = new OAHashTable();
t.put("A", 1);
t.put("B", 2);
t.put("C", 3);
System.out.println("size = " + t.size());
System.out.println(t);
t.put("X", 4);
t.put("Y", 5);
t.put("Z", 6);
t.remove("C");
t.remove("B");
t.remove("A");
t.entries().map(e -> e.key)
.map(key -> key + ": " + t.get(key))
.forEach(System.out::println);
}
}
java.util.HashMap implementation of java.util.Map internally provides linear probing that is HashMap can resolve collisions in hash tables.

Fastest way to check if a haystack contains set of needles

I have a haystack string and I would like to check if it contains any of the needle strings. Currently I do it that way:
Set<String> needles = ...;
...
String [] pieces = haystack.split(" ");
for (String piece: pieces) {
if (needles.contains(piece) {
return true;
}
}
return false;
It works, but it is relatively slow.
Question: Is there a faster way to accomplish the task?
Example.
Haystack: I am a big tasty potato .
Needles: big, tasty
== RUN ==
I am a big tasty potato .
|
[tasty] got a match, we are good!
You should take a look at Aho-Corasick algorithm. This suits your problem because it build an automaton of all words(needles) and traverse the text(haystack) over the built automaton to find all matching words. Its basically constructs a finite state machine that resembles a trie.
The time complexity is O(n + m + z) where
z is the total number of occurrences of words in text, n is the length of text and m is the total number characters in all words.
Edit 2
Here is a straight-forward implementation which stop traversing after finding first occurrence of any needle.
import java.util.*;
class AhoCorasick {
static final int ALPHABET_SIZE = 256;
Node[] nodes;
int nodeCount;
public static class Node {
int parent;
char charFromParent;
int suffLink = -1;
int[] children = new int[ALPHABET_SIZE];
int[] transitions = new int[ALPHABET_SIZE];
boolean leaf;
{
Arrays.fill(children, -1);
Arrays.fill(transitions, -1);
}
}
public AhoCorasick(int maxNodes) {
nodes = new Node[maxNodes];
// create root
nodes[0] = new Node();
nodes[0].suffLink = 0;
nodes[0].parent = -1;
nodeCount = 1;
}
public void addString(String s) {
int cur = 0;
for (char ch : s.toCharArray()) {
int c = ch;
if (nodes[cur].children[c] == -1) {
nodes[nodeCount] = new Node();
nodes[nodeCount].parent = cur;
nodes[nodeCount].charFromParent = ch;
nodes[cur].children[c] = nodeCount++;
}
cur = nodes[cur].children[c];
}
nodes[cur].leaf = true;
}
public int suffLink(int nodeIndex) {
Node node = nodes[nodeIndex];
if (node.suffLink == -1)
node.suffLink = node.parent == 0 ? 0 : transition(suffLink(node.parent), node.charFromParent);
return node.suffLink;
}
public int transition(int nodeIndex, char ch) {
int c = ch;
Node node = nodes[nodeIndex];
if (node.transitions[c] == -1)
node.transitions[c] = node.children[c] != -1 ? node.children[c] : (nodeIndex == 0 ? 0 : transition(suffLink(nodeIndex), ch));
return node.transitions[c];
}
// Usage example
public static void main(String[] args) {
AhoCorasick ahoCorasick = new AhoCorasick(1000);
ahoCorasick.addString("big");
ahoCorasick.addString("tasty");
String s = "I am a big tasty potato";
int node = 0;
for (int i = 0; i < s.length(); i++) {
node = ahoCorasick.transition(node, s.charAt(i));
if (ahoCorasick.nodes[node].leaf) {
System.out.println("A match found! Needle ends at: " + i); // A match found! Needle ends at: 9
break;
}
}
}
}
However currently this code will find the end position of any occurrences in text. If you need the starting position and/or the needle, you can trace back from the ending position until finding a space to get the matched word.
This doesn't guaranty speed in worst-case, but should work better on average and best cases.
You can use java8 plus with parallel streams with anymatch function
boolean hi=Arrays.stream(pieces).parallel().anyMatch(i->needle.contains(i));
You should make sure needless is an instance of a HashSet which makes contains a "fast", constant time operation. Next, don't process all of haystack if you don't have to... Try this:
int i, j, l = haystack.length();
for(i = 0; i < l; i = j + 1) {
j = haystack.indexOf(' ', i + 1);
if(j == -1) {
j = l - 1;
}
String hay = haystack.s substring(i, j - 1).trim();
if(hay.length() > 0 && needles.contains(hay)) {
return true;
}
}
return false;
*note: this is untested and indexes might be off by +-1, as well as some edge cases might exist. use at your own risk.
Generally most of your slowdown is the split command. You are way better off searching the one string you have than allocating a crap ton of objects. You'd be better off doing regex, and avoiding new object construction. And using Aho would be quite effective. Assuming your lists are big enough to be troublesome.
public class NeedleFinder {
static final int RANGEPERMITTED = 26;
NeedleFinder next[];
public NeedleFinder() {
}
public NeedleFinder(String haystack) {
buildHaystack(haystack);
}
public void buildHaystack(String haystack) {
buildHaystack(this,haystack,0);
}
public void buildHaystack(NeedleFinder node, String haystack, int pos) {
if (pos >= haystack.length()) return;
char digit = (char) (haystack.charAt(pos) % RANGEPERMITTED);
if (digit == ' ') {
buildHaystack(this,haystack,pos+1);
return;
}
if (node.next == null) node.next = new NeedleFinder[RANGEPERMITTED];
if (node.next[digit] == null) node.next[digit] = new NeedleFinder();
NeedleFinder nodeNext = node.next[digit];
buildHaystack(nodeNext,haystack,pos+1);
}
public boolean findNeedle(String needle) {
return findNeedle(this, needle,0);
}
private boolean findNeedle(NeedleFinder node, String needle, int pos) {
if (pos >= needle.length()) return true;
char digit = (char) (needle.charAt(pos) % RANGEPERMITTED);
if (node.next == null) return false;
if (node.next[digit] == null) return false;
return findNeedle(node.next[digit],needle,pos+1);
}
}
On success, check the contains to make sure it's not a false positive. But, it's fast. We're talking 1/5th the speed of binary search.
Speaking of, binary search is a great idea. It's in the right time complexity alone. Just sort your silly list of haystack strings then when you look through the needles do a binary search. In java these are really basic and items in Collections. Both the .sort() and the .binarySearch() commands. And it's going to be orders of magnitude better than brute.
value = Collections.binarySearch(haystackList, needle, strcomp);
If value is positive it was found.
Collections.sort(words, strcomp);
With the strcomp.
public Comparator<String> strcomp = new Comparator<String>() {
#Override
public int compare(String s, String t1) {
if ((s == null) && (t1 == null)) return 0;
if (s == null) return 1;
if (t1 == null) return -1;
return s.compareTo(t1);
}
};
If it's really all about speed, and you want to search through a list of items instead of a solid string, you could divide the work into different threads (I'm not sure how many items you're checking with, but if it's not taking minutes, this might not be the way to go)
If you don't need to make the haystack into an array, you could instead iterate through needles, and test haystack via String.contains();

Using for loop and charAt to check if each letter appears exactly twice in a word

i'm writing a program in java that checks if a letter appers exactly twice, i was able to write it but my problem is that for some words the code doesn't check if the letter appear exactly twice.
here is my code:
public class Test {
public static void main(String[] args) {
isDoubloon("abba");
isDoubloon("Shanghaiingss");/*it still prints out true though 's' does appear exactly twice*/}
//checks if every letter appears twice in a word
public static void isDoubloon(String s){
String l=s.toLowerCase();
int count=0;
for(int i= 0; i<l.length()-1;i++){
for(int j=i+1;j<l.length();j++){
if(l.charAt(i)==l.charAt(j)) count++;
}
}
if(count%2==0){
System.out.println("True, This is a doubloon");
}else
System.err.println("False, This is not a doubloon");
}}
Your whole logic is not correct. You have to check for every letter in your text if it occurs twice.
Try this:
String l=s.toLowerCase();
boolean check = true;
for(int i= 0; i<l.length();i++){
int count=0;
for(int j=0;j<l.length();j++){
if(l.charAt(i)==l.charAt(j)) count++;
}
if (count != 2) {
check = false;
break;
}
}
if(check==true){
System.out.println("True, This is a doubloon");
}else
System.out.println("False, This is not a doubloon");
}
Your code counts how often each letter occurs (-1) and adds all this values. If the result is even you imply that each letter is exactly twice in the word. That cannot work.
Simply try the word "aaabbbb". (your code think it is a doubloon)
So you need to check if no character occurs exactly twice and that for each character separately.
You could do it this way:
public static void main(String[] args) {
if(isDoubloon("Shanghaiingss")){
System.out.println("True, This is a doubloon");
}else{
System.err.println("False, This is not a doubloon");
}
}
public static boolean isDoubloon(final String s) {
final String l = s.toLowerCase();
for (int i = 0; i < l.length(); i++) {
int count = 0;
for (int j = 0; j < l.length(); j++) {
if (l.charAt(i) == l.charAt(j)) {
count++;
if (2 < count) {
return false; // more than twice
}
}
}
if (1 == count) {
return false; // character occurs only once
}
}
return true;
}
This algorithm is similar to yours. But it is far from fast O(n²). Is you need it you can implement it faster O(n) but you would need some extra space.
The main flaw here is that you are using a single "count" variable when you want to do a count for each letter.
I would suggest using a map to hold a count for each letter, loop over the list and add each letter to your map and finally iterate over the map and confirm all values are 2.
public static void isDoubloon(String s){
String l=s.toLowerCase();
Map<Character, Integer> counts = new HashMap();
for(int i= 0; i<l.length()-1;i++){
int prevValue = counts.getOrDefault(l.charAt(i), 0);
counts.put(l.charAt(i), prevValue + 1);
}
for (Map.Entry<Character, Integer> entry: counts.entrySet()) {
if (entry.getValue() != 2) {
System.err.println("False, This is not a doubloon");
}
}
System.out.println("True, This is a doubloon");
}
Other solution
private boolean isDoubloon(String s) {
String convertWord = s.toLowerCase();
char[] letter = convertWord.toCharArray();
int[] count = new int[26];
for (int letters = 0; letters < letter.length; letters++) {
char index = letter[letters];
count[index - 97]++;
}
for( int i = 0; i < 26; i++ ) {
if (count[i] != 0 && count[i] != 2) return false;
}
return true;
}
public static boolean isDoubloon(String s) {
if (s.length() %2 != 0)
return false;
String str = s.toLowerCase();
while (str.length() > 0) {
int index2 = str.indexOf(str.charAt(0), 1);
if (index2 == -1) {
return false;
}
int index3 = str.indexOf(str.charAt(0), index2 + 1);
if (index3 != -1) {
return false;
}
str = str.substring(1, index2) + str.substring(index2 + 1);
}
return true;
}
Obligatory Java Streams examples:
groupingBy() and counting()
public static boolean isDoubloon(String str) {
return
// Stream over chars, and box to Integer
// These will be the ASCII values of the chars
!str.chars().boxed()
// Group by identity
.collect(Collectors.groupingBy(Function.identity(),
// and map each key to the count of characters
Collectors.counting()))
// We now have a Map<Integer, Long>, the Integer being the character
// value and the Long being the number of occurrences.
// Stream over the Map's values
.values().stream()
// Retain all values unequal to 2
.filter(i -> !Objects.equals(i, 2L))
// Shortcut if found and check if a value is present
.findAny().isPresent();
// If a value is present, that means that there are one or more
// characters with less or more than two occurrences.
}
https://ideone.com/PT8sQi
distinct() and count()
public static boolean isDoubloon(String str) {
long distinct = str.chars().distinct().count();
long length = str.length();
return (length % 2 == 0 && length / 2 == distinct);
}
https://ideone.com/UaOKDF

Null pointer Exception in CompareTo method

Structure of my class:
public class Priorityy implement Comparable {
public int compareTo(Object pe) {
Priorityy p = (Priorityy) pe;
if (this.key < p.key) {
return 1;
} else if (this.key > p.key) {
return -1;
} else {
return 0;
}
}
}
Th problem is that p.key is always null, why exactly is that? I have my array initialized with elements in it but it always throws NullPointerException whenever I try Arrays.sort(arr).
How can I fix this?
Edit: Here is the complete code and print did print the elements of array arr:
import java.util.Arrays;
class Priorityy implements Comparable {
int size;
int front = 0;
int rear = 0;
static Priorityy[] arr = new Priorityy[3];
int key;
String value;
public Priorityy(int key, String value) {
this.key = key;
this.value = value;
insert();
}
public void insert() {
arr[front] = this;
System.out.println(arr[front].value);
while (front + 1 != 3) {
front = front + 1;
}
}
public Priorityy remove() {
Priorityy x = arr[front];
front = front - 1;
return x;
}
public int compareTo(Object pe) {
Priorityy p = (Priorityy) pe;
if (this.key < p.key) {
System.out.println(p.key);
return 1;
} else if (this.key > p.key) {
System.out.println("3");
return -1;
} else {
System.out.println("4");
return 0;
}
}
public static void main(String... s) {
new Priorityy(10, "Watch");
new Priorityy(40, "Laptop");
new Priorityy(60, "Wallet");
Arrays.sort(arr);
for (Priorityy element : arr) {
System.out.println(element.key);
System.out.println(element.value);
}
}
}
As per your code
Priorityy p = (Priorityy)pe;
^^ ---------- this is null
You have null object in the array. Handle null object gracefully.
For example
if(pe instanceof Priorityy){ // return false for null object
// your code goes here
}
Better use Generic Comparable and use Integer.compare(int,int) to compare two int values.
class Priorityy implements Comparable<Priorityy> {
public int compareTo(Priorityy pe) {
if (pe != null) {
return Integer.compare(this.key, pe.key);
} else {
// return what ever if pe is null
}
}
}
You're putting things into your array in a really strange manner.
But given that, the problem is that you're not using a static field to store the next position to insert an element into, so the next time you create an instance of Priorityy, the field first contains the value zero again. So you're inserting all three objects into element zero of the array.
Change one line of your code and it will work:
int front = 0;
To:
static int front = 0;
I don't see where you are using size and rear but you probably want these to be static too.
One other suggestion: Java has a nice short syntax for increasing or decreasing the value of a variable by one using the ++ or -- operator, so you can shorten things by saying:
front++;
instead of
front = front + 1;
(and front-- instead of front = front - 1)

Simple HashTable implementation using an array in Java?

I'm having a problem with implementing a very simple HashTable using an array. The problem is that the first Item put in the HashTable is always AVAILABLE. Maybe you guys can see what is going wrong. This is the HashTable class:
public class HashTable {
private Item[] data;
private int capacity;
private int size;
private static final Item AVAILABLE = new Item("Available", null);
public HashTable(int capacity) {
this.capacity = capacity;
data = new Item[capacity];
for(int i = 0; i < data.length; i++) {
data[i] = AVAILABLE;
}
size = 0;
}
public int size() {
return size;
}
public int hashThis(String key) {
return key.hashCode() % capacity;
}
public Object get(String key) {
int hash = hashThis(key);
while(data[hash] != AVAILABLE && data[hash].key() != key) {
hash = (hash + 1) % capacity;
}
return data[hash].element();
}
public void put(String key, Object element) {
if(key != null) {
size++;
int hash = hashThis(key);
while(data[hash] != AVAILABLE && data[hash].key() != key) {
hash = (hash + 1) % capacity;
}
data[hash] = new Item(key, element);
}
}
public Object remove(String key) {
// not important now.
throw new UnsupportedOperationException("Can't remove");
}
public String toString() {
String s = "<HashTable[";
for(int i = 0; i < this.size(); i++) {
s += data[i].toString();
if(i < this.size() - 1) {
s += ",";
}
}
s += "]>";
return s;
}
}
For more clarity, this is the Item class:
public class Item {
private String key;
private Object element;
public Item(String key, Object element) {
this.setKey(key);
this.setElement(element);
}
public String key() {
return key;
}
public void setKey(String key) {
this.key = key;
}
public Object element() {
return element;
}
public void setElement(Object element) {
this.element = element;
}
public String toString() {
String s = "<Item(";
s += this.key() + "," + this.element() + ")>";
return s;
}
}
To give an example:
HashTable ht = new HashTable(10);
ht.put("1", "a");
The output of toString() after putting has to be:
"<HashTable[<Item(1,a)>]>"
but I get:
"<HashTable[<Item(Available,null)>]>"
update: I should probably mention that the next Item gets put correctly and the one after that is not again.
I think the problem is in your toString method. You loop for 0 - size when size = 1 so once so you only print out the first value in your hashTable problem is the first value in your hash table is not a real value it's an AVAILABLE you have to do something like this
EDIT: Sorry I forgot to move the index over.
public String toString() {
String s = "<HashTable[";
int i = 0;
int count = 0;
while(count < this.size()) {
//Skip the AVAILABLE cells
if(data[i] == AVAILABLE) {
i++;
continue;
}
s += data[i].toString();
if(count < this.size() - 1) {
s += ",";
}
count++;
}
s += "]>";
return s;
}
Try this for toString() if still interested in the solution, I ran it and its fine:
public String toString()
{
String s = "<HashTable[";
for (int i = 0; i < this.capacity; i++)
{
if (data[i].Element != null)
{
s += data[i].toString();
if (i < this.size - 1)
{
s += ",";
}
}
}
s += "]>";
return s;
}

Categories

Resources