I'm trying to implement a dictionary with a hash table (not using Java's provided hash table classes, but rather made from scratch). Below is the find() method from my Dictionary class, used to detect whether or not a key is in the table when inserting/removing. If the key is already in the table, it returns a score associated with the key (elements in the table are inserted as pairs of key/score into LinkedLists in each table position). If not, it returns -1.
I am running a supplied test program to determine if my Dictionary class works, but I am encountering a NullPointerException when reaching a certain point. Included below is the particular test. Why would this exception be coming up? (I can provide more code if needed!)
Find:
public int find(String config) {
for (int i = 0; i < dictSize; i++) {
if (dict[i] != null) {
LinkedList<DictEntry> current = dict[i];
String currentConfig = current.peek().getConfig(); //Dictionary.java:66
if (currentConfig.equals(config)) {
int currentScore = current.peek().getScore();
return currentScore;
}
}
}
return -1;
}
Insert:
public int insert(DictEntry pair) throws DictionaryException {
String entryConfig = pair.getConfig();
int found = find(entryConfig); //Dictionary.java:27
if (found != -1) {
throw new DictionaryException("Pair already in dictionary.");
}
int entryPosition = hash(entryConfig);
if (dict[entryPosition] == null) { //Dictionary.java:35
LinkedList<DictEntry> list = new LinkedList<DictEntry>();
dict[entryPosition] = list;
list.add(pair);
return 0;
} else {
LinkedList<DictEntry> list = dict[entryPosition];
list.addLast(pair);
return 1;
}
}
The test:
// Test 7: insert 10000 different values into the Dictionary
// NOTE: Dictionary is of size 9901
try {
for (int i = 0; i < 10000; ++i) {
s = (new Integer(i)).toString();
for (int j = 0; j < 5; ++j) s += s;
collisions += dict.insert(new DictEntry(s,i)); //TestDict.java:69
}
System.out.println(" Test 7 succeeded");
} catch (DictionaryException e) {
System.out.println("***Test 7 failed");
}
Exception stack trace:
Exception in thread "main" java.lang.NullPointerException
at Dictionary.find(Dictionary.java:66)
at Dictionary.insert(Dictionary.java:27)
at TestDict.main(TestDict.java:69)
peek() returns null that's why. You can have a nullity check prior to getConfig() call.
Related
So I'm trying to complete an exercise where I've been asked to implement a method that does a binary search in an ArrayList of objects. From the exercise:
Binary search
In the Main-class, implement a method public static int binarySearch(ArrayList<Book> books, int searchedId), which searches the list it received as a parameter, for a book with an id variable that matches the value of searchedId variable it received as a parameter. If that book is found the method, should return the index it's located at, in the list it received as a parameter. If the book isn't found, the method should return the value -1.
The method must be implemented as a binary search, which assumes the list is ordered. You should also assume, that the ids towards the beginning of the list, are always smaller than the ids towards the end of the list.
I have created two methods, one to check whether the arraylist is sorted (isItSorted) and the other one that will perform the binary search if the aforementioned method evaluates to true (binarySearch). Please see below:
public static boolean isItSorted(ArrayList<Book> books) {
ArrayList<String> boo = new ArrayList<>();
String isItSorted = "";
for (int i = 0; i < books.size(); i++) {
for (int j = i + 1; j < books.size(); j++) {
if (books.get(i).getId() < books.get(j).getId()) {
isItSorted = "true";
boo.add(isItSorted);
} else {
isItSorted = "false";
boo.add(isItSorted);
}
}
}
if (!(boo.contains("false"))) {
return true;
}
return false;
}
public static int binarySearch(ArrayList<Book> books, long searchedId) {
if (searchedId < 0 || books.isEmpty()) {
return -1;
} else if (isItSorted(books)) {
int start = 0;
int end = books.size() - 1;
int middle = (start + end) / 2;
if (books.get(middle).getId() == searchedId) {
return middle;
} else if (books.get(middle).getId() > searchedId) {
end = middle - 1;
} else if (books.get(middle).getId() < searchedId) {
start = middle + 1;
}
while (start <= end) {
if (books.get(start).getId() == searchedId) {
return start;
}
start++;
}
}
return -1;
}
Inside these java files, there's a test package that tests whether my solution is correct or not. While 95% of the tests are successful, when it reaches the method below (where it compares the time of execution compared to my other method (linear search)), I get the error Java outOfMemory heap Space.
I use NetBeans. I've already tried the JVM commands.
My solution seems to work with every number of objects I've tried, so perhaps there's something wrong with the test code below?
#Test
#Points("07-05.2")
public void binarySearchIsFasterThanLinearSearch() throws Throwable {
ArrayList<Book> books = generateBooks(10000);
Collections.sort(books, (k1, k2) -> k1.getId() - k2.getId());
int searched = 1000001;
long bSearchStart = System.nanoTime();
int binarySearchId = Searching.binarySearch(books, searched);
long bSearchEnd = System.nanoTime();
assertTrue("When binary search does not find what was searched for, it must return -1", binarySearchId == -1);
long lSearchStart = System.nanoTime();
int linearSearchId = Searching.linearSearch(books, searched);
long lSearchEnd = System.nanoTime();
assertTrue("When linear search does not find what was searched for, it must return -1", linearSearchId == -1);
long bSearchTime = bSearchEnd - bSearchStart;
long lSearchTime = lSearchEnd - lSearchStart;
assertTrue("When there are 10000 books to search, and the searched book is not found, binary search should be a lot faster than linear search. Current this isn't so", bSearchTime * 2 < lSearchTime);
}
ArrayList<String> boo = new ArrayList<>();
String isItSorted = "";
for (int i = 0; i < books.size(); i++) {
for (int j = i + 1; j < books.size(); j++) {
if (books.get(i).getId() < books.get(j).getId()) {
isItSorted = "true";
boo.add(isItSorted);
} else {
isItSorted = "false";
boo.add(isItSorted);
}
}
}
Adds on the order of 100 million items to the ArrayList boo.
If you want to check if something is sorted you can use much simpler code:
Book prev = books[0];
for (int i = 1; i < books.size(); i++) {
if (prev.getId() > books[i].getId())
return false;
}
return true;
But you shouldn't need to call it inside binarySearch() because that will defeat the purpose of binarySearch() and make it as slow as linearSearch().
Okay so for my project in my CSC330 class I am supposed to use threads to quickly find the answer to queries in a massive data set. Each item in the array is a user and the string is a collection of sites they visited on a website identified by number.
Example (the array is String users[])
users[1] = "1 4 5 7" users[2] = "1 2 7 17 10" users[3] = "6"
The queries are:
are there more than ___ users who looked at X
What percent of users looked at X
Are there more users who looked at X than Y
How many users viewed X ____ number of times
What percent of users looked at X more than Y
there are about a million users in this array and we had to solve the following queries without threads on a smaller scale version of the data for testing. All of mine work. Now I need to switch to the massive text file and I need to use threads to increase the speed. I'm wondering where it would be beneficial and how I could implement these threads. I will supply my code for solving each query. I'm thinking that I could use multiple threads to go through parts of the array at the same time but I'm not sure how to execute this.
public boolean query1(String num, String pageName){
if(num == null){
return false;
}
else
{
int userCount = 0;
int pageNum = convert(pageName);
System.out.println(pageNum);
String pageNumString = Integer.toString(pageNum);
System.out.println(pageNumString);
for(int i = 0; i < users.length; i++ )
{
for(String entry : users[i].split(" "))
{
if(entry.equals(pageNumString))
{
userCount++;
break;
}
}
}
if(userCount > Integer.parseInt(num)){
return false;
}
else{
return true;
}
}
}
public float query2(String pageName){
int userCount = 0;
int pageNum = convert(pageName);
String pageNumString = Integer.toString(pageNum);
for(int i = 0; i < users.length; i++ )
{
for(String entry : users[i].split(" "))
{
if(entry.equals(pageNumString))
{
userCount++;
break;
}
}
}
float percentage = (userCount*100.0f)/users.length;
return percentage;
}
public boolean query3(String pageName, String pageName2){
int userCount1 = 0;
int userCount2 = 0;
String pageNumString = Integer.toString(convert(pageName));
String pageNumString2 = Integer.toString(convert(pageName2));
for(int i = 0; i < users.length; i++ )
{
for(String entry : users[i].split(" "))
{
if(entry.equals(pageNumString))
{
userCount1++;
break;
}
}
for(String entry : users[i].split(" "))
{
if(entry.equals(pageNumString2))
{
userCount2++;
break;
}
}
}
return userCount1 > userCount2;
}
public int query4(String pageName, int numTimes){
int userCount = 0;
String pageNumString = Integer.toString(convert(pageName));
for(int i = 0; i < users.length; i++ )//runs through each user
{ int pageCount = 0;
for(String entry : users[i].split(" "))// runs through each user's pages
{
if(entry.equals(pageNumString))
{
pageCount++; // each time page is found page count increments 1
}
} // once done running through user's pages
if(pageCount == numTimes){ // check if the number of pages is equal to the number given
userCount++; // if so increment userCount
}
}
return userCount;
}
public float query5(String pageName, String pageName2){
int viewedMore = 0;
int userCount1 = 0;
int userCount2 = 0;
String pageNumString = Integer.toString(convert(pageName));
String pageNumString2 = Integer.toString(convert(pageName2));
for(int i = 0; i < users.length; i++ )
{
for(String entry : users[i].split(" ")){
userCount1 = 0;
userCount2 = 0;
if(entry.equals(pageNumString))
{
userCount1++;
break;
}
}
for(String entry : users[i].split(" "))
{
if(entry.equals(pageNumString2))
{
userCount2++;
break;
}
}
if(userCount1 > userCount2){
viewedMore++;
}
}
return viewedMore*100.0f/users.length;
}
At the very least, in query3 and query5 you can spawn off threads for each of the two inner for-loops; there's no reason they must be run sequentially. And for any of the query functions, you can certainly split the array into sections. Since your data is growing large, that approach will most likely be faster than iterating over the data with the main thread.
I would suggest providing the threads contiguous segments (e.g. index 0 to N-1; N to N+N-1 etc). This previous StackOverflow answer provides good reasoning why such an approach is most efficient. Once you get something working, you can play around with the number of threads to optimize.
edit to address your comment below
One approach would be to implement the strategy pattern, such that each of your Query are interchangeable across a client, where an executeQuery() call is the interface method. Think of having a client's call look something like
interface Query {
boolean executeQuery();
}
// client code...
Client client = new Client(...);
client.setQuery(new Query3(String num, String pageNum));
client.query(); // calls query.executeQuery();
Within the concrete Query classes, you can define individual behaviors of what the threads would do. This is a rough example:
public Query3 implements Query {
Query3(String pageNum`, String pageNum2) {
this.pageNum1=pageNum1;
this.pageNum2=pageNum2;
}
boolean executeQuery() {
for(int i = 0; i < users.length; i++ ) {
SearchThread first = new SearchThread(pageNum1);
SearchThread second = new SearchThread(pageNum2);
first.run();
second.run();
}
first.join();
second.join();
return first.userCount > second.userCount;
}
SearchThread extends Thread {
String pageNumString;
int userCount;
SearchThread(String pageNumString) {
this.pageNumString=pageNumString;
}
public void run() {
// do your search over this segment of the array, adding up userCounts
}
Here is another StackOverflow question that describes how to run multiple threads over a single array, with some boilerplate code to use.
I have a class TypesHolder that has four properties which are each int values. I want to identify how many unique combinations of values are in the four int variables, and then to give a count of how many instances of TypesHolder have each specific combination of the four integer variables. How can I accomplish this in code? My code attempt below is failing, with the failed results summarized at the end. There must be a simpler way to do this correctly.
Here is my TypesHolder class:
public class TypesHolder {
private int with;
private int type;
private int reason1;
private int reason2;
//getters and setters
}
To hold the unique combinations during analysis, I created the following TypesSummaryHolder class:
public class TypesSummaryHolder {
private int with;
private int type;
private int reason1;
private int reason2;
private int count;
//getters and setters
}
I then created an ArrayList to store the 15000+ instances of TypesHolder and another ArrayList to store the TypesSummaryHolder objects who represent each of the unique combinations of width, type, reason1, and reason2 from the TypesHolder objects, along with a count variable for each of the unique combinations. I wrote the following code to populate the ArrayList of TypesSummaryHolder objects along with their counts:
#SuppressWarnings("null")
static void countCommunicationTypes(){
int CommunicationWithNumber;int CommunicationTypeNumber;int CommunicationReasonNumber;
int SecondReasonNumber;int counter = 0;
ArrayList<EncounterTypesHolder> types = new ArrayList<EncounterTypesHolder>();
ArrayList<EncounterTypesSummaryHolder> summaries = new ArrayList<EncounterTypesSummaryHolder>();
////////
try {Class.forName("sun.jdbc.odbc.JdbcOdbcDriver");}
catch (ClassNotFoundException e1) {e1.printStackTrace();}
Connection sourceConn = null;
try {sourceConn = DriverManager.getConnection("jdbc:odbc:PIC_NEW_32");}
catch (Exception e1) {e1.printStackTrace();}
Statement st = null;
try {st = sourceConn.createStatement();}
catch (Exception e1) { e1.printStackTrace();}
ResultSet rest = null;
try {
rest = st.executeQuery("SELECT * FROM someTable");
while (rest.next()) {
CommunicationWithNumber = rest.getInt(3);
CommunicationTypeNumber = rest.getInt(5);
CommunicationReasonNumber = rest.getInt(6);
SecondReasonNumber = rest.getInt(6);
EncounterTypesHolder etype = new EncounterTypesHolder();
etype.setWith(CommunicationWithNumber);
etype.setType(CommunicationTypeNumber);
etype.setReason1(CommunicationReasonNumber);
etype.setReason2(SecondReasonNumber);
if(!isDuplicateType(etype,types)){
EncounterTypesSummaryHolder summaryholder = new EncounterTypesSummaryHolder();
summaryholder.setWith(CommunicationWithNumber);
summaryholder.setType(CommunicationTypeNumber);
summaryholder.setReason1(CommunicationReasonNumber);
summaryholder.setReason2(SecondReasonNumber);
summaryholder.setCount(1);
summaries.add(summaryholder);
} else {
EncounterTypesSummaryHolder summaryholder = new EncounterTypesSummaryHolder();
summaryholder.setWith(etype.getWith());
summaryholder.setType(etype.getType());
summaryholder.setReason1(etype.getReason1());
summaryholder.setReason2(etype.getReason2());
if(isDuplicateSummaryType(summaryholder, summaries)){
for(int u = 0; u<summaries.size();u++){
if((CommunicationWithNumber==summaries.get(u).getWith()) && (CommunicationTypeNumber==summaries.get(u).getType()) && (CommunicationReasonNumber==summaries.get(u).getReason1()) && (SecondReasonNumber==summaries.get(u).getReason2()) ){
int oldcount = summaries.get(u).getCount();
int newcount = oldcount+1;
summaries.get(u).setCount(newcount);
}
}
}else {
summaryholder.setCount(1);
summaries.add(summaryholder);
}
}
types.add(etype);
counter += 1;
System.out.println("counter is: "+counter);
System.out.println("summaries.size() is: "+summaries.size());
}
} catch (Exception e) {e.printStackTrace();}
System.out.println("at end: counter is: "+counter);
System.out.println("at end: types.size() is: "+types.size());
System.out.println("at end: summaries.size() is: "+summaries.size());
int total = 0;
for(int r=0;r<summaries.size();r++){
total += summaries.get(r).getCount();
int with = summaries.get(r).getWith();int type = summaries.get(r).getType();int reason1 = summaries.get(r).getReason1();int reason2 = summaries.get(r).getReason2();int thiscount = summaries.get(r).getCount();
}
System.out.println("total is: "+total);
}
static boolean isDuplicateType(EncounterTypesHolder testType, ArrayList<EncounterTypesHolder> types){
for(int j = 0; j<types.size(); j++){
if( (testType.getWith() == types.get(j).getWith()) && (testType.getType() == types.get(j).getType()) && (testType.getReason1() == types.get(j).getReason1()) && (testType.getReason2() == types.get(j).getReason2())){
System.out.println("=====TRUE!!====");
return true;
}
}
return false;
}
static boolean isDuplicateSummaryType(EncounterTypesSummaryHolder testType, ArrayList<EncounterTypesSummaryHolder> types){
for(int j = 0; j<types.size(); j++){
if( (testType.getWith() == types.get(j).getWith()) && (testType.getType() == types.get(j).getType()) && (testType.getReason1() == types.get(j).getReason1()) && (testType.getReason2() == types.get(j).getReason2())){
System.out.println("=====TRUE!!====");
return true;
}
}
return false;
}
The code above is producing the following SYSO output at the end:
at end: counter is: 15415
at end: types.size() is: 15415
at end: summaries.size() is: 15084
total is: 2343089
The max possible value for summaries.size() should be around 600, but the 331 you get from types.size() minus summaries.size() above is within the range of believable values for summaries.size(). However, the value for total should be equal to the 15414 value of types.size(). What is wrong with my code above? How can I change my code above to get both a list of the unique combinations of with, type, reason1, and reason2, and also a count of the number of instances with each of those unique value combinations?
If I understand you right, you could add hashcode() and equals() methods to to TypesHolder, then add all your values to a Set<TypesHolder> of some sort. Then just count the total objects (call size()) in the set to get the number of unique combinations.
Here's a link to implementing hashcode() and equals() from SO, if you're not familiar with those methods. Google is your friend.
I am noticing a weird behavior when I perform some basic checks using objects that have been .initialize()'ed using Hibernate.
The following 'if condition' fails even when it is supposed to pass:
for (int j = 0; j < trcList.size(); j++)
{
if (trcList.get(j).getABC().getId() == abc.getId())
{
//do something
break;
}
}
However if I change it slightly, it passes where expected. In the snippet below, I grab the LHS value in a local variable and use that for comparison:
for (int j = 0; j < trcList.size(); j++)
{
int x = trcList.get(j).getABC().getId();
if (x == abc.getId())
{
//do something
break;
}
}
trcList is an ArrayList created from an array of objects grabbed from a database using hibernate. Various fields in those objects including 'ABC' have been Hibernate.initialize()'ed.
Session session = null;
try {
session = HibernateUtil.initializeHibernateConnection(session);
Criteria cr = ... //specify search criteria
List results = cr.list();
TRC[] trcArray = new TRC[results.size()];
for (int i = 0; i < results.size(); i++) {
trcArray[i] = (TRC) results.get(i);
if (trcArray[i].getABC() != null)
{
Hibernate.initialize(trcArray[i].getABC());
}
}
session.getTransaction().commit();
return trcArray;
} catch (RuntimeException re) {
log.error("get failed", re);
throw re;
}
I suspect trcList.get(j).getABC().getId() is java.lang.Integer and hence it should be compared with equals()
if (trcList.get(j).getABC().getId().equals(abc.getId())) {
}
Below test will assert the same
Integer i = new Integer(1); //set to 1
Integer j = new Integer(1); //also set to 1
System.out.println(i == j); //false, because it is reference comparison
System.out.println(i.equals(j)); //true
I am stuck.
The following function is supposed to return currVm, an integer. But if I make a return I will break the loop and next time when this function is called,the same process will begin again.
What shall I do, so that I continue from where I left off ? I tried making static variables but I that didn't help me.
#Override
public int getNextAvailableVm() {
Set<String> dataCenters = confMap.keySet();
for (String dataCenter : dataCenters) {
LinkedList<DepConfAttr> list = confMap.get(dataCenter);
Collections.sort(list, new MemoryComparator());
int size = list.size() - 1;
int count = 0;
while(size >= 0) {
DepConfAttr dca = (DepConfAttr)list.get(count);
int currVm = dca.getVmCount();
int c = 0;
while(c <= currVm) {
allocatedVm(currVm);
c++;
return currVm;
}
count++;
size--;
}
}
return 0;
}
The for-each loop assigns a new data center that acts as a key for the confMap.The list that I get as a value, is sorted.Then a loop is run till it escapes its size.Inside this while loop, another while loop is run from where a function named allocatedVm of the inherited class is called. A parameter named currVm is passed to it.
This is the variable that I need to return. What shall I do to return this variable ? I have to start from I left off. I mean the next call should appear to be the next step, whatever it was, while executing the loop.
Add List<Integer> object to your class, and change your method as follows:
private Iterator<Integer> availableVms = null;
#Override
public int getNextAvailableVm() {
if (availableVms != null) {
if (availableVms.hasNext()) {
return availableVms.next();
}
return 0;
}
List<Integer> tmp = new ArrayList<Integer>();
Set<String> dataCenters = confMap.keySet();
for (String dataCenter : dataCenters) {
LinkedList<DepConfAttr> list = confMap.get(dataCenter);
Collections.sort(list, new MemoryComparator());
int size = list.size() - 1;
int count = 0;
while(size >= 0) {
DepConfAttr dca = (DepConfAttr)list.get(count);
int currVm = dca.getVmCount();
int c = 0;
while(c <= currVm) {
allocatedVm(currVm);
c++;
tmp.add(currVm);
}
count++;
size--;
}
}
availableVms = tmp.iterator();
return availableVms.hasNext() ? availableVms.next() : 0;
}
The idea is to pre-generate the entire list, and store its iterator for future use. Before entering the method you check if the availableVms iterator has been prepared. If it has been prepared, grab the next item off of it if it's available; otherwise, return zero.
If the list has not been prepared yet, run your algorithm, and add the results to a temporary list tmp. Once the list is ready, grab its iterator, and use it for subsequent invocations.