Related
So I'm trying to complete an exercise where I've been asked to implement a method that does a binary search in an ArrayList of objects. From the exercise:
Binary search
In the Main-class, implement a method public static int binarySearch(ArrayList<Book> books, int searchedId), which searches the list it received as a parameter, for a book with an id variable that matches the value of searchedId variable it received as a parameter. If that book is found the method, should return the index it's located at, in the list it received as a parameter. If the book isn't found, the method should return the value -1.
The method must be implemented as a binary search, which assumes the list is ordered. You should also assume, that the ids towards the beginning of the list, are always smaller than the ids towards the end of the list.
I have created two methods, one to check whether the arraylist is sorted (isItSorted) and the other one that will perform the binary search if the aforementioned method evaluates to true (binarySearch). Please see below:
public static boolean isItSorted(ArrayList<Book> books) {
ArrayList<String> boo = new ArrayList<>();
String isItSorted = "";
for (int i = 0; i < books.size(); i++) {
for (int j = i + 1; j < books.size(); j++) {
if (books.get(i).getId() < books.get(j).getId()) {
isItSorted = "true";
boo.add(isItSorted);
} else {
isItSorted = "false";
boo.add(isItSorted);
}
}
}
if (!(boo.contains("false"))) {
return true;
}
return false;
}
public static int binarySearch(ArrayList<Book> books, long searchedId) {
if (searchedId < 0 || books.isEmpty()) {
return -1;
} else if (isItSorted(books)) {
int start = 0;
int end = books.size() - 1;
int middle = (start + end) / 2;
if (books.get(middle).getId() == searchedId) {
return middle;
} else if (books.get(middle).getId() > searchedId) {
end = middle - 1;
} else if (books.get(middle).getId() < searchedId) {
start = middle + 1;
}
while (start <= end) {
if (books.get(start).getId() == searchedId) {
return start;
}
start++;
}
}
return -1;
}
Inside these java files, there's a test package that tests whether my solution is correct or not. While 95% of the tests are successful, when it reaches the method below (where it compares the time of execution compared to my other method (linear search)), I get the error Java outOfMemory heap Space.
I use NetBeans. I've already tried the JVM commands.
My solution seems to work with every number of objects I've tried, so perhaps there's something wrong with the test code below?
#Test
#Points("07-05.2")
public void binarySearchIsFasterThanLinearSearch() throws Throwable {
ArrayList<Book> books = generateBooks(10000);
Collections.sort(books, (k1, k2) -> k1.getId() - k2.getId());
int searched = 1000001;
long bSearchStart = System.nanoTime();
int binarySearchId = Searching.binarySearch(books, searched);
long bSearchEnd = System.nanoTime();
assertTrue("When binary search does not find what was searched for, it must return -1", binarySearchId == -1);
long lSearchStart = System.nanoTime();
int linearSearchId = Searching.linearSearch(books, searched);
long lSearchEnd = System.nanoTime();
assertTrue("When linear search does not find what was searched for, it must return -1", linearSearchId == -1);
long bSearchTime = bSearchEnd - bSearchStart;
long lSearchTime = lSearchEnd - lSearchStart;
assertTrue("When there are 10000 books to search, and the searched book is not found, binary search should be a lot faster than linear search. Current this isn't so", bSearchTime * 2 < lSearchTime);
}
ArrayList<String> boo = new ArrayList<>();
String isItSorted = "";
for (int i = 0; i < books.size(); i++) {
for (int j = i + 1; j < books.size(); j++) {
if (books.get(i).getId() < books.get(j).getId()) {
isItSorted = "true";
boo.add(isItSorted);
} else {
isItSorted = "false";
boo.add(isItSorted);
}
}
}
Adds on the order of 100 million items to the ArrayList boo.
If you want to check if something is sorted you can use much simpler code:
Book prev = books[0];
for (int i = 1; i < books.size(); i++) {
if (prev.getId() > books[i].getId())
return false;
}
return true;
But you shouldn't need to call it inside binarySearch() because that will defeat the purpose of binarySearch() and make it as slow as linearSearch().
Recently I've been brushing up on my machine learning, and as such decided to implement a basic neural network in Java using the back propagation algorithm. I've gone over the maths and checked against various other tutorials, but am still having problems. Apologies for the size of this post.
I'll first let you know the problems I have been testing on, before going into more detail about the algorithm.
Test problem 1:
A single output neuron with linear activation, learning regression of the function x/2 + 2. This works pretty well, but doesn't really use back propagation yet.
Algorithm works, and converges to near zero error (no pic, since I can't post more than 2 links).
Test problem 2:
My next test was to learn the XOR problem. For this, I tried a simple network with 2 input nodes, 2 hidden nodes and 2 output nodes (input nodes only provide the input and are not trained).
Algorithm always gets stuck on an average of 0.5 error
It doesn't matter how many epochs I run the algorithm for, all errors seem to converge to this point, and the network performs poorly.
Implementation
To implement the algorithm, I represent nodes as objects, and also have objects to represent activation functions.
public class LogisticActivationFunction implements ActivationFunction {
#Override
public double apply(double in) {
return 1.0 / (1.0 + Math.exp(-in));
}
#Override
public double applyDerivative(double in) {
double sig = apply(in);
return sig * (1.0 - sig);
}
}
First, the feed forward process is run like so:
public List<Double> evaluate(List<Double> inputs, boolean training) {
// Set the weights in the first layer.
setInputWeights(inputs);
// Iterate through non-input layers one by one and evaluate.
NodeLayer previousLayer = layers.get(0);
for (int layerIndex = 1; layerIndex < layers.size(); layerIndex++) {
NodeLayer layer = layers.get(layerIndex);
for (int nodeIndex = 0; nodeIndex < layer.size(); nodeIndex++) {
Node node = layer.get(nodeIndex);
evaluateNode(node, previousLayer, training);
}
previousLayer = layer;
}
return getOutputWeights();
}
private void evaluateNode(Node node, NodeLayer previousLayer, boolean training) {
double sum = node.getBias();
// Create sum from all connected nodes.
for (int link : node.links()) {
if (training) {
previousLayer.get(link).registerDownstreamNode(node.getId());
}
sum += node.getUpstreamLinkStrength(link) * previousLayer.get(link).getOutput();
}
// apply the activation function.
double activation = node.getActivation().apply(sum);
node.setHiddenNode(sum, activation);
}
Next, error values are propagated backwards across the network:
protected void backPropogate(List<Double> correct) {
//float error = norm(correct, getOutputWeights());
// Final layer error.
NodeLayer outputLayer = getOutputLayer();
List<Double> output = getOutputWeights();
for (int i = 0; i < outputLayer.size(); i++) {
// Calculate error on the ith output.
double error = correct.get(i) - output.get(i);
System.out.println("error " + i + " = " + error + " = " + correct.get(i) + " - " + output.get(i));
// Set the delta to the error in dimension i multiplied by the activation derivative of the input.
Node node = outputLayer.get(i);
node.setDelta(error * node.getActivation().applyDerivative(node.getInput()));
}
NodeLayer layer = outputLayer.getUpstream(this);
while (layer != getInputLayer()) {
for (Node node : layer) {
double sum = 0;
for (Node downstream : node.downstreamNodes(this, layer)) {
sum += downstream.getDelta() * downstream.getUpstreamLinkStrength(node.getId());
}
node.setDelta(sum * node.getActivation().applyDerivative(node.getInput()));
}
layer = layer.getUpstream(this);
}
}
Finally, weights are updated using gradient descent. Note, I'm using the negative error, so this works by adding the delta * learning rate * output.
private void updateParameters(double learningRate) {
for (NodeLayer layer : this) {
if (layer == getInputLayer()) {
continue;
}
for (Node node : layer) {
double oldBias = node.getBias();
node.offsetBias(node.getDelta() * learningRate);
for (Node upstream : node.upstreamNodes(this, layer)) {
double oldW = node.getUpstreamLinkStrength(upstream);
node.offsetWeight(upstream.getId(), learningRate * node.getDelta() * upstream.getOutput());
}
}
}
}
To tie these all together, I use the train method:
public void trainExample(List<Double> inputs, List<Double> correct, double learningRate) {
System.out.println("training example... " + Data.toString(inputs) + " -> " + Data.toString(correct));
evaluate(inputs, true);
backPropogate(correct);
updateParameters(learningRate);
}
And to do this for a training set I use the following logic:
public List<Double> train(NodeNetwork network, List<List<Double>> trainingInput, List<List<Double>> trainingLabels, double learningRate, int epochs, boolean verbose) {
List<Double> errorLog = new ArrayList<>();
for (int i = 0; i < epochs; i++) {
for (int j = 0; j < trainingInput.size(); j++) {
int example = random.nextInt(trainingInput.size());
network.trainExample(trainingInput.get(example), trainingLabels.get(example), learningRate);
}
if (verbose) {
double error = network.checkErrorSet(trainingInput, trainingLabels);
errorLog.add(error);
System.out.println(i + " " + error);
}
}
return errorLog;
}
Does anyone have any ideas on how I might go about getting this to work? I've spent the last day doing various checks, and seem to be getting no closer to an answer.
Code is viewable on my github (sami016) which I cannot link due to URL restrictions.
I'd really appreciate if anyone could point me in the right direction. Thanks for your help!
So I have a program written so far that reads in a csv file of cities and distances in the following format:
Alaska Mileage Chart,Anchorage,Anderson,Cantwell,
Anchorage,0,284,210,
Anderson,284,0,74,
Cantwell,210,74,0,
So the algorithm works and outputs the cities in the order they should be visited following the shortest path using the nearest neighbor algorithm always starting with Anchorage as the city of origin or starting city.
Using this data, the example output for the algorithm is: 1,3,2. I have ran this with a 27 element chart and had good results as well. I am using this small one for writing and debugging purposes.
Ideally the output I am looking for is the Name of the City and a cumulative milage.
Right now I am having working on trying to get the cities into an array that I can print out. Help with both parts would be appreciated or help keeping in mind that is the end goal is appreciated as well.
My thought was that ultimately I may want to create an array of {string, int}
so my output would look something like this..
Anchorage 0
Cantwell 210
Anderson 284
I am able to set the first element of the array to 1, but can not get the 2nd and 3rd element of the new output array to correct
This is the code I am having a problem with:
public class TSPNearestNeighbor {
private int numberOfNodes;
private Stack<Integer> stack;
public TSPNearestNeighbor()
{
stack = new Stack<>();
}
public void tsp(int adjacencyMatrix[][])
{
numberOfNodes = adjacencyMatrix[1].length;
// System.out.print(numberOfNodes);
// System.out.print(Arrays.deepToString(adjacencyMatrix));
int[] visited = new int[numberOfNodes];
// System.out.print(Arrays.toString(visited));
visited[1] = 1;
// System.out.print(Arrays.toString(visited));
stack.push(1);
int element, dst = 0, i;
int min = Integer.MAX_VALUE;
boolean minFlag = false;
System.out.print(1 + "\n");
//System.arraycopy(arr_cities, 0, arr_final, 0, 1); // Copies Anchorage to Pos 1 always
//System.out.print(Arrays.deepToString(arr_final)+ "\n");
while (!stack.isEmpty())
{
element = stack.peek();
i = 1;
min = Integer.MAX_VALUE;
while (i <= numberOfNodes-1)
{
if (adjacencyMatrix[element][i] > 1 && visited[i] == 0)
{
if (min > adjacencyMatrix[element][i])
{
min = adjacencyMatrix[element][i];
dst = i;
minFlag = true;
}
}
i++;
}
if (minFlag)
{
visited[dst] = 1;
stack.push(dst);
System.out.print(dst + "\n");
minFlag = false;
continue;
}
stack.pop();
}
}
Given the existing structure you are using, you can output the cities in the path using:
public void printCities(Stack<Integer> path, int[][] distances, List<String> names) {
int cumulativeDistance = 0;
int previous = -1;
for (int city: path) {
if (previous != -1)
cumulativeDistance += distances[previous][city];
System.out.println(names.get(city) + " " + cumulativeDistance);
previous = city;
}
}
I'd like to answer your question slightly indirectly. You are making life hard for yourself by using arrays of objects. They make the code difficult to read and are hard to access. Things would become easier if you create a City class with appropriate methods to help you with the output.
For example:
class City {
private final String name;
private final Map<City,Integer> connections = new HashMap<>();
public static addConnection(City from, City to, int distance) {
from.connections.put(to, distance);
to.connections.put(from, distance);
}
public int getDistanceTo(City other) {
if (connections.containsKey(other))
return connections.get(other);
else
throw new IllegalArgumentException("Non connection error");
}
}
I've left out constructor, getters, setters for clarity.
Now outputting your path becomes quite a bit simpler:
public void outputPath(List<City> cities) {
int cumulativeDistance = 0;
City previous = null;
for (City current: cities) {
if (previous != null)
cumulativeDistance += previous.getDistanceTo(current);
System.out.println(current.getName + " " + cumulativeDistance);
previous = current;
}
}
I am a 2nd year student at a local university and I am currently taking a computer programming class. I do quite well in my programming class, although generally I do come to problems. Our professor has given us some incomplete algorithms that he wants us to finish as another diagnostic test. He had told us beforehand that we must do it without using shortcuts, meaning I cannot use comparators, I can only use basic sorting algorithms such as bubble, insertion, selection and merge sort, and I can only use binary or linear search.
I've been given an incomplete file designed to sort students and their marks. A particular problem that I've been coming up with is the sorting algorithm and the searching algorithm that I need to create. Our lecturer has given us some testing material to see if our algorithms work. Surprisingly, mine didn't. I have tried all types of sorting algorithms, but for some reason the test says that the algorithm failed. How do I solve this predicament.
OS: windows 7,
Java Workbench: Eclipse
Here is the code for the algorithm. I apologize if it appears to be quite messy.
This is the sorting algorihtm at the moment. The supposed design(by my professor) was that the array would be sorted in descending order.
public static void sort(Student[] students) {
if(students == null)
return;
for(int i=0;i<students.length-2;i++){
Student temp = students[i];
for(int k=i+1;k<students.length-1;k++){
Student temp2= students[k];
int result = temp2.compareTo(temp);
if(result > 0){
students[k] = temp;
students[i] = temp2;
}
}
}
}
here is the code for the searching algorithm. Again, the supposed design is that it would be able to search for a student's given name and family name using the string "name". The algorithm is to be made in a way such that it would ignore the formatting of the name such as "lastname firstname" and "firstname lastname" and it would ignore capital letters. Again, apologize for the messy work.
public static int search(Student[] students, String name) {
if(students == null || students.length == 0)
return -1;
for(int i=0;i<students.length;i++){
name.toLowerCase();
if(name.compareTo(students[i].getGivenName().toLowerCase()+" "+students[i].getFamilyName().toLowerCase()) == 0 || name.compareTo(students[i].getFamilyName().toLowerCase()+" "+students[i].getGivenName().toLowerCase()) == 0)
return 1;
}
return -1;
}
So, all in all, in case you skipped to the end, my question is: what did I do wrong with my sorting algorithm, and is there a better, simpler way to shorten the searching algorithm while still working properly
EDIT: here are the testing algorithms for the sorting and searching algorithm respectively. The test sorting algorithm can follow the sorting algorithm I made, but for some reason it doesn't pass the boolean conditions the professor has made.
public void testSort() throws OutOfRangeException, FileNotFoundException {
Student[] students = new Student[6];
students[0] = new Student("joey", "mitchel", new int[]{42,51,64,70,81});
students[1] = new Student("Sandy", "luchel", new int[]{64,51,64,70,81});
students[2] = new Student("Sandy", "luchel", new int[]{42,51,64,70,81});
students[3] = new Student("amanda", "jones", new int[]{95,51,64,70,81});
students[4] = new Student("Susane", "Louis", new int[]{42,51,64,70,81});
students[5] = new Student("Samuel", "jones", new int[]{95,51,64,70,81});
StudentSearcherSorter.sort(students);
for(int i=0; i<students.length - 1; i++) {
boolean b1 = students[i].total() > students[i+1].total();
boolean b2 = false;
boolean b3 = false;
if(b1 == false && students[i].total() == students[i+1].total())
b2 = students[i].getFamilyName().compareTo(students[i+1].getFamilyName()) < 0;
if(b2 == false && students[i].total() == students[i+1].total() && students[i].getFamilyName().compareTo(students[i+1].getFamilyName()) == 0)
b3 = students[i].getGivenName().compareTo(students[i+1].getGivenName()) < 0;
assertTrue(b1 || b2 || b3);
}
}
and the searching test algorithm. I am not sure what is wrong, although generally, It might have to do with the way I handled the code for the searching algorithm.
public void testSearch() throws FileNotFoundException, OutOfRangeException {
Student[] students = new Student[6];
students[0] = new Student("joey", "mitchel", new int[]{42,51,64,70,81});
students[1] = new Student("Sandy", "luchel", new int[]{64,51,64,70,81});
students[2] = new Student("Sandy", "luchel", new int[]{42,51,64,70,81});
students[3] = new Student("amanda", "jones", new int[]{95,51,64,70,81});
students[4] = new Student("Susane", "Louis", new int[]{42,51,64,70,81});
students[5] = new Student("Samuel", "jones", new int[]{95,51,64,70,81});
for(int i=0; i<students.length; i++) {
assertTrue(StudentSearcherSorter.search(students, students[i].getGivenName().toUpperCase()+" "+students[i].getFamilyName()) >= 0);
assertTrue(StudentSearcherSorter.search(students, students[i].getFamilyName()+" "+students[i].getGivenName().toUpperCase()) >= 0);
}
}
About the sorting, in the original version, the code does not compare the last two elements in the students array.
public static void sort(Student[] students) {
if(students == null)
return;
Your upper bound of the loop should be students.length - 1, so the last value
of i would be students.length - 2.
// for(int i=0;i<students.length-2;i++){
for(int i=0;i<students.length-1;i++){
Student temp = students[i];
Likewise, the upper bound of this loop should be students.length, so the last value
of k would be stidents.length - 1. Alternatively, in both cases you can
replace < with <=.
// for(int k=i+1;k<students.length-1;k++){
for(int k=i+1;k<students.length;k++){
Student temp2= students[k];
int result = temp2.compareTo(temp);
if(result > 0){
students[k] = temp;
students[i] = temp2;
}
}
}
}
Over the past couple of weeks I've read through the book Error Control Coding: Fundamentals and Applications in order to learn about BCH (Bose, Chaudhuri, Hocquenghem) Codes for an junior programming role at a telecoms company.
This book mostly covers the mathematics and theory behind the subject, but I'm struggling to implement some of the concepts; primarily getting the next n codewords.I have a GUI (implemented through NetBeans, so I won't post the code as the file is huge) that passes a code in order to get the next n numbers:
Generating these numbers is where I am having problems. If I could go through all of these within just the encoding method instead of looping through using the GUI my life would be ten times easier.
This has been driving me crazy for days now as it is easy enough to generate 0000000000 from the input, but I am lost as to where to go from there with my code. What do I then do to generate the next working number?
Any help with generating the above code would be appreciated.
(big edit...) Playing with the code a bit more this seems to work:
import java.util.ArrayList;
import java.util.List;
public class Main
{
public static void main(final String[] argv)
{
final int startValue;
final int iterations;
final List<String> list;
startValue = Integer.parseInt(argv[0]);
iterations = Integer.parseInt(argv[1]);
list = encodeAll(startValue, iterations);
System.out.println(list);
}
private static List<String> encodeAll(final int startValue, final int iterations)
{
final List<String> allEncodings;
allEncodings = new ArrayList<String>();
for(int i = 0; i < iterations; i++)
{
try
{
final int value;
final String str;
final String encoding;
value = i + startValue;
str = String.format("%06d", value);
encoding = encoding(str);
allEncodings.add(encoding);
}
catch(final BadNumberException ex)
{
// do nothing
}
}
return allEncodings;
}
public static String encoding(String str)
throws BadNumberException
{
final int[] digit;
final StringBuilder s;
digit = new int[10];
for(int i = 0; i < 6; i++)
{
digit[i] = Integer.parseInt(String.valueOf(str.charAt(i)));
}
digit[6] = ((4*digit[0])+(10*digit[1])+(9*digit[2])+(2*digit[3])+(digit[4])+(7*digit[5])) % 11;
digit[7] = ((7*digit[0])+(8*digit[1])+(7*digit[2])+(digit[3])+(9*digit[4])+(6*digit[5])) % 11;
digit[8] = ((9*digit[0])+(digit[1])+(7*digit[2])+(8*digit[3])+(7*digit[4])+(7*digit[5])) % 11;
digit[9] = ((digit[0])+(2*digit[1])+(9*digit[2])+(10*digit[3])+(4*digit[4])+(digit[5])) % 11;
// Insert Parity Checking method (Vandermonde Matrix)
s = new StringBuilder();
for(int i = 0; i < 9; i++)
{
s.append(Integer.toString(digit[i]));
}
if(digit[6] == 10 || digit[7] == 10 || digit[8] == 10 || digit[9] == 10)
{
throw new BadNumberException(str);
}
return (s.toString());
}
}
class BadNumberException
extends Exception
{
public BadNumberException(final String str)
{
super(str + " cannot be encoded");
}
}
I prefer throwing the exception rather than returning a special string. In this case I ignore the exception which normally I would say is bad practice, but for this case I think it is what you want.
Hard to tell, if I got your problem, but after reading your question several times, maybe that's what you're looking for:
public List<String> encodeAll() {
List<String> allEncodings = new ArrayList<String>();
for (int i = 0; i < 1000000 ; i++) {
String encoding = encoding(Integer.toString(i));
allEncodings.add(encoding);
}
return allEncodings;
}
There's one flaw in the solution, the toOctalString results are not 0-padded. If that's what you want, I suggest using String.format("<something>", i) in the encoding call.
Update
To use it in your current call, replace a call to encoding(String str) with call to this method. You'll receive an ordered List with all encodings.
I aasumed, you were only interested in octal values - my mistake, now I think you just forgot the encoding for value 000009 in you example and thus removed the irretating octal stuff.