Taking data from a text file, and putting into a hashtable (java) - java

So basically i have this java project for school, and it requires me to read information from a text file, create an object from that information, and then insert that object into a hash table.
I am able to read the information from the text file and create the object, however, for some reason, my program isnt inserting the object into the hash table. Because then at the end of the program, when i try to search for the object (via its ID), it just returns 'not found'.
EDIT: My question is not how to compare strings. It is how to take the information from the text file, turn it into an object, and then insert it into the hash table. I know how to take the info and turn it into an object, but for some reason, it is not being inserted into the hashtable. Nothing i am inserting into the hashtable from the textfile is actually being inserted. That is the problem I am having.
This is the code i have written:
package test;
import java.io.File;
import java.io.FileNotFoundException;
import java.util.Scanner;
public class testmain {
public static void main(String[] args) throws FileNotFoundException{
StorageSystem ss = new StorageSystem();
ss.createhashtable();
String line;
String [] parts;
File in = new File("database.txt");
Scanner sc = new Scanner(in);
while(sc.hasNextLine()){
line = sc.nextLine();
parts = line.split(" ");
String type = parts[0];
String name = parts[1];
String id = parts[2];
String price = parts[3];
if(type.equals("Insert")){
Product p1 = new Product(name, id, Double.parseDouble(price));
ss.insert(p1);
}
else if(type.equals("remove")){
ss.remove(id);
}
}
sc.close();
System.out.println(ss.searchbyID("123"));
System.out.println(ss.searchbyID("232"));
System.out.println(ss.searchbyID("444"));
System.out.println(ss.searchbyID("456"));
//If i do it manually (below), it works. But thats not the point of this project
/*
Product ex = new Product("joe", "123", 22.33);
ss.insert(ex);
System.out.println(ss.searchbyID("123"));
ss.remove("123");
System.out.println(ss.searchbyID("123"));
*/
//When i do it this way ^^, it inserts the object into the hashtable, it
//searches for the object and finds it. it then removes the object. and
//when it searches again it doesnt find anything. And thats how it
//should work.
}
}
//Below is the class that contains the information on the hashtable
import java.io.*;
import java.util.Scanner;
public class StorageSystem {
private final static int tablesize = 1000;
private static Product[] table = new Product[tablesize];
public StorageSystem(){
table = new Product[tablesize];
for(int i = 0; i < tablesize; i++){
table[i] = null;
}
}
public void createhashtable(){
table = new Product[tablesize];
for(int i = 0; i < tablesize; i++){
table[i] = null;
}
}
public void useExistingTable(Product[] pt){
table = pt;
}
public String searchbyID(String idnum){
int hash = (Integer.parseInt(idnum) % tablesize);
if(table[hash] == null){
return "Not Found.";
}
else{
Product entry = table[hash];
while((entry != null) && (entry.getID() != idnum)){
entry = entry.getNext();
}
if(entry == null){
return "Not Found.";
}
else
return entry.toString();
}
}
public void insert(Product p){
String n = p.getName();
String i = p.getID();
double pr = p.getPrice();
int hash = (Integer.parseInt(i) % tablesize);
if(table[hash] == null){
table[hash] = new Product(n, i, pr);
}
else{
Product entry = table[hash];
while((entry.getNext() != null) && (entry.getID() != i)){
entry = entry.getNext();
}
entry.setNext(new Product(n, i, pr));
}
}
public void remove(String idnum) {
int hash = (Integer.parseInt(idnum) % tablesize);
if (table[hash] != null) {
Product prevEntry = null;
Product entry = table[hash];
while (entry.getNext() != null && entry.getID() != idnum) {
prevEntry = entry;
entry = entry.getNext();
}
if (entry.getID() == idnum) {
if (prevEntry == null)
table[hash] = entry.getNext();
else
prevEntry.setNext(entry.getNext());
}
}
}
}
If anyone could help me out with this problem that would be great. I have been looking at this thing for a few days now and cant get it to work.

