Showing posts with label java. Show all posts
Showing posts with label java. Show all posts

Friday, September 20, 2013

Java: Get Instance of Inner Class


Today my good unpredictable friend Mishuk gave me a piece of Java code which is full of nested classes. I was not surprised at all as I already know his love for inner classes. Then he asked me whether it is possible to call a method from the innermost class, i.e. is it possible to get an instance of the nested classes. At first I thought how hard could it be, but it eventually turned out to be thought provoking. It was not as straight forward for me as I thought (I won't deny, I know a very little Java, which is why this little bit of trick had surprised me). So I just wanted to put it up here for future references.

The class he gave me follows:

class A {
    String name="A";
   
    public class B {
        String name="B";
       
        public class C {
            String name= "C";
           
            public void print(String name){
                System.out.println(name);
                System.out.println(C.this.name);
                System.out.println(B.this.name);
                System.out.println(A.this.name);                               
            }
        }
    }
}

As there was a restriction that the above code can't be modified, the only way to do this is to somehow get instances in a hierarchical manner. Because you cannot get instances of B without creating an instance of A and so on. But Java has a cool thing called reflection, and using reflection, it is possible to get instances from the inner class as well. So here is how the print() method from class C can be called. The idea is to create instances following the hierarchical order and then use the last one. Now it seems easy!

import java.lang.reflect.*;

class Main {
    public static void main(String[] args) throws Exception {
        Class classAB = A.B.class;
        Class classABC = A.B.C.class;
        Constructor constructorAB = classAB.getConstructor(A.class);
        Constructor constructorABC = classABC.getConstructor(A.B.class);
        A instanceA = new A();
        A.B instanceAB = constructorAB.newInstance(instanceA);
        A.B.C instanceABC = constructorABC.newInstance(instanceAB);
        instanceABC.print("JAVA SUCKS WITHOUT REFLECTION");
    }
}

Oh, one more thing, for those who don't know this yet and too lazy to run some Java codes, here is the output:

JAVA SUCKS WITHOUT REFLECTION
C
B
A

Yah I know this may be done in hundreds of different ways and exceptions should be handled and and and and .... who cares?


Friday, December 14, 2012

Apriori in Java (Part 2)


(Part 1)

Apriori Algorithm:

The algorithm works as follows: first it generates all the frequent itemsets of length 1 w.r.t. the given threshold (minimum support). Then it continue to generate itemsets of lengths 2,3, ... ,n if possible. There are lots of improvements and pruning possible in the implementation.

Do we need to sort frequently? First observation is, if the items are taken in sorted order on step k = 1, all the frequent patterns generated in future will also be in sorted order if maintained properly. So this eliminates the necessity of sorting or storing itemsets in logarithmic data structures like map or set. Rather, we can store them in arraylist or vector like data structure.

How do we generate itemsets of length k+1? We generate itemsets of length k+1 by merging two itemsets of length k. If two itemsets I1 and I2 have a common prefix of length k-1, and I1[k] < I2[k], we can take I1[1 ... k-1] I1[k] I2[k] which is an itemset of length k+1. As our itemsets are sorted, and frequent itemsets generated are also sorted, this can be done in O(N*K^2). Well, if we follow the naive approach, it will take O(N*K^3), however, as we can pre-calculate the length of common prefix of consecutive items in O(N*K), later, we can use this to perform joining operation stated above and also do early termination rather than looking for the entire N items. The approach is demonstrated in source code.

What are the prunings? The most important observation on apriori algorithm is, if an itemset is not frequent, none of its superset can be frequent. Which also tells us, if an itemset has to be frequent, all of its subset must be frequent. Well, the first one is automatically checked in the algorithm. As it takes the frequent itemsets of previous step to calculate itemsets of current step. Now, how the second rule is checked? Well, we don't need to check all the subsets really, all we need is to check the subsets of length k-1 for step k, which can be easily done by performing manual hashing, or using java hashmap. This saves a lots of hassles.

/*
Author: Zobayer Hasan
*/
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;

public class Apriori extends Thread {
    public static boolean debugger = false;
    
    private final Database db;
    private final List< Integer > itemset;
    private final List< List< Integer > > frequent;
    private double minsup;

    public Apriori(String thrName, Database db, double minsup) {
        super(thrName);
        this.db = db;
        itemset = db.getItemset();
        frequent = new ArrayList< List< Integer > >();
        this.minsup = minsup;
    }
    
    @Override
    public void run() {
        double startTime = System.currentTimeMillis();
        
        int k = 1, n = db.dbSize();
        List< List< Integer > > Ck = new ArrayList< List< Integer > >();
        List< List< Integer > > Lk = new ArrayList< List< Integer > >();
        HashMap< List< Integer>, Integer > seenK = new HashMap< List< Integer >, Integer >();
        
        for(Integer item : itemset) {
            List< Integer > temp = new ArrayList< Integer >();
            temp.add(item);
            Lk.add(temp);
        }
        
        while(k <= n && !Lk.isEmpty()) {
            if(debugger) {
                System.out.println("Step " + k);
                System.out.println("Lk: " + Lk);
            }
            
            seenK.clear();
            Ck.clear();
            for(List< Integer > kth : Lk) {
                int count = db.scanDatabase(kth);
                if((double)count < Math.ceil(minsup * (double)n / 100.0)) continue;
                Ck.add(kth);
            }
            
            if(debugger) {
                System.out.println("Ck: " + Ck);
            }
            
            if(Ck.isEmpty()) break;
            
            for(List< Integer > freq : Ck) {
                frequent.add(freq);
                seenK.put(freq, k);
            }
            
            int[] prefixlen = new int[Ck.size()];
            prefixlen[0] = 0;
            for(int i = 1; i < Ck.size(); i++) {
                prefixlen[i] = prefixLen(Ck.get(i-1), Ck.get(i));
            }
            
            List< List< Integer > > temp = new ArrayList< List< Integer > >();
            for(int i = 0; i < Ck.size(); i++) {
                for(int j = i + 1; j < Ck.size(); j++) {
                    if(prefixlen[j] == k-1) {
                        if(debugger) {
                            System.out.println("Joining: " + i + ":" + Ck.get(i) + " + " + j + ":" + Ck.get(j) + " Prefix Length " + prefixlen[j]);
                        }
                        temp.add(prefixJoin(Ck.get(i), Ck.get(j)));
                    }
                    else break;
                }
            }
            
            if(debugger) {
                System.out.println("Temporary: " + temp);
            }

            Lk.clear();
            for(List< Integer > list : temp) {
                boolean candid = true;
                if(k > 1) {
                    for(int i = 0; i < list.size(); i++) {
                        List< Integer > prev = new ArrayList< Integer >();
                        for(int j = 0; j < list.size(); j++) {
                            if(i != j) prev.add(list.get(j));
                        }
                        if(!seenK.containsKey(prev)) {
                            candid = false;
                            break;
                        }
                    }
                }
                if(candid) {
                    Lk.add(list);
                }
            }
            
            if(debugger) {
                System.out.println("Pruned: " + Lk);
            }
            
            k++;
        }
        
        double endTime = System.currentTimeMillis();
        System.out.println("Apriori completed in " + (endTime - startTime)/1000.0 + " seconds");
    }
    
    public void printPatterns() {
        System.out.println("Frequent Itemsets");
        for(List< Integer > pattern : frequent) {
            System.out.println(pattern);
        }
        System.out.println("Total " + frequent.size() + " itemsets");
    }
    
    private int prefixLen(List< Integer > left, List< Integer > right) {
        int len = 0;
        for(len = 0; len < left.size() && len < right.size(); len++) {
            if(left.get(len).compareTo(right.get(len)) != 0) return len;
        }
        return len;
    }
    
    private List< Integer > prefixJoin(List< Integer > left, List< Integer > right) {
        List< Integer > ret = new ArrayList< Integer >();
        for(Integer i : left) {
            ret.add(i);
        }
        ret.add(right.get(right.size() - 1));
        return ret;
    }
}
This class is threaded, so it is possible to take advantages of multicore processors.

A sample test class is shown here.
/*
Author: Zobayer Hasan
*/
public class FIMtest {

    public static void main(String[] args) {
        Database db = null;
        try {
            db = new Database("mushroom.dat");
            
        } catch(Exception e) {
            e.printStackTrace();
        }
        
        System.out.println("\nStarting Apriori");
        
        Apriori test1 = new Apriori("test1", db, 40.0);
        Apriori.debugger = true;
        test1.start();
        try {
            test1.join();
            test1.printPatterns();
        } catch(Exception e) {
            e.printStackTrace();
        }
    }
}

So, this is it, an efficient implementation of Apriori algorithm in java. It is possible that there are some lacking or mistakes in either source code or analysis. If you find any, please let me know. Here is a sample run on mushroom for 40% minimum support.

Have fun...

Thursday, December 13, 2012

Apriori in Java (Part 1)


Introduction:

Apriori is a very basic and straight forward algorithm for frequent pattern mining, I will not be discussing much about the approach, as those can already be studied from different lectures/books available on net. I will basically present an implementation of mine which is an efficient implementation of the standard apriori algorithm in Java. The target input files are taken from Frequent Itemset Mining Dataset Repository, for example, the mushroom dataset. Due to the space and runtime complexity, apriori is not suitable for larger files having 50,000 records or so. It also may take huge time for very dense files.

The Database:

First we need to read the files and store them in some data structure which will be easy to access and efficient at the same time. Here. I am presenting my java source code, and then I will present an explaining analysis why this works better.
/*
Author: Zobayer Hasan
*/

import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.PriorityQueue;

class Entry {
    public Integer first;
    public Integer second;
    Entry() {}
    Entry(Integer first, Integer second) {
        this.first = first;
        this.second = second;
    }
}

public class Database {
    public static boolean debugger = false;
    
    private final List< List< Integer > > transactions;
    private final List< Integer > items;

    public Database(String dataFileName) throws Exception {
        if(debugger) {
            System.out.println("Processing " + dataFileName);
        }
        
        transactions = new ArrayList< List< Integer > >();
        items = new ArrayList< Integer >();
        
        FileInputStream fin = new FileInputStream(dataFileName);
        InputStreamReader istream = new InputStreamReader(fin);
        BufferedReader stdin = new BufferedReader(istream);
        
        String line;
        
        double startTime = System.currentTimeMillis();
        
        while((line = stdin.readLine()) != null) {
            List< Integer > transaction = new ArrayList< Integer >();
            String[] temp = line.split("\\s+");
            
            for(String num : temp) {
                transaction.add(Integer.parseInt(num));
            }
            
            if(transaction.isEmpty()) continue;
            
            Collections.sort(transaction);
            transactions.add(transaction);
        }
        
        fin.close();
        istream.close();
        stdin.close();
        
        int n = transactions.size();
        int[] header = new int[n];
        PriorityQueue< Entry > pQ = new PriorityQueue< Entry >(n, new Comparator< Entry >() {
            public int compare(Entry item1, Entry item2) {
                if(item1.first.equals(item2.first)) {
                    return item1.second.compareTo(item2.second);
                } else {
                    return item1.first.compareTo(item2.first);
                }
            }
        });
        
        for(int i = 0; i < n; i++) {
            header[i] = 0;
            pQ.add(new Entry(transactions.get(i).get(header[i]), i));
        }
        
        while(!pQ.isEmpty()) {
            Entry peek = pQ.remove();
            int val = peek.first;
            int idx = peek.second;
            if(items.isEmpty() || items.get(items.size()-1) < val) {
                items.add(val);
            }
            while(header[idx] < transactions.get(idx).size() && transactions.get(idx).get(header[idx]) <= val) {
                header[idx]++;
            }
            if(header[idx] < transactions.get(idx).size()) {
                pQ.add(new Entry(transactions.get(idx).get(header[idx]), idx));
            }
        }
        
        double endTime = System.currentTimeMillis();
        System.out.println("Database created in " + (endTime - startTime)/1000.0 + " seconds");
    }
    
    public int scanDatabase(List< Integer > transaction) {
        int count = 0;
        for(List< Integer > row : transactions) {
            boolean found = true;
            for(Integer item : transaction) {
                int idx, stp, st = 0, en = row.size(), cnt = en - st;
                while(cnt > 0) {
                    stp = cnt >> 1; idx = st + stp;
                    if(row.get(idx).compareTo(item) < 0) {
                        st = ++idx;
                        cnt -= stp+1;
                    }
                    else {
                        cnt = stp;
                    }
                }
                if(st == row.size() || row.get(st).compareTo(item) != 0) {
                    found = false;
                    break;
                }
            }
            if(found) count++;
        }
        return count;
    }
    
    public List< Integer > getItemset() {
        return items;
    }
    
    public int dbSize() {
        return transactions.size();
    }
    
    public List< Integer > getRow(int row) {
        try {
            return transactions.get(row);
        } catch(Exception e) {
            throw e;
        }
    }
}
Clearly it provides some interface to access the database where the constructor must be called with a file name for example 'mushroom.dat'. The sorting on line 56 is not necessary if you know the transactions in the file will be sorted in ascending order. All the data files in this repository are already sorted, so sorting can be disabled.

Now, if we look at the constructor, what is this huge code doing actually? First it treads each transaction as a string, then parses it and inserts the transaction in a sorted list. Now, we need a list of unique elements. Well, this could be done by sorting all the records together, and then eliminating duplicates. However, this can be performed better with the help of a priority queue in O(NK log N) time, where we have n transactions, and each transaction has K records on an average. Actually this works much better than it would be in naive approach which would take O(NK log NK) because of extra sorting overhead.

Then comes the last important part, scanDatabase() method. Which basically searches each record in the database for a set of elements. It takes O(NK log K) time at most, where, we have N records, each having an average length of K. This is much better than looking in O(N*K^2) following a naive approach. Here is some improvement possible, if we know the length of transactions, we could use a bit vector in addition to each transaction. Then the query can be performed in O(NK). However, as the datasets are huge, I didn't go for it due to the necessity of using huge memory.

Part 2 contains the source code and explanation for the apriori algorithm.

Friday, March 30, 2012

Running Java Program Without Console


How to run a java executable or jar without popping up the command prompt window?

This can be done by running the following command instead of "java", assuming the jar file is named "Main.jar"

javaw -jar -Xms1024m -Xmx1024m Main.jar

For example, lets start with the following simple snippet, it just creates a frame and we will the run the program without the black console window. Lets name the file as FacelessVoid.java

import javax.swing.*;

public class FacelessVoid {
    public static void main(String[] args) throws Exception {
        JFrame frame = new JFrame("FrameDemo");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setSize(300, 300);
        frame.setVisible(true);
    }
}

Running the program from IDE's will straight show you the window, which contains nothing at all. This is just for demonstration purpose, so fill free to try something else if you need. Now, we will create a jar file containing this class (we are in windows os).

javac FacelessVoid.java
echo Main-Class: FacelessVoid > manifest.txt
jar cfm Main.jar manifest.txt FacelessVoid.class

Note, if you have more than one source file, i.e. .java files, you can write *.java instead of where we put FacelessVoid.java in line 1. In line 2, the main class name should be the class which contains the main() method. In line 3, if there are more than one class file to be put into jar file, you can use *.class instead of just FacelessVoid.class in our example.

If everything goes fine, the jar file named Main.jar should be created without any problem. Now we can create a batch file in the same directory where the Main.jar is located, lets call it Main.bat, we just put the following line into it:

start javaw -jar -Xms1024m -Xmx1024m Main.jar

Now double clicking on Main.bat will open the window without any command prompt window.

How can I vanish the window totally but still keep the program running?

There are a few ways to do this, I am presenting here a simple way using the previous files, the only thing needed to change is frame.setVisible(true); to frame.setVisible(false); This will hide the window now completely but the program is still running. Note, you will need to create the jar file again, i.e. re-compile and the make jar again. Now if you click on the bat file, it will start executing, but you wont be able to see it any more.

This can be helpful for servers which remains idle and waits for clients. We can just put them beyond visibility and they still keeps executing. For example, this code is just a modification of the previous one, and it will wait for a client to connect on the specified port. However, whenever a client gets a connection, we just change the visibility just to show that the program was actually running even though we were not able to see it. So you may wish to remove the line frame.setVisible(true); from the while loop and write your own program logic and make it permanently invisible.

import javax.swing.*;
import java.net.*;

public class FacelessVoid {
    public static void main(String[] args) throws Exception {
        JFrame frame = new JFrame("FrameDemo");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setSize(300, 300);
        frame.setVisible(false);
        ServerSocket ss = new ServerSocket(8080);
        Socket client = null;
        while((client = ss.accept()) != null) {
            frame.setVisible(true);
        }
    }
}

Now, we can keep the server running without being able to see it. Here is a sample client program at your disposal

import java.net.*;

public class Client {
    public static void main(String[] args) throws Exception {
        Socket sock = new Socket("localhost", 8080);
    }
}

You just run and compile it and the server window will pop in from nowhere :D

Let me know if this works for you too...


Thursday, January 13, 2011

Pollard's Rho in Java


This is a Pollard's Rho implementation in java. Not very fast, but works for uva online judge. The reason behind using java is the default support of the BigInteger class.

import java.math.BigInteger;
import java.security.SecureRandom;
import java.io.*;
import java.util.*;

public class PollardRho {

private final static BigInteger ZERO = new BigInteger("0");
private final static BigInteger ONE = new BigInteger("1");
private final static BigInteger TWO = new BigInteger("2");
private final static SecureRandom random = new SecureRandom();

static Vector<BigInteger> v = new Vector<BigInteger>();

public static BigInteger rho(BigInteger N) {

BigInteger divisor;
BigInteger c = new BigInteger(N.bitLength(), random);
BigInteger x = new BigInteger(N.bitLength(), random);
BigInteger xx = x;

if (N.mod(TWO).compareTo(ZERO) == 0) return TWO;

do {
x = x.multiply(x).mod(N).add(c).mod(N);
xx = xx.multiply(xx).mod(N).add(c).mod(N);
xx = xx.multiply(xx).mod(N).add(c).mod(N);
divisor = x.subtract(xx).gcd(N);
} while((divisor.compareTo(ONE)) == 0);

return divisor;
}

public static void factor(BigInteger N) {

if (N.compareTo(ONE) == 0) return;

if (N.isProbablePrime(20)) {
v.add(N);
return;
}

BigInteger divisor = rho(N);
factor(divisor);
factor(N.divide(divisor));
}

public static void main(String[] args) throws Exception {

String string = "";
InputStreamReader input = new InputStreamReader(System.in);
BufferedReader reader = new BufferedReader(input);

while(null != (string = reader.readLine())) {
BigInteger N = new BigInteger(string);
v.clear();
factor(N);
Collections.sort(v);
for(int i = 0; i < v.size(); i++) System.out.println(v.get(i));
System.out.println();
}
}
}
I have seen this piece of code years ago somewhere in the internet, but can't remember exactly where. So, I will be glad if anyone can comment/mail me the original source. However, for spoj, I need to write a much much better version of this in C++ :( Exam sucks life...

Thursday, January 6, 2011

Java Access Modifiers



Overview:


There are 4 types of access modifiers which are applicable to the members of a class, i.e. the variables and methods. Namely:

  1. Public

  2. Protected

  3. Default or no modifier

  4. Private

However, for a class declaration, protected and private are not allowed, and in a .java file, there can be only one public class, the rest must have been declared with default access. Well, we are more concerned about the access modifiers for the members of a class, as they are quite confusing on some aspects. Each of the four types is described below:

Public


As we can guess, the public members are visible from anywhere regardless of which package or file it is in. Then can be accessible from any other class of same or another package using just a '.' {dot} operator with the class reference.

Protected


This is probably most confusing modifier of java. Protected members are similar as members having default modifier, however, the difference is, protected members can be accessible outside the package it is in through inheritance, i.e. extending the parent class.

Default or no modifier


When no modifier is specified explicitly, it becomes the default modifier. Default modifiers can be thought of as a subset of the Public modifier. As, they are essentially same as Public when they are in the same package. However, members with default modifiers are not accessible from anywhere outside the package the class is in. When we don't specify a package, still there is a default package maintained by the java environment.

Private


It is also straight-forward as public, a private member can not be accessed from anywhere out side the class it is in.

More on "protected"


There are something more notable regarding protected type. As they are often very confusing with it's two near relatives, default and public.

Say, we have a "protected int x" in "class A" in package "pack1". And we derived "class B" from "class A" in package "pack2". In this case, variable x in "class B" is known as if it is just a member of "class B". so, in "class B", we can write in a method "System.out.println(x);". But note, we can't do this: "System.out.println(new A().x);". So, if the subclass is outside the package, we can't access it's parent class' protected member by a class reference. There is another interesting thing, Say, we have another "class C" which is extending the above "class B", then in "class C", we can't use 'x' as when a derived class have some protected member, it becomes a private data in the derived class, so farther extensions can not use those variables anymore.

Summery of the above









publicprotectedno modifierprivate
Same classYesYesYesYes
Same package subclassYesYesYesNo
Same package non-subclassYesYesYesNo
Different package subclassYesYesNoNo
Different package non-subclassYesNoNoNo


I think these are the cases.

Saturday, December 4, 2010

Setup connector/j for JDBC



Setting up MySQL driver connector/j for JDBC in Windows


This is basically not a hard task. Make sure you already have the following things installed and configured in your system, (this demonstration is targeted on the latest versions of the components):

If you don't have these components installed yet, you might try taking some online help on how to install and configure those, not hard as well.

Now, to install java to mysql connector, which is know as connector/j, go to this page and download the windows ZIP package. Unzip the archive anywhere in your pc, it won't matter at all. Now, follow these steps:
  1. Copy the file "mysql-connector-java-5.1.13-bin.jar" to your java installation directory and place it in "..\jdk1.6.0_21\jre\lib\ext".
  2. Now, you have to add this runtime library to your systems classpath environment variable. Go to the properties of My Computer and select the Advanced tab, there you'll see Environment Variables. You will find all your system variables here. Find out the name CLASSPATH and append the location of connector/j i.e. where you just pasted. In my pc, its "C:\Program Files\Java\jdk1.6.0_21\jre\lib\ext\mysql-connector-java-5.1.13-bin.jar". Don't forget to separate this entry from the previous one with e semi-colon. Now click ok and close the dialogue boxes, you are done! But if you don't have the CLASSPATH variable, you need to create it yourself.

That's pretty much all of the work, now we are going to test if it works.

Lets assume that you already have a mysql database named "mysqltest" and you are the "root" user with password "adminadmin" using default host "localhost" with default http port 80, the following code should work then:

import java.sql.*;

public class Main {
public static void main(String[] args) {
Connection conn = null;
try {
Class.forName("com.mysql.jdbc.Driver") ;
System.out.println("MySQL JDBC driver loaded ok.");

conn = DriverManager.getConnection("jdbc:mysql://localhost/mysqltest?user=root&password=adminadmin");
System.out.println("Connected with default port.");

DatabaseMetaData meta = conn.getMetaData();
System.out.println("Server name: " + meta.getDatabaseProductName());
System.out.println("Server version: " + meta.getDatabaseProductVersion());
System.out.println("Driver name: " + meta.getDriverName());
System.out.println("Driver version: " + meta.getDriverVersion());
System.out.println("JDBC major version: " + meta.getJDBCMajorVersion());
System.out.println("JDBC minor version: " + meta.getJDBCMinorVersion());

Statement query = conn.createStatement();
int count = query.executeUpdate(
"CREATE TABLE test (" +
"id INT PRIMARY KEY NOT NULL AUTO_INCREMENT," +
"username VARCHAR(20) NOT NULL," +
"password CHAR(40) NOT NULL );"
);
System.out.println("Table created.");

conn.close();
} catch(Exception e) {
System.err.println("Exception: " + e.getMessage());
}
}
}

As you see, you are using "DriverManager.getConnection()" method to connect it using connector/j which you previously specified by "Class.forName("com.mysql.jdbc.Driver") ;" So, make proper changes to test various things. Here, you will get some more methods of connecting and testing.

Well, if this doesn't work for you, then there must be something which is beyond the scope of this post, else "congratulations!".

Saturday, May 15, 2010

Expression Evaluation



Infix to Postfix transformation and evaluation


Here, I would like to share a java source for converting an Infix expression to a Postfix equivalent and evaluate the Postfix expression. Postfix is also known as "Reverse Polish Notation". If you want to know more about this algorithm, this will be helpful.

Here is a simple java implementation. (Oh, we could do it a lot easily in C++, but, actually it has a academic purpose as well). A few things to note:
  • Fixed format of input, as this is just a demonstration. Do not use spaces.
  • It doesn't check whether the given expression is consistent or not.
  • No math error is checked here, you have to add it to your own.
  • Check sample execution for more details.
  • Only for binary operators +,-,*,/,%,^ and parenthesis ()


Java Source



//
// @author Zobayer
// @date May 10, 2010
//

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.IOException;
import java.util.List;
import java.util.ArrayList;
import java.util.Stack;

//
// Demonstrates Expression evaluation process.
// Doesn't take care of wrong input,
// You need to handle that on your own.
//

public class Expression {

// A sample main() method to demonstrate this process
public static void main(String[] args) throws IOException {
BufferedReader stdin = new BufferedReader(new InputStreamReader(System.in));
String expr;
List<String> inFix, postFix;
int result;

while((expr = stdin.readLine())!=null) {
expr = "(" + expr + ")";
inFix = getInFix(expr);
postFix = getPostFix(inFix);
result = evaluate(postFix);
System.out.println("Postfix form: " + postFix);
System.out.println("Result: " + result);
}
}

// Parse the input string and form an infix notation
static List<String> getInFix(String expr) {
List<String> list = new ArrayList<String>();
int n, i;
char ch;
boolean hasInt;

for(i = n = 0, hasInt = false; i < expr.length(); i++) {
ch = expr.charAt(i);
if(!isDigit(ch)) {
if(hasInt) {
list.add("" + n);
n = 0;
hasInt = false;
}
list.add("" + ch);
}
else {
n = n * 10 + (ch - 48);
hasInt = true;
}
}

return list;
}

// Enlist the tokens in a postfix notation
static List<String> getPostFix(List<String> inFix) {
List<String> list = new ArrayList<String>();
Stack<String> oper = new Stack<String>();
int i;
char ch;
String token, peek;

for(i = 0; i < inFix.size(); i++) {
token = inFix.get(i);
ch = token.charAt(0);
if(isDigit(ch)) list.add(token);
else if(ch=='(') oper.push("" + ch);
else if(ch==')') {
while(!oper.empty()) {
peek = oper.pop();
if(peek.charAt(0)!='(') list.add(peek);
else break;
}
}
else {
while(!oper.empty()) {
peek = oper.peek();
if(peek.charAt(0)!='(' && preced(ch) <= preced(peek.charAt(0))) {
list.add(peek);
oper.pop();
}
else {
oper.push(token);
break;
}
}
}
}

return list;
}

// Evaluate the postfix notation passed as a list
static int evaluate(List<String> postFix) {
Stack<Integer> stack = new Stack<Integer>();
int i, a, b;
String token;
char ch;

for(i = 0; i < postFix.size(); i++) {
token = postFix.get(i);
ch = token.charAt(0);
if(isDigit(ch)) stack.push(Integer.parseInt(token));
else {
b = stack.pop();
a = stack.pop();
switch(ch) {
case '+': a = a + b; break;
case '-': a = a - b; break;
case '*': a = a * b; break;
case '/': a = a / b; break;
case '%': a = a % b; break;
case '^': a = (int)Math.pow(a, b); break;
}
stack.push(a);
}
}

return stack.pop();
}

// Provides operator precedence
static int preced(char op) {
if(op=='^') return 3;
if(op=='*' || op=='/' || op=='%') return 2;
if(op=='+' || op=='-') return 1;
return 0;
}

// Checks if ch is a digit or not
static boolean isDigit(char ch) {
return (ch >= '0' && ch <= '9');
}
}

Sample run



(3+8-90*36)*((((89-5%6+2^3-10-10-10)))-8)+100
Postfix form: [3, 8, +, 90, 36, *, -, 89, 5, 6, %, -, 2, 3, ^, +, 10, -, 10, -, 10, -, 8, -, *, 100, +]
Result: -174266
90+0
Postfix form: [90, 0, +]
Result: 90
6+763-67*2367-(54/234)
Postfix form: [6, 763, +, 67, 2367, *, -, 54, 234, /, -]
Result: -157820

The algorithm implemented here is pretty simple, so I guess I haven't made a mistake yet, but who knows? So please check it...