Spiral Order, Java

2012/03/19

This is a problem I’ve heard mentioned but never really had a reason to look into. As they say, the science is gone from computer science. I sat down today and put some thought into it.

Spiral order is what you’d think. Given a 2D array, you move from left to right, top to bottom, right to left, and bottom to top printing out the values in order. For example,

  1  2  3  4
  5  6  7  8
  9 10 11 12
 13 14 15 16

The spiral order of this matrix is,

{  1, 2, 3, 4, 8, 12, 16, 15, 14, 13, 9, 5, 6, 7, 11, 10 }

The algorithm to walk in spiral order works nicely with recursion. You recursively, “peel” off the top, right, bottom, left portions of the matrix until there’s nothing left. For example (forgive the ASCII art), peel off the top,

  1 2 3 4

  5  6  7  8
  9 10 11 12
 13 14 15 16

peel off the right,

  5  6  7     8
  9 10 11    12
 13 14 15    16

peel off the bottom,

  5  6  7
  9 10 11 

 13 14 15

peel off the left,

 5     6  7
 9    10 11

peel off the top (again, starting over here),

 6 7

 10 11

peel the right again,

 10    11

and finally, one more peel of the bottom gets the last element,

 10

and we are done.

The code is below. spiralOrderR() implements the recursive algorithm. It calls peelTop(), which calls peelLeft(), which calls peelBottom(),which calls peelLeft(), and so on, until it’s done.  The peeling happens in the arguments to the recursive call, where the bounds of the matrix are reduced as appropriate at each pass.

public class SpiralOrder {
	public static <T> List<T> spiralOrderR(T[][] matrix) {
		int startx = 0;
		int starty = 0;
		int endx = matrix.length - 1;
		int endy = matrix.length - 1;

		List<T> spiral = new ArrayList<T>();

		peelTopRight(matrix, startx, endx, starty, endy, spiral);
		return spiral;
	}

	private static <T> void peelTop(T[][] matrix, int startx, int endx, int starty, int endy, List<T> spiral) {
		if (startx > matrix.length / 2) {
			return;
		}
		for (int i = startx; i <= endx; i++) {
			spiral.add(matrix[i][starty]);
		}
		peelRight(matrix, startx, endx, starty+1, endy, spiral);
	}

	private static <T> void peelRight(T[][] matrix, int startx, int endx, int starty, int endy, List<T> spiral) {
		for (int i = starty; i <= endy; i++) {
			spiral.add(matrix[endx][i]);
		}
		peelBottom(matrix, startx, endx-1, starty, endy, spiral);
	}

	private static <T> void peelBottom(T[][] matrix, int startx, int endx, int starty, int endy, List<T> spiral) {
		for (int i = endx; i >= startx; i--) {
			spiral.add(matrix[i][endy]);
		}
		peelLeft(matrix, startx, endx, starty, endy-1, spiral);
	}

	private static <T> void peelLeft(T[][] matrix, int startx, int endx, int starty, int endy, List<T> spiral) {
		for (int i = endy; i >= starty; i--) {
			spiral.add(matrix[startx][i]);
		}
		peelTop(matrix, startx+1, endx, starty, endy, spiral);
	}

	public static void main(String[] args) {
		Integer[][] ints = new Integer[5][5];
		int count = 1;
		for (int i = 0; i < ints.length; i++) {
			for (int j = 0; j < ints[i].length; j++) {
				ints[j][i] = count++;
			}
		}

		List<Integer> spiral = spiralOrder(ints);
		System.out.println(spiral);
		spiral = spiralOrderR(ints);
		System.out.println(spiral);
	}
}


JSON Flattener

2012/01/21

I recently ran into the problem of needing to store a JSON object in a key, value store. I pasted a little utility class that does the job below. Here’s an example run against some nasty JSON,

ORIGINAL:

{ string: 'aString', integer: -1, nested: { x: 1, y: 2, z: 3}, moreNested: { a: [1,2,3], b: [4,5,6], c: [7,8,9]}, arrayFromHell: [{ innerArray: [{ innerInnerArray: [1,2,3]}]}]}

ENCODED:

