Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

This commit was manufactured by cvs2svn to create tag 'REL_1_2_19'.

  • Loading branch information...
commit f1d38574a10ca206a31cf62b98cee0fa99393fbc 2 parents 8812bd4 + 0b607f7
cvs2svn authored
Showing with 477 additions and 0 deletions.
  1. +409 −0 src/misc/avl_tree.c
  2. +68 −0 src/misc/avl_tree.h
View
409 src/misc/avl_tree.c
@@ -0,0 +1,409 @@
+/* ----------------------------------------------------------------------
+ * avl_tree.c
+ *
+ * AVL style self balancing tree support.
+ *
+ * Copyright (c) 2007-2009, PostgreSQL Global Development Group
+ * Author: Jan Wieck, Afilias USA INC.
+ *
+ * $Id: avl_tree.c,v 1.3 2009-08-17 17:25:50 devrim Exp $
+ * ----------------------------------------------------------------------
+ */
+
+#include "avl_tree.h"
+
+/* ----
+ * local function declarations
+ * ----
+ */
+static AVLnode *avl_makenode(void);
+static void avl_reset_node(AVLnode *node, AVLfreefunc *freefunc);
+static int avl_insertinto(AVLtree *tree, AVLnode **node,
+ void *cdata, AVLnode **result);
+static void avl_rotate_left(AVLnode **node);
+static void avl_rotate_right(AVLnode **node);
+
+
+/* ----
+ * avl_init() -
+ *
+ * Initilize an AVL tree structure.
+ *
+ * compfunc is a user supplied tri-state comparision function that compares
+ * two tree elements and returns <0, 0 or >0 (like strcmp).
+ *
+ * If freefunc is specified, it is called to free no longer used elements.
+ * Note that the element will not immediately be free'd on avl_delete(),
+ * but only on a avl_delete, avl_insert sequence using the same key.
+ * ----
+ */
+void
+avl_init(AVLtree *tree, AVLcompfunc *compfunc, AVLfreefunc *freefunc)
+{
+ tree->root = NULL;
+ tree->compfunc = compfunc;
+ tree->freefunc = freefunc;
+}
+
+
+/* ----
+ * avl_reset() -
+ *
+ * Reset an AVL tree to empty. This will call the user defined
+ * free function for all elements in the tree, destroy all nodes
+ * and declare the tree empty again.
+ * ----
+ */
+void
+avl_reset(AVLtree *tree)
+{
+ avl_reset_node(tree->root, tree->freefunc);
+ tree->root = NULL;
+}
+
+
+/* ----
+ * avl_reset_node() -
+ *
+ * avl_reset()'s workhorse.
+ * ----
+ */
+void
+avl_reset_node(AVLnode *node, AVLfreefunc *freefunc)
+{
+ if (node == NULL)
+ return;
+
+ avl_reset_node(node->lnode, freefunc);
+ avl_reset_node(node->rnode, freefunc);
+
+ if (freefunc != NULL)
+ freefunc(node->cdata);
+ free(node);
+}
+
+
+/* ----
+ * avl_insert() -
+ *
+ * Insert an element into an AVL tree. On return AVL_DATA(node) might
+ * point to an existing entry with the same key. If the caller replaces
+ * the entry, it must free the existing one since AVL will no longer
+ * keep track of it.
+ * ----
+ */
+AVLnode *
+avl_insert(AVLtree *tree, void *cdata)
+{
+ AVLnode *result;
+ int depth;
+
+ /*
+ * If this is an empty tree, create the root node.
+ */
+ if (tree->root == NULL)
+ return (tree->root = avl_makenode());
+
+ /*
+ * Traverse the tree to find the insert point.
+ */
+ result = NULL;
+ depth = avl_insertinto(tree, &(tree->root), cdata, &result);
+ return result;
+}
+
+
+/* ----
+ * avl_lookup() -
+ *
+ * Search for an existing key in the tree.
+ * ----
+ */
+AVLnode *
+avl_lookup(AVLtree *tree, void *cdata)
+{
+ AVLnode *node;
+ int cmp;
+
+ node = tree->root;
+ while (node != NULL)
+ {
+ cmp = tree->compfunc(cdata, node->cdata);
+ if (cmp == 0)
+ {
+ /*
+ * Found the node. If it is marked deleted, return NULL anyway.
+ * Otherwise return this node.
+ */
+ if (node->deleted)
+ return NULL;
+ return node;
+ }
+
+ /*
+ * Search on ...
+ */
+ if (cmp < 0)
+ node = node->lnode;
+ else
+ node = node->rnode;
+ }
+
+ /*
+ * No such element found
+ */
+ return NULL;
+}
+
+
+/* ----
+ * avl_delete() -
+ *
+ * Mark a given element as deleted. Subsequent lookups for the element
+ * will return NULL. Note that the caller should NOT free the memory
+ * of the element, as it is AVL's property altogether after the delete.
+ *
+ * avl_delete() returns 1 on success, 0 if no such element was found.
+ * ----
+ */
+int
+avl_delete(AVLtree *tree, void *cdata)
+{
+ AVLnode *node;
+
+ if ((node = avl_lookup(tree, cdata)) == NULL)
+ return 0;
+
+ node->deleted = 1;
+ return 1;
+}
+
+
+/* ----
+ * avl_insertinto() -
+ *
+ * The heart of avl_insert().
+ * ----
+ */
+static int
+avl_insertinto(AVLtree *tree, AVLnode **node,
+ void *cdata, AVLnode **result)
+{
+ int cmp;
+
+ /*
+ * Compare the node at hand with the new elements key.
+ */
+ cmp = (tree->compfunc) (cdata, (*node)->cdata);
+
+ if (cmp > 0)
+ {
+ /*
+ * New element is > than node. Insert to the right.
+ */
+ if ((*node)->rnode == NULL)
+ {
+ /*
+ * Right side of current node is empty. Create a new node there
+ * and return new maximum depth. Note that this can only be 1
+ * because otherwise this node would have been unbalanced before.
+ */
+ (*node)->rnode = *result = avl_makenode();
+ (*node)->rdepth = 1;
+ return 1;
+ }
+
+ /*
+ * Right hand node exists. Recurse into that and remember the new
+ * right hand side depth.
+ */
+ (*node)->rdepth = avl_insertinto(tree, &((*node)->rnode),
+ cdata, result) + 1;
+
+ /*
+ * A right hand side insert can unbalance this node only to the right.
+ */
+ if (AVL_BALANCE(*node) > 1)
+ {
+ if (AVL_BALANCE((*node)->rnode) > 0)
+ {
+ /*
+ * RR situation, rebalance the tree by left rotating this
+ * node.
+ */
+ avl_rotate_left(node);
+ }
+ else
+ {
+ /*
+ * RL situation, rebalance the tree by first right rotating
+ * the right hand side, then left rotating this node.
+ */
+ avl_rotate_right(&((*node)->rnode));
+ avl_rotate_left(node);
+ }
+ }
+
+ return AVL_MAXDEPTH(*node);
+ }
+ else if (cmp < 0)
+ {
+ /*
+ * New element is < than node. Insert to the left.
+ */
+ if ((*node)->lnode == NULL)
+ {
+ /*
+ * Left side of current node is empty. Create a new node there and
+ * return new maximum depth. Note that this can only be 1 because
+ * otherwise this node would have been unbalanced before.
+ */
+ (*node)->lnode = *result = avl_makenode();
+ (*node)->ldepth = 1;
+ return AVL_MAXDEPTH(*node);
+ }
+
+ /*
+ * Left hand node exists. Recurse into that and remember the new left
+ * hand side depth.
+ */
+ (*node)->ldepth = avl_insertinto(tree, &((*node)->lnode),
+ cdata, result) + 1;
+
+ /*
+ * A left hand side insert can unbalance this node only to the left.
+ */
+ if (AVL_BALANCE(*node) < -1)
+ {
+ if (AVL_BALANCE((*node)->lnode) < 0)
+ {
+ /*
+ * LL situation, rebalance the tree by right rotating this
+ * node.
+ */
+ avl_rotate_right(node);
+ }
+ else
+ {
+ /*
+ * LR situation, rebalance the tree by first left rotating the
+ * left node, then right rotating this node.
+ */
+ avl_rotate_left(&((*node)->lnode));
+ avl_rotate_right(node);
+ }
+ }
+
+ return AVL_MAXDEPTH(*node);
+ }
+ else
+ {
+ /*
+ * The new element is equal to this node. If it is marked for
+ * deletion, free the user element data now. The caller is supposed to
+ * replace it with a new element having the the key.
+ */
+ if ((*node)->deleted && tree->freefunc != NULL)
+ {
+ (tree->freefunc) ((*node)->cdata);
+ (*node)->cdata = NULL;
+ (*node)->deleted = 0;
+ }
+ *result = *node;
+ return AVL_MAXDEPTH(*node);
+ }
+}
+
+
+/* ----
+ * avl_makenode() -
+ *
+ * Create a new empty node.
+ * ----
+ */
+static AVLnode *
+avl_makenode(void)
+{
+ AVLnode *new;
+
+ new = (AVLnode *) malloc(sizeof(AVLnode));
+ memset(new, 0, sizeof(AVLnode));
+
+ return new;
+}
+
+
+/* ----
+ * avl_rotate_left() -
+ *
+ * Rebalance a node to the left.
+ * ----
+ */
+static void
+avl_rotate_left(AVLnode **node)
+{
+ AVLnode *rtmp;
+
+ /*
+ * save right node
+ */
+ rtmp = (*node)->rnode;
+
+ /*
+ * move right nodes left side to this nodes right
+ */
+ (*node)->rnode = rtmp->lnode;
+ if (rtmp->lnode != NULL)
+ (*node)->rdepth = AVL_MAXDEPTH(rtmp->lnode) + 1;
+ else
+ (*node)->rdepth = 0;
+
+ /*
+ * Move this node to right nodes left side
+ */
+ rtmp->lnode = *node;
+ rtmp->ldepth = AVL_MAXDEPTH(*node) + 1;
+
+ /*
+ * Let parent point to right node
+ */
+ *node = rtmp;
+}
+
+
+/* ----
+ * avl_rotate_right() -
+ *
+ * Rebalance a node to the right.
+ * ----
+ */
+static void
+avl_rotate_right(AVLnode **node)
+{
+ AVLnode *ltmp;
+
+ /*
+ * save left node
+ */
+ ltmp = (*node)->lnode;
+
+ /*
+ * move left nodes right side to this nodes left
+ */
+ (*node)->lnode = ltmp->rnode;
+ if (ltmp->rnode != NULL)
+ (*node)->ldepth = AVL_MAXDEPTH(ltmp->rnode) + 1;
+ else
+ (*node)->ldepth = 0;
+
+ /*
+ * Move this node to left nodes right side
+ */
+ ltmp->rnode = *node;
+ ltmp->rdepth = AVL_MAXDEPTH(*node) + 1;
+
+ /*
+ * Let parent point to left node
+ */
+ *node = ltmp;
+}
View
68 src/misc/avl_tree.h
@@ -0,0 +1,68 @@
+/* ----------------------------------------------------------------------
+ * avl_tree.h
+ *
+ * Declarations for AVL style balanced tree support.
+ *
+ * Copyright (c) 2003-2009, PostgreSQL Global Development Group
+ * Author: Jan Wieck, Afilias USA INC.
+ *
+ * $Id: avl_tree.h,v 1.3 2009-08-17 17:25:50 devrim Exp $
+ * ----------------------------------------------------------------------
+ */
+
+#ifndef _AVL_TREE_H_INCLUDED_
+#define _AVL_TREE_H_INCLUDED_
+
+/* ----
+ * Callback function type declarations
+ * ----
+ */
+typedef int (AVLcompfunc) (void *, void *);
+typedef void (AVLfreefunc) (void *);
+
+
+/* ----
+ * Data structures
+ * ----
+ */
+typedef struct AVLnode_s
+{
+ struct AVLnode_s *lnode,
+ *rnode;
+ int ldepth,
+ rdepth;
+ void *cdata;
+ int deleted;
+} AVLnode;
+
+typedef struct AVLtree_s
+{
+ AVLnode *root;
+ AVLcompfunc *compfunc;
+ AVLfreefunc *freefunc;
+} AVLtree;
+
+/* ----
+ * Macros
+ * ----
+ */
+#define AVL_DATA(n) (n)->cdata
+#define AVL_SETDATA(n,p) ((n)->cdata = (p))
+#define AVL_MAXDEPTH(n) (((n)->ldepth > (n)->rdepth) ? (n)->ldepth : (n)->rdepth)
+#define AVL_BALANCE(n) ((n)->rdepth - (n)->ldepth)
+
+#define AVL_INITIALIZER(cmp,free) {NULL, (cmp), (free)}
+
+
+/* ----
+ * Public functions
+ * ----
+ */
+void avl_init(AVLtree *tree, AVLcompfunc *compfunc,
+ AVLfreefunc *freefunc);
+void avl_reset(AVLtree *tree);
+AVLnode *avl_insert(AVLtree *tree, void *cdata);
+AVLnode *avl_lookup(AVLtree *tree, void *cdata);
+int avl_delete(AVLtree *tree, void *cdata);
+
+#endif /* _AVL_TREE_H_INCLUDED_ */
Please sign in to comment.
Something went wrong with that request. Please try again.