Insert into an already-sorted list - java

With Java, I have a class, known as TestClass, which has a member named Name, which is a string. I also have an ArrayList of this type, which is already sorted alphabetically by Name. What I want to do is find the best index in which to put a new instance of TestClass. The best approach I could come up with so far is this:
public static int findBestIndex(char entry, ArrayList<TestClass> list){
int desiredIndex = -1;
int oldPivot = list.size();
int pivot = list.size()/2;
do
{
char test = list.get(pivot).Name.charAt(0);
if (test == entry)
{
desiredIndex = pivot;
}
else if (Math.abs(oldPivot - pivot) <= 1)
{
if (test < entry)
{
desiredIndex = pivot + 1;
}
else
{
desiredIndex = pivot - 1;
}
}
else if (test < entry)
{
int tempPiv = pivot;
pivot = oldPivot - (oldPivot - pivot)/2;
oldPivot = tempPiv;
}
else
{
int tempPiv = pivot;
pivot = pivot - (oldPivot - pivot)/2;
oldPivot = tempPiv;
}
} while (desiredIndex < 0);
return desiredIndex;
}
Essentially, Break the array in half, check to see if your value goes before, after, or at that point. If it's after, check the first half of the array. Other wise, check the second half. Then, repeat. I understand that this method only tests by the first character, but that's easily fixed, and not relevant to my main problem. For some scenarios, this approach works well enough. For most, it works horribly. I assume that it isn't finding the new pivot point properly, and if that's the case, how would I fix it?
Edit: For clarification, I'm using this for an inventory system, so I'm not sure a LinkedList would be appropriate. I'm using an ArrayList because they are more familiar to me, and thus would be easier to translate into another language, if needed (which is likely, at the moment, might be moving over to C#). I'm trying to avoid things like Comparable for that reason, as I'd have to completely re-write if C# lacks it.
Edit part Duex: Figured out what I was doing wrong. Instead of using the previous pivot point, I should have been setting and changing the boundaries of the area I was checking, and creating the new pivot based on that.

It might not be a good idea to use a SortedSet (e.g. a TreeSet) for this, because Set‘s don't allow duplicate elements. If you have duplicate elements (i.e. TestClass instances with the same name), then a List should be used. To insert an element into an already sorted list is as simple as this:
void insert(List<TestClass> list, TestClass element) {
int index = Collections.binarySearch(list, element, Comparator.comparing(TestClass::getName));
if (index < 0) {
index = -index - 1;
}
list.add(index, element);
}
This code requires Java 8 or later, but can be rewritten to work in older Java versions as well.

As already pointed out, there is no reason to implement this by yourself, simple code example:
class FooBar implements Comparable<FooBar> {
String name;
#Override
public int compareTo(FooBar other) {
return name.compareTo(other.name);
}
}
TreeSet<FooBar> foobarSet = new TreeSet<>();
FooBar f1;
foobarSet.add(new FooBar("2"));
foobarSet.add(f1 = new FooBar("1"));
int index = foobarSet.headSet(f1).size();
(Based on How to find the index of an element in a TreeSet?)

I think the problem is in this bit of the code:
else if (test < entry)
{
int tempPiv = pivot;
pivot = oldPivot - (oldPivot - pivot)/2;
oldPivot = tempPiv;
}
else
{
int tempPiv = pivot;
pivot = pivot - (oldPivot - pivot)/2;
oldPivot = tempPiv;
}
You are peforming the same actions wether test < entry or wether test > entry. This will lead to a linear search when the item you are searching for is at the start of the array.
I prefer to use (low and high) like
high = list.size();
low = 0;
do {
pivot = (high + low) / 2;
if (test < entry) {
low = pivot;
} else if (test > entry) {
high = pivot
} else {
....
}
} while ...;

