Re: Splay trees



On Mon, Mar 15, 1999 at 11:29:48AM +0100, Soeren Sandmann wrote:
> 
> On march 5th I uploaded a patch that implements splay trees, but I have
> not heard anything since, nor has the patch been moved to
> ftp.gtk.org/pub/gtk/patches.
> 
> Is this patch going to be included in GLib?

I've got patches from the author and attach them in this letter. Please,
check and consider, if this'll go to the GLib. From my point of view, Splay
Trees is a useful code, and should go into the library. There are several 
cases, when they simplify our (programmers) life and give a neat solution.
One more point - caches, based on splay trees allows easy implementation
of LRU algorithm, if any...

			With best regards, Timur Bakeyev.

P.S> Where such pieces of code should go in CVS - into HEAD or HACKS?

==============================================================================
Here is the author's comments:

This patch implements splay trees.

Splay trees are self adjusting binary search trees that have several advantages over other trees:

*) They are faster for skewed access patterns since they contain a kind of
   builtin cache.

*) They do not use any memory for balancing information.

I will write reference documentation for them if the patch is accepted
into GLib.

The patch is made with diff -Pur.

Søren Sandmann

=============================================================================
Here is a comment from Samba, which also uses Splay Trees:

/*
 *  This module implements "splay" trees.  Splay trees are binary trees
 *  that are rearranged (splayed) whenever a node is accessed.  The
 *  splaying process *tends* to make the tree bushier (improves balance),
 *  and the nodes that are accessed most frequently *tend* to be closer to
 *  the top.
 *
 *  References: "Self-Adjusting Binary Search Trees", by Daniel Sleator and
 *              Robert Tarjan.  Journal of the Association for Computing
 *              Machinery Vol 32, No. 3, July 1985 pp. 652-686
 *
 *    See also: http://www.cs.cmu.edu/~sleator/
*/

=============================================================================
--- ./tests/Makefile.am.orig	Mon Mar 15 20:18:50 1999
+++ ./tests/Makefile.am	Thu Mar 18 03:20:47 1999
@@ -11,6 +11,7 @@
 	queue-test	\
 	relation-test	\
 	slist-test	\
+	splaytree-test  \
 	stack-test	\
 	string-test	\
 	strfunc-test	\
@@ -28,6 +29,7 @@
 queue_test_LDADD = $(top_builddir)/libglib.la
 relation_test_LDADD = $(top_builddir)/libglib.la
 slist_test_LDADD = $(top_builddir)/libglib.la
+splaytree_test_LDADD = $(top_builddir)/libglib.la
 stack_test_LDADD = $(top_builddir)/libglib.la
 string_test_LDADD = $(top_builddir)/libglib.la
 strfunc_test_LDADD = $(top_builddir)/libglib.la
