Constraining all combinations of an array-list - java

I know similar questions have been asked before but I have found the answers confusing. I am trying to make a program that will find every combination of an array-list with no repetitions and only of the maximum size. If the list has 4 items it should print out only the combinations with all 4 items present. This is what I have so far:
public main(){
UI.initialise();
UI.addButton("Test", this::testCreate);
UI.addButton("Quit", UI::quit);
}
public void createCombinations(ArrayList<String> list, String s, int depth) {
if (depth == 0) {
return;
}
depth --;
for (int i = 0; i < list.size(); i++) {
if (this.constrain(s + "_" + list.get(i), list.size())) {
UI.println(s + "_" + list.get(i));
}
createCombinations(list, s + "_" + list.get(i), depth);
}
}
public void testCreate() {
ArrayList<String> n = new ArrayList<String>();
n.add("A"); n.add("B"); n.add("C"); n.add("D");
this.createCombinations(n , "", n.size());
}
public boolean constrain(String s, int size) {
// Constrain to only the maximum length
if ((s.length() != size*2)) {
return false;
}
// Constrain to only combinations without repeats
Scanner scan = new Scanner(s).useDelimiter("_");
ArrayList<String> usedTokens = new ArrayList<String>();
String token;
while (scan.hasNext()) {
token = scan.next();
if (usedTokens.contains(token)) {
return false;
} else {
usedTokens.add(token);
}
}
// If we fully iterate over the loop then there are no repitions
return true;
}
public static void main(String[] args){
main obj = new main();
}
This prints out the following which is correct:
_A_B_C_D
_A_B_D_C
_A_C_B_D
_A_C_D_B
_A_D_B_C
_A_D_C_B
_B_A_C_D
_B_A_D_C
_B_C_A_D
_B_C_D_A
_B_D_A_C
_B_D_C_A
_C_A_B_D
_C_A_D_B
_C_B_A_D
_C_B_D_A
_C_D_A_B
_C_D_B_A
_D_A_B_C
_D_A_C_B
_D_B_A_C
_D_B_C_A
_D_C_A_B
_D_C_B_A
This works for small lists but is very inefficient for larger ones. I am aware that what I have done is completely wrong but I want to learn the correct way. Any help is really appreciated. Thanks in advance.
P.S. This is not homework, just for interest although I am a new CS student (if it wasn't obvious).

Implementing Heap's algorithm in Java:
import java.util.Arrays;
public class Main {
public static void swap(final Object[] array, final int index1, final int index2) {
final Object tmp = array[index1];
array[index1] = array[index2];
array[index2] = tmp;
}
public static void printPermutations_HeapsAlgorithm(final int n, final Object[] array) {
final int[] c = new int[n];
for (int i = 0; i < c.length; ++i)
c[i] = 0;
System.out.println(Arrays.toString(array)); //Consume first permutation.
int i=0;
while (i < n) {
if (c[i] < i) {
if ((i & 1) == 0)
swap(array, 0, i);
else
swap(array, c[i], i);
System.out.println(Arrays.toString(array)); //Consume permutation.
++c[i];
i=0;
}
else
c[i++] = 0;
}
}
public static void main(final String[] args) {
printPermutations_HeapsAlgorithm(4, new Character[]{'A', 'B', 'C', 'D'});
}
}
Possible duplicate of this.

Related

All Unique Permutations - Stack overflow issue

I am trying to solve the following problem:
Given a collection of numbers that might contain duplicates, return
all possible unique permutations.
Here is my code:
public class Solution {
public ArrayList<ArrayList<Integer>> permute(ArrayList<Integer> a) {
HashMap<ArrayList<Integer>, Boolean> unique = new HashMap<>();
ArrayList<ArrayList<Integer>> results = new ArrayList<>();
permu(results, a, 0, unique);
return results;
}
private void permu(ArrayList<ArrayList<Integer>> results, final ArrayList<Integer> a, int item, HashMap<ArrayList<Integer>, Boolean> unique) {
for(int i = 0; i < a.size(); i++) {
ArrayList<Integer> aClone = new ArrayList<>(a);
// swap
int backup = aClone.get(i);
aClone.set(i, aClone.get(item));
aClone.set(item, backup);
if(!unique.containsKey(aClone)) {
results.add(aClone);
unique.put(aClone, true);
permu(results, aClone, i, unique); //<--- Stack overflow error
}
}
}
}
I have a stack overflow error on this the call to the recurrence, line (19)
Well, I don't like to ruin good job interview questions, but this question was fun to think about, so...
Here's a super-L337 answer for generating all unique permutations very quickly and without using much memory or stack. If you use this in a job interview, the interviewer will ask you to explain how it works. If you can do that, then you deserve it :)
Note that I permuted the chars in a string instead of the instead of integers in a list, just because it's easier to pretty-print the result.
import java.util.Arrays;
import java.util.function.Consumer;
public class UniquePermutations
{
static void generateUniquePermutations(String s, Consumer<String> consumer)
{
char[] array = s.toCharArray();
Arrays.sort(array);
for (;;)
{
consumer.accept(String.valueOf(array));
int changePos=array.length-2;
while (changePos>=0 && array[changePos]>=array[changePos+1])
--changePos;
if (changePos<0)
break; //all done
int swapPos=changePos+1;
while(swapPos+1 < array.length && array[swapPos+1]>array[changePos])
++swapPos;
char t = array[changePos];
array[changePos] = array[swapPos];
array[swapPos] = t;
for (int i=changePos+1, j = array.length-1; i < j; ++i,--j)
{
t = array[i];
array[i] = array[j];
array[j] = t;
}
}
}
public static void main (String[] args) throws java.lang.Exception
{
StringBuilder line = new StringBuilder();
generateUniquePermutations("banana", s->{
if (line.length() > 0)
{
if (line.length() + s.length() >= 75)
{
System.out.println(line.toString());
line.setLength(0);
}
else
line.append(" ");
}
line.append(s);
});
System.out.println(line);
}
}
Here is the output:
aaabnn aaanbn aaannb aabann aabnan aabnna aanabn aananb aanban aanbna
aannab aannba abaann abanan abanna abnaan abnana abnnaa anaabn anaanb
anaban anabna ananab ananba anbaan anbana anbnaa annaab annaba annbaa
baaann baanan baanna banaan banana bannaa bnaaan bnaana bnanaa bnnaaa
naaabn naaanb naaban naabna naanab naanba nabaan nabana nabnaa nanaab
nanaba nanbaa nbaaan nbaana nbanaa nbnaaa nnaaab nnaaba nnabaa nnbaaa

Altering the value of k in kNN algorithm - Java

I have applied the KNN algorithm for classifying handwritten digits. the digits are in vector format initially 8*8, and stretched to form a vector 1*64..
As it stands my code applies the kNN algorithm but only using k = 1. I'm not entirely sure how to alter the value k after attempting a couple of things I kept getting thrown errors. If anyone could help push me in the right direction it would be really appreciated. The training dataset can be found here and the validation set here.
ImageMatrix.java
import java.util.*;
public class ImageMatrix {
private int[] data;
private int classCode;
private int curData;
public ImageMatrix(int[] data, int classCode) {
assert data.length == 64; //maximum array length of 64
this.data = data;
this.classCode = classCode;
}
public String toString() {
return "Class Code: " + classCode + " Data :" + Arrays.toString(data) + "\n"; //outputs readable
}
public int[] getData() {
return data;
}
public int getClassCode() {
return classCode;
}
public int getCurData() {
return curData;
}
}
ImageMatrixDB.java
import java.util.*;
import java.io.*;
import java.util.ArrayList;
public class ImageMatrixDB implements Iterable<ImageMatrix> {
private List<ImageMatrix> list = new ArrayList<ImageMatrix>();
public ImageMatrixDB load(String f) throws IOException {
try (
FileReader fr = new FileReader(f);
BufferedReader br = new BufferedReader(fr)) {
String line = null;
while((line = br.readLine()) != null) {
int lastComma = line.lastIndexOf(',');
int classCode = Integer.parseInt(line.substring(1 + lastComma));
int[] data = Arrays.stream(line.substring(0, lastComma).split(","))
.mapToInt(Integer::parseInt)
.toArray();
ImageMatrix matrix = new ImageMatrix(data, classCode); // Classcode->100% when 0 -> 0% when 1 - 9..
list.add(matrix);
}
}
return this;
}
public void printResults(){ //output results
for(ImageMatrix matrix: list){
System.out.println(matrix);
}
}
public Iterator<ImageMatrix> iterator() {
return this.list.iterator();
}
/// kNN implementation ///
public static int distance(int[] a, int[] b) {
int sum = 0;
for(int i = 0; i < a.length; i++) {
sum += (a[i] - b[i]) * (a[i] - b[i]);
}
return (int)Math.sqrt(sum);
}
public static int classify(ImageMatrixDB trainingSet, int[] curData) {
int label = 0, bestDistance = Integer.MAX_VALUE;
for(ImageMatrix matrix: trainingSet) {
int dist = distance(matrix.getData(), curData);
if(dist < bestDistance) {
bestDistance = dist;
label = matrix.getClassCode();
}
}
return label;
}
public int size() {
return list.size(); //returns size of the list
}
public static void main(String[] argv) throws IOException {
ImageMatrixDB trainingSet = new ImageMatrixDB();
ImageMatrixDB validationSet = new ImageMatrixDB();
trainingSet.load("cw2DataSet1.csv");
validationSet.load("cw2DataSet2.csv");
int numCorrect = 0;
for(ImageMatrix matrix:validationSet) {
if(classify(trainingSet, matrix.getData()) == matrix.getClassCode()) numCorrect++;
} //285 correct
System.out.println("Accuracy: " + (double)numCorrect / validationSet.size() * 100 + "%");
System.out.println();
}
In the for loop of classify you are trying to find the training example that is closest to a test point. You need to switch that with a code that finds K of the training points that is the closest to the test data. Then you should call getClassCode for each of those K points and find the majority(i.e. the most frequent) of the class codes among them. classify will then return the major class code you found.
You may break the ties (i.e. having 2+ most frequent class codes assigned to equal number of training data) in any way that suits your need.
I am really inexperienced in Java, but just by looking around the language reference, I came up with the implementation below.
public static int classify(ImageMatrixDB trainingSet, int[] curData, int k) {
int label = 0, bestDistance = Integer.MAX_VALUE;
int[][] distances = new int[trainingSet.size()][2];
int i=0;
// Place distances in an array to be sorted
for(ImageMatrix matrix: trainingSet) {
distances[i][0] = distance(matrix.getData(), curData);
distances[i][1] = matrix.getClassCode();
i++;
}
Arrays.sort(distances, (int[] lhs, int[] rhs) -> lhs[0]-rhs[0]);
// Find frequencies of each class code
i = 0;
Map<Integer,Integer> majorityMap;
majorityMap = new HashMap<Integer,Integer>();
while(i < k) {
if( majorityMap.containsKey( distances[i][1] ) ) {
int currentValue = majorityMap.get(distances[i][1]);
majorityMap.put(distances[i][1], currentValue + 1);
}
else {
majorityMap.put(distances[i][1], 1);
}
++i;
}
// Find the class code with the highest frequency
int maxVal = -1;
for (Entry<Integer, Integer> entry: majorityMap.entrySet()) {
int entryVal = entry.getValue();
if(entryVal > maxVal) {
maxVal = entryVal;
label = entry.getKey();
}
}
return label;
}
All you need to do is adding K as a parameter. Keep in mind, however, that the code above does not handle ties in a particular way.

recursive method not properly executing

I have a programming assignment for an introductory level Java class (the subset sum problem) - for some reason, my recursive method isn't executing properly (it just goes straight to the end of the method and prints out the sorted list). Any help would be appreciated - I'm a newbie and recursive functions are really confusing to me.
package programmingassignment3;
import java.io.*;
import java.util.*;
public class ProgrammingAssignment3 {
static int TARGET = 10;
static ArrayList<Integer> list = new ArrayList<>();
static int SIZE = list.size();
public static void main(String[] args) {
populateSortSet();
sumInt(list);
recursiveSS(list);
}//main
public static void populateSortSet() {
try {
File f = new File("set0.txt");
Scanner input = new Scanner(f);
while (input.hasNext()) {
int ele = input.nextInt();
if (ele < TARGET && !list.contains(ele)) {
list.add(ele);
}//if
}//while
Collections.sort(list);
}//try
catch (IOException e) {
e.printStackTrace();
}//catch
}//populateSet
public static void recursiveSS(ArrayList<Integer> Alist) {
if (Alist.size() == SIZE) {
if (sumInt(Alist) == TARGET) {
System.out.println("The integers that equal " + TARGET + "are: " + Alist);
} //if==TARGET
}//if==SIZE
else {
for (int i = 0; i < SIZE; i++) {
ArrayList<Integer> list1 = new ArrayList<>(Alist);
ArrayList<Integer> list0 = new ArrayList<>(Alist);
list1.add(1);
list0.add(0);
if (sumInt(list0) < TARGET) {
recursiveSS(list0);
}//if
if (sumInt(list1) < TARGET) {
recursiveSS(list1);
}//if
}//for
}//else
System.out.println("echo" + Alist);
}//recursiveSS
public static int sumInt(ArrayList<Integer> Alist) {
int sum = 0;
for (int i = 0; i < SIZE - 1; i++) {
sum += Alist.get(i);
}//for
if (Alist.size() == TARGET) {
sum += Alist.get(Alist.size() - 1);
}//if
return sum;
}//sumInt
}//class
This thing that you do at class level:
static ArrayList<Integer> list = new ArrayList<>();
static int SIZE = list.size();
means that SIZE will be initiated to 0, and stay 0 (even if you add elements to the list.)
This means that the code inside the for-loop will be executed 0 times.
Try something like:
public class ProgrammingAssignment3 {
private static int initialSize;
//...
public static void populateSortSet() {
//populate the list
initialSize = list.size();
}
So you don't set the value of the size variable until the list is actually populated.
That being said, there a quite a few other strange things in your code, so I think you need to specify exactly what you are trying to solve here.
Here's how I'd do it. I hope it clarifies the stopping condition and the recursion. As you can see, static methods are not an issue:
import java.util.ArrayList;
import java.util.List;
/**
* Demo of recursion
* User: mduffy
* Date: 10/3/2014
* Time: 10:56 AM
* #link http://stackoverflow.com/questions/26179574/recursive-method-not-properly-executing?noredirect=1#comment41047653_26179574
*/
public class RecursionDemo {
public static void main(String[] args) {
List<Integer> values = new ArrayList<Integer>();
for (String arg : args) {
values.add(Integer.valueOf(arg));
}
System.out.println(String.format("input values : %s", values));
System.out.println(String.format("iterative sum: %d", getSumUsingIteration(values)));
System.out.println(String.format("recursive sum: %d", getSumUsingRecursion(values)));
}
public static int getSumUsingIteration(List<Integer> values) {
int sum = 0;
if (values != null) {
for (int value : values) {
sum += value;
}
}
return sum;
}
public static int getSumUsingRecursion(List<Integer> values) {
if ((values == null) || (values.size() == 0)) {
return 0;
} else {
if (values.size() == 1) { // This is the stopping condition
return values.get(0);
} else {
return values.get(0) + getSumUsingRecursion(values.subList(1, values.size())); // Here is recursion
}
}
}
}
Here is the case I used to test it:
input values : [1, 2, 3, 4, 5, 6]
iterative sum: 21
recursive sum: 21
Process finished with exit code 0
Thanks everyone. I really appreciate the help. I did figure out the problem and the solution is as follows (closing brace comments removed for the reading pleasure of #duffymo ):
public class ProgrammingAssignment3 {
static int TARGET = 6233;
static ArrayList<Integer> set = new ArrayList<>();
static int SIZE;
static int count = 0;
public static void populateSortSet() {
try {
File f = new File("set3.txt");
Scanner input = new Scanner(f);
while (input.hasNext()) {
int ele = input.nextInt();
if (ele < TARGET && !set.contains(ele)) {
set.add(ele);
}
}
Collections.sort(set);
SIZE = set.size();
System.out.println("The original sorted set: " + set + "\t subset sum = " + TARGET);
}
catch (IOException e) {
e.printStackTrace();
}
}
public static void recursiveSS(ArrayList<Integer> list) {
if (list.size() == SIZE) {
if (sumInt(list) == TARGET) {
System.out.print("The Bit subset is: " + list + "\t");
System.out.println("The subset is: " + getSubset(list));
count++;
}
}
else {
ArrayList<Integer> list1 = new ArrayList<>(list);//instantiate list1
ArrayList<Integer> list0 = new ArrayList<>(list);//instantiate list0
list1.add(1);
list0.add(0);
if (sumInt(list0) <= TARGET) {
recursiveSS(list0);
}
if (sumInt(list1) <= TARGET) {
recursiveSS(list1);
}
}
}
public static int sumInt(ArrayList<Integer> list) {
int sum = 0;
for (int i = 0; i < list.size(); i++) {
if (list.get(i) == 1) {
sum += set.get(i);
}
}
return sum;
}
public static ArrayList<Integer> getSubset(ArrayList<Integer> list) {
ArrayList<Integer> l = new ArrayList<>();
for (int i = 0; i < list.size(); i++) {
if (list.get(i) == 1) {
l.add(set.get(i));
}
}
return l;
}
}

How to find N grams of a word in Java?

For example if the input is "name" and the minGram is 1 and maxGramSize is 2 output will consist of n,a,m,e,na,am,me. If the minGram=2, maxGram=4 inputWord=name, output = na,am,me,nam,ame,name.
Function signature can be something like this:
public List<String> generateNGrams(String input, int minGramSize, int maxGramSize)
Initially I tried doing it with for loops, but I was finding it hard to follow the indices. Then I tried solving it using recursion with pen and paper but I'm still struggling with it. Can someone help me with this?
One solution:
private static void addNgrams(final int size, final String input,
final List<String> list)
{
final int maxStartIndex = input.length() - size;
for (int i = 0; i < maxStartIndex; i++)
list.add(input.stubString(i, i + size));
}
public List<String> generateNGrams(final String input, final int minSize,
final int maxSize)
{
final List<String> ret = new ArrayList<>();
for (int size = minSize; size <= maxSize; size++)
addNgrams(size, input, ret);
return ret;
}
Note: lacks basic error checkings (for instance, maxSize greater than the size of input; minSize greater than maxSize; others); left as an exercise.
Here is a program that recursively generates nGrams: This code also handles the tail grams.
import java.util.ArrayList;
public class NGrams {
ArrayList<String> nGrams = new ArrayList<String>();
public void generateNGrams(String str, int n) {
if (str.length() == n ) {
int counter = 0;
while (counter < n) {
nGrams.add(str.substring(counter));
counter++;
}
return;
}
int counter = 0;
String gram = "";
while (counter < n) {
gram += str.charAt(counter);
counter++;
}
nGrams.add(gram);
generateNGrams(str.substring(1), n);
}
public void printNGrams() {
for (String str : nGrams) {
System.out.println(str);
}
}
public static void main(String[] args) {
NGrams ng = new NGrams();
ng.generateNGrams("hello world", 3);
ng.printNGrams();
}
}
Output:
hel
ell
llo
lo
o w
wo
wor
orl
rld
ld
d

Mergesort Implementation.. Counting number of inversions in an array

I'm taking an online class on Algorithms and trying to implement a mergesort implementation of finding the number of inversions in a list of numbers. But, I cant figure what Im doing wrong with my implementation as the number of inversions returned is significantly lower than the number I get while doing a brute force approach. Ive placed my implementation of the mergesort approach below
/**
*
*/
package com.JavaReference;
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
public class ReadFile {
public static void main(String args[]){
int count=0;
Integer n[];
int i=0;
try{
n=OpenFile();
int num[] = new int[n.length];
for (i=0;i<n.length;i++){
num[i]=n[i].intValue();
// System.out.println( "Num"+num[i]);
}
count=countInversions(num);
}
catch(IOException e){
e.printStackTrace();
}
System.out.println(" The number of inversions"+count);
}
public static Integer[] OpenFile()throws IOException{
FileReader fr=new FileReader("C:/IntegerArray.txt");// to put in file name.
BufferedReader textR= new BufferedReader(fr);
int nLines=readLines();
System.out.println("Number of lines"+nLines);
Integer[] nData=new Integer[nLines];
for (int i=0; i < nLines; i++) {
nData[ i ] = Integer.parseInt((textR.readLine()));
}
textR.close();
return nData;
}
public static int readLines() throws IOException{
FileReader fr=new FileReader("C:/IntegerArray.txt");
BufferedReader br=new BufferedReader(fr);
int numLines=0;
//String aLine;
while(br.readLine()!=null){
numLines++;
}
System.out.println("Number of lines readLines"+numLines);
return numLines;
}
public static int countInversions(int num[]){
int countLeft,countRight,countMerge;
int mid=num.length/2,k;
if (num.length<=1){
return 0;// Number of inversions will be zero for an array of this size.
}
int left[]=new int[mid];
int right[]=new int [num.length-mid];
for (k=0;k<mid;k++){
left[k]=num[k];
}
for (k=0;k<mid;k++){
right[k]=num[mid+k];
}
countLeft=countInversions(left);
countRight=countInversions(right);
int[] result=new int[num.length];
countMerge=mergeAndCount(left,right,result);
/*
* Assign it back to original array.
*/
for (k=0;k<num.length;k++){
num[k]=result[k];
}
return(countLeft+countRight+countMerge);
}
private static int mergeAndCount(int left[],int right[],int result[]){
int count=0;
int a=0,b=0,i,k=0;
while((a<left.length)&&(b<right.length)){
if(left[a]<right[b]){
result[k]=left[a++];// No inversions in this case.
}
else{// There are inversions.
result[k]=right[b++];
count+=left.length-a;
}
k++;
// When we finish iterating through a.
if(a==left.length){
for (i=b;i<right.length;i++){
result[k++]=right[b];
}
}
else{
for (i=a;i<left.length;i++){
}
}
}
return count;
}
}
I'm a beginner in Java and Algorithms so any insightful suggestions would be great!
I found two bugs:
In countInversions(), when num is split into left and right you assume right has m elements. When num.length is odd, however, it will be m + 1 elements. The solution is to use right.length instead of m.
In mergeAndCount(), handling of the bit where one subarray is empty and the other one still has some elements is not done correctly.
Side note:
There is absolutely no reason to use Integer in your program, except for the Integer.parseInt() method (which, by the way, returns an int).
Corrected code:
/**
*
*/
package com.JavaReference;
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
public class ReadFile {
public static void main(String args[]){
int count=0;
Integer n[];
int i=0;
try{
n=OpenFile();
int num[] = new int[n.length];
for (i=0;i<n.length;i++){
num[i]=n[i].intValue();
// System.out.println( "Num"+num[i]);
}
count=countInversions(num);
}
catch(IOException e){
e.printStackTrace();
}
System.out.println(" The number of inversions"+count);
}
public static Integer[] OpenFile()throws IOException{
FileReader fr=new FileReader("C:/IntegerArray.txt");// to put in file name.
BufferedReader textR= new BufferedReader(fr);
int nLines=readLines();
System.out.println("Number of lines"+nLines);
Integer[] nData=new Integer[nLines];
for (int i=0; i < nLines; i++) {
nData[ i ] = Integer.parseInt((textR.readLine()));
}
textR.close();
return nData;
}
public static int readLines() throws IOException{
FileReader fr=new FileReader("C:/IntegerArray.txt");
BufferedReader br=new BufferedReader(fr);
int numLines=0;
//String aLine;
while(br.readLine()!=null){
numLines++;
}
System.out.println("Number of lines readLines"+numLines);
return numLines;
}
public static int countInversions(int num[]){
int countLeft,countRight,countMerge;
int mid=num.length/2,k;
if (num.length<=1){
return 0;// Number of inversions will be zero for an array of this size.
}
int left[]=new int[mid];
int right[]=new int [num.length-mid];
for (k=0;k<mid;k++){
left[k]=num[k];
}
// BUG 1: you can't assume right.length == m
for (k=0;k<right.length;k++){
right[k]=num[mid+k];
}
countLeft=countInversions(left);
countRight=countInversions(right);
int[] result=new int[num.length];
countMerge=mergeAndCount(left,right,result);
/*
* Assign it back to original array.
*/
for (k=0;k<num.length;k++){
num[k]=result[k];
}
return(countLeft+countRight+countMerge);
}
private static int mergeAndCount(int left[],int right[],int result[]){
int count=0;
int a=0,b=0,i,k=0;
while((a<left.length)&&(b<right.length)){
if(left[a]<right[b]){
result[k]=left[a++];// No inversions in this case.
}
else{// There are inversions.
result[k]=right[b++];
count+=left.length-a;
}
k++;
}
// BUG 2: Merging of leftovers should be done like this
while (a < left.length)
{
result[k++] = left[a++];
}
while (b < right.length)
{
result[k++] = right[b++];
}
return count;
}
}
The way I see it, counting the number of inversions in an array is finding a way to sort the array in an ascending order. Following that thought, here is my solution:
int countInversionArray(int[] A) {
if(A.length<=1) return 0;
int solution = 0;
for(int i=1;i<A.length;i++){
int j = i;
while(j+2<A.length && A[j] > A[j+1]){
invert2(j,j+1,A);
solution++;
j++;
}
j=i;
while(j>0 && A[j] < A[j-1]){
invert2(j,j-1,A);
solution++;
j--;
}
}
return solution;
}
private void invert2(int index1, int index2, int[] A){
int temp = A[index1];
A[index1] = A[index2];
A[index2] = temp;
}
I found a rigth solution in Robert Sedgewick book "Algorithms on java language"
Read here about merge
See java code for counting of inversion
You can try this In-Place Mergesort implemention on java. But minimum 1 temporary data container is needed (ArrayList in this case). Also counts inversions.
///
Sorter.java
public interface Sorter {
public void sort(Object[] data);
public void sort(Object[] data, int startIndex, int len);
}
MergeSorter implementation class (others like QuickSorter, BubbleSorter or InsertionSorter may be implemented on Sorter interface)
MergeSorter.java
import java.util.List;
import java.util.ArrayList;
public class MergeSorter implements Sorter {
private List<Comparable> dataList;
int num_inversion;
public MergeSorter() {
dataList = new ArrayList<Comparable> (500);
num_inversion = 0;
}
public void sort(Object[] data) {
sort(data, 0, data.length);
}
public int counting() {
return num_inversion;
}
public void sort(Object[] data, int start, int len) {
if (len <= 1) return;
else {
int midlen = len / 2;
sort(data, start, midlen);
sort(data, midlen + start, len - midlen);
merge(data, start, midlen, midlen + start, len - midlen);
}
}
private void merge(Object[] data, int start1, int len1, int start2, int len2) {
dataList.clear();
int len = len1 + len2;
// X is left array pointer
// Y is right array pointer
int x = start1, y = start2;
int end1 = len1 + start1 - 1;
int end2 = len2 + start2 - 1;
while (x <= end1 && y <= end2) {
Comparable obj1 = (Comparable) data[x];
Comparable obj2 = (Comparable) data[y];
Comparable<?> smallobject = null;
if (obj1.compareTo(obj2) < 0) {
smallobject = obj1;
x++;
}
else {
smallobject = obj2;
y++;
num_inversion += (end1 - x + 1);
}
dataList.add(smallobject);
}
while (x <= end1) {
dataList.add((Comparable)data[x++]);
}
while (y <= end2) {
dataList.add((Comparable)data[y++]);
}
for (int n = start1, i = 0; n <= end2; n++, i++) {
data[n] = dataList.get(i);
}
}
}
For testing, create a driver class and type the main method
public static void main(String[] args) {
Object[] data = ...............
Sorter sorter = new MergeSorter();
sorter.sort(data)
for (Object x : data) {
System.out.println(x);
}
System.out.println("Counting invertion: " + ((MergeSorter)sorter).counting());
}

Categories