You should use something like a PriorityQueue that already has a sense of order. Inserting into a collection with a sense of order will automatically place the element in the correct place with minimal time(usually log(n) or less).
If you want to do arbitrary inserts without this, then I would suggest using a LinkedList that won't have to be resorted or completely copied over to insert a single item like the ArrayList you currently have. While finding the correct insert location for a LinkedList will take up to O(n) time, in practice it will still be faster than using a log(n) search for the correct location in an ArrayList, but then needing to copy or sort it afterwards.
Also the code for finding the insert location in a linked list is much simpler.
if (next != null && next.compareTo(insertElement) > 0){
// You have the right location
}

There are other data structures used could use instead of list like a tree, priority queue etc.

Make a list implementation of your own, and in your add method have these lines:
wrappedList.add(object);
Collections.sort(wrappedList);

Related

How can I fix my array so I don't have an IndexOutOfBoundsException?

For a HW assignment, I was tasked to add a bunch of methods into a BinarySearchTree class. Two methods I have are balance and InsertTree (I think it should've been named InsertNode). The authors from the textbook provided pseudo code of what the methods should look like. Both methods work with each other; balance is supposed to take an unbalanced tree and insert each element into an array. I believe InsertTree is supposed to take the elements from the array and put them back into the new formed tree.
The BST Class itself is quite large so I don't think posting it is a good idea. But you can find the Source code here under Sample Materials. The code in reference is in the ch07.trees package.
This is my interpretation of the authors pseudo code so far:
ArrayList<T> array = new ArrayList<T>();
public void balance()
// Will read, store, and recreate the tree
{
Iterator<T> iter = this.iterator();
int index = 0;
while(iter.hasNext())
{
array.add(iter.next());
index++;
}
System.out.println(array.toString());
System.out.println(index);
tree = new BinarySearchTree<T>();
tree.InsertTree(0, index -1);
}
public void InsertTree(int low, int high)
// Will find the mid-point and insert other elements into left and right subtrees
{
if (low == high)
{
tree.add(array.get(low));
}
else if((low + 1) == high)
{
tree.add(array.get(low));
tree.add(array.get(high));
}
else
{
int mid = (low + high)/2;
tree.add(array.get(mid));
tree.InsertTree(low,mid-1);
tree.InsertTree(mid+1,high);
}
}
I have to use ArrayList because all of the methods are generics of type T. In my driver class I am simply adding an unbalanced set of elements [A, B, C, D, E, F] and index will correctly show I have incremented index to 6. But, when the new tree calls for InsertTree( 0, index - 1), I get this:
Exception in thread "main" java.lang.IndexOutOfBoundsException: Index: 2, Size: 0
at java.util.ArrayList.rangeCheck(Unknown Source)
at java.util.ArrayList.get(Unknown Source)
at ch07.trees.BinarySearchTree.InsertTree(BinarySearchTree.java:180)
at ch07.trees.BinarySearchTree.balance(BinarySearchTree.java:163)
at ch07.trees.HWDriver.main(HWDriver.java:67)
Line 163 is tree.InsertTree(0, index -1); and Line 180 is tree.add(array.get(mid));
Seems the problem is involved with the mid-point, but I'm not sure what the issue could be. I'm not an expert at using ArrayLists, so any help on solving this would be much appreciated.
edit:
I believe the problem has been fixed. I put the array that I created back into the balance method instead of outside the method, and added the array to the InsertTree methods arguments. Then, I had to change every conditional output from this.tree.add to this.add. I also moved my BinarySearchTree tree back into the balanced method because before I was getting a NullPointerException.
Whether or not my method is working as intended is still to be determined.
Look what happens when you have an empty collection...
int index = 0;
[...]
tree = new BinarySearchTree<T>();
tree.InsertTree(0, index -1);
You are trying to insert something at index (-1). That is not legal.
Here is your answer more concisely:
this.tree = new BinarySearchTree<T>();
this.tree.InsertTree(0, index-1);
So you have created a new, empty tree and stored it in the member variable "tree". You then attempt tell your new, empty tree to insertTree(0, 5) .

Delete elements within a Linked List

Looking for help again as my professor seems to do an awful job of explaining things (assumes that we know way too much about java programming, when in fact, it's the first java class most of us are taking).
Not looking for someone to write the code for me, but rather someone who can let me know if I'm on the right track and guide me in the right direction. I really want to learn this stuff, not be spoon-fed it, but the professor is making it very hard to do so, so I turn here for help.
The question is to take a LinkedList and create a function to delete the k-th element in that list. I have figured out how to remove the first item if k == 0, but I'm getting lost on how to access the proper element for the "k" within my loop. Here's what I have so far:
public class MyLinked {
static class Node {
public Node(double item, Node next) {
this.item = item;
this.next = next;
}
public double item;
public Node next;
}
int N;
Node first;
// delete the kth element (where k is between 0 and N-1 inclusive)
public void delete(int k) {
if (k < 0 || k >= N) throw new IllegalArgumentException();
{
if (k == 0) {
remove(first.item);
} else if (k > 0) {
kElem = LinkedList.get();
remove(kElem);
}
}
}
}
I'm trying to assign a variable to the .get function but I am definitely wrong there, but not quite sure how to go about this. I know I need to get the value of the k-th element and delete it, however.
I'm also aware that after this, I need to adjust the pointers within the LinkedList to fill the gap where the element I deleted would have been.
Thank you.
Your Link List looks like this:
On this image prev is the object in front of the object you want to delete. Cur is the object you want to delete.
You loop until the next-pointer targets the object you want to delete. After that you set the next pointer of prev to the the object, which follows cur (cur is the object you want to delete).
In pseudo-code it would look like this:
prev = head;
while(prev.next != cur) {
prev = prev.next
}
After this step the prev is on the correct position.
You can see, that this algorithm works with every case except removing the head. You can make a check if you are removing the head and use a different algorithm or you use a dummy-node. Use the dummy-node as head and a dummy-node as tail (here not displayed, but used in double-linked-lists). This dummy-nodes are called sentinels. You won't ever remove this sentinel but your algorithm works without the additional-check because you will remove elements > 0.
Sources:
https://www.cs.cmu.edu/~adamchik/15-121/lectures/Linked%20Lists/linked%20lists.html
In the comments I saw a discussion about clean-code. If you are learning clean-code you will see, that a lot of algorithms are easier to understand, if the variables express their purpose. For example N should be size. But in a different context it could be an upper-limit-of-elements for a cache. There is a good book on this topic: Clean Architecture: A Craftsman's Guide to Software Structure and Design (Robert C. Martin Series)
What do you think is easier to read:
int[][] a = new int[100][200];
for(int i = 0; i < a.length) {
for(int j = 0; j < a[i].length) {
a[i][j] = i*j;
}
}
or this:
int[][] productOfRowColumns = new int[100][200];
for(int row = 0; i < productOfRowColumns.length) {
for(int column = 0; j < productOfRowColumns[row].length) {
productOfRowColumns[row][column] = row*column;
}
}
First go to the k-1 element. Set element.next=element.next.next. Thats how you skip the element, which should be deleted.
Exception: When k=0 (the head element), just set head=head.next.
Optionally you can set next = null for the deleted element (when you went for k-1 elements, deleted=element.next before setting element.next=element.next.next. then say deleted.next=null to clear its next-pointer.
There is also a second common way where you go to the kth element, but you always save the previous (k-1) element in a variable. Performance wise it is worse, because you update 2 variables in each step. It could be more intuitive. Check that video: https://www.youtube.com/watch?v=2RwWsHePdr8 (I hope yt-links are allowed on SO)
By the way, your
static class Node {
public Node(double item, Node next) {
this.item = item;
this.next = next;
}
public double item;
public Node next;
}
int N;
Node first;
is your implementation of the list. LinkedList is the implementation provided by java. https://docs.oracle.com/javase/7/docs/api/java/util/LinkedList.html. You can not mix them.
Hints:
Don't forget to decrease the size of the list (N--;)
You can "go" to the n-th element with "Node current=head; for(int i = 0; i < n; i++) current=current.next;"
What I mean with "head" is your "first". It is the first element of the list.
The "get" method does not do what you want. You will need to write the code to iterate to position k-1 and switch the pointer, as you said:-
eg. list 1->2->3->4, k=2
iterate using next pointer upto 2, switch the next pointer to point to 4. You don't need to do anything else(remove etc)

A matter in the method "transfer " in HashMap ( jdk 1.6 )?

the source code is like this:
void transfer(Entry[] newTable) {
Entry[] src = table;
int newCapacity = newTable.length;
for (int j = 0; j < src.length; j++) {
Entry<K,V> e = src[j];
if (e != null) {
src[j] = null;
do {
Entry<K,V> next = e.next;
int i = indexFor(e.hash, newCapacity);
e.next = newTable[i];
newTable[i] = e;
e = next;
} while (e != null);
}
}
}
but I want to do like this,does this work well or any problem?
I think the hash value of all elements in the same list is same ,so we don't need calculate the buketIndex of the new table;the only thing we should do is
transfer the head element to the new table,and this will save time.
Thank you for your answer.
void transfer(Entry[] newTable){
Entry[] src = table;
int newCapacity = newTable.length;
for(int j = 0 ;j< src.length;j++){
Entry<K,V> e = src[j];
if(null != e){
src[j] = null;
int i = indexFor(e.hash,newCapacity);
newTable[i] = e;
}
}
}
I think you are asking about the HashMap class as implemented in Java 6, and (specifically) whether your idea for optimizing the internal transfer() method would work.
The answer is No it won't.
This transfer method is called when the main array has been resized, and its purpose is to transfer all existing hash entries to the correct hash chain in the resized table. Your code is simply moving entire chains. That won't work. The problem is that the hash chains typically hold entries with multiple different hashcodes. While a given group of entries all belonged on the same chain in the old version of the table, in the new version they probably won't.
In short, your proposed modification would "lose" some entries because they would be in the wrong place in the resized table.
There is a meta-answer to this too. The standard Java classes were written and tested by a group of really smart software engineers. Since then, the code has probably been read by tens or hundreds of thousands of other smart people outside of Sun / Oracle. The probability that everyone else has missed a simple / obvious optimization like this is ... vanishingly small.
So if you do find something that looks to you like an optimization (or a bug) in the Java source code for Java SE, you are probably mistaken!

Calling function from several vectors ordered by element value

I have several vectors of different elements but all extending a class which has a specific function, lets say for example
Vector<classone> one;
Vector<classtwo> two;
Vector<classthree> three;
and classone, classtwo and classthree extend Number, and number has two functions:
doThing()
getValue()
And what i want is to call doThing in the order of the getValues received from all the vectors.
One cheap solution would be to concatenate all the vectors in a single Vector, sort it by value and iterate to call the function, but that makes me have to create a huge new vector, occupying new ram, and since the doThing will happen 60 times a second, if the vectors become big, it might be an overkill, i dont really want to create a new vector just to sort it, is there any other solution using the already existing vectors?
Its Java btw.
If one, two and three are sorted, you could create an custom iterator that checks for a given set of lists what the smallest value at the current position is and proceed there.
Should look similar to this (not tested):
class MultiListIterator {
List<Number>[] lists;
int[] positions;
MultiListIterator(List<Number>... lists) {
this.lists = lists;
positions = new int[lists.length];
}
boolean hasNext() {
for (int i = 0; i < lists.length; i++) {
if (positions[i] < lists[i].length) return true;
}
return false;
}
Number next() {
int bestIndex = -1;
Number bestNumber = null;
for (int i = 0; i < lists.length; i++) {
var p = positions[i];
if (p >= positions[i].length) continue;
Number n = lists[i].get(p);
if (bestNumber == null || n.getValue() < bestNumber.getValue()) {
bestIndex = i;
bestNumer = n;
}
}
if (bestNumber == null) throw new RuntimeException("next() beyond hasNext()");
positions[bestIndex++];
return bestNumber;
}
}
Usage:
MultiListIterator mli = new MultiListIterator(one, two, three);
while (mli.hasNext()) {
mli.next().doThing();
}
You may want to let MultiListIterator implement Iterator<Number>.
Note that Java already has a built-in class Number. Using the same name for your class might lead to a lot of confusion when you forget to import it somewhere.
Premature optimizations are generally a bad idea.
Try the method that came to mind first: creating a giant Vector1 ArrayList and sorting it. If it turns out to be a performance issue, then you can start trying new things.

Java: Recursively Finding the minimum element in a list

I will preface this by saying it is homework. I am just looking for some pointers. I have been racking my brain with this one, and for the life of me i am just not getting it. We are asked to find the minimum element in a list. I know i need a sublist in here, but after that i am not sure. any pointers would be great. thanks.
/** Find the minimum element in a list.
*
* #param t a list of integers
*
* #return the minimum element in the list
*/
public static int min(List<Integer> t) {
if (t.size() == 1){
return t.get(0);
}
else{
List<Integer> u = t.subList(1, t.size());
The point of a recursive algorithm is that everything that must be computed is done through return values or additional parameters. You shouldn't have anything outside the local call of the recursive step.
Since you have to find the minimum element you should take some considerations:
the min element of a list composed by one element is that element
the min element of a generic list is the minimum between the first element and the minimum of the remaining list
By taking these into consideration it should be easy to implement. Especially because recursive algorithms have the convenience of being really similar to their algorithmic description.
You need to find the relationship between the function min applied to a list and the function min applied to a sublist.
min([a b c d e ...]) = f(a, min([b c d e ...]))
Now you just need to find the function f. Once you have the relationship, then to implement it is easy. Good luck.
In the most general sense, recursion is a concept based on breaking down work, and then delegating the smaller chunk of work to a copy of yourself. For recursion to work, you need three main things:
The breakdown of work. How are you going to make each step "simpler"?
The recursive call. At some point your function must call itself, but with less "work".
The base case. What is a (usually trivial) end case that will stop the recursion process?
In your case, you're trying to create a function min that operates on a list. You're correct in thinking that you could somehow reduce (breakdown) your work by making the list one smaller each time (sublist out the first element). As others have mentioned, the idea would be to check the first element (which you just pulled off) against the "rest of the list". Well here's where the leap of faith comes in. At this point, you can "assume" that your min function will work on the sublist, and just make a function call on the sublist (the recursive call). Now you have to make sure all your calls will return (i.e. make sure it will not recurse forever). That's where your base case comes in. If your list is of size 1, the only element is the smallest of the list. No need to call min again, just return (that part you already have in your original post).
/**
* The function computes the minimum item of m (-1 if m is empty).
* #param m: The MyList we want to compute its minimum item.
* #return: The minimum item of MyList
*/
public int minimum(MyList<Integer> m){
int res = 0;
int e0 = 0;
int e1 = 0;
// Scenarios Identification
int scenario = 0;
// Type 1. MyLyst is empty
if(m.length() == 0) {
scenario = 1;
}else {
// Type 2. MyLyst is not empty
scenario = 2;
}
// Scenario Implementation
switch(scenario) {
// If MyLyst is empty
case 1:
res = -1;
break;
// If there is 1 or more elements
case 2:
//1. Get and store first element of array
e0 = m.getElement(0);
//2. We remove the first element from MyList we just checked
m.removeElement(0);
//3. We recursively solve the smaller problem
e1 = minimum(m);
//4. Compare and store results
if(e0 < e1) {
res = e0;
}
else {
res = e1;
}
//5. Return removed element back to the array
m.addElement(0, e0);
break;
}
//6. Return result
return res;
}
There you go, Try this out in the method:
public static Integer minimum(List<Integer> t) {
int minInt;
if (t.size() == 1) {
return t.get(0);
} else {
int first = t.get(0);
List<Integer> u = t.subList(1, t.size());
minInt = Math.min(first, u.get(0));
minInt = IntegerList.minimum(u);
}
return minInt;
}
Hopefully this solves your issue.

Categories