Equivilent of STL Set in D ? ...
BLS
nanali at wanadoo.fr
Mon Oct 23 12:41:05 PDT 2006
Walter Bright schrieb:
> Sean Kelly wrote:
>
>> The C++ set is implemented as a balanced binary tree, and some sort of
>> binary tree is probably your best bet if you want a sorted container
>> with decent lookup performance.
>
>
> C++'s balanced binary trees are red-black trees. I had just proposed
> that someone do a red-black tree implementation for D. It's not hard,
> the algorithms are well known. It just takes a little time to sit down
> and do it.
http://www.cs.fiu.edu/~weiss/dsj3/code/weiss/nonstandard/RedBlackTree.java
(a generic implementation)
My roots are in Modula/Oberon, but if somebody is willing to translate
the Java sources into D I am willing to help in translating/implementing
the *missing* remove-method (-as good as possible-) , and some helper
methods from Modula 3 into D.
Björn
// *Java basic impl.*
public class RedBlackTree<AnyType extends Comparable<? super AnyType>>
{
/**
* Construct the tree.
*/
public RedBlackTree( )
{
nullNode = new RedBlackNode<AnyType>( null );
nullNode.left = nullNode.right = nullNode;
header = new RedBlackNode<AnyType>( null );
header.left = header.right = nullNode;
}
/**
* Compare item and t.element, using compareTo, with
* caveat that if t is header, then item is always larger.
* This routine is called if is possible that t is header.
* If it is not possible for t to be header, use compareTo directly.
*/
private final int compare( AnyType item, RedBlackNode<AnyType> t )
{
if( t == header )
return 1;
else
return item.compareTo( t.element );
}
/**
* Insert into the tree.
* @param item the item to insert.
* @throws DuplicateItemException if item is already present.
*/
public void insert( AnyType item )
{
current = parent = grand = header;
nullNode.element = item;
while( compare( item, current ) != 0 )
{
great = grand; grand = parent; parent = current;
current = compare( item, current ) < 0 ?
current.left : current.right;
// Check if two red children; fix if so
if( current.left.color == RED && current.right.color == RED )
handleReorient( item );
}
// Insertion fails if already present
if( current != nullNode )
throw new DuplicateItemException( item.toString( ) );
current = new RedBlackNode<AnyType>( item, nullNode, nullNode );
// Attach to parent
if( compare( item, parent ) < 0 )
parent.left = current;
else
parent.right = current;
handleReorient( item );
}
/**
* Remove from the tree.
* @param x the item to remove.
* @throws UnsupportedOperationException if called.
*/
public void remove( AnyType x )
{
throw new UnsupportedOperationException( );
}
/**
* Find the smallest item the tree.
* @return the smallest item or null if empty.
*/
public AnyType findMin( )
{
if( isEmpty( ) )
return null;
RedBlackNode<AnyType> itr = header.right;
while( itr.left != nullNode )
itr = itr.left;
return itr.element;
}
/**
* Find the largest item in the tree.
* @return the largest item or null if empty.
*/
public AnyType findMax( )
{
if( isEmpty( ) )
return null;
RedBlackNode<AnyType> itr = header.right;
while( itr.right != nullNode )
itr = itr.right;
return itr.element;
}
/**
* Find an item in the tree.
* @param x the item to search for.
* @return the matching item or null if not found.
*/
public AnyType find( AnyType x )
{
nullNode.element = x;
current = header.right;
for( ; ; )
{
if( x.compareTo( current.element ) < 0 )
current = current.left;
else if( x.compareTo( current.element ) > 0 )
current = current.right;
else if( current != nullNode )
return current.element;
else
return null;
}
}
/**
* Make the tree logically empty.
*/
public void makeEmpty( )
{
header.right = nullNode;
}
/**
* Print all items.
*/
public void printTree( )
{
printTree( header.right );
}
/**
* Internal method to print a subtree in sorted order.
* @param t the node that roots the tree.
*/
private void printTree( RedBlackNode<AnyType> t )
{
if( t != nullNode )
{
printTree( t.left );
System.out.println( t.element );
printTree( t.right );
}
}
/**
* Test if the tree is logically empty.
* @return true if empty, false otherwise.
*/
public boolean isEmpty( )
{
return header.right == nullNode;
}
/**
* Internal routine that is called during an insertion
* if a node has two red children. Performs flip and rotations.
* @param item the item being inserted.
*/
private void handleReorient( AnyType item )
{
// Do the color flip
current.color = RED;
current.left.color = BLACK;
current.right.color = BLACK;
if( parent.color == RED ) // Have to rotate
{
grand.color = RED;
if( ( compare( item, grand ) < 0 ) !=
( compare( item, parent ) < 0 ) )
parent = rotate( item, grand ); // Start dbl rotate
current = rotate( item, great );
current.color = BLACK;
}
header.right.color = BLACK; // Make root black
}
/**
* Internal routine that performs a single or double rotation.
* Because the result is attached to the parent, there are four cases.
* Called by handleReorient.
* @param item the item in handleReorient.
* @param parent the parent of the root of the rotated subtree.
* @return the root of the rotated subtree.
*/
private RedBlackNode<AnyType> rotate( AnyType item,
RedBlackNode<AnyType> parent )
{
if( compare( item, parent ) < 0 )
return parent.left = compare( item, parent.left ) < 0 ?
rotateWithLeftChild( parent.left ) : // LL
rotateWithRightChild( parent.left ) ; // LR
else
return parent.right = compare( item, parent.right ) < 0 ?
rotateWithLeftChild( parent.right ) : // RL
rotateWithRightChild( parent.right ); // RR
}
/**
* Rotate binary tree node with left child.
*/
private static <AnyType> RedBlackNode<AnyType> rotateWithLeftChild(
RedBlackNode<AnyType> k2 )
{
RedBlackNode<AnyType> k1 = k2.left;
k2.left = k1.right;
k1.right = k2;
return k1;
}
/**
* Rotate binary tree node with right child.
*/
private static <AnyType> RedBlackNode<AnyType>
rotateWithRightChild( RedBlackNode<AnyType> k1 )
{
RedBlackNode<AnyType> k2 = k1.right;
k1.right = k2.left;
k2.left = k1;
return k2;
}
private static class RedBlackNode<AnyType>
{
// Constructors
RedBlackNode( AnyType theElement )
{
this( theElement, null, null );
}
RedBlackNode( AnyType theElement, RedBlackNode<AnyType> lt,
RedBlackNode<AnyType> rt )
{
element = theElement;
left = lt;
right = rt;
color = RedBlackTree.BLACK;
}
AnyType element; // The data in the node
RedBlackNode<AnyType> left; // Left child
RedBlackNode<AnyType> right; // Right child
int color; // Color
}
private RedBlackNode<AnyType> header;
private RedBlackNode<AnyType> nullNode;
private static final int BLACK = 1; // BLACK must be 1
private static final int RED = 0;
// Used in insert routine and its helpers
private RedBlackNode<AnyType> current;
private RedBlackNode<AnyType> parent;
private RedBlackNode<AnyType> grand;
private RedBlackNode<AnyType> great;
// Test program
public static void main( String [ ] args )
{
RedBlackTree<Integer> t = new RedBlackTree<Integer>( );
final int NUMS = 400000;
final int GAP = 35461;
System.out.println( "Checking... (no more output means success)" );
for( int i = GAP; i != 0; i = ( i + GAP ) % NUMS )
t.insert( i );
if( t.findMin( ) != 1 || t.findMax( ) != NUMS - 1 )
System.out.println( "FindMin or FindMax error!" );
for( int i = 1; i < NUMS; i++ )
if( t.find( i ) != i )
System.out.println( "Find error1!" );
}
}
// *Modula 3 Remove*
PROCEDURE Delete (t: T; k: Key.T; VAR (*OUT*) v: Value.T): BOOLEAN =
VAR
curr := t.root;
rep, repCh: Node;
BEGIN
(* find the node to delete (if any *)
WHILE curr # t.nil DO
CASE t.keyCompare(k, curr.k) OF
| -1 => curr := curr.l
| 1 => curr := curr.r
| 0 => EXIT
END
END;
IF curr = t.nil THEN RETURN FALSE END;
(* locate replacement node and one of its children *)
IF curr.l = t.nil OR curr.r = t.nil THEN
rep := curr
ELSE
rep := Successor(t, curr)
END;
IF rep.l # t.nil THEN repCh := rep.l ELSE repCh := rep.r END;
(* splice out "rep" node *)
repCh.p := rep.p;
IF rep.p = t.nil THEN
t.root := repCh
ELSE
IF rep = rep.p.l THEN repCh.p.l := repCh ELSE repCh.p.r := repCh END
END;
(* save value of node to be deleted *)
v := curr.v;
(* copy "rep" fields into "curr" if they are different *)
IF rep # curr THEN curr.k := rep.k; curr.v := rep.v END;
(* rebalance tree if necessary *)
IF rep.color = Color.Black THEN DeleteFixup(t, repCh) END;
DEC(t.num);
RETURN TRUE
END Delete;
PROCEDURE DeleteFixup (t: T; ch: Node) =
VAR p, sib: Node;
BEGIN
WHILE ch # t.root AND ch.color = Color.Black DO
p := ch.p;
IF ch = p.l THEN
(* "ch" is the left child of "p" *)
sib := p.r;
<* ASSERT sib # t.nil *>
IF sib.color = Color.Red THEN
(* case 1 *)
sib.color := Color.Black;
p.color := Color.Red;
LeftRotate(t, p, sib);
sib := p.r
END;
<* ASSERT sib.color = Color.Black AND sib # t.nil *>
IF sib.l.color = Color.Black AND sib.r.color = Color.Black THEN
(* case 2 *)
sib.color := Color.Red;
ch := p
ELSE
IF sib.r.color = Color.Black THEN
(* case 3 *)
<* ASSERT sib.l.color = Color.Red *>
sib.l.color := Color.Black;
sib.color := Color.Red;
RightRotate(t, sib, sib.l);
sib := p.r
END;
<* ASSERT sib.r.color = Color.Red *>
(* case 4 *)
sib.color := p.color;
p.color := Color.Black;
sib.r.color := Color.Black;
LeftRotate(t, p, sib);
ch := t.root
END
ELSE
(* "ch" is the right child of "p" *)
sib := p.l;
<* ASSERT sib # t.nil *>
IF sib.color = Color.Red THEN
(* case 1 *)
sib.color := Color.Black;
p.color := Color.Red;
RightRotate(t, p, sib);
sib := p.l
END;
<* ASSERT sib.color = Color.Black AND sib # t.nil *>
IF sib.r.color = Color.Black AND sib.l.color = Color.Black THEN
(* case 2 *)
sib.color := Color.Red;
ch := p
ELSE
IF sib.l.color = Color.Black THEN
(* case 3 *)
<* ASSERT sib.r.color = Color.Red *>
sib.r.color := Color.Black;
sib.color := Color.Red;
LeftRotate(t, sib, sib.r);
sib := p.l
END;
<* ASSERT sib.l.color = Color.Red *>
(* case 4 *)
sib.color := p.color;
p.color := Color.Black;
sib.l.color := Color.Black;
RightRotate(t, p, sib);
ch := t.root
END
END
END;
ch.color := Color.Black
END DeleteFixup;
Indeed, a wild mixture!!!
More information about the Digitalmars-d-learn
mailing list