The essence of the trick is that you simply make a type difference between "filled in" pointers and "null" pointers.
A tree would be defined like so :
abstract class TreeNode {}
abstract class EmptyTreeNode extends TreeNode {}
abstract class FilledTreeNode extends TreeNode {
TreeNode first;
TreeNode second;
}
If you combine this with runtime polymorphism you can do something like this (won't work in Java, but I'm using java code anyway)
void processTreeNode(EmptyTreeNode et) {}
void processTreeNode(FilledTreeNode ft) {
// you might want to do something useful here
processTreeNode(ft.first);
processTreeNode(ft.second);
// or here
}
then simply call processTreeNode(tree), and the compiler would figure out whether to call the first or the second function.