How to shift elements in a 2D array of Strings - java

So I am working on an 8puzzle slide game and I am having some trouble. So lets say that my current state S is:
1 5 6
3 7 B
2 8 4
where B represents the blank space (which is why I am doing my 2D array in String type). So I am trying to call move methods which will ultimately move the B space either up,down,left,or right. I have already recorded the position of B, so in this case it would be [1,2]. I use this B location to see if I can make a valid move up (can't make it if B[0] = 0), valid move down (can't make it if B[0] = 2), valid move left (can't make it if B[1] = 0) or valid move right (can't make it if B[1] = 2). So now if I do have a valid move for lets say up, how would I go about implementing that move function? I don't know how exactly to replace the location of B in my S state with the one above it if everything is in String type.
public class EightPuzzle {
String[][] gameBoard = new String[3][3];
String[] bLocation = new String[2];
String board;
String dir;
/*public void ReadFromTxt(String file) throws FileNotFoundException, IOException {
String read;
FileReader f = new FileReader(file);
int i = 0;
int j;
BufferedReader b = new BufferedReader(f);
System.out.println("Loading puzzle from file...");
while((read = b.readLine())!=null){
if(read.length()==3){
for(j=0;j<3;j++){
board[i][j] = (int)(read.charAt(j)-48);
}
}
i++;
}
b.close();
System.out.println("Puzzle loaded!");
}*/
public String[][] setState(String board){
gameBoard[0][0] = board.substring(0,1);
gameBoard[0][1] = board.substring(1,2);
gameBoard[0][2] = board.substring(2,3);
gameBoard[1][0] = board.substring(4,5);
gameBoard[1][1] = board.substring(5,6);
gameBoard[1][2] = board.substring(6,7);
gameBoard[2][0] = board.substring(8,9);
gameBoard[2][1] = board.substring(9,10);
gameBoard[2][2] = board.substring(10,11);
System.out.println(Arrays.deepToString(gameBoard));
return gameBoard;
}
public String[][] randomizeState(){
return null;
}
public void move(String dir){
if(dir.equalsIgnoreCase("up")){
if(bLocation[0].equals("0")){
//cannot move up
}
else{
int[] temp;
}
}
if(dir.equalsIgnoreCase("down")){
if(bLocation[0].equals("2")){
//cannot move down
}
else{
}
}
if(dir.equalsIgnoreCase("left")){
if(bLocation[1].equals("0")){
//cannot move left
}
else{
}
}
if(dir.equalsIgnoreCase("right")){
if(bLocation[1].equals("2")){
//cannot move right
}
else{
}
}
}
public void bLocation(String board){
setState(board);
for(int i=0; i<gameBoard.length; i++){
for(int j=0; j<gameBoard[i].length; j++){
if(gameBoard[i][j].equals("b"))
{
bLocation[0] = Integer.toString(i);
bLocation[1] = Integer.toString(j);
}
}
}
}
public static void main (String[]args){
EightPuzzle b1=new EightPuzzle();
b1.setState("156 37b 284");
b1.bLocation("156 37b 284");
}
}

A shift upwards would mean swapping B with the the tile above it.
For code simplicity, make a method moveB which swaps two locations:
private void moveB(int deltaRow, int deltaCol) {
int newRow = bLocation[0] + deltaRow;
int newCol = bLocation[1] + deltaCol;
String temp = gameboard[newRow][newCol];
gameBoard[newRow][newCol] = gameBoard[bLocation[0]][bLocation[1]];
gameBoard[bLocation[0]][bLocation[1]] = temp;
bLocation[0] = newRow;
bLocation[1] = newCol;
}
To shift upwards: moveB(-1, 0);
To shift downwards: moveB(1, 0);
To shift left: moveB(0, -1);
To shift right: moveB(0, 1);

Related

Cannot find ArrayList object