entry.getID() != idnum
change to
!idnum.equals(entry.getID())
in case of entry.getID() returns null
entry.getID() == idnum
is also the same
==================
update:
Since you said the object is not insert into array. I guess it happens here:
There's an id let's say "100" in array. And you want to insert an Product with id "100", so it goes to
else{
Product entry = table[hash];
while((entry.getNext() != null) && (entry.getID() != i)){
entry = entry.getNext();
}
entry.setNext(new Product(n, i, pr));
}
You use entry.getID() != i or !i.equals(entry.getID(), both are ok. But in the end, you set new Product to entry.next.
But in your searchByID() method. You are trying to search through table[hash]
while((entry != null) && (entry.getID() != idnum)){
entry = entry.getNext(); // comment 1
}
if(entry == null){
return "Not Found.";
}
Issue happens here, entry is null will jump out the loop. It means when while loop is done, entry would always be null. You can set a breakpoint on comment 1.

Related

Java Trie Matching using Iterator

I have an assignment which involves creating a Trie of company names (read from a file) and then reading a news article input and counting the number of times a company name from the Trie occurs in the article.
I have coded a pretty standard Trie structure, however for the assignment it made more sense to have the TrieNodes hold the full word rather than just each character.
To make things more complicated, each company name from the file has one "primary name" and can have multiple "secondary names". For example: Microsoft Corporation, Microsoft, Xbox - where the first name is always the primary.
The assignment requires that I count all matches in the article for any of the company names, but only return the company's primary name when printing the results. Because of this, my TrieNode has the String primeName datafield, along with the standard isEnd bool. However, in my case, isEnd represents whether or not the specified node and its parent(s) form a full company name.
For example, with the article input "Microsoft Corporation just released a new Xbox console." I would need to return something along the lines of "Microsoft:2" because both Microsoft Corporation and Xbox share the same primary company name which is Microsoft.
I am using an iterator in the getHits() method but when I do find a hit, I need to look at the next word in the array to make sure it is not a continuation before I decide whether to stop or continue. The problem is that calling iter.next() doesn't just "peek" the next value but it moves forward, essentially causing me to skip words.
For example, if you look at the below code and my example, after "Best" gets a hit, it should see that "Buy" is a child and the next time it loops get a match on "Buy", but since I already call iter.next() to look at "Buy" within the While loop, the next iteration entirely skips "Buy". Is there some way I can simply peek at the next iter value within the While loop without actually moving to it? Also, any improvements to this code are greatly appreciated! I am sure there are many places where I sloppily implemented something.
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.*;
public class BuildTrie {
// Class Methods
public static void main(String[] args) throws IOException {
Trie Companies = new Trie();
String filename = "companies.dat";
try {
BufferedReader reader = new BufferedReader(new FileReader(filename));
String line;
while ((line = reader.readLine()) != null) {
// Split line by tab character
String[] aliases = line.replaceAll("\\p{P}", "").split("\t");
// Loop over each "alias" of specific company
for (int n = 0; n < aliases.length; n++) {
String[] name = aliases[n].split(" ");
// Insert each alias into Trie with index 0 as primary
Companies.insert(name, aliases[0]);
}
}
reader.close();
} catch (Exception e) {
System.err.format("Exception occurred trying to read '%s'.", filename);
e.printStackTrace();
}
/*System.out.println("Article Input: ");
try (BufferedReader input = new BufferedReader(new InputStreamReader(System.in))) {
String line;
while ((line = input.readLine()) != null) {
if (".".equals(line)) break;
String[] items = line.trim().replaceAll("\\p{P}", "").split("\\s+");
for (int i = 0; i < items.length; i++) {
Companies.words.add(items[i]);
//System.out.println(items[i]);
}
}
}*/
Companies.articleAdd("The");
Companies.articleAdd("company");
Companies.articleAdd("Best");
Companies.articleAdd("Buy");
Companies.articleAdd("sell");
Companies.articleAdd("Xbox");
Companies.getHits();
}
}
// Trie Node, which stores a character and the children in a HashMap
class TrieNode {
// Data Fields
private String word;
HashMap<String,TrieNode> children;
boolean bIsEnd;
private String primary = "";
// Constructors
public TrieNode() {
children = new HashMap<>();
bIsEnd = false;
}
public TrieNode(String st, String prime) {
word = st;
children = new HashMap<>();
bIsEnd = false;
primary = prime;
}
// Trie Node Methods
public HashMap<String,TrieNode> getChildren() {
return children;
}
public String getValue() {
return word;
}
public void setIsEnd(boolean val) {
bIsEnd = val;
}
public boolean isEnd() {
return bIsEnd;
}
public String getPrime() {
return primary;
}
}
class Trie {
private ArrayList<String> article = new ArrayList<String>();
private HashMap<String,Integer> hits = new HashMap<String,Integer>();
// Constructor
public Trie() {
root = new TrieNode();
}
// Insert article text
public void articleAdd(String word) {
article.add(word);
}
// Method to insert a new company name to Trie
public void insert(String[] names, String prime) {
// Find length of the given name
int length = names.length;
//TrieNode currNode = root;
HashMap<String,TrieNode> children = root.children;
// Traverse through all words of given name
for( int i=0; i<length; i++)
{
String name = names[i];
System.out.println("Iter: " + name);
TrieNode t;
// If there is already a child for current word of given name
if( children.containsKey(name))
t = children.get(name);
else // Else create a child
{
System.out.println("Inserting node " + name + " prime is " + prime);
t = new TrieNode(name, prime);
children.put( name, t );
}
children = t.getChildren();
int j = names.length-1;
if(i==j){
t.setIsEnd(true);
System.out.println("WordEnd");
}
}
}
public void getHits() {
// String[] articleArr = article.toArray(new String[0]);
// Initialize reference to traverse through Trie
// TrieNode crawl = root;
// int level, prevMatch = 0;
Iterator<String> iter = article.iterator();
TrieNode currNode = root;
while (iter.hasNext()) {
String word = iter.next();
System.out.println("Iter: " + word);
// HashMap of current node's children
HashMap<String,TrieNode> child = currNode.getChildren();
// If hit in currNode's children
if (child.containsKey(word)) {
System.out.println("Node exists: " + word);
// Update currNode to be node that matched
currNode = child.get(word);
System.out.println(currNode.isEnd());
String next = "";
// If currNode is leaf and next node has no match in children, were done
if (iter.hasNext()) {next = iter.next();}
if (currNode.isEnd() && !child.containsKey(next)) {
System.out.println("Matched word: " + word);
System.out.println("Primary: " + currNode.getPrime());
currNode = root;
} else {
// Else next node is continuation
}
} else {
// Else ignore next word and reset
currNode = root;
}
}
}
private TrieNode root;
}
I think instead of using while and iter.next() you can use for loop as below
for (Map.Entry entry : article.entrySet()) {
String word = entry.getKey();
}
So you are not really moving to the next items of your hashmap.
If this is not your point, please clarify us.
Thanks,
Nghia
I opted to use a for-loop style instead of While loop for this, as well as tweaked some logic to get it working. For those interested, the new code is below, as well as an example of the "companies.dat" file (what is populated to the Trie). The stdin is any text excerpt which ends with a "." on new line.
Companies.dat:
Microsoft Corporation Microsoft Xbox
Apple Computer Apple Mac
Best Buy
Dell
TrieBuilder:
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.*;
public class BuildTrie {
// Class Methods
public static void main(String[] args) throws IOException {
Trie Companies = new Trie();
String filename = "companies.dat";
try {
BufferedReader reader = new BufferedReader(new FileReader(filename));
String line;
while ((line = reader.readLine()) != null) {
// Split line by tab character
String[] aliases = line.replaceAll("\\p{P}", "").split("\t");
// Loop over each "alias" of specific company
for (int n = 0; n < aliases.length; n++) {
String[] name = aliases[n].split(" ");
// Insert each alias into Trie with index 0 as primary
Companies.insert(name, aliases[0]);
}
}
reader.close();
} catch (Exception e) {
System.err.format("Exception occurred trying to read '%s'.", filename);
e.printStackTrace();
}
System.out.println("Article Input: ");
try (BufferedReader input = new BufferedReader(new InputStreamReader(System.in))) {
String line;
while ((line = input.readLine()) != null) {
if (".".equals(line)) break;
String[] items = line.trim().replaceAll("\\p{P}", "").split("\\s+");
for (int i = 0; i < items.length; i++) {
Companies.articleAdd(items[i]);
}
}
}
Companies.getHits();
}
}
// Trie Node, which stores a character and the children in a HashMap
class TrieNode {
// Data Fields
private String word;
HashMap<String,TrieNode> children;
boolean bIsEnd;
private String primary = "";
// Constructors
public TrieNode() {
children = new HashMap<>();
bIsEnd = false;
}
public TrieNode(String st, String prime) {
word = st;
children = new HashMap<>();
bIsEnd = false;
primary = prime;
}
// Trie Node Methods
public HashMap<String,TrieNode> getChildren() {
return children;
}
public String getValue() {
return word;
}
public void setIsEnd(boolean val) {
bIsEnd = val;
}
public boolean isEnd() {
return bIsEnd;
}
public String getPrime() {
return primary;
}
}
class Trie {
private ArrayList<String> article = new ArrayList<String>();
private HashMap<String,Integer> hits = new HashMap<String,Integer>();
// Constructor
public Trie() {
root = new TrieNode();
}
// Insert article text
public void articleAdd(String word) {
article.add(word);
}
// Method to insert a new company name to Trie
public void insert(String[] names, String prime) {
// Find length of the given name
int length = names.length;
HashMap<String,TrieNode> children = root.children;
// Traverse through all words of given name
for( int i=0; i<length; i++)
{
String name = names[i];
TrieNode t;
// If there is already a child for current word of given name
if( children.containsKey(name))
t = children.get(name);
else // Else create a child
{
t = new TrieNode(name, prime);
children.put( name, t );
}
children = t.getChildren();
int j = names.length-1;
if(i==j){
t.setIsEnd(true);
}
}
}
public void getHits() {
// Initialize reference to traverse through Trie
TrieNode currNode = root;
for (int i=0; i < article.size(); i++) {
String word = article.get(i);
System.out.println("Searching: " + word);
// HashMap of current node's children
HashMap<String, TrieNode> child = currNode.getChildren();
// If hit in currNode's children
if (child.containsKey(word)) {
System.out.println("Node exists: " + word);
// Update currNode to be node that matched
currNode = child.get(word);
child = currNode.getChildren();
System.out.println("isEnd?: " + currNode.isEnd());
String next = "";
if (i+1 < article.size()) {
next = article.get(i+1);
}
// If currNode is leaf and next node has no match in children, were done
if (currNode.isEnd() && !child.containsKey(next)) {
System.out.println("Primary of match: " + currNode.getPrime());
currNode = root;
}
} else {
// Else ignore next word and reset
System.out.println("No match.");
currNode = root;
}
}
}
private TrieNode root;
}

I implemented my own hash table in java,but I need to remove object using value not key

In own hash table in java,but I need to write a function remove object using value not key.So please help me.And I also need to check a particular value exists in the table or not in a separate function.
Here is my code:
import java.util.Scanner;
class LinkedHashEntry
{
String key;
int value;
LinkedHashEntry next;
LinkedHashEntry(String key, int value)
{
this.key = key;
this.value = value;
this.next = null;
}
}
class HashTable
{
private int TABLE_SIZE;
private int size;
private LinkedHashEntry[] table;
public HashTable(int ts)
{
size = 0;
TABLE_SIZE = ts;
table = new LinkedHashEntry[TABLE_SIZE];
for (int i = 0; i < TABLE_SIZE; i++)
table[i] = null;
}
public int getSize()
{
return size;
}
public void makeEmpty()
{
for (int i = 0; i < TABLE_SIZE; i++)
table[i] = null;
}
public int get(String key)
{
int hash = (myhash( key ) % TABLE_SIZE);
if (table[hash] == null)
return -1;
else
{
LinkedHashEntry entry = table[hash];
while (entry != null && !entry.key.equals(key))
entry = entry.next;
if (entry == null)
return -1;
else
return entry.value;
}
}
public void insert(String key, int value)
{
int hash = (myhash( key ) % TABLE_SIZE);
if (table[hash] == null)
table[hash] = new LinkedHashEntry(key, value);
else
{
LinkedHashEntry entry = table[hash];
while (entry.next != null && !entry.key.equals(key))
entry = entry.next;
if (entry.key.equals(key))
entry.value = value;
else
entry.next = new LinkedHashEntry(key, value);
}
size++;
}
public void remove(String key)
{
int hash = (myhash( key ) % TABLE_SIZE);
if (table[hash] != null)
{
LinkedHashEntry prevEntry = null;
LinkedHashEntry entry = table[hash];
while (entry.next != null && !entry.key.equals(key))
{
prevEntry = entry;
entry = entry.next;
}
if (entry.key.equals(key))
{
if (prevEntry == null)
table[hash] = entry.next;
else
prevEntry.next = entry.next;
size--;
}
}
}
private int myhash(String x )
{
int hashVal = x.hashCode( );
hashVal %= TABLE_SIZE;
if (hashVal < 0)
hashVal += TABLE_SIZE;
return hashVal;
}
public void printHashTable()
{
for (int i = 0; i < TABLE_SIZE; i++)
{
System.out.print("\nBucket "+ (i + 1) +" : ");
LinkedHashEntry entry = table[i];
while (entry != null)
{
System.out.print(entry.value +" ");
entry = entry.next;
}
}
}
}
public class Hash_tab
{
public static void main(String[] args)
{
Scanner scan = new Scanner(System.in);
System.out.println("Hash Table Test\n\n");
System.out.println("Enter size");
HashTable ht = new HashTable(scan.nextInt() );
char ch;
do
{
System.out.println("\nHash Table Operations\n");
System.out.println("1. insert ");
System.out.println("2. remove");
System.out.println("3. get");
System.out.println("4. clear");
System.out.println("5. size");
int choice = scan.nextInt();
switch (choice)
{
case 1 :
System.out.println("Enter key and value");
ht.insert(scan.next(), scan.nextInt() );
break;
case 2 :
System.out.println("Enter key");
ht.remove( scan.next() );
break;
case 3 :
System.out.println("Enter key");
System.out.println("Value = "+ ht.get( scan.next() ));
break;
case 4 :
ht.makeEmpty();
System.out.println("Hash Table Cleared\n");
break;
case 5 :
System.out.println("Size = "+ ht.getSize() );
break;
default :
System.out.println("Wrong Entry \n ");
break;
}
ht.printHashTable();
System.out.println("\nDo you want to continue (Type y or n) \n");
ch = scan.next().charAt(0);
} while (ch == 'Y'|| ch == 'y');
}
}
I think the only efficient way you can do is- maintain another mapping of <value, List<Keys>>. When you need to remove any value, remove the entries related to all those keys maintained in the other table.
Otherwise there is no escape from full scan.
Hashtables do not work that way. Getting (and therefore deleting) a value with its key is what Hashtables are for.
(I am unable to see how you implemented your Hashtable, I guess it is an array).
You have to iterate through the array and delete
all
the first occurrence
Again: A Hashtable might be either the wrong Structure or used false. Either Switch key and value (which is possible for multiple values as well).
Your HashMap<Integer,Integer> will be a HashMap<Integer,List<Integer>, but as you need it that way.
PS: At least in Java 8 it is 'easy' to do with the built-in Hashmap (JavaDoc)

How to optimize nested loops?

I have two foreach loops. One of them contains list of unique emails (outer). I would like to have that as outer loop and increase count by one every time there is a match between an element of outer loop and the inner loop.
My code now:
outer: for (String email : emailsOfContactsWhoFitDynConFilter) {
for (Contact contact : emailClicks.items) {
String[] contactLink = (contact.link).split("\\?", -1);
String queryStringActivity = getQueryStringByName("elqTrackId", contactLink[1]);
if (email.equals(contact.EmailAddress) && contactLink[0].equals(linkInDynamicContentSplit[0])) {
if (queryStringActivity !=null && queryStringDynConLink!=null && queryStringActivity.equals(queryStringDynConLink)){
count++;
break outer;
} else if (queryStringActivity == null || queryStringDynConLink == null) {
System.out.println(" - Missing elqTrackId. But base the same, count++");
count++;
break outer;
}
}
}
}
It works, but problem is these two lines:
String[] contactLink = (contact.link).split("\\?", -1);
String queryStringActivity = getQueryStringByName("elqTrackId", contactLink[1]);
Are executed too many times which consumes a lot of time.
I could reverse the loops, so it would look like this:
outer: for (Contact contact : emailClicks.items) {
String[] contactLink = (contact.link).split("\\?", -1);
String queryStringActivity = getQueryStringByName("elqTrackId", contactLink[1]);
for (String email : emailsOfContactsWhoFitDynConFilter) {
if (email.equals(contact.EmailAddress) && contactLink[0].equals(linkInDynamicContentSplit[0])) {
if (queryStringActivity !=null && queryStringDynConLink!=null && queryStringActivity.equals(queryStringDynConLink)){
count++;
break outer;
} else if (queryStringActivity == null || queryStringDynConLink == null) {
System.out.println(" - Missing elqTrackId. But base the same, count++");
count++;
break outer;
}
}
}
}
That would be much faster, but my count++ would happen more times than I want, it wouldn't be +1 per unique email.
There are a couple good options here, but the first would be to simply cache the String[]. This is a valuable lesson in why you should use methods instead of members.
I suggest having a method of contact.getLinkCache() method, implemented something like I have below. This gives you the benefit of not splitting over and over again (there is a clone in there to protect the data, but clone is a pretty fast method, and unless you've identified this as being too slow, you should probably go with this.
class Contact {
String link;
String[] linkSplitCache;
public void setLink(String link) {
this.link = link;
this.linkSplitCache = null;
}
public String getLink() {
return link;
}
public String[] getLinkCache() {
if(linkSplitCache == null) {
linkSplitCache = link.split("\\?",-1);
}
// return linkSplitCache; // could corrupt!
return linkSplitCache.clone(); // pretty fast array copy
}
}
If it is too slow, then you would want some kind of map to cache it in, and this would probably be outside the Contact class.
Map<Contact, String[]> linkSplitCache = new HashMap<>();
outer: for (Contact contact : emailClicks.items) {
String[] contactLink = linkSplitCache.get(contact);
if(contactLink == null) {
contactLink = (contact.link).split("\\?", -1);
linkSplitCache.put(contact,contactLink);
}
// rest of loop here
With a great help from #corsiKlause Ho Ho Ho I could come to the solution:
Map<String, String[]> linkSplitCache = new HashMap<>();
int count = 0;
String[] linkInDynamicContentSplit = linkInDynamicContent.split("\\?", -1);
String queryStringDynConLink = getQueryStringByName("elqTrackId", linkInDynamicContentSplit[1]);
if (emailClicks != null && emailsOfContactsWhoFitDynConFilter != null) {
for (String email : emailsOfContactsWhoFitDynConFilter) {
inner: for (Contact contact : emailClicks.items) {
String[] contactLink = linkSplitCache.get(contact.EmailAddress);
if (contactLink == null){
contactLink = (contact.link).split("\\?", -1);
contactLink[1] = getQueryStringByName("elqTrackId", contactLink[1]);
linkSplitCache.put(contact.EmailAddress, contactLink);
}
if (email.equals(contact.EmailAddress) && contactLink[0].equals(linkInDynamicContentSplit[0])) {
if (contactLink[1] !=null && queryStringDynConLink!=null && contactLink[1].equals(queryStringDynConLink)){
count++;
break inner; // this excludes link clicks which were done
// twice by the same person
} else if (contactLink[1] == null || queryStringDynConLink == null) {
System.out.println(" - Missing elqTrackId. But base the same, count++");
count++;
break inner;
}
}
}
}
}
Basically what I did was adding the link into the HashMap with the unique key Email address, which makes sure that I don't do the same operation more than once where it's not necessary.

Search Tree , modifications are not saving

I am currently trying to implement a dictionary using a search tree. (The exercise tells me to use such a structure). My tree is made out of nodes that save 2 strings: abreviere(the abreviation of a phrase) and acronim(the phrase). Here is my implementation so far:
Node Class:
public class Nod {
String acronim;
String abreviere;
Nod st,dr;
Nod(String acronim,String abreviere){
this.acronim = acronim;
this.abreviere = abreviere;
st = null;
dr = null;
}
}
Tree Class:
Constructor and insert:
public class Arbore {
Nod root;
Arbore(Nod x){
root = x;
}
public void insert(Nod x,Nod curr){
if(curr.acronim.compareTo(x.acronim) < 0){
if(curr.st == null){
curr.st = new Nod(x.acronim,x.abreviere);
}
else insert(x,curr.st);
}
else if(curr.dr == null){
curr.dr = new Nod(x.acronim, x.abreviere);
}
else insert(x,curr.dr);
}
}
I made them to work. I don't understand why I can't have this code instead:
public class Arbore {
Nod root;
Arbore(){
}
public void insert(Nod x,Nod curr){
if(curr == null) {curr = x; return;}
if(curr.acronim.compareTo(x.acronim) < 0){
if(curr.st == null){
curr.st = new Nod(x.acronim,x.abreviere);
}
else insert(x,curr.st);
}
else if(curr.dr == null){
curr.dr = new Nod(x.acronim, x.abreviere);
}
else insert(x,curr.dr);
}
This wouldn't save my structure either (I am clearly missing something and seems to be related). The problem I am facing now is deleting a node. I have to search for an abreviation(abreviere) and if I find it I must print the phrase and delete the node. These are the methods that I use to do this:
public void search(String acronim){
if(root.acronim.compareTo(acronim) == 0) delete(root);
if(root.acronim.compareTo(acronim) < 0) search(acronim,root.st);
if(root.acronim.compareTo(acronim) > 0) search(acronim,root.dr);
}
private void search(String acronim,Nod curr){
if(curr == null){System.out.println("Nu exista"); return;}
if(curr.acronim.compareTo(acronim) == 0) this.delete(curr);
if(curr.acronim.compareTo(acronim) < 0) this.search(acronim,curr.st);
if(curr.acronim.compareTo(acronim) > 0) this.search(acronim,curr.dr);
}
private void delete(Nod x){
if(x.st == null && x.dr == null){ x = null; System.out.println("deleting");}
else if(x.st == null && x.dr != null) {x = x.dr;System.out.println("deleting right");}
else if(x.st != null && x.dr == null) {x = x.st;System.out.println("deleting left");}
else{
System.out.println("Il deletez");
Nod aux = new Nod(x.acronim,x.abreviere);
x.abreviere = x.st.abreviere;
x.acronim = x.st.acronim;
x.st.abreviere = aux.abreviere;
x.st.acronim = aux.acronim;
delete(x.st);
}
}
They seem to do the job(from the printed messages) . However the changes don't save, after I apply the method I am left with the same tree. Here is the printing method that shows me the current tree:
public String inordine(Nod root){
if(root == null) return "";
return inordine(root.st) + afis(root) + inordine(root.dr);
}
private String afis(Nod n){
if(n == null) return "E nula?!";
return n.abreviere + "->" + n.acronim + "\n";
}
public void afisare(){
System.out.println(inordine(this.root));
}
What am I doing wrong? Is it the garbage collector or something? I use my class like this:
public static void main(String[] args) throws FileNotFoundException, IOException {
FileReader fr = new FileReader("Acronime.txt");
BufferedReader bf = new BufferedReader(fr);
String line = bf.readLine();
String[] array = line.split("=>");
Nod x = new Nod(array[0],array[1]);
Arbore a = new Arbore(x);
while((line = bf.readLine()) != null){
String[] array2 = line.split("=>");
Nod y = new Nod(array2[0],array2[1]);
a.insert(y,a.root);
}
a.afisare();
a.search("JSE");
a.afisare();
}
The words come like this but this part works .
JSE=>JavaScript Encoding
ESP=>Enhanced Serial Port
MSB=>Most Significant Byte
CDRAM=>Cached Dynamic RAM
EMI=>Electro-Magnetic Interference
CDRAM=>Cached Dynamic RAM
AIFF=>Audio Interface File
BASM=>Built in AsseMbler
After looking at the suggested post I changed 2 rows in the delete method and added 1 more method:
Changed Rows:
else if(x.st == null && x.dr != null) {copy(x,x.dr); x.dr = null; System.out.println("deleting right");}
else if(x.st != null && x.dr == null) {copy(x,x.st); x.st = null; System.out.println("deleting left");}
This way the changes stick(if you want to know why read the question from the suggested post below).
In the end the question is : "How to delete an instance of a class because you can't do it with x = null;? "
About the constructor:
In the method you would like to use (with the empty constructor) you need to set the class member root at some point. Something like this should do it:
public void insert(Nod x,Nod curr){
if(curr == null) {
this.root = x;
return;
}
...
About deletion
I don't understand the case when st and dr is not null. You seem to keep the tree structure intact but switch the payload data (abreviere, acronim) of the st side and then delte the st node. I don't get it yet. I will update my answer when I understand better.
You can't destroy an instance of a class in java like I was trying to do in the delete method if(x.st == null && x.dr == null){ x = null;} . To delete the node from the tree you have to find the parent of x and then parent.x = null. This way the reference to x is lost and the garbage collector does his job.
This is because , like #Seelenvirtuose said, java uses pass-by-value which you can read more about in the link that he provided: click!

Using Comparable's compareTo to compare an object to the elements in an arraylist

I created an object Student using Comparable with getters/setters as well as a method that overrides compareTo. In a separate file an arraylist of objects is populated from a text file. Now I need to compare the values in the arraylist to another Student object.
The file was used to create an arraylist as below:
try {
private static ArrayList<Student> array = new ArrayList<Student>();
File file = new File("students.txt");
Scanner scanner = new Scanner(file);
while (scanner.hasNextLine()) {
String inline = scanner.nextLine();
String[] split = inline.split(":");
Student myStudent = new Student();
myStudent.setUsername(split[0]);
myStudent.setPassword(split[1]);
array.add(myStudent);
}
scanner.close();
}
catch (FileNotFoundException e)
{
System.out.println("ERROR.");
}
The text file looks like this:
John:password1
Jane:password2
Jack:password3
(One on each line, no blank lines in between.)
And in a separate method a created Student object is compared to the elements in the arraylist:
Student aStudent = new Student();
aStudent.setUsername("student");
aStudent.setPassword("password");
boolean found = false;
for (int i = 0; i < array.size(); i++)
{
if (array.get(i).compareTo(aStudent) == 0)
{
System.out.println(aStudent.equals(array.get(i)));
found = true;
break;
}
else
{
System.out.println("No such records found!");
found = false;
break;
}
System.out.println(found);
}
The problem is that the object aStudent is not being compared with the objects in the arraylist. It does not print out anything (a -1, 0, or 1) for the call to compareTo, but it always shows that found is true, even though it should be false when there are no matches for aStudent in the file (which there aren't any matches to the username "student" or the password "password").
All together my code complies and works - it just works incorrectly.
Sorry if this sounds confusing. In short, my question is how can I compare the objects of an arraylist to another object using the Comparable interface and compareTo? A plus is if you can tell me what I'm doing wrong.
Thank you in advance.
EDIT
Here is the overriding of the compareTo method:
public int compareTo(Student obj){
int result = 1;
if ((this.Username.compareToIgnoreCase(object.Username) < 0) || (this.Password.compareTo(object.Password) < 0))
{
result = -1;
}
else if ((this.Username.compareToIgnoreCase(object.Username) == 0) && (this.Password.compareTo(object.Password) == 0))
{
result = 0;
}
return result;
}
More context would be useful, but your for-loop looks wrong...
for (int i = 0; i < array.size(); i++)
{
if (array.get(i).compareTo(aStudent) == 0)
{
System.out.println(aStudent.equals(array.get(i)));
found = true;
break; // out of loop
}
else
{
System.out.println("No such records found!");
found = false;
break; // break out loop
}
System.out.println(found);
}
The break statement is used to break out of the loop, meaning that you will only ever compare the first element in the list.
The entire else branch isn't required (or at least I don't think it is ;)), for example...
for (int i = 0; i < array.size(); i++)
{
if (array.get(i).compareTo(aStudent) == 0)
{
System.out.println(aStudent.equals(array.get(i)));
found = true;
break; // out of loop
}
}
System.out.println(found);
Updated
Based on you new compareTo code snippet, this...
if ((this.Username.compareToIgnoreCase(object.Username) < 0) || (this.Password.compareTo(object.Password) < 0))
{
result = -1;
}
else if ((this.Username.compareToIgnoreCase(object.Username) < 0) && (this.Password.compareTo(object.Password) < 0))
{
result = 0;
}
seems wrong to me...the else if should be more like
else if ((this.Username.compareToIgnoreCase(object.Username) == 0) && (this.Password.compareTo(object.Password) == 0))
if the contract for the Comparable interface is to be met, where 0 is equal...
For example...
import java.io.File;
import java.io.FileNotFoundException;
import java.util.ArrayList;
import java.util.Scanner;
public class Test {
private static ArrayList<Student> array = new ArrayList<Student>();
public static void main(String[] args) {
array.add(new Student("John", "password1"));
array.add(new Student("Jane", "password2"));
array.add(new Student("Jack", "password3"));
Student aStudent = new Student("Jack", "password3");
boolean found = false;
for (int i = 0; i < array.size(); i++) {
if (array.get(i).compareTo(aStudent) == 0) {
System.out.println(aStudent.equals(array.get(i)));
found = true;
break;
}
}
System.out.println(found);
}
public static class Student implements Comparable<Student> {
private String name;
private String password;
public Student(String name, String password) {
this.name = name;
this.password = password;
}
public String getName() {
return name;
}
public String getPassword() {
return password;
}
public void setName(String name) {
this.name = name;
}
public void setPassword(String password) {
this.password = password;
}
#Override
public int compareTo(Student object) {
int result = 1;
if ((this.getName().compareToIgnoreCase(object.getName()) < 0) || (this.getPassword().compareTo(object.getPassword()) < 0)) {
result = -1;
} else if ((this.getName().compareToIgnoreCase(object.getName()) == 0) && (this.getPassword().compareTo(object.getPassword()) == 0)) {
result = 0;
}
return result;
}
}
}
Which will print out...
false
true
Where the objects are not equal but where they are comparable...which is kind of weird...to me ;)
Your problem may lie in the compareTo function that you overrode, you need to include that code otherwise no one can determine why certain values are being returned
EDIT:
Note that when objects are created, they are not necessarily equal solely because their contained values are equal. They are separate instances of the object and treated as such.
You will need to override the equals function as well, not just the compareTo function, in order to get the result that you seek.

Categories

Resources