--- ./tests/splaytree-test.c.orig	Thu Mar 18 03:44:09 1999
+++ ./tests/splaytree-test.c	Thu Mar 18 03:13:28 1999
@@ -0,0 +1,108 @@
+/* GLIB - Library of useful routines for C programming
+ * Copyright (C) 1995-1997  Peter Mattis, Spencer Kimball and Josh MacDonald
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+#undef G_LOG_DOMAIN
+
+#include <stdio.h>
+#include <string.h>
+#include "glib.h"
+
+int array[10000];
+gboolean failed = FALSE;
+
+#define	TEST(m,cond)	G_STMT_START { failed = !(cond); \
+if (failed) \
+  { if (!m) \
+      g_print ("\n(%s:%d) failed for: %s\n", __FILE__, __LINE__, ( # cond )); \
+    else \
+      g_print ("\n(%s:%d) failed for: %s: (%s)\n", __FILE__, __LINE__, ( # cond ), (gchar*)m); \
+  } \
+else \
+  g_print ("."); fflush (stdout); \
+} G_STMT_END
+
+#define	C2P(c)		((gpointer) ((long) (c)))
+#define	P2C(p)		((gchar) ((long) (p)))
+
+#define GLIB_TEST_STRING "el dorado "
+#define GLIB_TEST_STRING_5 "el do"
+
+typedef struct {
+	guint age;
+	gchar name[40];
+} GlibTestInfo;
+
+
+static gint
+my_compare (gconstpointer a,
+	    gconstpointer b)
+{
+  const char *cha = a;
+  const char *chb = b;
+
+  return *cha - *chb;
+}
+
+static gint
+my_traverse (gpointer key,
+	     gpointer value,
+	     gpointer data)
+{
+  char *ch = key;
+  g_assert ((*ch) > 0);
+  return FALSE;
+}
+
+int
+main (int   argc,
+      char *argv[])
+{
+  gint i, j;
+  GSplayTree *tree;
+  char chars[62];
+
+  tree = g_splay_tree_new (my_compare);
+  i = 0;
+  for (j = 0; j < 10; j++, i++)
+    {
+      chars[i] = '0' + j;
+      g_splay_tree_insert (tree, &chars[i], &chars[i]);
+    }
+  for (j = 0; j < 26; j++, i++)
+    {
+      chars[i] = 'A' + j;
+      g_splay_tree_insert (tree, &chars[i], &chars[i]);
+    }
+  for (j = 0; j < 26; j++, i++)
+    {
+      chars[i] = 'a' + j;
+      g_splay_tree_insert (tree, &chars[i], &chars[i]);
+    }
+
+  g_splay_tree_traverse (tree, my_traverse, G_IN_ORDER, NULL);
+
+  g_assert (g_splay_tree_nnodes (tree) == (10 + 26 + 26));
+
+  for (i = 0; i < 10; i++)
+    g_splay_tree_remove (tree, &chars[i]);
+
+  g_splay_tree_traverse (tree, my_traverse, G_IN_ORDER, NULL);
+
+  return 0;
+}
+
--- ./glib.def.orig	Mon Mar 15 20:18:40 1999
+++ ./glib.def	Thu Mar 18 03:22:16 1999
@@ -324,6 +324,15 @@
 	g_source_remove
 	g_source_remove_by_source_data
 	g_source_remove_by_user_data
+	g_splay_tree_new      
+	g_splay_tree_destroy  
+	g_splay_tree_insert   
+	g_splay_tree_remove   
+	g_splay_tree_lookup   
+	g_splay_tree_traverse 
+	g_splay_tree_height   
+	g_splay_tree_nnodes   
+	g_splay_tree_delete_min 
 	g_static_mutex_get_mutex_impl
 	g_static_private_get
 	g_static_private_set
--- ./Makefile.am.orig	Mon Mar 15 20:18:36 1999
+++ ./Makefile.am	Thu Mar 18 03:17:54 1999
@@ -48,6 +48,7 @@
 	grel.c		\
 	gscanner.c	\
 	gslist.c	\
+	gsplaytree.c    \
 	gstack.c	\
 	gstrfuncs.c	\
 	gstring.c	\
--- ./glib.h.orig	Wed Mar 17 18:58:56 1999
+++ ./glib.h	Thu Mar 18 03:16:13 1999
@@ -702,6 +702,7 @@
 typedef struct _GScanner	GScanner;
 typedef struct _GScannerConfig	GScannerConfig;
 typedef struct _GSList		GSList;
+typedef struct _GSplayTree      GSplayTree;
 typedef struct _GStack		GStack;
 typedef struct _GString		GString;
 typedef struct _GStringChunk	GStringChunk;
@@ -1097,6 +1098,26 @@
 gint	 g_tree_height	 (GTree		*tree);
 gint	 g_tree_nnodes	 (GTree		*tree);
 
+
+
+/* Splay trees
+ */
+GSplayTree* g_splay_tree_new        (GCompareFunc  key_compare_func);
+void        g_splay_tree_destroy    (GSplayTree   *stree);
+void        g_splay_tree_insert     (GSplayTree   *stree, 
+				     gpointer      key, 
+				     gpointer      value);
+void        g_splay_tree_remove     (GSplayTree   *stree, 
+				     gpointer      key);
+gpointer    g_splay_tree_lookup     (GSplayTree   *stree, 
+				     gpointer      key);
+void        g_splay_tree_traverse   (GSplayTree   *stree,
+				     GTraverseFunc traverse_func,
+				     GTraverseType traverse_type,
+				     gpointer      data);
+gint        g_splay_tree_height     (GSplayTree   *stree);
+gint        g_splay_tree_nnodes     (GSplayTree   *stree);
+void        g_splay_tree_delete_min (GSplayTree   *stree);
 
 
 /* N-way tree implementation
--- ./gsplaytree.c.orig	Thu Mar 18 03:43:39 1999
+++ ./gsplaytree.c	Thu Mar 18 03:13:27 1999
@@ -0,0 +1,642 @@
+/* GLIB - Library of useful routines for C programming
+ * Copyright (C) 1995-1997  Peter Mattis, Spencer Kimball and Josh MacDonald
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+/* 
+ * MT safe
+ */
+#include "glib.h"
+
+
+typedef struct _GRealSplayTree GRealSplayTree;
+typedef struct _GSplayTreeNode GSplayTreeNode;
+
+struct _GRealSplayTree
+{
+  GSplayTreeNode *root;
+  GCompareFunc key_compare;
+};
+
+struct _GSplayTreeNode
+{
+  GSplayTreeNode *left;     /* left subtree */
+  GSplayTreeNode *right;    /* right subtree */
+  gpointer key;             /* key for this node */
+  gpointer value;           /* value stored at this node */
+};
+
+static GSplayTreeNode *g_splay_tree_node_new          (gpointer key, 
+						       gpointer value);
+static void            g_splay_tree_node_free         (GSplayTreeNode *node);
+static void            g_splay_tree_node_destroy      (GSplayTreeNode *node);
+static GSplayTreeNode *g_splay_tree_node_splay        (GSplayTreeNode *node, 
+						       GCompareFunc    compare, 
+						       gpointer        key);
+static GSplayTreeNode *g_splay_tree_node_splay_max    (GSplayTreeNode *node);
+static GSplayTreeNode *g_splay_tree_node_splay_min    (GSplayTreeNode *node);
+static GSplayTreeNode *g_splay_tree_node_insert       (GSplayTreeNode *node, 
+						       GCompareFunc    compare, 
+						       gpointer        key,
+						       gpointer        value);
+static GSplayTreeNode *g_splay_tree_node_join         (GSplayTreeNode *node1, 
+						       GSplayTreeNode *node2);
+static GSplayTreeNode *g_splay_tree_node_remove       (GSplayTreeNode *node,
+						       GCompareFunc    compare,
+						       gpointer        key);
+static GSplayTreeNode *g_splay_tree_node_delete_min   (GSplayTreeNode *node);
+static gint            g_splay_tree_node_pre_order    (GSplayTreeNode *node,
+						       GTraverseFunc   traverse_func,
+						       gpointer        data);
+static gint            g_splay_tree_node_in_order     (GSplayTreeNode *node,
+						       GTraverseFunc   traverse_func,
+						       gpointer        data);
+static gint            g_splay_tree_node_post_order   (GSplayTreeNode *node,
+						       GTraverseFunc   traverse_func,
+						       gpointer        data);
+static gint            g_splay_tree_node_count        (GSplayTreeNode *node);
+static gint            g_splay_tree_node_height       (GSplayTreeNode *node);
+
+G_LOCK_DEFINE_STATIC (g_splay_tree_global);
+static GMemChunk *node_mem_chunk = NULL;
+static GSplayTreeNode *node_free_list = NULL;
+
+
+static GSplayTreeNode *
+g_splay_tree_node_new (gpointer key, gpointer value)
+{
+  GSplayTreeNode *node;
+  
+  G_LOCK (g_splay_tree_global);
+  if (node_free_list)
+    {
+      node = node_free_list;
+      node_free_list = node->right;
+    }
+  else
+    {
+      if (!node_mem_chunk)
+	node_mem_chunk = g_mem_chunk_new ("GLib GSplayTreeNode mem chunk",
+					  sizeof (GSplayTreeNode),
+					  1024,
+					  G_ALLOC_ONLY);
+
+      node = g_chunk_new (GSplayTreeNode, node_mem_chunk);
+    }
+  G_UNLOCK (g_splay_tree_global);
+
+  node -> key = key;
+  node -> value = value;
+  return node;
+}
+
+static void 
+g_splay_tree_node_destroy (GSplayTreeNode *node)
+{
+  if (node)
+    {
+      g_splay_tree_node_destroy (node->right);
+      g_splay_tree_node_destroy (node->left);
+      g_splay_tree_node_free (node);
+    }
+}
+
+static void
+g_splay_tree_node_free (GSplayTreeNode *node)
+{
+  G_LOCK (g_splay_tree_global);
+  node->right = node_free_list;
+  node_free_list = node;
+  G_UNLOCK (g_splay_tree_global);
+}
+
+static GSplayTreeNode *
+g_splay_tree_node_splay (GSplayTreeNode *node, 
+			 GCompareFunc compare, 
+			 gpointer key)
+{
+  gint cmp;
+
+  GSplayTreeNode *left_max, *right_min, header, *tmp;
+
+  header.left = header.right = NULL;
+  left_max = right_min = &header;
+  
+  if (node == NULL)
+    return node;
+
+  while ( (cmp = (* compare)(key, node->key)) != 0)
+    {
+      if (cmp < 0)
+	{
+	  if (node->left == NULL)
+	    break;
+	  cmp = (* compare)(key, node->left->key);
+	  if (cmp == 0)
+	    {
+	      /* link right */
+	      right_min->left = node;
+	      right_min = node;
+	      node = node->left;
+	    }	     
+	  else if (cmp < 0)
+	    {
+	      /* rotate right */
+	      tmp = node->left;
+	      node->left = tmp->right;
+	      tmp->right = node;
+	      if (tmp->left == NULL)
+		{
+		  node = tmp;
+		  break;
+		}
+	      /* link right */
+	      right_min->left = tmp;
+	      right_min = tmp;
+	      node = tmp->left;
+	    }
+	  else
+	    {
+	      /* link right */
+	      right_min->left = node;
+	      right_min = node;
+	      node = node->left;
+	      if (node->right == NULL)
+		break;
+	      /* link left */
+	      left_max->right = node;
+	      left_max = node;
+	      node = node->right;
+	    }
+	}
+      else
+	{
+	  if (node->right == NULL)
+	    break;
+	  cmp = (* compare)(key, node->right->key);
+	  if (cmp == 0)
+	    {
+	      /* link left */
+	      left_max->right = node;
+	      left_max = node;
+	      node = node->right;
+	    }
+	  else if (cmp > 0)
+	    {  
+	      /* rotate left */
+	      tmp = node->right;
+	      node->right = tmp->left;
+	      tmp->left = node;
+	      if (tmp->right == NULL)
+		{
+		  node = tmp;
+		  break;
+		}
+	      /* link left */
+	      left_max->right = tmp;
+	      left_max = tmp;
+	      node = tmp->right;
+	    }
+	  else
+	    {
+	      /* link left */
+	      left_max->right = node;
+	      left_max = node;
+	      node = node->right;
+	      if (node->left == NULL)
+		break;
+	      /* link right */
+	      right_min->left = node;
+	      right_min = node;
+	      node = node->left;
+	    }
+	}
+    }
+  /* assemble */
+  left_max->right = node->left;
+  right_min->left = node->right;
+  node->left = header.right;
+  node->right = header.left;
+  return node;
+}
+
+static GSplayTreeNode *
+g_splay_tree_node_splay_min (GSplayTreeNode *node)
+{
+  GSplayTreeNode *left_max, *right_min, header, *tmp;
+
+  header.left = header.right = NULL;
+  left_max = right_min = &header;
+  
+  if (node == NULL)
+    return node;
+
+  while ( TRUE )
+    {
+      if (node->left == NULL)
+	break;
+      /* rotate right */
+      tmp = node->left;
+      node->left = tmp->right;
+      tmp->right = node;
+      if (tmp->left == NULL)
+	{
+	  node = tmp;
+	  break;
+	}
+      /* link right */
+      right_min->left = tmp;
+      right_min = tmp;
+      node = tmp->left;
+    }
+  /* assemble */
+  left_max->right = node->left;
+  right_min->left = node->right;
+  node->left = header.right;
+  node->right = header.left;
+  return node;
+}
+
+static GSplayTreeNode *
+g_splay_tree_node_splay_max (GSplayTreeNode *node)
+{
+  GSplayTreeNode *left_max, *right_min, header, *tmp;
+
+  header.left = header.right = NULL;
+  left_max = right_min = &header;
+  
+  if (node == NULL)
+    return node;
+
+  while ( TRUE )
+    {
+      if (node->right == NULL)
+	break;
+      /* rotate left */
+      tmp = node->right;
+      node->right = tmp->left;
+      tmp->left = node;
+      if (tmp->right == NULL)
+	{
+	  node = tmp;
+	  break;
+	}
+      /* link left */
+      left_max->right = tmp;
+      left_max = tmp;
+      node = tmp->right;
+      
+    }
+  /* assemble */
+  left_max->right = node->left;
+  right_min->left = node->right;
+  node->left = header.right;
+  node->right = header.left;
+  return node;
+}
+
+
+static GSplayTreeNode *
+g_splay_tree_node_insert (GSplayTreeNode *node, 
+			  GCompareFunc compare, 
+			  gpointer key,
+			  gpointer value)
+{
+  GSplayTreeNode *n;
+  gint cmp;
+  
+  if (node)
+    {
+      cmp = (* compare)(node->key, key);
+
+      node = g_splay_tree_node_splay (node, compare, key);
+      
+      if (cmp == 0)
+	return node;
+      else
+	{
+	  n = g_splay_tree_node_new (key, value);
+	  if (cmp > 0)
+	    {
+	      n -> right = node;
+	      n -> left = node->left;
+	      node -> left = NULL;
+	      return n;
+	    }
+	  else
+	    {
+	      n -> left = node;
+	      n -> right = node->right;
+	      node -> right = NULL;
+	      return n;
+	    }
+	}
+    }
+  else
+    {
+      n = g_splay_tree_node_new (key, value);
+      n -> left = NULL;
+      n -> right = NULL;
+      return n;
+    }
+}
+
+static GSplayTreeNode *
+g_splay_tree_node_join (GSplayTreeNode *node1, GSplayTreeNode *node2)
+{
+  if (!node1)
+    return node2;
+  node1 = g_splay_tree_node_splay_max (node1);
+  node1 -> left = node2;
+  return node1;
+}
+
+static GSplayTreeNode *
+g_splay_tree_node_remove (GSplayTreeNode *node,
+			  GCompareFunc compare,
+			  gpointer key)
+{
+  GSplayTreeNode *r;
+
+  if (!node)
+    return node;
+
+  node = g_splay_tree_node_splay (node, compare, key);
+  if ((* compare)(node->key, key)==0)
+    {
+      r = g_splay_tree_node_join (node->left, node->right);
+      g_splay_tree_node_free (node);
+      return r;
+    }
+  else
+    return node;
+}
+
+static GSplayTreeNode *
+g_splay_tree_node_delete_min (GSplayTreeNode *node)
+{
+  GSplayTreeNode *n;
+
+  if (!node)
+    return node;
+
+  n = g_splay_tree_node_splay_min (node)->left;
+  g_splay_tree_node_free (node);
+
+  return n;
+}
+
+GSplayTree *
+g_splay_tree_new (GCompareFunc key_compare_func)
+{
+  GRealSplayTree *rst;
+
+  g_return_val_if_fail (key_compare_func != NULL, NULL);
+  
+  rst = g_new (GRealSplayTree, 1);
+
+  rst -> root = NULL;
+  rst -> key_compare = key_compare_func;
+
+  return (GSplayTree *) rst;
+}
+
+void
+g_splay_tree_destroy (GSplayTree *stree)
+{
+  GRealSplayTree *rst;
+
+  g_return_if_fail (stree != NULL);
+  
+  rst = (GRealSplayTree *)stree;
+
+  g_splay_tree_node_destroy (rst -> root);
+  g_free (rst);
+}
+
+void
+g_splay_tree_insert (GSplayTree *stree, gpointer key, gpointer value)
+{
+  GRealSplayTree *rst;
+
+  g_return_if_fail (stree != NULL);
+  
+  rst = (GRealSplayTree *)stree;
+  
+  rst->root = g_splay_tree_node_insert (rst->root, rst->key_compare, key, value);
+}
+
+void
+g_splay_tree_remove (GSplayTree *stree, gpointer key)
+{
+  GRealSplayTree *rst;
+
+  g_return_if_fail (stree != NULL);
+
+  rst = (GRealSplayTree *)stree;
+
+  rst->root = g_splay_tree_node_remove (rst->root, rst->key_compare, key);
+}
+
+void
+g_splay_tree_delete_min (GSplayTree *stree)
+{
+  GRealSplayTree *rst;
+
+  g_return_if_fail (stree != NULL);
+
+  rst = (GRealSplayTree *)stree;
+
+  rst->root = g_splay_tree_node_delete_min (rst->root);
+}
+
+gpointer
+g_splay_tree_lookup (GSplayTree *stree, gpointer key)
+{
+  GRealSplayTree *rst;
+
+  g_return_val_if_fail (stree != NULL, NULL);
+
+  rst = (GRealSplayTree *)stree;
+
+  if (rst->root)
+    {
+      rst -> root = g_splay_tree_node_splay (rst->root, rst->key_compare, key);
+      if ( (* rst->key_compare)(rst->root->key, key) == 0)
+	return rst->root->value;
+      else
+	return NULL;
+    }
+  else
+    return NULL;
+}
+
+static gint
+g_splay_tree_node_pre_order (GSplayTreeNode *node,
+			     GTraverseFunc traverse_func,
+			     gpointer data)
+{
+  if ((*traverse_func)(node->key, node->value, data))
+    return TRUE;
+  if (node->left)
+    {
+      if (g_splay_tree_node_pre_order (node->left, traverse_func, data))
+	return TRUE;
+    }
+  if (node->right)
+    {
+      if (g_splay_tree_node_pre_order (node->right, traverse_func, data))
+	return TRUE;
+    }
+  return FALSE;
+}
+
+static gint
+g_splay_tree_node_in_order (GSplayTreeNode *node,
+			    GTraverseFunc traverse_func,
+			    gpointer data)
+{
+  if (node->left)
+    {
+      if (g_splay_tree_node_in_order (node->left, traverse_func, data))
+	return TRUE;
+    }
+  if ((*traverse_func) (node->key, node->value, data))
+    return TRUE;
+  if (node->right)
+    {
+      if (g_splay_tree_node_in_order (node->right, traverse_func, data))
+	return TRUE;
+    }
+  return FALSE;
+}
+
+static gint
+g_splay_tree_node_post_order (GSplayTreeNode *node,
+			    GTraverseFunc traverse_func,
+			    gpointer data)
+{
+  if (node->left)
+    {
+      if (g_splay_tree_node_post_order (node->left, traverse_func, data))
+	return TRUE;
+    }
+  if (node->right)
+    {
+      if (g_splay_tree_node_post_order (node->right, traverse_func, data))
+	return TRUE;
+    }
+  if ((*traverse_func) (node->key, node->value, data))
+    return TRUE;
+  return FALSE;
+}
+
+void
+g_splay_tree_traverse (GSplayTree *stree,
+		       GTraverseFunc traverse_func,
+		       GTraverseType traverse_type,
+		       gpointer data)
+{
+  GRealSplayTree *rst;
+
+  g_return_if_fail (stree != NULL);
+
+  rst = (GRealSplayTree *)stree;
+  
+  if (!rst->root)
+    return;
+  
+  switch (traverse_type)
+    {
+    case G_PRE_ORDER:
+      g_splay_tree_node_pre_order (rst->root, traverse_func, data);
+      break;
+ 
+    case G_IN_ORDER:
+      g_splay_tree_node_in_order (rst->root, traverse_func, data);
+      break;
+    
+    case G_POST_ORDER:
+      g_splay_tree_node_post_order (rst->root, traverse_func, data);
+      break;
+    
+    case G_LEVEL_ORDER:
+      g_warning ("g_splay_tree_traverse(): traverse type G_LEVEL_ORDER isn't implemented.");
+      break;
+    }
+}
+
+static gint
+g_splay_tree_node_count (GSplayTreeNode *node)
+{
+  gint count;
+  
+  count = 1;
+
+  if (node->left)
+    count += g_splay_tree_node_count (node->left);
+  if (node->right)
+    count += g_splay_tree_node_count (node->right);
+  
+  return count;
+}
+			 
+gint
+g_splay_tree_nnodes (GSplayTree *stree)
+{
+  GRealSplayTree *rst;
+
+  g_return_val_if_fail (stree != NULL, 0);
+  
+  rst = (GRealSplayTree *)stree;
+  
+  if (rst->root)
+    return g_splay_tree_node_count (rst->root);
+  else
+    return 0;
+}
+
+gint
+g_splay_tree_height (GSplayTree *stree)
+{
+  GRealSplayTree *rst;
+  
+  g_return_val_if_fail (stree != NULL, 0);
+  
+  rst = (GRealSplayTree *)stree;
+
+  if (rst->root)
+    return g_splay_tree_node_height (rst->root);
+  else
+    return 0;
+}
+
+gint 
+g_splay_tree_node_height (GSplayTreeNode *node)
+{
+  gint left_height;
+  gint right_height;
+
+  if (node)
+    {
+      left_height = g_splay_tree_node_height (node->left);
+      right_height = g_splay_tree_node_height (node->right);
+      return MAX (left_height, right_height) + 1;
+    }
+  else
+    return 0;
+}



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]