The NumberTile class models a number tile which is an arrayList of 4 integers, the TileGame class inserts a tile into the board, and a test class to start the game. A hand is an arraylist of 5 NumberTiles, but when I compile this, every time I reference to an ArrayList of NumberTile in TileGame, it cannot find the symbol NumberTile.
Do I need to create a package so it would recognize it? My instructor provided most of those statements and I cannot change them. I did not type the other methods because I do not think they are necessary.
Also, the line TileGame game = new TileGame(); says cannot find symbol. What would be the right way to initialize it?
I need any help I can get. Thank you.
Class TileGame:
public class TileGame
{
//provided by instructor
private ArrayList<NumberTile> board ;
// Creates an empty board
public TileGame()
{
//do not modify this method
board = new ArrayList<NumberTile>();
}
// Accessor for the board
public ArrayList<NumberTile> getBoard()
{
// Do not modify this method
return board ;
}
// Creates and returns a hand of 5 random number tiles
public ArrayList<NumberTile> getHand()
{
ArrayList<NumberTile> hand = new ArrayList<NumberTile>() ;
for (int a = 0; a < 5; a++)
{
hand.add(a, new NumberTile());
}
return hand;
}
// If the current tile fits in the board (without rotating) then
// return the index i of a tile in the board so that the current tile
// fits before ti for i = 0..k-1, or return k if the current tile fits
// after the last tile. If the tile does not fit, return -1
public int getIndexForFit(NumberTile currentTile)
{
NumberTile firstTile = board.get(0);
NumberTile lastTile = board.get(board.size() - 1);
if(firstTile.getLeft() == currentTile.getRight())
{
return 0;
}
else if (lastTile.getRight() == currentTile.getLeft())
{
return board.size() - 1;
}
else
{
return -1 ;
}
}
// Call the method getIndexForFit to see whether a tile can be inserted
// into the board. In this method the tile can be rotated. If the tile
// can be inserted, return true. If the tile does not fit after
// rotating (at most 3 times), return false.
public boolean canInsertTile(NumberTile currentTile)
{
//call get index for fit
int canInsert = getIndexForFit(currentTile);
boolean canInsertOrNot = false;;
//if true, modify index
if(canInsert == -1)
{
//rotate
for (int rotations = 0; rotations < 3; rotations++)
{
currentTile.rotate();
int didRotationWork = getIndexForFit(currentTile);
if (didRotationWork == -1)
{
continue;
}
else if (didRotationWork != -1)
{
canInsertOrNot = true;
}
}
return false;
}
else if(canInsert != -1)
{
return true;
}
return canInsertOrNot;
}
// Make a move. I.e. if a tile in the hand fits on the board
// then remove it from the hand and place it in the board. If no tile
// from the hand fits, then add another tile to the hand
public void makeMove(ArrayList<NumberTile> hand)
{
boolean fits;
for (int x = 0; x < hand.size(); x++)
{
//call caninterserttile
fits = canInsertTile(hand.get(x));
if(fits)
{
int index = getIndexForFit(hand.get(x));
board.add(index, hand.get(x));
hand.remove(x);
break;
}
else
{
hand.add(hand.size() -1, new NumberTile());
}
}
}
public String toString()
{
// Do not modify this method
return board.toString() ; // ArrayList as a String
}
} // end of TileGame class
Class NumberTile:
public class NumberTile
{
public ArrayList<Integer> tile = new ArrayList<>();
// Constructs a NumberTile object using 4 random integers in the
// range 1 to 9
public NumberTile()
{
Random generator = new Random() ;
for (int a = 0; a < 4; a++)
{
int random = generator.nextInt(9);
tile.add(a, random);
}
}
// Rotate the tile 90 degrees
public void rotate()
{
int temp = tile.get(0);
tile.set(0, tile.get(1));
tile.set(1, tile.get(3));
tile.set(3, tile.get(2));
tile.set(2, temp);
}
public int getLeft()
{
// Do not modify this method
return tile.get(0) ;
}
public int getRight()
{
// Do not modify this method
return tile.get(2) ;
}
public String toString()
{
String out = "";
out += " "+tile.get(0)+" ";
out += tile.get(1) + " " + tile.get(2);
out += " "+tile.get(3)+" ";
return out;
}
} // end of NumberTile class
Class TileGameTester:
public class TileGameTester {
public static void main(String[] args){
TileGame game = new TileGame();
boolean winner = false;
//get two hands
ArrayList<NumberTile> hand1 = game.getHand();
ArrayList<NumberTile> hand2 = game.getHand();
//create an empty board
System.out.println(game.getBoard());
do{
//make moves
game.makeMove(hand1);
game.makeMove(hand2);
//check if they won
if (hand1.isEmpty() || hand2.isEmpty())
{
winner = true;
}
}while(!winner);
hand1.toString();
hand2.toString();
if (hand1.isEmpty() && hand2.isEmpty())
{
System.out.println("It is a tie!");
}
else if (hand1.isEmpty())
{
System.out.println("Player 1 won!");
}
else if (hand2.isEmpty())
System.out.println("Player 2 won!");
}
}
Though it is incomplete so i am not sure if you are adding data to the arraylist or not but if you are getting Symbol not found .
I am also not able to see any import statements . Did you import the objects
eg TileGameTester should have import -> import com.something.TileGame and import com.something.NumberTile
also check if you have import statement in TileGame and common imports like arraylist
I think you may need to insert "import java.util.Random;" and "import java.util.ArrayList;" between your package declaration (if you have one) and the class declaration in the files where these are used.
You can import TileGame class to TileGameTester class that might solve your issue.

