/* RISO: an implementation of distributed belief networks.
* This file (TopDownSplayTree.java) is a translation of splay tree
* C code written by Danny Sleator, and it is redistributed as part
* of the RISO project by permission of Danny Sleator, quoted below.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA, 02111-1307, USA,
* or visit the GNU web site, www.gnu.org.
*/
package riso.general;
import java.io.*;
/* From: "Danny Sleator" <sleator+@cs.cmu.edu>
* To: "Robert Dodier" <robert_dodier@yahoo.com>
* Subject: Re: Permission to redistribute splay tree code?
* Date: Mon, 31 Dec 2001 00:50:32 -0500
*
* You're welcome to distribute your project under any license you want.
* My splay tree code is unrestricted. Do whatever you want with it.
* Of course I'd prefer that you at least leave my name in the comments
* somewhere, and perhaps even mention that you use splay trees to the
* person using the software. But these are only suggestions.
*
* Daniel Sleator, PhD
* Carnegie Mellon University
* Phones: 412-268-7563, 412-422-5377, 412-654-9585
* Email: sleator@cmu.edu
*/
/** <pre>
* An implementation of top-down splaying
* D. Sleator <sleator@cs.cmu.edu>
* http://www.cs.cmu.edu/afs/cs.cmu.edu/user/sleator/www/home.html
* March 1992
*
* [Java translation of splay(), insert(), and delete() by Robert Dodier,
* July 1998; max() and min() added by Robert Dodier. Permission to
* redistribute under GPL given by Danny Sleator to Robert Dodier.
* Following comments are from the original C code.]
*
* "Splay trees", or "self-adjusting search trees" are a simple and
* efficient data structure for storing an ordered set. The data
* structure consists of a binary tree, without parent pointers, and no
* additional fields. It allows searching, insertion, deletion,
* deletemin, deletemax, splitting, joining, and many other operations,
* all with amortized logarithmic performance. Since the trees adapt to
* the sequence of requests, their performance on real access patterns is
* typically even better. Splay trees are described in a number of texts
* and papers [1,2,3,4,5].
*
* The code here is adapted from simple top-down splay, at the bottom of
* page 669 of [3]. It can be obtained via anonymous ftp from
* ftp://ftp.cs.cmu.edu/user/sleator/.
*
* The chief modification here is that the splay operation works even if the
* key being splayed is not in the tree, and even if the tree root of the
* tree is null. So the line:
*
* t = splay(a, t);
*
* causes it to search for node with key a in the tree rooted at t. If it's
* there, it is splayed to the root. If it isn't there, then the node put
* at the root is the last one before null that would have been reached in a
* normal binary search for a. (It's a neighbor of a in the tree.) This
* allows many other operations to be easily implemented, as shown below.
*
* [1] "Fundamentals of data structures in C", Horowitz, Sahni,
* and Anderson-Freed, Computer Science Press, pp 542-547.
* [2] "Data Structures and Their Algorithms", Lewis and Denenberg,
* Harper Collins, 1991, pp 243-251.
* [3] "Self-adjusting Binary Search Trees" Sleator and Tarjan,
* JACM Volume 32, No 3, July 1985, pp 652-686.
* [4] "Data Structure and Algorithm Analysis", Mark Weiss,
* Benjamin Cummins, 1992, pp 119-130.
* [5] "Data Structures, Algorithms, and Performance", Derick Wood,
* Addison-Wesley, 1993, pp 367-375.
* </pre>
*/
public class TopDownSplayTree implements java.io.Serializable
{
/** Number of nodes in the tree; not needed for any of the operations.
*/
public int size;
/** Root of this splay tree.
*/
public TreeNode root;
public static class TreeNode implements java.io.Serializable
{
public TreeNode left, right;
public double key, value;
}
/** Returns a reference to the node containing the minimum
* value of the subtree rooted on <tt>t</tt>.
* This is just the leftmost child of <tt>t</tt>.
*/
public static TreeNode min( TreeNode t )
{
if ( t == null ) return null;
while ( t.left != null )
t = t.left;
return t;
}
/** Returns a reference to the node containing the maximum
* value of the subtree rooted on <tt>t</tt>.
* This is just the rightmost child of <tt>t</tt>.
*/
public static TreeNode max( TreeNode t )
{
if ( t == null ) return null;
while ( t.right != null )
t = t.right;
return t;
}
/** Simple top down splay, not requiring <tt>a</tt> to be in the
* subtree rooted on <tt>t</tt>.
* What it does is described in the header comment for the class.
*/
public static TreeNode splay( double a, TreeNode t )
{
if (t == null) return null;
TreeNode N = new TreeNode(), l, r, y;
N.left = N.right = null;
l = r = N;
for (;;)
{
if (a < t.key)
{
if (t.left == null) break;
if (a < t.left.key)
{
y = t.left; /* rotate right */
t.left = y.right;
y.right = t;
t = y;
if (t.left == null) break;
}
r.left = t; /* link right */
r = t;
t = t.left;
}
else if (a > t.key)
{
if (t.right == null) break;
if (a > t.right.key)
{
y = t.right; /* rotate left */
t.right = y.left;
y.left = t;
t = y;
if (t.right == null) break;
}
l.right = t; /* link left */
l = t;
t = t.right;
}
else
{
break;
}
}
l.right = t.left; /* assemble */
r.left = t.right;
t.left = N.right;
t.right = N.left;
return t;
}
/** Inserts <tt>new_key</tt> into this tree, unless it's already there.
*/
public void insert( double new_key, double value )
{
TreeNode t = root;
TreeNode new_node = new TreeNode();
// System.err.print( "insert: new_key: "+new_key+", value: "+value+" ... " );
new_node.key = new_key;
new_node.value = value;
if (t == null)
{
new_node.left = new_node.right = null;
size = 1;
root = new_node;
// System.err.println( "OK (now "+size+" nodes)." );
return;
}
t = splay(new_key,t);
if (new_key < t.key)
{
new_node.left = t.left;
new_node.right = t;
t.left = null;
size ++;
root = new_node;
// System.err.println( "OK (now "+size+" nodes)." );
return;
}
else if (new_key > t.key)
{
new_node.right = t.right;
new_node.left = t;
t.right = null;
size++;
root = new_node;
// System.err.println( "OK (now "+size+" nodes)." );
return;
}
else
{
/* We get here if it's already in the tree; don't add it again. */
// System.err.println( "oops, already in tree." );
root = t;
return;
}
}
/** Deletes <tt>some_key</tt> from this tree, if it's there.
*/
public void delete( double some_key )
{
TreeNode t = root, x;
if (t==null) return;
System.err.print( "delete: some_key: "+some_key+"... " );
t = splay(some_key,t);
if (some_key == t.key)
{
/* found it */
if (t.left == null)
{
x = t.right;
}
else
{
x = splay(some_key, t.left);
x.right = t.right;
}
size--;
root = x;
System.err.println( "OK (now "+size+" nodes)." );
return;
}
System.err.println( "oops, not in tree." );
root = t; /* It wasn't there */
}
/** Return the contents of the tree as an array with two columns and
* a number of rows equal to the number of keys in the tree.
* The first column corresponds to the keys and the second corresponds
* to the values.
*/
public double[][] dump()
{
double[][] xy = new double[size][2];
int[] i = new int[1]; // pass an int by reference; initial value is 0
traverse_inorder( root, xy, i );
return xy;
}
/** Traverse the sub-tree rooted on <tt>t</tt> from least to greatest keys.
* Load up the array <tt>xy</tt> with key+value pairs. Increment the
* index <tt>i</tt> with every pair stored.
*/
public static void traverse_inorder( TreeNode t, double[][] xy, int[] i )
{
if ( t == null ) return;
traverse_inorder( t.left, xy, i );
xy[ i[0] ][0] = t.key;
xy[ i[0] ][1] = t.value;
i[0] += 1;
traverse_inorder( t.right, xy, i );
}
/** A sample use of these functions. Start with the empty tree,
* insert some stuff into it, and then delete it.
*/
public static void main( String[] args )
{
int n = 1024;
if ( args.length > 0 )
n = Integer.parseInt( args[0] );
TopDownSplayTree t = new TopDownSplayTree();
t.root = null; /* the empty tree */
t.size = 0;
int i;
for (i = 0; i < n; i++)
t.insert( (double)((541*i) & (n-1)), (double)i );
System.out.println("t.size = "+t.size);
double[][] xy = t.dump();
System.out.println( "contents: " );
for ( i = 0; i < xy.length; i++ )
System.out.println( "key: "+xy[i][0]+" value: "+xy[i][1] );
try
{
SmarterTokenizer st = new SmarterTokenizer( new InputStreamReader( System.in ) );
System.out.print( "number? " );
for ( st.nextToken(); st.ttype != StreamTokenizer.TT_EOF; st.nextToken() )
{
double a = Double.parseDouble( st.sval );
t.root = splay( a, t.root );
if ( t.root.key == a )
System.out.println( "found "+a+", value: "+t.root.value );
else
{
System.out.print( a+" not found; " );
if ( a > t.root.key )
System.out.println( "key bracketed by "+t.root.key+" and "+min(t.root.right).key+"; bracket values: "+t.root.value+", "+min(t.root.right).value );
else
System.out.println( "key bracketed by "+max(t.root.left).key+" and "+t.root.key+"; bracket values: "+max(t.root.left).value+", "+t.root.value );
}
System.out.print( "number? " );
}
}
catch (Exception e)
{
System.err.println( "exception: "+e+"; stagger onward." );
}
for (i = 0; i < n; i++)
t.delete( (double) ((541*i) & (n-1)) );
System.out.println("t.size = "+t.size);
}
}