{"arrayFromHell.0.innerArray.0.innerInnerArray.0":1,"arrayFromHell.0.innerArray.0.innerInnerArray.1":2,"arrayFromHell.0.innerArray.0.innerInnerArray.2":3,"nested.z":3,"nested.y":2,"nested.x":1,"integer":-1,"string":"aString","moreNested.b.0":4,"moreNested.b.1":5,"moreNested.b.2":6,"moreNested.c.0":7,"moreNested.c.1":8,"moreNested.c.2":9,"moreNested.a.0":1,"moreNested.a.1":2,"moreNested.a.2":3}

DECODED:

{"nested":{"z":3,"y":2,"x":1},"arrayFromHell":[{"innerArray":[{"innerInnerArray":[1,2,3]}]}],"integer":-1,"string":"aString","moreNested":{"b":[4,5,6],"c":[7,8,9],"a":[1,2,3]}}

As you can see, it simply looks at every leaf value (string, int) and derives the key path and stores the value there. For example,

{ x: { y: { z: 1 } } }

becomes,

{ x.y.z: 1 }

Arrays are a special case. Each value in an array becomes the path so far to the array appended with the array index. For example,

{ anArray: [1,2,3] }

becomes,

{ anArray.0: 1, anArray.1: 2, anArray.2: 3 }

Of course this isn’t foolproof. If you have dots in your key names, it will break. If you use numbers as keys, it will break as it makes an assumption that a numbered key path element indicates an array. Here’s the source.
package org.test.flatjson;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

public class JsonFlattener {
	public static String encode(JSONObject jo) throws JSONException {
		String s = "{" + encode(null, jo) + "}";
		return s;

	}

	public static String encode(String json) throws JSONException {
		JSONObject jo = new JSONObject(json);
		return encode(jo);
	}

	private static String encode(String parent, Object val)
			throws JSONException {
		StringBuilder sb = new StringBuilder();
		if (val instanceof JSONObject) {
			JSONObject jo = (JSONObject) val;
			for (Iterator<String> i = jo.keys(); i.hasNext();) {
				String key = i.next();
				String hkey = (parent == null) ? key : parent + "." + key;
				Object jval = jo.get(key);
				String json = encode(hkey, jval);
				sb.append(json);
				if (i.hasNext()) {
					sb.append(",");
				}
			}
		} else if (val instanceof JSONArray) {
			JSONArray ja = (JSONArray) val;
			for (int i = 0; i < ja.length(); i++) {
				String hkey = (parent == null) ? "" + i : parent + "." + i;
				Object aval = ja.get(i);
				String json = encode(hkey, aval);
				sb.append(json);
				if (i < ja.length() - 1) {
					sb.append(",");
				}
			}
		} else if (val instanceof String) {
			sb.append("\"").append(parent).append("\"").append(":");
			String s = (String) val;
			sb.append(JSONObject.quote(s));
		} else if (val instanceof Integer) {
			sb.append("\"").append(parent).append("\"").append(":");
			Integer integer = (Integer) val;
			sb.append(integer);
		}

		return sb.toString();
	}

	public static String decode(String flatJson) throws JSONException {
		JSONObject encoded = new JSONObject(flatJson);
		return decodeToString(encoded);
	}

	public static String decodeToString(JSONObject encoded)
			throws JSONException {
		return decodeToObject(encoded).toString();
	}