Java objects and 2D arrays

I am working on my A-Level computing project, and I have a 2D array, with in the x direction name, password, state (just a variable). I want to sort the 2D array using a bubble sort so that I can implement a binary search on the data. Here is the code I have come up with:
public String[][] sort(String[][] details, int len){
boolean flag = false;
String[] temp = new String[3];
int z=0;
do{
flag = false;
for (int i = 0; i < len; i++){
if(details[0][i].charAt(0) > details[0][i + 1].charAt(0)){
flag = true;
temp[0] = details[0][i];
temp[1] = details[1][i];
temp[2] = details[2][i];
details[0][i] = details[0][i + 1];
details[1][i] = details[1][i + 1];
details[2][i] = details[2][i + 1];
details[0][i + 1] = temp[0];
details[1][i + 1] = temp[1];
details[2][i + 1] = temp[2];
}
}
len--;
} while (flag);
return details;
}
However it has sort of come to my attention I could do this much easier using object orientation which is something I would love to try and have a go at. Does anyone know where I could start learning about object orientation in this sort of context, the guides I have searched for online, just talk about shapes etc... and I am really not sure how to implement those guides into this situation.
From my understanding, what I could do is set up an object with three variables, name, password and state; and when I called upon a name, I could also get the details for the password and state. Am I along the right lines here? and if so can anyone show me how I can do this please.
Thanks a lot.
Sam
edit -
Thanks for all the help guys, thanks to this, I have worked out how to implement this in my project, and it is amazing how much easier it makes the code! Thanks a lot!
For anyone else struggling with this problem, this is my final code:
public class loginDetailsOO {
public static void main (String[] args){
loginDetailsOO object = new loginDetailsOO();
object.run();
}
public void run(){
String password = encrypt("password");
String location = "textFiles\\PasswordScreen.txt";
int lines = numberOfLines(location);
User[] user = fileToArray(location, lines);
int index = searchForUsername(user, lines / 4, "VELINGUARD");
if (password.equals(user[index].getPassword())){
System.out.println("entrance is granted");
}
User u = new User("ball", "pass", 0);
addToFile(u, "VELINGUARD");
}
public void addToFile(User newUser, String currentUsername){
String location = "textFiles\\PasswordScreen.txt";
newUser.setUsername(newUser.getUsername().toUpperCase());
int lines = numberOfLines(location);
User[] user = fileToArray(location, lines);
int line = lines / 4;
int index = searchForUsername(user, line, currentUsername);
if (user[index].getState() == 1){
if (searchForUsername(user,line, newUser.getUsername()) == -1) {
newUser.setPassword(encrypt(newUser.getPassword()));
user[line] = newUser;
user = sort(user, line);
writeToFile(location, user, line);
} else {
System.out.println("User already exists");
}
} else {
System.out.println("Permission not granted");
}
}
public User[] sort(User[] user, int len){
boolean flag = false;
User temp;
int z=0;
do{
flag = false;
for (int i = 0; i < len; i++){
if(user[i].getUsername().compareTo(user[i + 1].getUsername()) > 0){
flag = true;
temp = user[i];
user[i] = user[i + 1];
user[i + 1] = temp;
}
}
len--;
} while (flag);
return user;
}
public String encrypt (String password){
String encrypted = "";
char temp;
int ASCII;
for (int i = 0; i < password.length(); i++){
temp = password.charAt(i);
ASCII = (int) temp;
if (ASCII >= 32 && ASCII <= 127)
{
int x = ASCII - 32;
x = (x + 6) % 96;
if (x < 0)
x += 96; //java modulo can lead to negative values!
encrypted += (char) (x + 32);
}
}
return encrypted;
}
public String decrypt (String password){
String decrypted = "";
char temp;
int ASCII;
for (int i = 0; i < password.length(); i++){
temp = password.charAt(i);
ASCII =(int) temp;
if (ASCII >= 32 && ASCII <= 127)
{
int x = ASCII - 32;
x = (x - 6) % 96;
if (x < 0)
x += 96;
decrypted += (char) (x + 32);
}
}
return decrypted;
}
public User[] fileToArray(String file, int lines) {
try {
BufferedReader reader = new BufferedReader(new InputStreamReader(getClass().getResourceAsStream(file)));
int line = lines / 4;
String temp[] = new String[3];
User[] user = new User[line];
for (int i = 0; i < line; i++){
temp[0] = reader.readLine();
temp[1] = reader.readLine();
temp[2] = reader.readLine();
reader.readLine();
user[i] = new User(temp[0], temp[1], Integer.parseInt(temp[2]));
}
return user;
} catch(Exception e){
System.out.println("File not found");
return null;
}
}
public void writeToFile(String location, User[] user, int length){
try {
File f = new File(getClass().getResource(location).toURI());
f.setWritable(true);
FileWriter w = new FileWriter(f);
BufferedWriter writer = new BufferedWriter(w);
wipeFile(f);
for (int i = 0; i <= length; i++){
writer.write(user[i].getUsername());
writer.newLine();
writer.write(user[i].getPassword());
writer.newLine();
writer.write(user[i].getState());
writer.newLine();
writer.write("-");
writer.newLine();
}
writer.close();
f.setReadOnly();
} catch(Exception e){System.out.println("error writing to file");}
}
public void wipeFile(File f) {
try {
PrintWriter wiper = new PrintWriter(f);
wiper.println("");
} catch (Exception ex) {
System.out.println("error wiping file");
}
}
public int searchForUsername(User[] user, int lines, String name){ //implements binary search
int low = 0;
int high = lines - 1;
int mid;
while (low <= high){ //by using a while loop it means if it is an empty file than there will be no issue
mid = low + high;
mid = mid / 2;
if ((int) name.charAt(0) > (int) user[mid].getUsername().charAt(0)){
low = mid + 1;
} else if ((int) name.charAt(0) < (int) user[mid].getUsername().charAt(0)) {
high = mid - 1;
} else {
if (user[mid].getUsername().equals(name)){
return mid;
}
else {
int pass = 0;
do{
if (user[mid - pass].getUsername().equals(name)){
return mid - pass;
} else if (user[mid + pass].getUsername().equals(name)) {
return mid + pass;
}
} while (true);
}
}
}
System.out.println("Name not found");
return -1;
}
public int numberOfLines(String file) {
try{
LineNumberReader lnr = new LineNumberReader(new InputStreamReader(getClass().getResourceAsStream(file)));
lnr.skip(Long.MAX_VALUE);
int length = (lnr.getLineNumber() + 1); //Add 1 because line index starts at 0
lnr.close();
return length;
}catch(Exception e){
System.out.println("File not Found");
return 0;
}
}
and:
public class User{
private String username;
private String password;
private int state;
public User(){
username = "";
password = "";
state = 0;
}
public User(String user, String pass, int st){
username = user;
password = pass;
state = st;
}
public void setUsername(String name){
username = name;
}
public void setPassword(String pass){
password = pass;
}
public void setState(int st){
state = st;
}
public String getUsername(){
return username;
}
public String getPassword(){
return password;
}
public int getState(){
return state;
}
Bubble sort is meant to be used in only one context in Computer Science, as an example of how simple approaches can sometimes be the worst approach. If you don't remember anything else about sorting, remember that you should never use bubble sort (quicksort is almost always a safer bet).
In order to do this with object orientation, you need objects. These are the code equivalent of which "nouns" are going to be describing the problem. This might mean you would need (minimally) a:
List
Entry
Comparison (Thing)
The problem is that the ordering of something is an action (a verb) and not typically a noun. However, we can make it a noun (thank you English for having "gerunds"). This adds:
Sorter (an interface)
BubbleSorter (ick, yuck, boo!)
QuickSorter
HeapSorter
The main problems come into play when one realizes that without information hiding you don't have much in the way of Object-Orientation. To do this many of the items would require their data being private, and it is something of a try a few times to find the right balance between the "data structure" approach of all exposed data and the OO approach of all private data.
A very pure OO-approach might look like:
class Book extends Entry {
public String getTitle() {
...
}
}
List<Book> books = new List<Book>();
books.add(new Book(...));
books.add(new Book(...));
books.add(new Book(...));
Sorter sorter = new QuickSorter();
Comparison<Book> byTitle = new Comparison<Book>() {
public int compare(Book one, Book two) {
return String.compare(one.getTitle(), two.getTitle());
}
}
sorter.sort(books, byTitle);
Of course, there are different things that people value, and so they might come up with valid, but entirely different OO structures.
Finally, there is already a very good OO-ish set of data structure in java.util, and while it may be fun to create a new one, one should use the java.util.List and friends because they already implement the fastest sorting algorithms (in Collections.sort) and most other libraries expect a java.util.List and not a my.custom.List.
Have fun, and happy hacking!
Make a Detail class that stores the details you are currently storing in an array. Something like:
public class Detail {
public String name;
public String password;
public String state;
}
Then modify your existing code to work with Detail objects instead of arrays of arrays.
public Detail[] sort(Detail[] details){
boolean flag = false;
do{
flag = false;
for (int i = 0; i < details.length; i++){
if(details[i].name.compareTo(details[i + 1].name) > 0){
flag = true;
Detail temp = details[i];
details[i] = details[i + 1];
details[i + 1] = temp;
}
}
len--;
} while (flag);
return details;
}
Note that it would be even better to just use a library function to sort the array, but if you want to do it this way to learn about bubble sort, that's fine.
You will probably need to modify the other parts of your code to use Detail objects as well.

How to load/create a level/room from a text file in java?

Basically each room has a size of 10 by 10, the "W" represents the Walls, and the blank spaces -" " represent the Floor, and the numbers are Doors.I figured the best way to create the room is to create a method that receives a file and reads it and put its "information" into a String[10][10], and then create another method(or just do it in my Main) that receives the String[10][10] created and creates the room(adds the images to the room), but i am having some difficulties reading the file so if you guys could help me with that part i would be thankful.
Here is the type of text files from which i want to create my room:
WWWW0WWWWW
W W
W W
W W
W W
W WW
W WW
W WW
W W1
WWWWWWWWWW
Here are the Door, Wall and Floor classes:
public class Door implements ImageTile {
private Position position;
public Door(Position position) {
this.position = position;
}
#Override
public String getName() {
return "Door";
}
#Override
public Position getPosition() {
return position;
}
}
public class Floor implements ImageTile {
private Position position;
public Floor(Position position) {
this.position = position;
}
#Override
public String getName() {
return "Floor";
}
#Override
public Position getPosition() {
return position;
}
}
public class Wall implements ImageTile {
private Position position;
public Wall(Position position) {
this.position = position;
}
#Override
public String getName() {
return "Wall";
}
#Override
public Position getPosition() {
return position;
}
}
And this is my method for adding images to my frame:
public void newImages(final List<ImageTile> newImages) {
if (newImages == null)
return;
if (newImages.size() == 0)
return;
for (ImageTile i : newImages) {
if (!imageDB.containsKey(i.getName())) {
throw new IllegalArgumentException("No such image in DB " + i.getName());
}
}
images.addAll(newImages);
frame.repaint();
}
If you guys could help me i would appreciate it very much, thanks guys.Her is what i have now:
public class Room {
private String[][]room;
public Room(){
room = new String[10][10]; }
public static Room fromFile(File file){
if(file.exists()){
Scanner sc = null;
Room room = new Room();
try {
sc = new Scanner(file);
while(sc.hasNextLine()){
if(sc.nextLine().startsWith("#"))
sc.nextLine();
else{
String[] s0 = sc.nextLine().split("");
//Here is where my trouble is, i dont know how to add the content of this String s0 to the String s
if(s0.length==10){
for(int x = 0; x < 10; x++){
for(int y = 0; y < 10; y++){
String[x][y] s= String[x] s0;
}
}
} catch (FileNotFoundException e) {
System.out.println("Ficheiro "+file.getAbsolutePath()+
" não existe. "); }
finally{
if(sc!=null)sc.close();
}
}
else
System.out.println("Ficheiro "+file.getAbsolutePath()+
" não existe. ");
return null;
}
Each call to sc.nextLine() is reading another line from your file. You need to save the line into a temporary variable, and then refer to that temporary.
Maintain a counter of lines you've processed, so you can fill in the appropriate line in your s[][] matrix.
You only need to allocate storage for the 10 rows, since splitting the line you read in will result in an array of strings (the columns in one row) being allocated for you.
int row = 0;
String[][] s = new String[10][];
while(sc.hasNextLine() && i < 10) {
String line = sc.nextLine();
if( !line.startsWith("#")) {
String[] s0 = sc.line.split("");
s[row] = s0;
row++;
}
}
BTW, Use String[][] is overkill; since each string will only hold one character. Perhaps you could consider using char[][]. And line.toCharArray() would split the line into a char[] for you.
EDIT: (Due to edit of your question's code)
Instead of:
if(s0.length==10){
for(int x = 0; x < 10; x++){
for(int y = 0; y < 10; y++){
String[x][y] s= String[x] s0;
}
}
}
you want:
if(s0.length==10){
for(int y = 0; y < 10; y++){
s[row][y] = s0[y];
}
row++;
}
With row being the row counter in my above code.

ArrayList replacing everything before when new element is added?

I'm attempting to add elements into an arraylist (also append an arraylist to the other), however it seems to rewrite everything else already present in that arraylist too - so I'm left with an arraylist filled with the last element added.
Here's the method concerned:
private static ArrayList<Move> checkX(int r, int c) {
ArrayList<Move> moves = new ArrayList<Move>();
if (jumps()) { // if jumps are found && this piece can jump
for (int i = 0; i <= 1; i+=2) {
if (Character.isLowerCase(board[r-1][c+i]) && board[r-2][c+2*i] == ' ') {
}
}
} else { // if no jumps are found then move normally
for (int i = -1; i <= 1; i+=2) {
try {
if (board[r-1][c+i] == ' ') {
Move tempMove = new Move(r, c);
tempMove.addDestination((r-1), (c+i));
moves.add(tempMove);
}
} catch (Exception e) {}
}
}
for (int i = 0; i < moves.size(); i++) {
System.out.println(moves.get(i).toString());
}
return moves;
}
Move class:
public class Move {
private static ArrayList<int[]> destinations;
// private static char[][] tmpboard;
public Move(int r, int c) {
destinations = new ArrayList<int[]>();
int[] initSquare = {r, c};
destinations.add(initSquare);
}
public void addDestination(int r, int c) {
int[] destinationSquare = {r, c};
destinations.add(destinationSquare);
}
public ArrayList<int[]> getMove() {
return destinations;
}
public String toString() {
String returnStr = "";
for (int i = 0; i < destinations.size(); i++) {
returnStr += Arrays.toString(destinations.get(i));
}
return returnStr;
}
}
Every time I attempt to print out everything stored in an instance of 'moves' it seems to only print out the last element added to the list n times.
private static ArrayList<int[]> destinations;
Here's your issue. Try removing the static modifier.
What static here means that the latest additions of destinations will affect all Move instances, which makes them identical.
It's possible you were thinking of final there instead, which would make more sense.

Why isn't the bubbleDown method working as intended (Heap Sort)?

This was an assignment that was due, and I attempted it in both C++ and Java, but in both versions, the bubbleDown method wasn't working as intended, though I believe the logic says it should. I've already handed in both versions, but since the Java version is the most recent, I'll post it here.
Here's the Java version:
import java.io.*;
import java.util.Scanner;
public class HeapSort {
static int[] heap;
Integer[] sorted;
String in, out;
int fullLength = 0;
public HeapSort(String inf, String outf) throws FileNotFoundException {
in = inf;
out = outf;
Scanner scan = new Scanner(new File(in));
while (scan.hasNextInt()) {
fullLength++;
scan.nextInt();
}
sorted = new Integer[fullLength];
heap = new int[fullLength+1];
heap[0] = 0;
scan.close();
}
public boolean isFull() {
return heap[0] == fullLength;
}
public boolean isEmpty() {
return heap[0] == 0;
}
public void buildHeap() throws IOException {
Scanner scan = new Scanner(new File(in));
while (scan.hasNextInt())
insertOneDataItem(scan.nextInt());
scan.close();
}
public void deleteHeap() throws IOException {
while (!isEmpty()) {
deleteRoot();
printHeap();
}
}
public void deleteRoot() throws IOException {
if (isEmpty())
return;
FileWriter f = new FileWriter(out, true);
f.write("Deleting " + heap[1] + "\n");
f.close();
int i;
for(i = 0; sorted[i] != null; i++);
sorted[i] = heap[1];
heap[1] = heap[heap[0]--];
bubbleDown();
}
public void insertOneDataItem(int num) throws IOException {
if (isFull()) {
p("Heap is full");
return;
}
heap[++heap[0]] = num;
bubbleUp();
printHeap();
}
public void printHeap() throws IOException {
FileWriter f = new FileWriter(out, true);
f.write("Current Heap:\t");
for (int i = 1; i <= heap[0]; i++) {
if (i > 10) break;
f.write(heap[i] + " ");
}
f.write("\n");
f.close();
}
public void printSorted() throws IOException {
FileWriter f = new FileWriter(out, true);
f.write("Current Sorted:\t");
for (int i = 1; i <= sorted.length; i++) {
if (i > 10) break;
f.write(sorted[i] + " ");
}
f.write("\n");
f.close();
}
public void bubbleUp() {
int h = heap[0];
while (h >= 2 && heap[h] < heap[h/2]) {
int x = heap[h];
heap[h] = heap[h/2];
heap[h/2] = x;
h = h/2;
}
}
public void bubbleDown() {
int k = 1;
// make sure we have at least a left child
// before continuing on
while (2*k <= heap.length) {
int left = 2*k;
int right = 2*k+1;
if (heap[k] >= heap[left]) {
int x = heap[k];
heap[k] = heap[left];
heap[left] = x;
k = left;
continue;
}
if (right <= heap.length &&
heap[k] >= heap[right]) {
int x = heap[k];
heap[k] = heap[right];
heap[right] = x;
k = right;
} else {
return;
}
}
}
public void begin() throws IOException {
buildHeap();
deleteHeap();
printSorted();
}
public static void main(String[] args) throws IOException {
if (args.length < 2) {
p("Please start with: program file1.txt file2.txt");
System.exit(1);
}
// empty the output file
(new FileOutputStream(args[1])).close();
(new HeapSort(args[0], args[1])).begin();
}
public static void p(String s) {
System.out.println(s);
}
}
The input file (args[0]) with have only integers in the file, with some on the same row, and on different lines. args[1] is the output file name.
When the program goes through bubbleDown, it starts to work as intended in the beginning, but then it skips some numbers, and towards the end I'll eventually see a number that should have been at the top. Can someone explain to me what I did wrong in this function?
Your code looks suspicious for a number of reasons. 1 -- you are mixing the actual data structure implementation with reading a file which makes no sense. Very hard to follow. Then this piece can't be right:
sorted[i] = heap[1];
heap[1] = heap[heap[0]--];
First line suggests that heap array contains actual data elements.
But second line is treating heap contents as indexes of some sort? heap[0]-- will decrement the value stored at location 0 of the heap array, but first it will use it to move the contents of heap[heap[0]] to heap[1]? What? Are you using heap[0] as a special thing to store the index of the last element in the array? I suggest you start by rewriting code w/o hacks like this, it should make it easier to understand and fix. In reality your heap should start at element 0 and your left node will be at 2k+1 and right will be at 2k+2.
Now this smells like it is wrong:
right <= heap.length
you should be comparing right to that terrible heap[0], because heap.length will not be shrinking when you remove things from it.
for (int i = 1; i <= sorted.length; i++) {
should be
for (int i = 0; i < sorted.length; i++) {
and the final main mistake is in the bubbleDown method. When bubbling down you need to be swapping the downward shifting node with the smaller of its children. So that is 7 is bubbling down and its left child is 6 and right child is 4, you need to swap 7 and 4, otherwise you get invalid tree of
6
/ \
7 4
So code should be
if (heap[k] >= heap[left] && heap[left] < heap[right]) {
You are welcome. And your professor owes me lunch for doing his job for him.

Categories

Resources