Having a casting issue with traveling salesperson using a greedy algorithm - java

I figure I have the general idea down for how to solve the algorithm but the implementation seems to elude me. What I have thus far is this:
public class GreedySalesman {
public static int[] greedySalesmanSolution(int[][] distances) {
List cityList = new ArrayList();
for(int[] array: distances) {
cityList.add(Arrays.asList(array));
}
List<Integer> initialResult = new ArrayList();
initialResult.add(0);
List<Integer> finalResult = findMinDistance(cityList, cityList, initialResult, 0);
/*int finalResultArray = new int[finalResult.size()+1];
int i = 0;
while (!(finalResult.isEmpty)) {
finalResultArray[i] = finalResult.poll();
i++;
}
return finalResultArray;
*/
return null;
}
public static List<Integer> findMinDistance(List<List<Integer>> initialCityInput, List<List<Integer>> cityInput, List<Integer> distanceResult, int index) {
if(cityInput.isEmpty()) {
distanceResult.add(0);
return distanceResult;
}
int min = Collections.min(initialCityInput.get(index));
List<Integer> city = initialCityInput.get(index);
index = city.indexOf(min);
distanceResult.add(index);
cityInput.remove(city);
return findMinDistance(initialCityInput,cityInput,distanceResult,index);
}
}
That is, the algorithm will take an two dimensional array of ints as an input, then make a List cityList referring to distances, then pass it into findMinDistance. The commented out part is where the result from findMinDistance will be converted into an array of ints and returned as finalResultArray but that part is not important yet.
findMinDistance will take in a two dimensional list of Integers twice, a List of Integers that will become the result and an int representing an index.
The function will return the distanceResult when cityInput has been emptied. Otherwise it will start with the first city based on the index, get the minimum distance from that List and its index and add the index to the distanceResult.
Once that has been done, the city will be removed from the cityInput and the program will go into recursion until cityInput has been emptied.
The issue I am getting currently is
I cannot be cast to java.lang.Integer
at
int min = Collections.min(initialCityInput.get(index));
And in main upon trying to run the program with some test data.
Any help will be appreciated.
======
Edit:
I made some changes to my code
public class GreedyTSP {
public int[] greedySalesmanSolution(int[][] distances) {
List<List<Integer>> cityList = new ArrayList();
List<List<Integer>> initialCityList = new ArrayList();
int iLength = distances.length;
for (int i = 0; i < iLength; ++i) {
int jLength = distances[0].length;
cityList.add(new ArrayList(jLength));
initialCityList.add(new ArrayList(jLength));
for (int j = 0; j < jLength; ++j) {
cityList.get(i).add(distances[i][j]);
initialCityList.get(i).add(distances[i][j]);
}
}
List<Integer> initialResult = new ArrayList();
initialResult.add(0);
List<Integer> finalResult = findMinDistance(initialCityList, cityList, initialResult, 0);
int[] finalResultArray = new int[finalResult.size()];
Iterator<Integer> iterator = finalResult.iterator();
for (int i = 0; i < finalResultArray.length; i++){
finalResultArray[i] = iterator.next().intValue();
}
return finalResultArray;
}
public List<Integer> findMinDistance(List<List<Integer>> initialCityInput, List<List<Integer>> cityInput, List<Integer> distanceResult, int initialIndex) {
if(cityInput.isEmpty()) {
distanceResult.add(0);
return distanceResult;
}
List<Integer> city = initialCityInput.get(initialIndex);
Integer min = findMin(city, distanceResult, initialIndex);
int resultIndex = city.indexOf(min);
distanceResult.add(resultIndex);
cityInput.remove(city);
return findMinDistance(initialCityInput,cityInput,distanceResult,resultIndex);
}
public Integer findMin(List<Integer> city, List<Integer> distanceResult, int inputIndex) {
Integer min = Integer.MAX_VALUE;
for(int i = 0; i < city.size();i++) {
if (city.get(i) > inputIndex && city.get(i) < min) min = city.get(i);
}
int resultIndex = city.indexOf(min);
if(distanceResult.contains(resultIndex)) {
return findMin(city, distanceResult, inputIndex);
}
return min;
}
}
Im not having any cast errors at the moment but it seems that the parts of my program dealing with recursion are causing StackOverflowError-s. I've been messing with this thing for literally 16 hours now and I'm all out of ideas as to why. Any ideas?