	public static JSONObject decodeToObject(JSONObject encoded)
			throws JSONException {
		JSONObject decoded = new JSONObject();

		for (Iterator<String> i = encoded.keys(); i.hasNext();) {
			String hkey = i.next();
			String[] keys = hkey.split("\\.");

			Object json = decoded;

			for (int j = 0; j < keys.length; j++) {
				if (j == keys.length - 1) {
					Object val = encoded.get(hkey);
					if (json instanceof JSONObject) {
						JSONObject jo = (JSONObject)json;
						jo.put(keys[j], val);
					} else if (json instanceof JSONArray) {
						JSONArray ja = (JSONArray)json;
						int index = Integer.parseInt(keys[j]);
						ja.put(index, val);
					}
				} else {
					// we're NOT at a leaf key

					if (!isNumber(keys[j + 1])) {
						// next index is an object

						JSONObject joChild;

						if (json instanceof JSONObject) {
							// last index was an object
							// we're creating an object in an object
							JSONObject jo = (JSONObject)json;
							if (jo.has(keys[j])) {
								joChild = jo.getJSONObject(keys[j]);
							} else {
								joChild = new JSONObject();
								jo.put(keys[j], joChild);
							}
						} else if (json instanceof JSONArray) {
							// last index was an array
							// we're creating an object in an array
							JSONArray ja = (JSONArray)json;
							int index = Integer.parseInt(keys[j]);
							if (!ja.isNull(index)) {
								joChild = ja.getJSONObject(index);
							} else {
								joChild = new JSONObject();
								ja.put(index, joChild);
							}
						} else {
							throw new AssertionError("unhandled object type");
						}
						json = joChild;
					} else {
						// next index is an array element

						JSONArray jaChild;

						if (json instanceof JSONObject) {
							// last index was an object,
							// we're creating an array in an object
							JSONObject jo = (JSONObject)json;
							if (jo.has(keys[j])) {
								jaChild = jo.getJSONArray(keys[j]);
							} else {
								jaChild = new JSONArray();
								jo.put(keys[j], jaChild);
							}
						} else if (json instanceof JSONArray) {
							// last index was an array
							// we're creating an array in an array
							JSONArray ja = (JSONArray)json;
							int index = Integer.parseInt(keys[j + 1]);
							if (!ja.isNull(index)) {
								jaChild = ja.getJSONArray(index);
							} else {
								jaChild = new JSONArray();
								ja.put(index, jaChild);
							}
						} else {
							throw new AssertionError("unhandled object type");
						}
						json = jaChild;
					}
				}
			}
		}
		return decoded;
	}

	private static boolean isNumber(String s) {
		try {
			Integer.parseInt(s);
			return true;
		} catch (NumberFormatException e) {
			return false;
		}

	}
}


Iterative Tree Traversal

2010/11/16

While studying for an interview, I some how got it into my head that I should understand the iterative algorithms for the three standard tree traversal methods (pre-, post-, in-). While the recursive algorithms for these are straightforward and intuitive, the iterative ones are most certainly not. Worse, googling on this topic turned up a lot of incomplete or just plain wrong solutions.

With some painstaking work I believe I came up with some nearly as simple as possible solutions. Some solutions I found required parent pointers, some required visit markers. These require neither of these.

After each algorithm, I include a walkthrough of the algorithm based on this sample tree from the Wikipedia tree traversal page.

Pre-order,

void preOrderIterative(Node n) {
	Stack<Node> s = new new Stack<Node>();
	s.push(n);

	while (!s.empty()) {
		n = s.pop();
		n.visit();

		if (n.right != null) {
			s.push(n.right);
		}
		if (n.left != null) {
			s.push(n.left);
		}
	}
}

Each line of the example shows the stack at the beginning of the iteration, the set of visited nodes so far after the iteration, and the stack at the end of the iteration.

1: s={}, visited={F}, s={B,G}
2: s={G}, visited={F,B}, s={A,D,G}
3: s={D,G}, visited={F,B,A}, s={D,G}
4: s={G}, visited={F,B,A,D}, s={C,E,G}
5: s={E,G}, visited={F,B,A,D,C}, s={E,G}
6: s={G}, visited={F,B,A,D,C,E}, s={G}
7: s={}, visited={F,B,A,D,C,E,G}, s={I}
8: s={}, visited={F,B,A,D,C,E,G,I}, s={H}
9: s={}, visited={F,B,A,D,C,E,G,I,H}, s={}

Post-order,

This one uses two stacks. It consumes the input stack and builds the output stack. At the end of the method, it pops each node from the output stack and visits it.

