Array of linked lists of arrays for hash table - java

So I am creating a Hash Table that uses an Array of Linked Lists of Arrays. Let me take a second to explain why this is.
So I have previously implemented Hash Tables by creating an Array, and each element of the array is a Linked List. This way I could quickly look up a LL of 450,000 elements by searching for the hash value first in the array, and searching the elements of this LL. I should add that this is a project for school and I cannot just use the Hash Tables that comes with java.
Now I want to do something similar... but I massive have a LL of Arrays that I need to search. Here each element of the LL is line of a text file, which represented by a 4 element array, where each of the 4 elements is a different string that was tab delimited in the input file. I need to be able to quickly access the 2nd, 3rd, and 4th string that was located in each line, and that is now an element of this array.
So What I want is to be able to create an Array of LL of Arrays... first I will find the sum of the ascii values of the second element of an array. Then I will hash the entire array using this value into by Hash Table. Then when I later need to find this element, I will go to the corresponding element of the array, where I have a list of arrays. I will the search for the 2nd value of each array in the list. If i find the one I want, then I return that array, and use the 3rd and 4th element of this array.
As I said, I have this working fine for an Array of LL, but adding the extra dimension of Arrays inside has thrown me off completely. I think it is mostly just figuring out syntax, since I have successfully initialized a Array of LL of Arrays (public static LinkedList[] RdHashLL) so it appears that Java is okay with this in principal. However, I have no idea how to put elements into the Hash Table, and how to read them out.
Below is my code for a ARRAY OF LINKED LISTS that works FINE. I just need help getting it to work for an ARRAY OF LL OF ARRAYS!
public class TableOfHash{
public static LinkedList<String>[] HashLL;
//HASH FUNCTION - Finds sum of ascii values for string
public static int charSum(String s){
int hashVal = 0;
int size = 1019; //Prime Number around size of 8 char of 'z', (8 chars is amoung largest consistantly in dictionary)
for(int i = 0; i < s.length(); i++){
hashVal += s.charAt(i);
}
return hashVal % size;
}
//CREATE EMPTY HASH TABLE - Creates an array of LL
public static void makeHash(){
HashLL = new LinkedList[1019];
for(int i=0; i<HashLL.length; i++){
HashLL[i] = new LinkedList<String>();
}
}
//HASH VALUES INTO TABLE!
public static void dictionary2Hash(LinkedList<String> Dict){
for(String s : Dict){
HashLL[charSum(s)].add(s);
//Finds sum of char vales of dictionary element i,
//and then word at i to the HashLL at point defined
//by the char sum.
}
//Print out part of Hash Table (for testing! for SCIENCE!)
//System.out.println("HASH TABLE::");
//printHashTab();
}
//SEARCH HashTable for input word, return true if found
public boolean isWord(String s){
if(HashLL[charSum(s)].contains(s)){
wordsfound++;
return true;
}
return false;
}
}
I have made some attempts to change this, but for things like if(HashLL[charSum(s)].contains(s)) which searches the LL at the element returned by charsum(s)... I have no idea how to get it to work when it is a LL of Arrays and not of Strings. I have tired HashLL[charSum(s)].[1].contains(s)), and HashLL[charSum(s)][1].contains(s)), and various other things.
The fact that a Google search for "Array of Linked Lists of Arrays" (with quotes) turns up empty has not helped.
Last bit. I realize there might be another data structure that would do what I want, but unless you believe that a Array of LL of Arrays is a totally hopeless cause, I'd like to get it to work as is.

if you have
LinkedList<String[]>[] hashLL;
you can read a specific String like this (one of many ways)
String str = hashLL[outerArrayIndex].get(listIndex)[innerArrayIndex];
To write into the fields, this is possible (assuming everything is initialized correctly).
String[] arr = hashLL[outerArrayIndex].get(listIndex);
arr[index] = "value";

Related

Need help figuring how to write a multidimentional array to store names by letter

I am currently working on a project with a lot of different componenets but one of them is really stumping me. I have to wrte a mutltidimensional array that stores a list of names. The names are are already in a single dimensional array and have been sorted into alphabetical order. For the multidimentioal array I need to store all the names that begin with A in the first set, all the names that begin with B in the second, and so on. I know I can use the ASCII value of the charachters to keep track of the first postion by subrtacting 65 from the value of the letter in the first position of the name and setting that equal to i for array[i] but I don't really know how to store the name after that. Needless to say, I'm really confused and can hardly even say what it is I need. Any help at all is appreciated I haven't written any code yet because I dont't know what to write
I would use a ArrayList as the second dimension of the array. That way you can arbitrarily add any number of strings. Here is a sample to give you some ideas
ArrayList<String>[] nameList = new ArrayList[25];
for(int i =0; i < nameList.length; i++){
nameList[i] = new ArrayList<String>();
}
String[] names = {"Ali","Joe","Sue","Jane"};
for(int i = 0; i < names.length;i++){
int firstLetterCharacterCode = names[i].charAt(0) - 65;
nameList[firstLetterCharacterCode].add(names[i]);
}
for(int i =0; i < nameList.length;i++){
for(String name : nameList[i]){
System.out.println(name);
}
}
If your feeling bold you can look into maps. It would make accessing a particular set of names list more elegant since you could use the letter of the key.

