I have a method that sorts a hand of cards in an endogenous doubly linked list.
public void sort(Comparator<Card> cmp) {
// source code that I am adapting my code from
// for (int i=0; i < a.length; i++) {
// /* Insert a[i] into the sorted sublist */
// Object v = a[i];
// int j;
// for (j = i - 1; j >= 0; j--) {
// if (((Comparable)a[j]).compareTo(v) <= 0) break;
// a[j + 1] = a[j];
// }
// a[j + 1] = v;
// }
for(Card f = first; f!=null; f = f.next){
Card insert = f;
for(Card l = last; l!=null || l!= f; l = l.prev)
{
Card compare = l;
if(cmp.compare(compare, insert) <=0)
remove(insert);
this.add(insert);
break;
}
}
// Make sure to test invariant before and after
// You may find it helpful to use "remove" (but watch about size!)
}
When I run this code it is not sorting correctly. Any pointers?
At a quick glance, I see three bugs. There may be more.
Instead of l != null || l != f, I'm pretty sure you want && - the condition as you've written it is always true.
You should use {} to delimit the "true" branch of your if. Currently, this.add(insert); and break; will run whether the if condition is true or false - and your indentation suggests that this isn't what you're expecting.
In this.add(insert), you're not specifying where in the list to add the new node. I would expect to see something that specifies you'll be adding it at the position indicated by l.
Related
I have change my bubble sort from implementing the application traverses the entire list during each step of the sort.
This is not necessary since after the first traversal the smallest item will be at the end of the list and after the second traversal, the second smallest item will be in its correct position (2nd last) and so on. i'm a little unsure on what needs to changed exactly.
I need to modify the bubble sort so it doesn't perform unnecessary comparisons.
private void bubbleSort() {
int currentCount = 0;
showStatus("Sorting ...");
boolean swap = true;
while (swap) {
swap = false;
for (int i = 0; i < items.length - 1; i++) {
if (greaterThan(items[i], items[i + 1])) {
swapItems(items[i], items[i + 1]);
swap = true;
currentCount++;
}
} // for
} // while
showStatus("Sort complete, number of swaps = " + currentCount);
} // bubbleSort private void bubbleSort() {
A bubble sort will perform unnecessary comparisons, that's why you don't use it in production for any dataset of any reasonable size. Regarding your code in particular. A simple look at the reference implementation on Rosettacode(because I don't feel like actually writing it again, you only do that in school) looks to show it doing exactly the same number of comparisons. If you want an actually good sorting algorithm for sufficiently large N try merge-sort.
Reference
public static <E extends Comparable<? super E>> void bubbleSort(E[] comparable) {
boolean changed = false;
do {
changed = false;
for (int a = 0; a < comparable.length - 1; a++) {
if (comparable[a].compareTo(comparable[a + 1]) > 0) {
E tmp = comparable[a];
comparable[a] = comparable[a + 1];
comparable[a + 1] = tmp;
changed = true;
}
}
} while (changed);
}
First of all, at the end of first iteration of the for loop the biggest element will be at the end of the array and not the smallest.
If you want to modify your code to save unneeded comparison you can check last comparison and use if as the end of the next for-loop.
Consider the following code: (I hope java allow while(int) - I'm not a java expert...)
integer swap = items.length - 1;
while (swap) {
swap = 0;
integer lastSwap = swap ;
for (int i = 0; i < lastSwap ; i++) {
if (greaterThan(items[i], items[i + 1])) {
swapItems(items[i], items[i + 1]);
swap = i;
currentCount++;
}
} // for
} // while
I am trying to see what possibility there is for something (don't tell me there isn't, this is my failed project) throughout an arrangement of points and their distances.
for (Point p1 : results) {
remove.clear();
for (Point p2 : results) {
if (Math.sqrt(
Math.pow(p1.getX() - p2.getX(), 2)
+ Math.pow(p1.getY() - p2.getY(), 2)
) % 1 > 0) {
results.remove(p2);
}
}
}
Basically, I am trying to check if two points have an integer distance, and, if not, remove it from the set, and do this for all points (that remain).
However, I am getting a ConcurrentModificationException and I am not certain how to refactor it to accomplish the same task without just provoking the error in another way.
Are there any ways around this or is it just a limitation of Java?
EDIT: While the duplicate suggested link offers insight, the answers' focus on single loops has berth of excess that is not applicable. If this question is duplicate, it's on premise of that using an Iterator is just the answer.
Some Collection implementations use a "fail-fast" iterator. When removing an item from a Collection directly (using Collection#remove) while iterating over it will cause that exception.
Enhanced for-loops uses the collection's iterator to iterate through the collection.
You could change your enhanced loops to regular for loops:
for(int i = 0; i < results.size(); i++) {
for(int j = 0; j < results.size(); j++) {
Point result = results.get(j);
if(...) {
//results.remove(j); or
//results.remove(result);
}
}
}
As mentioned in the comments, this will not work for Set. In that case, you could simply keep a reference to the collection's iterator, and use that to remove the item:
Iterator<Point> firstIter = results.iterator();
while(firstIter.hasNext()) {
Point p1 = iterator.next();
Iterator<Point> secondIter = results.iterator();
while(secondIter.hasNext()) {
Point p2 = secondIter.next();
if(...) {
secondIter.remove();
}
}
}
You could do this:
Iterator<Point> iterator = results.iterator();
while (iterator.hasNext()) {
Point p1 = iterator.next();
boolean shouldBeRemoved = false;
for(Point p2 : results) {
if (p2 != p1 && (Math.sqrt(Math.pow(p1.getX() - p2.getX(), 2)
+ Math.pow(p1.getY() - p2.getY(), 2))
% 1 > 0)) {
shouldBeRemoved = true;
break;
}
}
if (shouldBeRemoved) {
iterator.remove();
}
}
The difference is that obviously p1 gets removed instead of p2, but since we're dealing with a Set here...
remove it from the set
... the ordering isn't important, right?
This seems to be happening because you are trying to remove the same Point structure. Consider the case of the first point. Both p1 and p2 refer to the first point in results. The distance between p1 and p2 is zero because they refer to the same point. You are then trying to remove p2 which is actually p1 itself. Please refer to the link http://docs.oracle.com/javase/7/docs/api/java/util/ConcurrentModificationException.html for more on why you can get this exception even in the case when one thread is trying to access and modify some structure.
You could modify the above code like the following:-
boolean[] if_deleted = new boolean[results.size()];
for (int i = 0; i < results.size(); ++i) {
if_deleted[i] = false;
}
for (int i = 0; i < results.size(); ++i){
for(int j = i + 1; j < results.size(); ++j)
Point p1 = (Point)results.get(i);
Point p2 = (Point)results.get(j);
if (!if_deleted[i] && !if_deleted[j]) {
if (Math.sqrt(
Math.pow(p1.getX() - p2.getX(), 2)
+
Math.pow(p1.getY() - p2.getY(), 2))
% 1 > 0){
if_deleted[j] = true;
results.remove(p2);
}
}
}
}
for (int i = 0; i < results.size(); ++i) {
if (if_deleted[i]) {
results.remove(i);
}
}
I refactored to
for (int p1 = 0; p1 < results.size() ; p1++){
for (int p2 = p1; p2 < results.size() ; p2++){
if (Math.sqrt(
Math.pow(results.get(p1).getX() - results.get(p2).getX(), 2)
+
Math.pow(results.get(p1).getY() - results.get(p2).getY(), 2))
% 1 > 0){
results.remove(p2);
p2--;
}
}
}
But I'm not sure it's working as I expected it to.
I have a class Card which contains value (int), suit (String) and faceValue (String). It seems like a regular insertion sort on Card.value should work fine. I just use the whole object when moving things around. For some reason, this crashes and burns. It ends up duplicating the highest card into every element except for a random element that I can't understand.
value, suit, and faceValue are pulic, also.
This is my code:
public static void insertionSort(ArrayList<Card> Array) {
int i,j;
Card key = new Card(0, "","");
for (i = 1; i < Array.size(); i++) {
key.value = Array.get(i).value;
key.suit = Array.get(i).suit;
key.faceValue = Array.get(i).faceValue;
j = i;
while((j > 0) && (Array.get(j - 1).value > key.value)) {
Array.set(j,Array.get(j - 1));
j--;
}
Array.set(j,key);
}
}
I checked this against Wikipedia's pseudo code, and I can't find any fundamental difference. I've been through the debugger a dozen times, and I can't see any reason for the compiler to do what it's doing. Does anyone have an idea why it's not working?
Thanks.
I would like to extend ginz's answer.
Java objects are passed by reference.
So you are changing one object and setting it to multiple indexes.
To visualize (before and after):
For after: Please note that not all indexes must reference to same object. Some of them could remain unchanged.
Better approach would be to move objects, instead of trying to duplicate them.
Also, by Java standard, name of properties (variables) should always start with small letter.
Here is working code:
public static void insertionSort(ArrayList<Card> array) {
int i, j;
for (i = 1; i < array.size(); i++) {
Card tmp = array.get(i);
j = i;
while ((j > 0) && (array.get(j - 1).value > tmp.value)) {
array.set(j, array.get(j - 1));
j--;
}
array.set(j, tmp);
}
}
At every cycle, you insert the object "key" into the list (Array.set(j,key);). So, at the end your whole list will be made of references to the object "key". So when you set key.value, key.suit and key.faceValue at the end, you are setting the fields of every element of your list, because your list consists of references of the same object.
move Card key = new Card(0, "",""); inside the for cycle. Like this:
public static void insertionSort(ArrayList<Card> Array) {
int i,
j;
for (i = 1; i < Array.size(); i++) {
Card key = new Card(0, "","");
key.value = Array.get(i).value;
key.suit = Array.get(i).suit;
key.faceValue = Array.get(i).faceValue;
j = i;
while((j > 0) && (Array.get(j - 1).value > key.value)) {
Array.set(j,Array.get(j - 1));
j--;
}
Array.set(j,key);
}
}
gl with your studies :)
You're setting all the fields of Array(OMG, please rename it!) with the same element: key. So, all the elements would be the same.
The basic algorithm is
for each element
search for the first smaller element going downward
insert element right after that
So, in your case:
public static void insertionSort(ArrayList<Card> cards) {
for (int i = 1; i < cards.size(); i++) {
int value = cards.get(i).value;
j = i;
for (j = i-1; j >= 0; j--) {
if (cards.get(j).value <= key.value) {
break;
}
}
cards.add(j,cards.remove(i));
}
}
One important point here is that at no point does the array contains duplicated values (which happens when you use set)
Use Iterator for getting the elements.
public static void insertionSort(ArrayList<Integer> arrL) {
Iterator<Integer> it = arrL.iterator();
while(it.hasNext()){
int new_element = it.next();
int j = arrL.indexOf(new_element);
while(j>0 && arrL.get(j-1)>new_element){
arrL.set(j, arrL.get(j-1));
j--;
}
arrL.set(j, new_element);
}
}
I was assigned to write a delete algorithm for my sorted array structure. It continues to be a source of problems for my program because, in certain instances, it is completing the delete when it should be returning False for "node not found". So the delete function works, but it does it even when the node is not found. Where is the flaw in my logic?
public boolean delete(String targetListing)
{
int low = 0;
int high = next - 1;
int i = (low + high) / 2;
//check to see if target listing is the same as the current node key field
while(data[i].getName().compareToIgnoreCase(targetListing) != 0 && high != low)
{
if(data[i].getName().compareToIgnoreCase(targetListing) >= 1)
{
high = i - 1; //eliminate the bottom of the array
}
else
{
low = i + 1; //eliminate the top of the array
}
i = (low + high) / 2;
}
//this is my logic to determine if the node was found or not
//I also tried if(low == high) but sometimes that would be true at the
//at the position that the node was found
if(i == next || i < 0)
{
return false; //node not found
}
for(int j = i; j < next - 1; j++)
{
data[j] = data[j + 1];
}
next = next - 1;
data[next] = null;
return true;//node found and deleted
If anyone could also point me to a good example of a sorted array delete algorithm that accounts for a node not found scenario I would really appreciate it. I would have thought that would be a very easy thing to find, but I am having a hard time finding it.
Simplest answer: Replace your if(i == next || i < 0) with if(data[i].getName().compareToIgnoreCase(targetListing) != 0) -- in other words, check that you've actually found a match rather than simply having narrowed down to a single possibility.
I have a list and I'd like to get the values at i-1, i and i+1 positions. When i is the first or the last index, it would throw an IndexOutOfBoundsException. To prevent that, I would write a few if-statements and hardcode it like that:
if (i == 0){
a = list.get(list.size()-1);
b = list.get(0);
c = list.get(1);
} else if (i == list.size()-1){
a = list.get(i-1);
b = list.get(i);
c = list.get(0);
} else {
a = list.get(i-1);
b = list.get(i);
c = list.get(i+1);
}
I find this way is a littlebit static. Let's say I want to get n entries from the list in this way, how would you do that?
You can use (i-1+list.size()) % list.size() and (i+1) % list.size().
This will also handle lists of length 1.
Heavier options:
Write a method
<T> T get(List<T> list, int i)
{
i %= list.size();
return list.get(i >= 0 ? i : i + list.size());
}
Subclass and override get()
Make a wrapper class which wraps around indices
You could use the ternary operator to shorten the code a little, and factor out the get calls to shorten the code further.
int prev, i, next;
//start loop here
prev = (i == 0 ? list.size()-1 : i-1);
next = (i == list.size()-1 ? 0 : i+1);
a = list.get(prev);
b = list.get(i);
c = list.get(next);
// end loop here
You will have to handle small lists, (size() <= 2) to stop repeating elements.
Why you can't just iterate with foreach and reassign old values like this:
List<Integer> list = Arrays.asList(1, 5, 7, 3, 4);
int n = 3; // how much entries we take
int a = 0, b = 0, c;
for (int i = 0; i < n; i++) {
c = b;
b = a;
a = list.get(i);
// do some stuff
}