void postOrderIterative(Node n) {
	Stack<Node> s = new new Stack<Node>();
	Stack<Node> o = new new Stack<Node>();
	s.push(n);

	while (!s.empty()) {
		n = s.pop();
		o.push(n);

		if (n.left != null) {
			s.push(n.left);
		if (n.right != null) {
			s.push(n.right);
		}
	}
	while (!o.empty()) {
		o.pop().visit();
	}
}

Each line of the example below shows state of the input stack and output stack after the iteration.

1: out={F}, in={G,B}
2: out={G,F}, in={I,B}
3: out={I,G,F}, in={H,B}
4: out={H,I,G,F}, in={B}
5: out={B,H,I,G,F}, in={D,A}
6: out={D,B,H,I,G,F}, in={E,C,A}
7: out={E,D,B,H,I,G,F}, in={C,A}
8: out={C,E,D,B,H,I,G,F}, in={A}
9: out={A,C,E,D,B,H,I,G,F}, in={}

In-order,

void inOrderIterative(Node n) {
	Stack<Node> s = new new Stack<Node>();
	s.push(n);

	while (!s.empty()) {
		while (n.left != null) {
			n = n.left;
			s.push(n);
		}
		n = s.pop();
		n.visit();
		if (n.right != null) {
			s.push(n.right);
		}
	}
}

Each line of the example shows the stack at the beginning of the iteration, the set of visited nodes so far after the iteration, and the stack at the end of the iteration.

1: s={A,B,F}, v={A}, s={B,F}
2: s={B,F}, v={A,B}, s={D,F}
3: s={C,D,F}, v={A,B,C}, s={D,F}
4: s={D,F}, v={A,B,C,D}, s={E,F}
5: s={E,F}, v={A,B,C,D,E}, s={F}
6: s={F}, v={A,B,C,D,E,F}, s={G}
7: s={G}, v={A,B,C,D,E,F,G}, s={I}
8: s={H,I}, v={A,B,C,D,E,F,G,H}, s={I}
9: s={I}, v={A,B,C,D,E,F,G,H,I}, s={}


Java EE Got it Wrong

2009/11/17

After working on two large-scale, cross contains / platform, web application projects, I’ve come to the conclusion that Java EE is fatally flawed.

If someone asked you to state the most important, guiding principle of the Java language, what would you say? You would would probably say “write once, run anywhere.” Indeed, for Java SE this holds true most all of the time. In Java EE however, it is hopelessly broken. The reality is that every web container is slightly different in ways that force developers work around problems, avoid certain features, or even have different code paths. Different code paths in a language that was never designed for it.

Different aspects of Java EE have different levels of stability. JSP works almost the same across all containers. Things like JSF and Java Persistence (JPA) however are hopeless. My most recent experience is writing a web administration console using JSF for the OpenSSO project. OpenSSO claims to support at at least 8 different web containers. Every container required JSF tweaking that ranged from annoying to just plain terrible. Needless to say I had egg on my face to some degree over the choice to use JSF. It was a no-brainer for me. JSF is the chosen MVC framework for Java EE. My mistake.

The only container where JSF “just worked” was Tomcat. Tomcat isn’t a Java EE container at all.Tomcat doesn’t include JSF or any of it’s dependencies. We might be on to something here. Let’s look at another example: Spring. Spring is essentially a lighter-weight, simpler replacement for Java EE. Why is Spring so popular? One reason is that it is an elegant design. But another, perhaps more important reasons is that no matter what container you are developing on, Spring is Spring. It’s the same JAR, the same code, the same implementation. It makes very few assumptions about the capabilities of the underlying container. Another example is Facelets, a light-weight JSP replacment. I use JSF+Facelets on the OpenSSO project, and it has been flawless (the Facelets part). Why? Because I include the Facelets JAR, it is not provided by the system.

What if Java EE had followed the same model? Java EE should have been nothing more than a plugin framework and some base services. Want to use JSF in your project? Just include it from a managed, networked Java EE module repository. Include the one, common implementation of JSF. Include the approved version for your level of Java EE. If you support Java EE 5, you get JSF version X, across all web containers.

 

 


Reverse a Linked List, Java

2009/10/09

Reviewing for interview questions, I ran across this. Most solutions you’ll find are in C, and that can be easily adapted … however, the C-ness sometimes gets in the way of spotting the subtleties. Here is the function in Java,

static void Node reverse(Node head) {
Node current = head;
Node newHead = null;
while (current != null) {
Node tmp = current;
current = current.next;
tmp.next = newHead;
newHead = tmp;
}
return newHead;
}

So how does it work? In a nutshell, we always have 2 lists: 1) the remaining portion of the original list pointed to by current, and 2) the new list pointed to by newHead. Each iteration strips the head element from the original list, and adds it to the head of the new list.

  • line 5 saves the current loop pointer, this will be our new head at the end of each loop.
  • line 6 advances the current loop pointer one past the head, but remember we saved the old current pointer in tmp at line 5.
  • line 7 assigns the next pointer of our new head (tmp) to the previous head pointer. The first time through the loop, this is null, and we’ll have a new list containing one item.
  • line 8 permanently tracks our new head by moving it out of the temporary loop var.

I can’t imagine it gets better than this. No new allocations, and O(n).


Follow

Get every new post delivered to your Inbox.