Most efficient way to find unique entries in a large data set

Before anything, I am making it clear that this is an assignment and I do not expect full coded answers. All I seek is advice and maybe snippets of code that helps me.
So, I am reading in about 900,000 words all stored in a arrayList. I need to count unique words using a sorted array (or arraylist) in java.
So far, I am simply looping over the given arrayList and use
Collections.sort(words);
and Collections.binarySearch(words, wordToLook); to achieve it like the following:
OrderedSet set = new OrderedSet();
for(String a : words){
if(!set.contains(a)){
set.add(a);
}
}
and
public boolean contains(String word) {
Collections.sort(uniqueWords);
int result = Collections.binarySearch(uniqueWords, word);
if(result<0){
return false;
}else{
return true;
}
}
This code has a running time of about 60 seconds but I was wondering if there is any better way to do this because running a sort every time an element is added seems very inefficient (but of couse necessary if I were to use binary search).
Any sort of feedback would be greatly appreciated. Thanks.
So, you are required to use a sorted array. That is ok, since you are (not yet) programming in the real world.
I will suggest two alternatives:
The first uses binary search (which you are using in your current code).
I would create a class that contains two fields: the word (a String) and the count for that word (an int). You will build a sorted array of these classes.
Start with an empty array and add to it as you read each word. For each word, do a binary search for the word in the array you are building. The search will either find the entry containing the word (and you will increment the count), or you will determine that the word is not yet in the array.
When your binary search ends without finding the word, you will create a new object to hold the word+count and add it to the array in the location where your search ended (be careful to make sure that your logic really puts it in the right spot to keep your list sorted). Of course, your count is set to 1 for new words.
Another alternative:
Read all of your words into a list and sort it. After sorting, all duplicates will be next to each other in the list.
You will walk down this sorted list once and create a list of word+count as you go. If the next word you see is the same as the last word+count, increment the count. If it is a new word, add a new word+count to your result list with count=1.
I would not use a sorted array. I would create a Map<String, Integer> where the key is your word and the value is the count of the number of occurrences of the word. As you read each word, do something like this:
Integer count = map.get(word);
if (count == null) {
count = 0;
}
map.put(word, count + 1);
Then just iterate over the map's entry set and do whatever you need to do with the counts.
If you know, or can estimate, the number of unique words then you should use this number in the HashMap constructor (so you don't grow the map many times).
If you use a sorted array, your run time cannot be better than proportional to NlogN (where N is the number of words in your list). If you use a HashMap, you can achieve a runtime that grows linearly with N (you save yourself the factor of logN).
Another advantage of using a Map is the memory used is proportional to the number of unique words, rather than the total number of words (assuming that you build the map while reading the words, rather than reading all words into a collection and then adding them to the map).
public static int countUnique(array) {
if(array.length == 0) return 0;
int count = 1;
for i from 1 to array.length - 1 {
if(!array[i].equals(array[i - 1])) count++;
}
return count;
}
This is a O(N) algorithm in pseudocode for counting the number of unique entries in a sorted array. The idea behind it is that we count the number of transitions between groups of equal elements. Then, the number of unique entries is the number of transitions plus one (for the first entry).
Hopefully you see how to apply this algorithm to your array after the elements are sorted.
You could always use comparator to get unique values.
List newList = new ArrayList(new Comparator() {
#Override
public int compare(words o1, words o2) {
if(o1.equalsIgnoreCase(o2)){
return 0;
}
return 1;
}
});
Now count:
words - newList = no. of repeated values.
Hope this helps!!!!

insert a word into an alphabetical array and shift elements over

I have a really simple task but I'm a beginner and have no idea how do do it. I have to make a method that will take two parameters: an array of Strings, and a word. We are assuming that the array contains a group of words that are already alphabetized in order. I need to take the word and insert it into the array in the correct alphabetical position, and shift all the previous array elements over accordingly. Here is my code so far but I think it's completely wrong...
public static void insertWordIntoArray(String[] arr, String word){
int i = 0;
while(arr[i].compareTo(word) > 0){i++;}
String temp = ""; String tempV = "";
temp = arr[i];
arr[i] = word;
for (String ind : arr){
i++;
if(i<9)tempV = arr[i+1];
if(i<9)arr[i+1] = temp;
temp = tempV;
}
}
what do you mean by 9? is it the size of the arr? if it is the size, then this will only work if the elements in the array is less then the array size... I think you will find yourself with array out of bound error if elements is same as array size...
array is dynamic...
i think best not to use number such as 9, because this will make the method is not portable...
Can I increase the size of a statically allocated array?
http://en.wikipedia.org/wiki/Dynamic_array
yeah, that's an insertion sort.
You may be better off using a
LinkedList<String>
, you can insert into it without the need to move the elements.

2D Array but with indexing - java

I'm looping into a number of rows and trying to filter these rows with some if statements. within each if statement I need to have an index for a number of elements. I could have done that using 2d String[][] but the problem is I don't know what is the size of each row at this stage.
I'm looking to store my data like the following :
0 1 3 4 5 6 7 etc..
0 str str str str str str str
1 str str str
2
3 str str str str str str
Any suggestion would be appreciate it
Edit:
Sorry if my question wasn't clear. But I'll explain it more here.
My Loop looks like this:
newArrayList
for (i; i < List ;i++)
{
if(...)
{
newArrayList.add.(0, List.get(i));
} else if(...)
{
newArrayList.add.(2, List.get(i));
} else if(...)
{
newArrayList.add.(6, List.get(i));
}
}
The above code doesn't work but I'm just trying to explain what I need to do actually! My if statements can occur several times and I would like to consider an index for each if statement expectation plus a set of strings. Thanks.
You could try an ArrayList of ArrayList's:
ArrayList<ArrayList<String>> strings = new ArrayList<ArrayList<String>>();
strings.add(new ArrayList<String>()); // Adding a first array to the 'array of arrays'
strings.get(0).add("String1"); // Add a string to the first array,
// Similar to: arr[0][0] = "String1"
//To access them element by element use a double for, note that "s" is each element
for (ArrayList<String> l : strings) {
for (String s : l) {
}
}
PS: An ArrayList<Object> is like an array Object[] but more flexible. It has some useful methods like:
arr_list.get(index); // Getting an object in position 'index'
arr_list.add(object); // Adding an element (Similar to assignment in arrays)
Edit
If you know the number of "rows" then you have to add them to the array of arrays. With this for you are "creating the empty rows of your array":
Rows:
0
1
...
n
for (int i = 0; i < n; i++) { // n is the number of "rows"
strings.add(new ArrayList<String>());
}
Then add an element to a "row":
strings.get(0).add("String1"); // get(0) to obtain the first row, get(1) to obtain the second...
If your index is consecutive form 0 to n and you are inserting them in that order, but n is not known in advance: There are two classical solution:
1) If you do it with a pre-allocated fixed array, you obviously need two passes. The first pass is scanning the row and counting the elements. The second pass is then creating the index.
2) You can do it with a collection allowing dynamic growth via an .add(item) method, like List
If you will convert the collection to an fixed size array later, then it is maybe faster to use method 1) since the add method may be slower due to memory management / allocation / re-allocation.
If your index is consecutive form 0 to n and n is known in advance, but you are inserting the elements not in that order:
You should use solution 1) above.
If your index is not consecutive and n is known known in advance:
3) You create a Map<Integer,String> strings and add the elements via strings.put(index, string) (in any order).
If your index is not unique (as we have finally found out):
4) You crate a Map<Integer,ArrayList<String>> stringMap and add elements via
addStringForIndex(String string, Integer index)
{
listForString = stringMap.get(index);
if(listForString == null) {
listForString = new ArrayList<String>;
map.put(index, listForString);
}
listForString.add(string);
}
If you don't know the size of your array, you could use a List implementation, for example:
ArrayList<ArrayList<String>> 2D = new ArrayList<ArrayList<String>>();
And then use a for-each loop

