199 lines
4.4 KiB
C
199 lines
4.4 KiB
C
/* Balanced binary trees using treaps.
|
|
Copyright (C) 2000-2021 Free Software Foundation, Inc.
|
|
Contributed by Andy Vaught
|
|
|
|
This file is part of GCC.
|
|
|
|
GCC 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 3, or (at your option) any later
|
|
version.
|
|
|
|
GCC 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 GCC; see the file COPYING3. If not see
|
|
<http://www.gnu.org/licenses/>. */
|
|
|
|
/* The idea is to balance the tree using pseudorandom numbers. The
|
|
main constraint on this implementation is that we have several
|
|
distinct structures that have to be arranged in a binary tree.
|
|
These structures all contain a BBT_HEADER() in front that gives the
|
|
treap-related information. The key and value are assumed to reside
|
|
in the rest of the structure.
|
|
|
|
When calling, we are also passed a comparison function that
|
|
compares two nodes. We don't implement a separate 'find' function
|
|
here, but rather use separate functions for each variety of tree.
|
|
We are also restricted to not copy treap structures, which most
|
|
implementations find convenient, because we otherwise would need to
|
|
know how long the structure is.
|
|
|
|
This implementation is based on Stefan Nilsson's article in the
|
|
July 1997 Doctor Dobb's Journal, "Treaps in Java". */
|
|
|
|
#include "config.h"
|
|
#include "system.h"
|
|
#include "coretypes.h"
|
|
#include "gfortran.h"
|
|
|
|
typedef struct gfc_treap
|
|
{
|
|
BBT_HEADER (gfc_treap);
|
|
}
|
|
gfc_bbt;
|
|
|
|
/* Simple linear congruential pseudorandom number generator. The
|
|
period of this generator is 44071, which is plenty for our
|
|
purposes. */
|
|
|
|
static int
|
|
pseudo_random (void)
|
|
{
|
|
static int x0 = 5341;
|
|
|
|
x0 = (22611 * x0 + 10) % 44071;
|
|
return x0;
|
|
}
|
|
|
|
|
|
/* Rotate the treap left. */
|
|
|
|
static gfc_bbt *
|
|
rotate_left (gfc_bbt *t)
|
|
{
|
|
gfc_bbt *temp;
|
|
|
|
temp = t->right;
|
|
t->right = t->right->left;
|
|
temp->left = t;
|
|
|
|
return temp;
|
|
}
|
|
|
|
|
|
/* Rotate the treap right. */
|
|
|
|
static gfc_bbt *
|
|
rotate_right (gfc_bbt *t)
|
|
{
|
|
gfc_bbt *temp;
|
|
|
|
temp = t->left;
|
|
t->left = t->left->right;
|
|
temp->right = t;
|
|
|
|
return temp;
|
|
}
|
|
|
|
|
|
/* Recursive insertion function. Returns the updated treap, or
|
|
aborts if we find a duplicate key. */
|
|
|
|
static gfc_bbt *
|
|
insert (gfc_bbt *new_bbt, gfc_bbt *t, compare_fn compare)
|
|
{
|
|
int c;
|
|
|
|
if (t == NULL)
|
|
return new_bbt;
|
|
|
|
c = (*compare) (new_bbt, t);
|
|
|
|
if (c < 0)
|
|
{
|
|
t->left = insert (new_bbt, t->left, compare);
|
|
if (t->priority < t->left->priority)
|
|
t = rotate_right (t);
|
|
}
|
|
else if (c > 0)
|
|
{
|
|
t->right = insert (new_bbt, t->right, compare);
|
|
if (t->priority < t->right->priority)
|
|
t = rotate_left (t);
|
|
}
|
|
else /* if (c == 0) */
|
|
gfc_internal_error("insert_bbt(): Duplicate key found");
|
|
|
|
return t;
|
|
}
|
|
|
|
|
|
/* Given root pointer, a new node and a comparison function, insert
|
|
the new node into the treap. It is an error to insert a key that
|
|
already exists. */
|
|
|
|
void
|
|
gfc_insert_bbt (void *root, void *new_node, compare_fn compare)
|
|
{
|
|
gfc_bbt **r, *n;
|
|
|
|
r = (gfc_bbt **) root;
|
|
n = (gfc_bbt *) new_node;
|
|
n->priority = pseudo_random ();
|
|
*r = insert (n, *r, compare);
|
|
}
|
|
|
|
static gfc_bbt *
|
|
delete_root (gfc_bbt *t)
|
|
{
|
|
gfc_bbt *temp;
|
|
|
|
if (t->left == NULL)
|
|
return t->right;
|
|
if (t->right == NULL)
|
|
return t->left;
|
|
|
|
if (t->left->priority > t->right->priority)
|
|
{
|
|
temp = rotate_right (t);
|
|
temp->right = delete_root (t);
|
|
}
|
|
else
|
|
{
|
|
temp = rotate_left (t);
|
|
temp->left = delete_root (t);
|
|
}
|
|
|
|
return temp;
|
|
}
|
|
|
|
|
|
/* Delete an element from a tree. The 'old' value does not
|
|
necessarily have to point to the element to be deleted, it must
|
|
just point to a treap structure with the key to be deleted.
|
|
Returns the new root node of the tree. */
|
|
|
|
static gfc_bbt *
|
|
delete_treap (gfc_bbt *old, gfc_bbt *t, compare_fn compare)
|
|
{
|
|
int c;
|
|
|
|
if (t == NULL)
|
|
return NULL;
|
|
|
|
c = (*compare) (old, t);
|
|
|
|
if (c < 0)
|
|
t->left = delete_treap (old, t->left, compare);
|
|
if (c > 0)
|
|
t->right = delete_treap (old, t->right, compare);
|
|
if (c == 0)
|
|
t = delete_root (t);
|
|
|
|
return t;
|
|
}
|
|
|
|
|
|
void
|
|
gfc_delete_bbt (void *root, void *old, compare_fn compare)
|
|
{
|
|
gfc_bbt **t;
|
|
|
|
t = (gfc_bbt **) root;
|
|
*t = delete_treap ((gfc_bbt *) old, *t, compare);
|
|
}
|