The problem with your casting is the following
List<List<Integer>> initialCityInput is a List containing Lists with integers.
Therefore initalCityInput.get(index) returns a List not an Int, which cannot be cast to int.

Well, I looked around a bit and I was basically overcomplicating the task through using multidimensional arraylists. I changed the code quite a bit:
public class GreedyTSP {
public static int[] greedySolution(int[][] adjacencyMatrix) {
List<Integer> visitedCities = new ArrayList<>();
int min = Integer.MAX_VALUE;
int startLocation = 0;
int tempStartLocation = 0;
int[] resultArray = new int[adjacencyMatrix.length+1];
visitedCities.add(0);
while(visitedCities.size() < adjacencyMatrix.length ){
for(int i = 0; i < adjacencyMatrix.length; i++){
if(!visitedCities.contains(i) && adjacencyMatrix[startLocation][i] < min){
min = adjacencyMatrix[startLocation][i];
tempStartLocation = i;
}
}
startLocation = tempStartLocation;
visitedCities.add(tempStartLocation);
min = Integer.MAX_VALUE;
}
visitedCities.add(0);
for(int i = 0; i < resultArray.length; i++){
int temp = visitedCities.get(i);
resultArray[i] = temp;
}
return resultArray;
}
}
This will solve the task using a greedy algorithm

Related

Find Common Elements between two Arrays