Finding index of duplicate values in an ArrayList

I have an ArrayList which contains duplicate values at diff diff index.
for example {"Indian","American","Chinese","Australian","Indian","Russian","Indian"}
as u can see the value - "Indian" exists at index - 0, 4 & 6.
I need to know all these indexes where "Indian" exists and create an arrayList of that.
Here is my code:
public void filter(){
categoryArray = Arrays.asList(category);
for(String k : category){
//Log.v("filter", filterTerm);
if(k.equals(filterTerm.toLowerCase()))
{
int p = categoryArray.indexOf(k);
Log.v("index of categArr", ""+p);
String id = Integer.toString(p);
indexes.add(id);
}// end of if
}// end of for
Here I get how many times duplicate occurs by getting the size of indexes(ArrayList)
but when I check the values . Its one value at all index since in the method : indexOf() it always brings the index of first value that it finds in the Array.
So if duplicate exists at index - 2,5,7
I get the array size of index as 3.
But the values are {2,2,2,};
This is a situation where an index-based for loop is more appropriate than enhanced for loop that you're using, as what you need to grab is the index.
You can base all your work on the original array rather than converting it to a list, and I suspect you were going for case-insensitive match.
public void filter(){
for(int i=0; i<category.length; i++){
if(category[i].equalsIgnoreCase(filterTerm))
{
String id = Integer.toString(i);
indexes.add(id);
}
}
}
If you have an ArrayList rather than an array, of course similar code will work, but using list.get(i) instead of category[i].
You need to know which index in the array you are currently at, not the first index where it is to be found. To keep track of that, put
int i = 0;
before the loop, and at the very end of the loop put
i++;
Then the variable i tells you where you have found the value, so you can add i to the indexes list.

Categories