So I have this project and im writing the add method for my catalog class and this add method needs to add an item to a sorted array into the right place using insertion sort, unless the array has nothing in it in that case i just want to add it in normally. this whole project must use an array I cannot use an arraylist or anything else.
The problem I am having here is that the way my program currently is, its only adding one object to my array and each time i try to add a new one during run tine it jst replaces the item already in there. I know that my problem is something in the body of my while loop and the way i initialize my position variable.
here is the method im having trouble with.
public void addItem(Item theItem)
{
int position = size;
if(size != 0){
while (position > 0 && theItem.compareTo(items[position - 1]) < 0){
items[position] = items[position - 1];
position--;
}
items[position] = theItem;
}
else{
items[size] = theItem;
size++;
}
here is my compareTo method
public int compareTo(Item other){
if(this.getItemType().equals(other.getItemType())){
return this.itemnum - other.itemnum;
}
//item types are not equal
else
return this.getItemType().compareTo(other.getItemType());
//try writing code to compare by price as well
}
The most likely problem in your code is this line:
items[position-1] = items[position];
This will copy an item in you array from the current position to the position to the left of it.
When you insert a new item you want to copy items from the left to the current position to make room for the new item to the left.
Change it to
items[position] = items[position-1];
A size++ is also missing after the while block, inside the first if block.
I realized this when adding a second call to addItem in my test code below.
You could also put a single size++ statement outside of the if statement.
A Complete, Minimal, Reproducible Example that I used trying to fix it. I have used Integer instead of Item to avoid having to add more classes.
public class Main {
private int size = 0;
private Integer[] items = new Integer[20];
public static void main(String... args) {
new Main().execute(); // Moving us into a non-static context
}
public void execute() {
System.arraycopy(new Integer[] {1,2,3,4,6,7,8,9}, 0, items, 0, 8);
size = 8;
// items = [1,2,3,4,6,7,8,9,null,null,...]
addItem(5);
addItem(5); // test adding a second item
// items = [1,2,3,4,5,6,7,8,9,null,null,...]
for (Integer i : items) {
System.out.println(i);
}
}
public void addItem(Integer item) {
int position = size;
if (size != 0) {
while (position > 0 && item.compareTo(items[position - 1]) < 0) {
// items[position-1] = items[position]; // Result [1,2,3,4,5,null,null,...]
items[position] = items[position-1]; // Result [1,2,3,4,5,6,7,8,9,null,null,...]
position--;
}
items[position] = item;
size++; // this line was missing as well
} else {
items[size] = item;
size++;
}
// or a single size++; here, removing the other two
}
}
The ugly solution by making new array
public int[] addItem(int item, int[] items){
int[] tempArr = new int[items.length + 1];
boolean hasAlready = false;
for(int i = 0 ; i < items.length; i++){
if(hasAlready)tempArr[i + 1] = items[i];
else if(item < items[i]){
tempArr[i] = item;
tempArr[i + 1] = items[i];
hasAlready = true;
}else {
tempArr[i] = items[i];
}
}
//items = tempArr; if items is global variable
return tempArr;
}
One can use existing utility functions, Arrays.binarySearch, and System.arraycopy. Your loop was 1 off.
public void addItem(Item theItem) {
Comparator<Item> comparator = Comparator.comparing(Item::getItemType)
.thenComparingInt(it -> it.itemnum);
int position = Arrays.binarySearch(items, 0, size, theItem, comparator);
// If position >= 0 the item was found (maybe no need to insert?)
if (position < 0) {
position = ~position; // Insert position of not found item
}
System.arraycopy(items, position, items, position + 1, size - position);
items[position] = theItem;
size++;
}
Binary search results in the non-negative index when found, or the negative ~index when not found. Here binary search is done on a subarray from 0 upto size (excluded).
Same as Roger Gustavsson
public class Main {
private int size = 0;
private Integer[] items = new Integer[20];
public static void main(String... args) {
new Main().execute(); // Moving us into a non-static context
}
public void execute() {
System.arraycopy(new Integer[] {1,2,3,4,6,7,8,9}, 0, items, 0, 8);
size = 8;
// items = [1,2,3,4,6,7,8,9,null,null,...]
addItem(5);
// items = [1,2,3,4,5,6,7,8,9,null,null,...]
for (Integer i : items) {
System.out.println(i);
}
}
public void addItem(Integer item) {
if (size == 0) {
items[size] = item;
size++;
return;
}
int position = size;
while (position > 0 && item.compareTo(items[position - 1]) < 0) {
items[position] = items[position - 1];
position--;
}
items[position] = item;
size++;
}
}
on what you are trying to achieve, i think next solution will be starting point from where you can build your own solution depending your specific needs. i have Changed your main method a little bit, and i do not know if your classes implements comparable /Comparator or not.
public void addItem(Item theItem) {
int position = position(items, theItem); // position is a method that finds best position for inseriton
if (items[position] == null){ // if items at best position is null then add new element there
items[position] = theItem;
} else{
items[size] = theItem; // if not add element at last position
swapUp(size); // and swap them up to perfect position.
}
size++;
}
method that find best position looks like this.
private static int position(Item[] items, Item newItem) {
if (isEmpty(items))
return 0;
int pos=0;
int target=items.length-1;
while(pos < target){
int m = pos+(target-pos)/2;
if (items[m] !=null){
if(newItem.getNumber()>items[m].getNumber()){ // comparing depending on item number
pos=m+1;
}else{
target=m;
}
}else{
target = m;
}
}
return pos;
}
as you can see method is looking for position depending on item number, you can change this with your type, or do both type and number comparison. Swaping up is handled by thus 2 method.
private void swapUp(int lastPosition){
if (lastPosition == -1){
return;
}
Item lastItem = items[lastPosition];
Item p = items[lastPosition-1];
if (lastItem.getNumber() < p.getNumber())
replace(lastPosition, lastPosition-1);
else
lastPosition = 0;
swapUp(lastPosition-1);
}
private void replace(int from, int to){
Item temporary = items[from];
items[from] = items[to];
items[to] = temporary;
}
and again i'm doing comparison of numbers you can implement any kind of comparison you want. i saw your previous question and modeled your classes
Music{number=1111, name='White and Nerdy', price=2.5, pro='"Weird Al" Yankovic'}
Music{number=2222, name='Amish Paradise', price=2.22, pro='"Weird Al" Yankovic'}
Music{number=3333, name='The Saga Begins', price=2.0, pro='"Weird Al" Yankovic'}
Movie{number=4444, name='UHF', price=9.99, pro='"Weird Al" Yankovic'}
Movie{number=5555, name='The Dark Crystal', price=8.99, pro='"Jim Henson'}
Movie{number=6666, name='Die Hard', price=13.99, pro='Bruce Willis'}
Movie{number=6969, name='The Adventures of Mr. Winky', price=9.99, pro='Richard Dickinson'}
Book{number=7777, name='When I Grow Up', price=7.98, pro='"Weird Al" Yankovic'}
Book{number=8888, name='The Chronicles of Pern: First Fall', price=5.99, pro='"Anne McCaffrey'}
Book{number=9999, name='Get gud you scrub', price=2.5, pro='Steve "Troll" Rathier'}
as you can see they are in sorted order.
So, I have created a java class to implement onClickListener and inside this class I have written the onClick public method. Outside of this method, I have created an int object and I want to modify this object inside the onClick method. I have researched a lot by also checking other similar SO questions and I have tried many things, like creating the object as a public int, or making it a private int and have another method to change it and then call this method inside onClick. However, nothing seems to work.
The code shown below has the int object created as a private int and named turn. To change it inside onClick, I have first created a public method named changeTurn that modifies it and then I call this method inside onClick.
public class TicTacToe implements View.OnClickListener {
Button buttons[] = new Button[9];
TextView result;
public TicTacToe(Button[] buttonList, TextView text) {
buttons = buttonList;
result = text;
}
//public void
private int turn = 1; // The object that needs to be modified in onCLick
#Override
public void onClick(View v) {
Button b = (Button) v;
if((((Button) v).getText() != "X") && (((Button) v).getText() != "O")) {
if(this.turn == 1) {
b.setText("X");
changeTurn(); // ***Should change the value of turn***
result.setText("Turn is: " + this.turn);
}
if(this.turn == 2) {
b.setText("O");
changeTurn(); // ***Should change the value of turn***
result.setText("Turn is: " + turn);
}
}
}
public void changeTurn() {
if(this.turn == 1) {
this.turn = 2;
}
if(this.turn == 2) {
this.turn = 1;
}
}
}
From what I've tried, the program goes only inside the first if every time I click any of my 9 buttons, whose setOnClickListeners are connected to this onClick method. Also, the value of turn is always 1 when I print it out, which basically means that its value is not changed by changeTurn inside the onClick method.
General info on the application: I'm trying to make a tic-tac-toe game in a 3x3 grid with 9 buttons. Since there would be 2 players, I'm trying to use this turn integer to keep track of whose turn it is to press a button. If turn is 1, the button's text gets changed to X and if turn is 2, it changes to O. Right now, every time I press a button, it always changes to X.
I would really appreciate any help or ideas.
You're setting the turn to 2 and then immediately setting it back to 1.
// turn == 1
if(this.turn == 1) { // true
this.turn = 2; // turn == 2
}
if(this.turn == 2) { // now true!
this.turn = 1; // turn == 1
}
The easiest thing to do is to only enter the second block if the first is skipped, i.e.:
if(this.turn == 1) {
this.turn = 2;
} else if(this.turn == 2) {
this.turn = 1;
}
Alternatively, if you're expecting to expand the block with more turn numbers, use switch:
switch(this.turn) {
case 1:
this.turn = 2;
break;
case 2:
this.turn = 1;
break;
}
The only trouble with switch is if you forget a break statement you end up with an unpredictable mess.
Finally, a quick bit of advice: if you're trying to create a loop of numbers (1 .. n then back to 1) then you should consider the modulus operator (%) like x = x % n + 1;
try use it like this
final private int[] turn = {0}
Then change code to
if(turn[0] == 1) {
b.setText("X");
turn[0]=2; // ***Should change the value of turn***
result.setText("Turn is: " + turn);
}
if(turn[0] == 2) {
b.setText("O");
turn[0]=1; // ***Should change the value of turn***
result.setText("Turn is: " + turn);
}
I'm creating a program in Java that solves the n-puzzle, without using heuristics, simply just with depth-first and breadth-first searches of the state space. I'm struggling a little bit with my implementation of depth-first search. Sometimes it will solve the given puzzle, but other times it seems to give up early.
Here's my DFS class. DepthFirstSearch() is passed a PuzzleBoard, which is initially generated by shuffling a solved board (to ensure that the board is in a solvable state).
public class DepthFirst {
static HashSet<PuzzleBoard> usedStates = new HashSet<PuzzleBoard>();
public static void DepthFirstSearch(PuzzleBoard currentBoard)
{
// If the current state is the goal, stop.
if (PuzzleSolver.isGoal(currentBoard)) {
System.out.println("Solved!");
System.exit(0);
}
// If we haven't encountered the state before,
// attempt to find a solution from that point.
if (!usedStates.contains(currentBoard)) {
usedStates.add(currentBoard);
PuzzleSolver.print(currentBoard);
if (PuzzleSolver.blankCoordinates(currentBoard)[1] != 0) {
System.out.println("Moving left");
DepthFirstSearch(PuzzleSolver.moveLeft(currentBoard));
}
if (PuzzleSolver.blankCoordinates(currentBoard)[0] != PuzzleSolver.n-1) {
System.out.println("Moving down");
DepthFirstSearch(PuzzleSolver.moveDown(currentBoard));
}
if (PuzzleSolver.blankCoordinates(currentBoard)[1] != PuzzleSolver.n-1) {
System.out.println("Moving right");
DepthFirstSearch(PuzzleSolver.moveRight(currentBoard));
}
if (PuzzleSolver.blankCoordinates(currentBoard)[0] != 0) {
System.out.println("Moving up");
DepthFirstSearch(PuzzleSolver.moveUp(currentBoard));
}
return;
} else {
// Move up a level in the recursive calls
return;
}
}
}
I can assert that my moveUp(), moveLeft(), moveRight(), and moveDown() methods and logic work correctly, so the problem must lie somewhere else.
Here's my PuzzleBoard object class with the hashCode and equals methods:
static class PuzzleBoard {
short[][] state;
/**
* Default constructor for a board of size n
* #param n Size of the board
*/
public PuzzleBoard(short n) {
state = PuzzleSolver.getGoalState(n);
}
public PuzzleBoard(short n, short[][] initialState) {
state = initialState;
}
#Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + Arrays.deepHashCode(state);
return result;
}
#Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
PuzzleBoard other = (PuzzleBoard) obj;
for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++) {
if (state[i][j] != other.state[i][j])
return false;
}
}
return true;
}
}
As previously stated, sometimes the search works properly and finds a path to the solution, but other times it stops before it finds a solution and before it runs out of memory.
Here is a snippet of the output, beginning a few moves before the search stops searching.
...
Moving down
6 1 3
5 8 2
0 7 4
Moving right
6 1 3
5 8 2
7 0 4
Moving left
Moving right
Moving up
6 1 3
5 0 2
7 8 4
Moving left
Moving down
Moving right
Moving up
Moving up
Moving right
Moving down
Moving up
Moving down
Moving up
Moving down
Moving up
Moving down
Moving up
Moving down
...
I truncated it early for brevity, but it ends up just moving up and down dozens of times and never hits the solved state.
Can anyone shed light on what I'm doing wrong?
Edit: Here is MoveUp(). The rest of the move methods are implemented in the same way.
/**
* Move the blank space up
* #return The new state of the board after the move
*/
static PuzzleBoard moveUp(PuzzleBoard currentState) {
short[][] newState = currentState.state;
short col = blankCoordinates(currentState)[0];
short row = blankCoordinates(currentState)[1];
short targetCol = col;
short targetRow = row;
newState[targetCol][targetRow] = currentState.state[col - 1][row];
newState[targetCol - 1][targetRow] = 0;
return new PuzzleBoard(n, newState);
}
I have had many problems with hashset in the past best thing to try is not to store object in hashset but try to encode your object into string.
Here is a way to do it:-
StringBuffer encode(PuzzleBoard b) {
StringBuffer buff = new StringBuffer();
for(int i=0;i<b.n;i++) {
for(int j=0;j<b.n;j++) {
// "," is used as separator
buff.append(","+b.state[i][j]);
}
}
return buff;
}
Make two changes in the code:-
if(!usedStates.contains(encode(currentBoard))) {
usedStates.add(encode(currentBoard));
......
}
Note:- Here no need to write your own hashcode function & also no need to implement equals function as java has done it for you in StringBuffer.
I got one of the problems in your implementation:-
In th following code:-
static PuzzleBoard moveUp(PuzzleBoard currentState) {
short[][] newState = currentState.state;
short col = blankCoordinates(currentState)[0];
short row = blankCoordinates(currentState)[1];
short targetCol = col;
short targetRow = row;
newState[targetCol][targetRow] = currentState.state[col - 1][row];
newState[targetCol - 1][targetRow] = 0;
return new PuzzleBoard(n, newState);
}
Here you are using the reference of same array as newState from currentState.state so when you make changes to newState your currentState.state will also change which will affect DFS when the call returns. To prevent that you should initialize a new array. Heres what to be done:-
static PuzzleBoard moveUp(PuzzleBoard currentState) {
short[][] newState = new short[n][n];
short col = blankCoordinates(currentState)[0];
short row = blankCoordinates(currentState)[1];
short targetCol = col;
short targetRow = row;
for(int i=0;i<n;i++) {
for(int j=0;j<n;j++) {
newState[i][j] = currentState.state[i][j];
}
}
newState[targetCol][targetRow] = currentState.state[col - 1][row];
newState[targetCol - 1][targetRow] = 0;
return new PuzzleBoard(n, newState);
}
Do this change for all moveup,movedown....
Moreover I donot think your hashset is working properly because if it was then you would always find your new state in hashset and your program would stop. As in equals you comparing the state arrays with same reference hence will always get true. Please try and use my encode function as hash.
This is a small library with two books for the sake of the question, it allows the user to type in a random number, and if that number matches up with a book the title of the book is outputted. I've created a class called 'Book' which houses all the titles.
String book1, book2;
class Book {
Book (int _input, String book_1, String book_2) {
book1 = book_1 = "Read This Book";
book2 = book_2 = "How to Read a Book";
I apologize if my code is all one big mess that makes no sense...
}
}
ArrayList <Book> titles = new ArrayList <Book>(50);
public static Boolean binarySearch(String [] A, int left, int right, String V) { //binary search
int middle;
Boolean found = false;
while (found == false && left <= right) {
//If middle item == 0, returns true
middle = (left + right)/2;
int compare = A[middle].compareTo(V);
if (compare == 0) {
found = true;
} else {
if (compare >0) {
right = middle -1;
} else {
left = middle + 1;
}
}
}
if (left > right) {
return false;
} else {
return true;
}
}
Then the problem...I'm not sure how to use the binary search to actually output any information after pressing the "find" button, any ideas on what I should below to make this work?
private void findButtonActionPerformed(java.awt.event.ActionEvent evt) {
//Take inputted values which will match with book title
int input = Integer.parseInt(enterNumberField.getText());
//Store values in array
Book c = new Book (input, book1, book2);
titles.add(c);
String temp;
//calls out information in array
for (int j=0; j<=input; j++) {
for (int x=0; x<=input; x++) {
temp = titles.get(x) + "\n";
}
binarySearchField.setText("" + j); //should output book title
}
You want your binary search to return not just a true or false. You want it to return Book, the item it found, or null if it found no book matching this query. To be consistent you probably want to change the name from binarySearch, to getBook, or some other better suited name. In your case you don't want to know if an element is there, you want to get the element for use later (printing).
This is how collections are expected to behave when you query them. Just check out the get methods from any of the Java collections and you will see they do the same, returning the item if it's there, or null.
Here is some example code. This is just example code! So modify as you like, and also be careful about bugs, I used your search which I'm going to assume is correct to start with. Also know that there are better many good ways of storing a key to a value, Map for example, that I'm not going to use here.
public class Book{
public String title;
public int sameTitle(String bookTitle) {
return this.title.compareTo(bookTitle);
}
}
public static Book getBook(Book [] A, int left, int right, String bookTitle) { //binary search
int middle;
while (left <= right) {
//If middle item == 0, returns true
middle = (left + right)/2;
int compare = A[middle].sameTitle(bookTitle);
if (compare == 0) {
return A[middle];
} else {
if (compare >0) {
right = middle -1;
} else {
left = middle + 1;
}
}
}
return null;
}
// example use of getting and using the book
Book b = getBook(...);
if (b != null){
System.out.println("Success! you found the book " + b);
}
Try to change this line:
int compare = A[middle].compareTo(V);
if (compare == 0) {
found = true;
To:
int compare = A[middle].compareTo(V);
if (compare == 0) {
return A[middle];
And be sure to get the result in your findButtonActionPerformed method.
Also, it appears to be a mistake in your code... Should not A be a book array instead of a string array?
For a school project i have a list of 50k containers that arrive on a boat.
These containers need to be sorted in a list in such a way that the earliest departure DateTimes are at the top and the containers above those above them.
This list then gets used for a crane that picks them up in order.
I started out with 2 Collection.sort() methods:
1st one to get them in the right X>Y>Z order
Collections.sort(containers, new Comparator<ContainerData>()
{
#Override
public int compare(ContainerData contData1, ContainerData contData2)
{
return positionSort(contData1.getLocation(),contData2.getLocation());
}
});
Then another one to reorder the dates while keeping the position in mind:
Collections.sort(containers, new Comparator<ContainerData>()
{
#Override
public int compare(ContainerData contData1, ContainerData contData2)
{
int c = contData1.getLeaveDateTimeFrom().compareTo(contData2.getLeaveDateTimeFrom());
int p = positionSort2(contData1.getLocation(), contData2.getLocation());
if(p != 0)
c = p;
return c;
}
});
But i never got this method to work..
What i got working now is rather quick and dirty and takes a long time to process (50seconds for all 50k):
First a sort on DateTime:
Collections.sort(containers, new Comparator<ContainerData>()
{
#Override
public int compare(ContainerData contData1, ContainerData contData2)
{
return contData1.getLeaveDateTimeFrom().compareTo(contData2.getLeaveDateTimeFrom());
}
});
Then a correction function that bumps top containers up:
containers = stackCorrection(containers);
private static List<ContainerData> stackCorrection(List<ContainerData> sortedContainerList)
{
for(int i = 0; i < sortedContainerList.size(); i++)
{
ContainerData current = sortedContainerList.get(i);
// 5 = Max Stack (0 index)
if(current.getLocation().getZ() < 5)
{ //Loop through possible containers above current
for(int j = 5; j > current.getLocation().getZ(); --j)
{ //Search for container above
for(int k = i + 1; k < sortedContainerList.size(); ++k)
if(sortedContainerList.get(k).getLocation().getX() == current.getLocation().getX())
{
if(sortedContainerList.get(k).getLocation().getY() == current.getLocation().getY())
{
if(sortedContainerList.get(k).getLocation().getZ() == j)
{ //Found -> move container above current
sortedContainerList.add(i, sortedContainerList.remove(k));
k = sortedContainerList.size();
i++;
}
}
}
}
}
}
return sortedContainerList;
}
I would like to implement this in a better/faster way. So any hints are appreciated. :)
I think you probably want to sort with a single Comparator that compares on all of the criteria. E.g.:
compareTo(other)
positionComparison = this.position.compareTo(other.position)
if positionComparison != 0
return positionComparison
return this.departureTime.compareTo(other.departureTime)