import java.io.*;
import java.util.*;
class StepfordHouses {
private ArrayList<Integer> houses; // A list containing houses
private TreeSet<Integer> ordered; // An ordered treeset of houses
private TreeSet<Integer> processed; // Elements already processed
private String inpline[]; // An array of String holing houses heights in physical order
private int disorientedindex; // The index for the Street
private int size; // Number of houses in the Street
public StepfordHouses() // Constructor for init
{
houses = new ArrayList<Integer>();
ordered = new TreeSet<Integer>();
processed = new TreeSet<Integer>();
// Basic Input from Text-File (Codechef Requirment)
try {
BufferedReader br = new BufferedReader(new InputStreamReader(
System.in));
size = Integer.parseInt(br.readLine());
inpline = br.readLine().split(" ");
} catch (IOException e) {
System.out.println("BAAAAAAAAAM!!");
}
for (int c = 0; c < size; c++) // Populating Houses
{
Integer tmp = Integer.parseInt(inpline[c]);
houses.add(tmp);
ordered.add(tmp);
}
}
public int calcIndex()
{
int c = 0;
while (c < size) {
Iterator<Integer> it = ordered.iterator();
Integer h1 = houses.get(c); // Get an element from the raw ArrayList of Houses
Integer h = it.next(); // Get an element from the Iterator
while (h1.equals(h) != true) {
if (processed.contains(h1) == false) { // The element is not already processed
System.out.println(h1 + " " + h);
disorientedindex++;
}
h = it.next(); // Get an element from the Iterator
}
processed.add(h1);
c++;
it = null;
}
return disorientedindex;
}
}
public class Work {
public static void main(String args[]) {
StepfordHouses sh = new StepfordHouses();
System.out.println(sh.calcIndex());
}
}
The contains() method doesn't work the way I expect it to, i.e compare Integers!
The output is 15 , which should be 9 when
if(processed.contains(h1)==false) works correctly and returns true when an element is already present!
Where could the code be wrong?
The logic is flawed. processed.add(h1); is called N times but processed.contains(h1) is called N*N times. So depending on the input you can have disorientedindex <> N.
Related
I recently completed an assignment that asked us to sort names out of a text file alphabetically, I used three different classes to get it to work properly.
class Person {
String firstName;
String lastName;
}
I then created this to sort in to alphabetical order by last name and then by first name
class SortNames {
void sortNames(Person[] arr, int type) {
if (type == 1) {
int j;
boolean flag = true; // will determine when the sort is finished
Person temp;
while (flag) {
flag = false;
for (j = 0; j < arr.length - 1; j++) {
if (arr[j].lastName.compareToIgnoreCase(arr[j + 1].lastName) > 0) { // ascending
// sort
temp = arr[j];
arr[j] = arr[j + 1]; // swapping
arr[j + 1] = temp;
flag = true;
}
}
}
for (int k = 0; k < arr.length; k++)
System.out.println(arr[k].firstName +" "+arr[k].lastName);
} else if (type == 2) {
int j;
boolean flag = true; // will determine when the sort is finished
Person temp;
while (flag) {
flag = false;
for (j = 0; j < arr.length - 1; j++) {
if (arr[j].firstName.compareToIgnoreCase(arr[j + 1].firstName) > 0) { // ascending
// sort
temp = arr[j];
arr[j] = arr[j + 1]; // swapping
arr[j + 1] = temp;
flag = true;
}
}
}
for (int k = 0; k < arr.length; k++)
System.out.println(arr[k].firstName +" "+arr[k].lastName);
}
}
}
Then I used a simple program to print all of the names, first in the order that they were given, then in order by last name and then in order by first name.
import java.io.*;
import java.util.*;
public class SortNameApp {
public static void main(String[] args) throws IOException {
Scanner scanner=new Scanner(new File(args[0]));
try {
int namesCount = Integer.parseInt(scanner.nextLine());
Person[] arr = new Person[namesCount];
String line = null;
int i = 0;
while (scanner.hasNextLine()) {
line = scanner.nextLine();
Person person = new Person();
person.firstName = line.split(" ")[0];
person.lastName = line.substring(person.firstName.length(),
line.length()).trim();
arr[i] = person;
System.out.println(arr[i].firstName +" "+arr[i].lastName);
i++;
}
System.out.println("---------SORT BY LAST NAME---------");
new SortNames().sortNames(arr, 1);// sort by last name
System.out.println("---------SORT BY FIRST NAME---------");
new SortNames().sortNames(arr, 2);// sort by first name
} catch (IndexOutOfBoundsException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
I wanted to create a GUI that does all three things with different buttons printing in different relative JtextFields, however when i go to print it out, only one name is printed out on to the jtextfield, even though the the text file has about 30 names in it. this is what i am calling under the "load file" button
public void Read() {
try {
String file = filename.getText();
int filesize = file.length();
Scanner input = new Scanner(getClass().getResourceAsStream(file));
int namesCount = Integer.parseInt(input.nextLine());
Person[] arr = new Person[namesCount];
String line = null;
int i = 0;
while (input.hasNextLine()) {
line = input.nextLine();
Person person = new Person();
person.firstName = line.split(" ")[0];
person.lastName = line.substring(person.firstName.length(),
line.length()).trim();
arr[i] = person;
display.setText(arr[i].firstName +" "+arr[i].lastName);
i++;
For the sorting i tried to do this, but it still does not work properly:
display2.setText(new SortNames().sortNames(arr, 2));
here
What is the proper way to do something like this?
This is my GUI so far
import java.awt.*;
import java.awt.event.*;
import java.io.*;
import javax.swing.*;
import java.util.*;
public class SortNamesGUI extends JFrame {
private final LayoutManager layout;
private final LayoutManager layout2;
private JButton loadButton;
private JTextField filename;
private JTextArea display;
private JTextArea display2;
private JTextArea display3;
public SortNamesGUI()
{
super("Sorting Names");
setLayout(new BorderLayout());
JPanel buttonPanel = new JPanel();
layout = new FlowLayout();
buttonPanel.setLayout(layout);
JButton LoadFile = new JButton("Load File");
JButton FirstName = new JButton("Sort First Name");
JButton LastName = new JButton("Sort Last Name");
filename = new JTextField("Data file", 15);
buttonPanel.add(filename);
buttonPanel.add(LoadFile);
buttonPanel.add(FirstName);
buttonPanel.add(LastName);
JPanel DisplayPanel = new JPanel();
layout2 = new GridLayout(1,3);
DisplayPanel.setLayout(layout2);
display = new JTextArea("Unsorted list");
display2 = new JTextArea("Sorted based on first name");
display3 = new JTextArea("Sorted based on last name");
DisplayPanel.add(display);
DisplayPanel.add(display2);
DisplayPanel.add(display3);
DisplayPanel.add(new JScrollPane(display));
DisplayPanel.add(new JScrollPane(display2));
DisplayPanel.add(new JScrollPane(display3));
add(buttonPanel,BorderLayout.NORTH);
add(DisplayPanel,BorderLayout.CENTER);
LoadFile.addActionListener(
new ActionListener() {
public void actionPerformed(ActionEvent e) {
Read(); }
}
);
}
/*public void actionPerformed(ActionEvent event) {
Read();
}*/
public void Read() {
try {
String file = filename.getText();
int filesize = file.length();
Scanner input = new Scanner(getClass().getResourceAsStream(file));
int namesCount = Integer.parseInt(input.nextLine());
Person[] arr = new Person[namesCount];
String line = null;
int i = 0;
while (input.hasNextLine()) {
line = input.nextLine();
Person person = new Person();
person.firstName = line.split(" ")[0];
person.lastName = line.substring(person.firstName.length(),
line.length()).trim();
arr[i] = person;
display.setText(arr[i].firstName +" "+arr[i].lastName);
i++;
person.toString();
}
} catch (IndexOutOfBoundsException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public void SoftFirstName() {
String file = filename.getText();
int filesize = file.length();
Scanner input = new Scanner(getClass().getResourceAsStream(file));
int namesCount = Integer.parseInt(input.nextLine());
Person[] arr = new Person[namesCount];
new SortNames().sortNames(arr, 2);// sort by first name
display2.setText(new SortNames().sortNames(arr, 2));
}
public static void main(String[] args) {
SortNamesGUI testing= new SortNamesGUI();
testing.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
testing.setSize(620, 180);
testing.setVisible(true);
}
}
display2.setText(new SortNames().sortNames(arr, 2));
If you have tried this, you most likely get a compiler error. This is because the sortNames() method returns void but the setText() method requires a String argument. You need to modify sortNames() to return the sorted array rather than printing it out directly. In your original code, main() should get the sorted array and then print it. This is an example of what we call the Single Responsibility Principle. Each method should be responsible for a single task. In this case, your sortNames() does two things: 1. Sort the array and 2. Print the sorted array. If you separate these two tasks into separate methods, it will make your job a lot easier when you convert it to a GUI.
Once you have separated these two tasks, you will then need to decide how you want the names to appear in the JTextAray. I can think of at least two solutions:
Convert the entire array to a String and display the result in the JTextArea. This should be very easy to implement, but the output will have a list of names separated by commas inside square brackets.
Add each name one at a time to the JTextArea. Note that setText() will completely replace the entire contents of the JTextArea with the given text. I suggest look at the documentation for JTextArea to find another method that will be useful for your purposes.
My assignment is to create a non-directed, unweighted graph class called Graph. My second part is to create a method 'count' which is passed a Graph object as an argument and returns a
count of the number of connected components in the graph.
For some reason whenever I run this 'count' method, I get returned 'I expect '1'. I think my error has to do with my 'getToVertices' method, which says all of these nodes are connected, even though I don't believe I made them connected purposefully. Attached is my getToVertices method and my 'count' method.
It's suppose to return 3, the connected nodes and 2 unconnected nodes. Am I missing something?
public QueueInterface<T> getToVertices(T vertex)
// Returns a queue of the vertices that vertex is adjacent to.
{
QueueInterface<T> adjVertices = new LinkedQueue<T>();
int fromIndex;
int toIndex;
fromIndex = indexIs(vertex);
for (toIndex = 0; toIndex < numVertices; toIndex++)
if (edges[fromIndex][toIndex] != true)
adjVertices.enqueue(vertices[toIndex]);
return adjVertices;
}
public class CountCC {
private static int count(Graph <String> graph)
{
int count = 0;
StackInterface<String> stack = new LinkedStack<String>();
QueueInterface<String> vertexQueue = new LinkedQueue<String>();
String currVertex; // vertex being processed
String adjVertex;
String startVertex;
graph.clearMarks();
while(graph.getUnmarked() != null)
{
startVertex = graph.getUnmarked();
graph.markVertex(startVertex);
stack.push(startVertex);
do
{
currVertex = stack.top();
stack.pop();
System.out.println(currVertex);
vertexQueue = graph.getToVertices(currVertex);
while (!vertexQueue.isEmpty())
{
adjVertex = vertexQueue.dequeue();
if (!graph.isMarked(adjVertex))
{
graph.markVertex(adjVertex);
stack.push(adjVertex);
}
}
} while (!stack.isEmpty());
count++;
System.out.println(graph.getUnmarked());
}
return count;
}
public static void main(String[] args) {
Graph<String> graph1=new Graph<String>();
String s0 = new String("0 ");
String s1 = new String("1 ");
String s2 = new String("2 ");
String s3 = new String("3 ");
String s4 = new String("4 ");
graph1.clearMarks();
graph1.addVertex(s0);
graph1.addVertex(s1);
graph1.addVertex(s2);
graph1.addVertex(s3);
graph1.addVertex(s4);
graph1.addEdge(s0, s1);
graph1.addEdge(s1, s2);
graph1.addEdge(s2, s0);
System.out.println("I expect "+ count(graph1));
}
}
I have a simple file that contains two integer values per line (a source integer and a target integer). Each line represents a relation between two values. The file is not sorted and the actual file contains about 4 million lines. After sorting it may look like this:
sourceId;targetId
1;5
2;3
4;7
7;4
8;7
9;5
My goal is to create a new object that will represent all unique related integers in a list with a unique identifier. The expected output of this example should be the following three objects:
0, [1, 5, 9]
1, [2, 3]
2, [4, 7, 8]
So groupId 0 contains a group of relations (1, 5 and 9).
Below is my current way to create a list of these objects. The list of Relation objects contains all the lines in memory. And the list of GroupedRelation should be the end result.
public class GroupedRelationBuilder {
private List<Relation> relations;
private List<GroupedRelation> groupedRelations;
private List<String> ids;
private int frameId;
public void build() {
relations = new ArrayList<>();
relations.add(new Relation(1, 5));
relations.add(new Relation(4, 7));
relations.add(new Relation(8, 7));
relations.add(new Relation(7, 4));
relations.add(new Relation(9, 5));
relations.add(new Relation(2, 3));
// sort
relations.sort(Comparator.comparing(Relation::getSource).thenComparing(Relation::getTarget));
// build the groupedRelations
groupId = 0;
groupedRelations = new ArrayList<>();
for (int i = 0; relations.size() > 0;) {
ids = new ArrayList<>();
int compareSource = relations.get(i).getSource();
int compareTarget = relations.get(i).getTarget();
ids.add(Integer.toString(compareSource));
ids.add(Integer.toString(compareTarget));
relations.remove(i);
for (int j = 0; j < relations.size(); j++) {
int source = relations.get(j).getSource();
int target = relations.get(j).getTarget();
if ((source == compareSource || source == compareTarget) && !ids.contains(Integer.toString(target))) {
ids.add(Integer.toString(target));
relations.remove(j);
continue;
}
if ((target == compareSource || target == compareTarget) && !ids.contains(Integer.toString(source))) {
ids.add(Integer.toString(source));
relations.remove(j);
continue;
}
}
if (relations.size() > 0) {
groupedRelations.add(new GroupedRelation(groupId++, ids));
}
}
}
class GroupedRelation {
private int groupId;
private List<String> relatedIds;
public GroupedRelation(int groupId, List<String> relations) {
this.groupId = groupId;
this.relatedIds = relations;
}
public int getGroupId() {
return groupId;
}
public List<String> getRelatedIds() {
return relatedIds;
}
}
class Relation {
private int source;
private int target;
public Relation(int source, int target) {
this.source = source;
this.target = target;
}
public int getSource() {
return source;
}
public void setSource(int source) {
this.source = source;
}
public int getTarget() {
return target;
}
public void setTarget(int target) {
this.target = target;
}
}
}
When I run this small example program, it takes 15 seconds to create 1000 GroupedRelation objects. To create 1 million GroupedRelation it would take 250 minutes..
I am looking for help in optimizing my code that does get the result I want but simply takes to long.
Is it possible to optimize the iteration in such a way that the expected result is the same but the time it takes to get the expected result is reduced significantly? If this is possible, how would you go about it?
The current implementation is slow due to the ids.contains step.
The time complexity of the ArrayList.contains method is O(n):
to check if it contains an element it checks the elements one by one,
in the worst case scanning the entire list.
You can greatly improve the performance if you change the type of ids from List<String> to Set<String>, and use HashSet<String> instances.
The expected time complexity of Set.contains implementations is O(1),
significantly faster compared to a list.
As much as possible I would attempt to do it in a single pass from source.
import java.io.*;
import java.util.*;
/**
* Created by peter on 10/07/16.
*/
public class GroupedRelationBuilder {
public static List<List<Integer>> load(File file) throws IOException {
Map<Integer, Group> idToGroupMap = new HashMap<>();
try (BufferedReader br = new BufferedReader(new FileReader(file))) {
br.readLine();
for (String line; (line = br.readLine()) != null; ) {
String[] parts = line.split(";");
Integer source = Integer.parseInt(parts[0]);
Integer target = Integer.parseInt(parts[1]);
Group grp0 = idToGroupMap.get(source);
Group grp1 = idToGroupMap.get(target);
if (grp0 == null) {
if (grp1 == null) {
Group grp = new Group();
List<Integer> list = grp.ids;
list.add(source);
list.add(target);
idToGroupMap.put(source, grp);
idToGroupMap.put(target, grp);
} else {
grp1.ids.add(source);
idToGroupMap.put(source, grp1);
}
} else if (grp1 == null) {
grp0.ids.add(target);
idToGroupMap.put(target, grp0);
} else {
grp0.ids.addAll(grp1.ids);
grp1.ids = grp0.ids;
}
}
}
Set<List<Integer>> idsSet = Collections.newSetFromMap(new IdentityHashMap<>());
for (Group group : idToGroupMap.values()) {
idsSet.add(group.ids);
}
return new ArrayList<>(idsSet);
}
static class Group {
List<Integer> ids = new ArrayList<>();
}
public static void main(String[] args) throws IOException {
File file = File.createTempFile("deleteme", "txt");
Set<String> pairs = new HashSet<>();
try (PrintWriter pw = new PrintWriter(file)) {
pw.println("source;target");
Random rand = new Random();
int count = 1000000;
while (pairs.size() < count) {
int a = rand.nextInt(count);
int b = rand.nextInt(count);
if (a < b) {
int t = a;
a = b;
b = t;
}
pairs.add(a + ";" + b);
}
for (String pair : pairs) {
pw.println(pair);
}
}
System.out.println("Processing");
long start = System.currentTimeMillis();
List<List<Integer>> results = GroupedRelationBuilder.load(file);
System.out.println(results.size() + " took " + (System.currentTimeMillis() - start) / 1e3 + " sec");
}
}
For one million pairs this prints
Processing
105612 took 12.719 sec
You implementation is slow due to the Integer.toString() usage.
Changing the type means object and memory allocations. This is now done 4-5 times in the subloop.
Changing it took me from 126ms to 35ms: 4 times faster!
Several other things I see are:
first for loop can be changed into while(!relations.isEmpty())
the second loop could be done by using an iterator for (Iterator<Relation> iterator = relations.iterator(); iterator.hasNext();). When you remove an item, you are now skipping the next.
Place the declaration of ids inside the loop
I have been assigned a task that requires me to utilise a 2D Array. I have to read in a file and export it to a 2D array. I can only have a single method but I am unable to sort the array correctly. I am supposed to sort the data in 3 ways (alphabetically by name and with scores highest to lowest; highest to lowest scores for each student and highest to lowest by the average of 3 scores.) So far I have
import java.util.*;
import java.io.*;
public class ScoreSorter {
public static void main(String[] args) {
int student_num = 30;
String[][] DataInTableArr = new String[30][6];
try {
BufferedReader ReadIn = new BufferedReader(new FileReader("classZ.csv"));
for (int i = 0; i < 30; i++) {
String DataIn = ReadIn.readLine();
String[] DataInArr = DataIn.split(",");
DataInTableArr[i][0] = DataInArr[0];
DataInTableArr[i][1] = DataInArr[1];
DataInTableArr[i][2] = DataInArr[2];
DataInTableArr[i][3] = DataInArr[3];
int temptest1 = Integer.parseInt(DataInArr[1]);
int temptest2 = Integer.parseInt(DataInArr[2]);
int temptest3 = Integer.parseInt(DataInArr[3]);
}
} catch (Exception e) {
System.out.println("Whoops, you messed up, RESTART THE PROGRAM!!!!!");
}
}
}
I have no idea as to how to solve the rest of the task... I would appreciate if someone could tell me of the most efficient way and perhaps an example...
One plausible way is to create a Student class which implements Comparable interface, with the following members:
String name;
int scoreOne;
int scoreTwo;
int scoreThree;
compareTo(Student s) { //implement the comparison following 3 criteria you mentioned }
And, read the files row by row, for each row we create a Student object, and put all rows in a TreeSet. In this way, the TreeSet together with the compareTo method will help us sort the Students automatically.
Finally, iterate the sorted TreeSet to fill up the 2D array.
import java.util.*;
import java.io.*;
public class ScoreSorter {
public static void main(String[] args) {
int student_num = 30;
String[][] DataInTableArr = new String[30][6];
try {
BufferedReader ReadIn = new BufferedReader(new FileReader("classZ.csv"));
for (int i = 0; i < 30; i++) {
String DataIn = ReadIn.readLine();
String[] DataInArr = DataIn.split(",");
DataInTableArr[i][0] = DataInArr[0];
DataInTableArr[i][1] = DataInArr[1];
DataInTableArr[i][2] = DataInArr[2];
DataInTableArr[i][3] = DataInArr[3];
int temptest1 = Integer.parseInt(DataInArr[1]);
int temptest2 = Integer.parseInt(DataInArr[2]);
int temptest3 = Integer.parseInt(DataInArr[3]);
}
/*Code To be Inserted Here*/
} catch (Exception e) {
System.out.println("Whoops, you messed up, RESTART THE PROGRAM!!!!!");
}
}
}
If there are 6 columns such that First is name and the other 3 are scores then what does other 2 columns contain?? I ignore your array declaration :
String[][] DataInTableArr = new String[30][6];
and assume it to be 30x4 array
String[][] DataInTableArr = new String[30][4];
Logic for sorting Alphabetically
if(DataInTableArr[i][0].compareTo(DataInTableArr[i+1][0])){
/* Sorting Name of adjacent rows*/
String temp = DataInTableArr[i][0];
DataInTableArr[i][0] = DataInTableArr[i+1][0];
DataInTableArr[i+1][0] = temp;
/*Sorting the three marks similarly*/
temp = DataInTableArr[i][1];
DataInTableArr[i][1] = DataInTableArr[i+1][1];
DataInTableArr[i+1][1] = temp;
temp = DataInTableArr[i][2];
DataInTableArr[i][2] = DataInTableArr[i+1][2];
DataInTableArr[i+1][2] = temp;
temp = DataInTableArr[i][3];
DataInTableArr[i][3] = DataInTableArr[i+1][3];
DataInTableArr[i+1][3] = temp;
}
Put the above code in bubble sorting algorithm i.e. 2 loops.
Logic for sorting according to highest marks
In this case you have to find the highest marks in all three subjects of each DataInTableArr[i] and then compare the highest marks with that of next row.
Logic for sorting according to Average marks
Calculate the average of each i'th row as
(Integer.parseInt(DataInTableArr[i][1]) + Integer.parseInt(DataInTableArr[i][2]) + Integer.parseInt(DataInTableArr[i][3]))/3
and compare it with [i+1] th rows average.(same formula just replace [i] with [i+1])
I'm trying to write a bin-packing program using worst-fit heuristic so that the it adds weights into bins until they cannot store any more as they are read by the file and put the sequence of bins into a priority queue so that it places the bin with the least remaining space on the top. But I'm having trouble with writing the comparator of the Bin class. Here's the full code:
public class BinPacking{
public static class Bin implements Comparable<Bin> {
int ID ;
int remSpace;
ArrayList<Integer> weights = new ArrayList<Integer>();
public Bin(int ID){
this.ID = ID;
remSpace = 100;
}
public void add(int size){
remSpace -= size;
weights.add(size);
}
#Override
public int compareTo(Bin o) {
return remSpace;
}
}
public static void main(String[] args) throws FileNotFoundException{
PriorityQueue<Bin> pq =new PriorityQueue<Bin>();
File myFile = new File("input.txt");
int binId = 1;
Bin d = new Bin(binId);
pq.add(d);
int size;
Scanner input = new Scanner(myFile);
while (input.hasNext())
{
size = input.nextInt();
d = (Bin)pq.peek();
if (d.remSpace >= size)
{
pq.remove(d);
d.add(size);
pq.add(d);
}
else
{
binId++;
d = new Bin(binId);
d.add(size);
pq.add(d);
}
}
System.out.println("Number of bins used: " + binId);
int mylst[][] = new int[binId][1000];
int k =1;
for(int i=0;i<binId;i++){
System.out.println("Bin" + k + ": ");
k++;
for(int j=0;j<pq.peek().weights.size();j++){
mylst[i][j] = pq.peek().weights.get(j);
System.out.print(" "+mylst[i][j]);
}
System.out.println();
pq.poll();
}
}
}
Comparable#compareTo(T) is meant to return the difference between two objects, allowing an algorithm to decide whether one item i equal, less than or greater than another. Returning the remaining space of one will not give the order than you want, as this does not compare the two objects. Try:
public int compareTo(Bin o) {
if(o == null)return 1;
if(remSpace > o.remSpace)return 1;
else if(remSpace < o.remSpace)return -1;
return 0;
}
Notice how this returns the difference in the spaces of the two Bins, so that a difference may be gauged.