I want to find the common elements between two arrays with different sizes and put them in another array.
Can you tell what's wrong with my code?
public static int[] numratEQelluar(int[] vargu, int[]varguPer)
{
int count = 0;
int [] nrQelluar = new int[count];
for(int i = 0; i<vargu.length; i++)
{
for(int idx = 1;idx<varguPer.length ; idx++)
{
if(vargu[i] == (varguPer[idx]))
{
count++;
for(int index = 0; index<nrQelluar.length; index++)
{
nrQelluar[index] = vargu[i];
}
}
}
}
return nrQelluar;
The reason it doesn't work is indeed due to incorrect memory allocation to nrEqualler as been said in the comments.
However, there are a few thing i'd change in your code:
using a LinkedList instead of primitive int [] for dynamic sized
array is much more efficient (add in O(1)).
less indentations and confusing indexes by extracting methods.
So this should do:
public static int[] numratEQelluar(int[] vargu, int[]varguPer){
List<Integer> nrQelluar = new LinkedList<Integer> ();
for(int i = 0; i < vargu.length; i++) {
if (contains(varguPer, vargu[i])) nrQelluar.add(vargu[i]);
}
return toPrimitive(nrQelluar);
}
private static boolean contains(int [] array, int num){
for(int i = 0; i < array.length; i++){
if(array[i] == num) return true;
}
return false;
}
private static int[] toPrimitive(List<Integer> list) {
int[] primitiveArray = new int[list.size()];
for(int i = 0; i < list.size(); i++){
primitiveArray[i] = list.get(i);
}
return primitiveArray;
}
The problem is between these lines of code
int count = 0;
int [] nrQelluar = new int[count];
The size of your new array will be zero. try changing this to the sum of the length of both the arrays.
Updated with a working code.
Try this code :
public static Integer[] findCommonElements(int[] arr1, int[] arr2){
HashSet set = new HashSet<>();
for(int i=0;i<arr1.length;i++){
for(int j=0;j<arr2.length;j++){
if(arr1[i] == arr2[j]){
set.add(arr1[i]);
}
}
}
Integer[] resultArray = (Integer[]) set.toArray(new Integer[set.size()]);
return resultArray;
}
Using a set will ensure that you won't get any duplicates in the resulting array. If duplicates are fine, then you can use ArrayList to store the common elements and then convert them into Array.

How to return specific int values from an array; How to make a testclass?

I started to code an assignment for uni, but after a short while, i got stuck.
public class MostCommonElemnt
{
//private int[] liste;
public MostCommonElemnt()
{
//int[] liste = {1,2,3,4,5,6,7,8,9};
}
Is it bad to initialize an array in the constructor, or is it just not necassary?
public int findMostCommonElemnt(int[] list)
{
int help = 0;
for(int i = 0; i < liste.length; i++)
{
help = list[i];
}
return help;
}
Here i tried to get a specific int value (or number) returned from my int array, but "help" only returns the last number from the int array. How do i get the 2nd or 4th? To see all of them i can use System.out.println();
public static void main (int[] args)
{
//int[] liste = {1,2,3,4,5,6,7,8,9};
System.out.println(new MostCommonElemnt().findMostCommonElemnt(int[] list));
}
}
In this section i tried to make a testMethod but, i can not get it to work,
BlueJ (we have to use it for uni) always complaints about something.
I especially to not know, what to do after the
new MostCommonElemnt().
I just want, the programm to take specific numbers, with which i want to test. e.g: {1,2,3,4,5,6,7...}
otherwise i always have to type them in, which gets boring fast.
This could probably be shorter, but it works.
public static int findMostCommonElement(int[] list) {
int max = 0;
for (int i : list)
if (i > max)
max = i;
int[] newArr = new int[max];
for (int i = 0; i < max; i++)
newArr[i] = 0;
for (int i = 0; i < max; i++)
newArr[list[i]] += 1;
int mostCommon = 0;
int mostCommonMax = 0;
for (int i = 0; i < max; i++)
if (newArr[i] > mostCommonMax) {
mostCommonMax = newArr[i];
mostCommon = i;
}
return mostCommon;
}
To pass fixed values to your method, you can use:
int[] liste = {1,2,3,4,5,6,7,8,9};
System.out.println(new MostCommonElemnt().findMostCommonElemnt(liste));
You can return the second value of the array using return list[1]; inside the findMostCommonElemnt method, but this probably isn't what the method should do.

Iterating over an ArrayList adding values

Is it possible to iterate over a ArrayList adding not all instances but every 12? There are many threads on using addAll to add all instances but not sections.
I currently have an ArrayList containing hundreds of float values:
Snippet:
120.5, 22.2, 76.2, 64.5, 38.3, 27.1, 149.4, 62.3, 127.9, 79.1, 83.4, 68.3, 61.0, 83.4, 5.4, 83.8, 78.3, 111.8, 104.1, 145.2, 94.3, 20.0, 104.7, 35.9, 68.6, 10.1, 41.1, 82.2, 170.7, 17.2, 122.1, 61.0, 46.3, 101.1, 59.0, 30.0, ...
What I want to do is sum the first 12 instances and put this total in a new ArrayList, sum the next 12 instances, store this into the newly created ArrayList and so on. There are exactly 996 instances so i should have 83 new values in this new ArrayList (996/12=83).
Can this be done? If so how? Here is where I have got to...
// ArrayList that contains the float values shown above
public MonthData depthValues() {
ArrayList<Float> rValue = new ArrayList<>();
for (int i = 0; i<months.size(); i++)
{
rValue.add(months.get(i).getDepthMM());
}
System.out.println(rValue);
System.out.println(rValue.size());
return null;
}
//New arrayList im trying to make
//probably done this wrong, help needed here
public MonthData depthTotals() {
ArrayList<Float> depthAdd = new ArrayList<Float>();
int t = 12;
for(int i = 0; i<rValue.size(); ++i)
{
??????????????????
}
}
Any help will be greatly appreciated I cant seem to find anything on this anywhere as I think the sum of all instances is such a popular topic. Its probably a case of iterating properly. In regards to the summing I would have use accumulate in c++, but do not know the equivalent of this in java (if there is one). Thank you for any advice/assistance in advance!
MORE CODE:
public class WeatherStation {
private ArrayList<MonthData> months;
private ArrayList<MonthData> rValue;
private ArrayList<MonthData> depthAdd;
MonthData is a model for data being read to this class it consists on a lot of getters....
public class MonthData {
int y;
int m;
float h;
...
public MonthData(String data) throws Exception {
...
this.parseData(data);
}
void parseData(String csvData) {
String[] parseResult = csvData.trim().split("\\s+");
this.setYear(parseResult[0]);
this.setMonth(parseResult[1]);
...
public String toString() {
return "y =" + year + ", m =" + month + ",...
}
public int getY() {
return y;
}
// followed by lots of getters for: m, h, c, f, r, s, ...
public MonthData depthValues() {
ArrayList<Float> rValue = new ArrayList<>();
for (int i = 0; i<months.size(); i++)
{
rValue.add(months.get(i).getDepthMM());
}
System.out.println(rValue);
System.out.println(rValue.size());
return null;
}
Code recommended:
public MonthData depthTotals() {
ArrayList<Float> depthAdd = new ArrayList<>();
Iterator<Float> it = rValue.iterator();
final int MAX = 12;
while (it.hasNext()){
float sum = 0f;
int counter = 1;
//iterating 12 times
//still check if there is an element in list
while (counter < MAX && it.hasNext()){
sum += it.next();
counter++;
}
depthAdd.add(sum);}
}
ISSUE: Iterator<Float> it = rValue.iterator();
Type mismatch: cannot convert from Iterator<MonthData> to Iterator<Float>
The best way to do this is using Iterator and a counter of 12 by using a while. Here's an example:
List<Float> yourList = ...;
// fill yourList
List<Float> results = new ArrayList<>();
Iterator<Float> it = yourList.iterator();
final int MAX = 12;
while (it.hasNext()) {
float sum = 0f;
int counter = 1;
//iterating 12 times
//still, check if there's an element in your list
while (counter <= MAX && it.hasNext()) {
sum += it.next();
counter++;
}
result.add(sum);
}
I would recommend you use double or Double instead of float as it has around half a trillion times the accuracy.
You can sum every block of 12 like this
public static List<Double> sumBlocks(List<Double> list, int blockSize) {
List<Double> ret = new ArrayList<>();
for(int i = 0; i < list.size(); i += blockSize) {
double sum = 0;
for(int j = 0, len = Math.min(list.size() - i, blockSize); j < len; j++)
sum += list.get(i + j);
ret.add(sum);
}
return ret;
}
and call
List<Double> sums = sumBlocks(list, 12);
Just to demonstrate yet another way to accomplish this:
public static List<Double> sumBlocks(List<Double> list, int blockSize) {
List<Double> result = new ArrayList<>();
double sum = 0d;
for (int i = 0; i < list.size(); i++) {
if (i > 0 && i % blockSize == 0) {
result.add(sum);
sum = 0d;
}
sum += list.get(i);
}
result.add(sum);
return result;
}
Lista<Double> list = // original list
List<Double> ret = new ArrayList<>();
int counter = 0;
double sum = 0;
for (Double f : list) {
if (counter == 12) {
sum = 0;
counter = 0;
ret.add(sum);
}
sum += f;
counter++;
}
// if list is not a multiple of 12
if (list.size() % 12 != 0) {
ret.add(sum);
}
return ret;
try this:
public float total;
for(int i; i < rValue.Size(); i ++)
{
total += rValue[i];
if(i%12=0)
{
add total to new ArrayList
total = 0;
}
}
Arraylist objects inherit the sublist(start, end) method from the List class. You can use myList.sublist(i, j) to access the sublist and get your sum. From there, it should be just simple arithmetic to get your iteration. Inside your for-loop, it should be: myList.sublist(i*12, i*12 + 12).
//Input list
ArrayList<Float> inputList = new ArrayList<Float>();
ArrayList<Float> result = new ArrayList<Float>();
int groupSize = 12;
int offset=0;
while(offset < inputList.size()) {
int toIndex = (inputList.size()-offset)>=groupSize? offset+groupSize : inputList.size();
result.add( listSum(inputList.subList(offset, toIndex)) );
offset += groupSize;
}
Helper method to add items in a list
static float listSum(List<Float> ar) {
float accumulator = 0f;
for(float item:ar) {
accumulator += item;
}
return accumulator;
}

Sorting an array on more than one criterion

I have this method to sort an array of objects by the variable id, there's name & GPA, too. How would you go about sorting the entire array of objects? Im only getting the id's sorted but the names when outputted are mixed. This is what I have thus far.
private Student[] st;
private int count;
public ProcessStudents() {
st = new Student[5];
count = 0;
public void sortAscendingID() {
for (int n = 0; n < count - 1; n++) {
int min = st[n].getId();
int index = n;
for (int o = n + 1; o < count; o++) {
if (st[o].getId() < min) {
min = st[o].getId();
index = o;
}
}
if (st[n].getId() > min) {
int p = st[n].getId();
st[n].setId(min);
st[index].setId(p);
}
}
}
}
If I were writing code for a production system rather than say homework or whatever I'd do this:
List<Student> list = new ArrayList<Student>(Arrays.asList(st));
Collections.sort(list);
Would implement Comparable and override its method:
#Override
public int compareTo(Object arg0) {
// return -1, 0 or 1 depending on compared fields.
// if(this.GetId()>((Student)arg0).GetId())
// ...
return 0;
}
...
Collections.sort(collectionOfStudentObjects);

Creating an Array with the same numbers from an old one but without repetitions

So I created an array with random numbers, i printed and counted the repeated numbers, now I just have to create a new array with the same numbers from the first array but without any repetitions. Can't use ArrayList by the way.
What I have is.
public static void main(String[] args) {
Random generator = new Random();
int aR[]= new int[20];
for(int i=0;i<aR.length;i++){
int number=generator.nextInt(51);
aR[i]=number;
System.out.print(aR[i]+" ");
}
System.out.println();
System.out.println();
int countRep=0;
for(int i=0;i<aR.length;i++){
for(int j=i+1;j<aR.length-1;j++){
if(aR[i]==aR[j]){
countRep++;
System.out.println(aR[i]+" "+aR[j]);
break;
}
}
}
System.out.println();
System.out.println("Repeated numbers: "+countRep);
int newaR[]= new int[aR.length - countRep];
}
Can someone help?
EDIT: Can't really use HashSet either. Also the new array needs to have the correct size.
Using Java 8 and streams you can do the following:
int[] array = new int[1024];
//fill array
int[] arrayWithoutDuplicates = Arrays.stream(array)
.distinct()
.toArray();
This will:
Turn your int[] into an IntStream.
Filter out all duplicates, so retaining distinct elements.
Save it in a new array of type int[].
Try:
Set<Integer> insertedNumbers = new HashSet<>(newaR.length);
int index = 0;
for(int i = 0 ; i < aR.length ; ++i) {
if(!insertedNumbers.contains(aR[i])) {
newaR[index++] = aR[i];
}
insertedNumbers.add(aR[i]);
}
One possible approach is to walk through the array, and for each value, compute the index at which it again occurs in the array (which is -1 if the number does not occur again). The number of values which do not occur again is the number of unique values. Then collect all values from the array for which the corresponding index is -1.
import java.util.Arrays;
import java.util.Random;
public class UniqueIntTest
{
public static void main(String[] args)
{
int array[] = createRandomArray(20, 0, 51);
System.out.println("Array " + Arrays.toString(array));
int result[] = computeUnique(array);
System.out.println("Result " + Arrays.toString(result));
}
private static int[] createRandomArray(int size, int min, int max)
{
Random random = new Random(1);
int array[] = new int[size];
for (int i = 0; i < size; i++)
{
array[i] = min + random.nextInt(max - min);
}
return array;
}
private static int[] computeUnique(int array[])
{
int indices[] = new int[array.length];
int unique = computeIndices(array, indices);
int result[] = new int[unique];
int index = 0;
for (int i = 0; i < array.length; i++)
{
if (indices[i] == -1)
{
result[index] = array[i];
index++;
}
}
return result;
}
private static int computeIndices(int array[], int indices[])
{
int unique = 0;
for (int i = 0; i < array.length; i++)
{
int value = array[i];
int index = indexOf(array, value, i + 1);
if (index == -1)
{
unique++;
}
indices[i] = index;
}
return unique;
}
private static int indexOf(int array[], int value, int offset)
{
for (int i = offset; i < array.length; i++)
{
if (array[i] == value)
{
return i;
}
}
return -1;
}
}
This sounds like a homework question, and if it is, the technique that you should pick up on is to sort the array first.
Once the array is sorted, duplicate entries will be adjacent to each other, so they are trivial to find:
int[] numbers = //obtain this however you normally would
java.util.Arrays.sort(numbers);
//find out how big the array is
int sizeWithoutDuplicates = 1; //there will be at least one entry
int lastValue = numbers[0];
//a number in the array is unique (or a first duplicate)
//if it's not equal to the number before it
for(int i = 1; i < numbers.length; i++) {
if (numbers[i] != lastValue) {
lastValue = i;
sizeWithoutDuplicates++;
}
}
//now we know how many results we have, and we can allocate the result array
int[] result = new int[sizeWithoutDuplicates];
//fill the result array
int positionInResult = 1; //there will be at least one entry
result[0] = numbers[0];
lastValue = numbers[0];
for(int i = 1; i < numbers.length; i++) {
if (numbers[i] != lastValue) {
lastValue = i;
result[positionInResult] = i;
positionInResult++;
}
}
//result contains the unique numbers
Not being able to use a list means that we have to figure out how big the array is going to be in a separate pass — if we could use an ArrayList to collect the results we would have only needed a single loop through the array of numbers.
This approach is faster (O(n log n) vs O (n^2)) than a doubly-nested loop through the array to find duplicates. Using a HashSet would be faster still, at O(n).

Categories