mirror of
https://github.com/gnustep/libs-base.git
synced 2025-04-25 09:41:15 +00:00
git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/libs/base/trunk@4853 72102866-910b-0410-8b05-ffd578937521
607 lines
15 KiB
Objective-C
607 lines
15 KiB
Objective-C
/* Implementation for Objective-C BinaryTree collection object
|
||
Copyright (C) 1993, 1994, 1995, 1996 Free Software Foundation, Inc.
|
||
|
||
Written by: Andrew Kachites McCallum <mccallum@gnu.ai.mit.edu>
|
||
Date: May 1993
|
||
|
||
This file is part of the GNUstep Base Library.
|
||
|
||
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 USA.
|
||
*/
|
||
|
||
#include <config.h>
|
||
#include <base/BinaryTree.h>
|
||
#include <base/IndexedCollectionPrivate.h>
|
||
#include <base/BinaryTreeNode.h>
|
||
#include <base/NSString.h>
|
||
|
||
/* the sentinal */
|
||
static id nilBinaryTreeNode;
|
||
|
||
@implementation BinaryTree
|
||
|
||
+ (void) initialize
|
||
{
|
||
if (self == [BinaryTree class])
|
||
{
|
||
nilBinaryTreeNode = [[BinaryTreeNode alloc] init];
|
||
}
|
||
}
|
||
|
||
/* This is the designated initializer of this class */
|
||
- init
|
||
{
|
||
_count = 0;
|
||
_contents_root = [self nilNode];
|
||
return self;
|
||
}
|
||
|
||
/* Archiving must mimic the above designated initializer */
|
||
|
||
/* xxx See Collection _decodeContentsWithCoder:.
|
||
We shouldn't do an -addElement. finishEncodingInterconnectedObjects
|
||
should take care of all that. */
|
||
|
||
- _initCollectionWithCoder: aCoder
|
||
{
|
||
[self notImplemented:_cmd];
|
||
[super _initCollectionWithCoder:aCoder];
|
||
_count = 0;
|
||
_contents_root = [self nilNode];
|
||
return self;
|
||
}
|
||
|
||
- (void) _encodeContentsWithCoder: (id <Encoding>)aCoder
|
||
{
|
||
[aCoder startEncodingInterconnectedObjects];
|
||
[super _encodeContentsWithCoder:aCoder];
|
||
[aCoder finishEncodingInterconnectedObjects];
|
||
}
|
||
|
||
- (void) _decodeContentsWithCoder: (id <Decoding>)aCoder
|
||
{
|
||
[aCoder startDecodingInterconnectedObjects];
|
||
[super _decodeContentsWithCoder:aCoder];
|
||
[aCoder finishDecodingInterconnectedObjects];
|
||
}
|
||
|
||
/* Empty copy must empty an allocCopy'ed version of self */
|
||
- emptyCopy
|
||
{
|
||
BinaryTree *copy = [super emptyCopy];
|
||
copy->_count = 0;
|
||
copy->_contents_root = [self nilNode];
|
||
return copy;
|
||
}
|
||
|
||
/* This must work without sending any messages to content objects */
|
||
- (void) _empty
|
||
{
|
||
_count = 0;
|
||
_contents_root = [self nilNode];
|
||
}
|
||
|
||
- nilNode
|
||
{
|
||
return nilBinaryTreeNode;
|
||
}
|
||
|
||
- rootNode
|
||
{
|
||
return _contents_root;
|
||
}
|
||
|
||
- leftmostNodeFromNode: aNode
|
||
{
|
||
id left;
|
||
|
||
if (aNode && aNode != [self nilNode])
|
||
{
|
||
while ((left = [aNode leftNode]) != [self nilNode])
|
||
aNode = left;
|
||
}
|
||
return aNode;
|
||
}
|
||
|
||
- rightmostNodeFromNode: aNode
|
||
{
|
||
id right;
|
||
|
||
if (aNode && aNode != [self nilNode])
|
||
while ((right = [aNode rightNode]) != [self nilNode])
|
||
{
|
||
aNode = right;
|
||
}
|
||
return aNode;
|
||
}
|
||
|
||
- firstObject
|
||
{
|
||
return [self leftmostNodeFromNode: _contents_root];
|
||
}
|
||
|
||
- lastObject
|
||
{
|
||
return [self rightmostNodeFromNode: _contents_root];
|
||
}
|
||
|
||
/* This is correct only if the tree is sorted. How to deal with this? */
|
||
- maxObject
|
||
{
|
||
return [self rightmostNodeFromNode: _contents_root];
|
||
}
|
||
|
||
/* This is correct only is the tree is sorted. How to deal with this? */
|
||
- minObject
|
||
{
|
||
return [self leftmostNodeFromNode: _contents_root];
|
||
}
|
||
|
||
- successorOfObject: anObject
|
||
{
|
||
id tmp;
|
||
|
||
/* Make sure we actually own the anObject. */
|
||
NSAssert([anObject binaryTree] == self, NSInternalInconsistencyException);
|
||
|
||
// here tmp is the right node;
|
||
if ((tmp = [anObject rightNode]) != [self nilNode])
|
||
return [self leftmostNodeFromNode: tmp];
|
||
// here tmp is the parent;
|
||
tmp = [anObject parentNode];
|
||
while (tmp != [self nilNode] && anObject == [tmp rightNode])
|
||
{
|
||
anObject = tmp;
|
||
tmp = [tmp parentNode];
|
||
}
|
||
if (tmp == [self nilNode])
|
||
return NO_OBJECT;
|
||
return tmp;
|
||
}
|
||
|
||
// I should make sure that [_contents_root parentNode] == [self nilNode];
|
||
// Perhaps I should make [_contents_root parentNode] == binaryTreeObj ??;
|
||
|
||
- predecessorObject: anObject
|
||
{
|
||
id tmp;
|
||
|
||
/* Make sure we actually own the anObject. */
|
||
NSAssert([anObject binaryTree] == self, NSInternalInconsistencyException);
|
||
|
||
// here tmp is the left node;
|
||
if ((tmp = [anObject leftNode]) != [self nilNode])
|
||
return [self rightmostNodeFromNode:tmp];
|
||
// here tmp is the parent;
|
||
tmp = [anObject parentNode];
|
||
while (tmp != [self nilNode] && anObject == [tmp leftNode])
|
||
{
|
||
anObject = tmp;
|
||
tmp = [tmp parentNode];
|
||
}
|
||
if (tmp == [self nilNode])
|
||
return NO_OBJECT;
|
||
return tmp;
|
||
}
|
||
|
||
/* This relies on [_contents_root parentNode] == [self nilNode] */
|
||
- rootFromNode: aNode
|
||
{
|
||
id parentNode;
|
||
|
||
/* Make sure we actually own the aNode. */
|
||
NSAssert([aNode binaryTree] == self, NSInternalInconsistencyException);
|
||
|
||
while ((parentNode = [aNode parentNode]) != [self nilNode])
|
||
aNode = parentNode;
|
||
return aNode;
|
||
}
|
||
|
||
/* This relies on [_contents_root parentNode] == [self nilNode] */
|
||
- (unsigned) depthOfNode: aNode
|
||
{
|
||
unsigned count = 0;
|
||
|
||
/* Make sure we actually own the aNode. */
|
||
NSAssert([aNode binaryTree] == self, NSInternalInconsistencyException);
|
||
|
||
if (aNode == nil || aNode == [self nilNode])
|
||
[self error:"in %s, Can't find depth of nil node", sel_get_name(_cmd)];
|
||
do
|
||
{
|
||
aNode = [aNode parentNode];
|
||
count++;
|
||
}
|
||
while (aNode != [self nilNode]);
|
||
return count;
|
||
}
|
||
|
||
- (unsigned) heightOfNode: aNode
|
||
{
|
||
unsigned leftHeight, rightHeight;
|
||
id tmpNode;
|
||
|
||
/* Make sure we actually own the aNode. */
|
||
NSAssert([aNode binaryTree] == self, NSInternalInconsistencyException);
|
||
|
||
if (aNode == nil || aNode == [self nilNode])
|
||
{
|
||
[self error:"in %s, Can't find height of nil node", sel_get_name(_cmd)];
|
||
return 0;
|
||
}
|
||
else
|
||
{
|
||
leftHeight = ((tmpNode = [aNode leftNode])
|
||
?
|
||
(1 + [self heightOfNode:tmpNode])
|
||
:
|
||
0);
|
||
rightHeight = ((tmpNode = [aNode rightNode])
|
||
?
|
||
(1 + [self heightOfNode:tmpNode])
|
||
:
|
||
0);
|
||
return MAX(leftHeight, rightHeight);
|
||
}
|
||
}
|
||
|
||
- (unsigned) nodeCountUnderNode: aNode
|
||
{
|
||
unsigned count = 0;
|
||
|
||
/* Make sure we actually own the aNode. */
|
||
NSAssert([aNode binaryTree] == self, NSInternalInconsistencyException);
|
||
|
||
if ([aNode leftNode] != [self nilNode])
|
||
count += 1 + [self nodeCountUnderNode:[aNode leftNode]];
|
||
if ([aNode rightNode] != [self nilNode])
|
||
count += 1 + [self nodeCountUnderNode:[aNode rightNode]];
|
||
return count;
|
||
}
|
||
|
||
- leftRotateAroundNode: aNode
|
||
{
|
||
id y;
|
||
|
||
/* Make sure we actually own the aNode. */
|
||
NSAssert([aNode binaryTree] == self, NSInternalInconsistencyException);
|
||
|
||
y = [aNode rightNode];
|
||
if (y == [self nilNode])
|
||
return self;
|
||
[aNode setRightNode:[y leftNode]];
|
||
if ([y leftNode] != [self nilNode])
|
||
[[y leftNode] setParentNode:aNode];
|
||
[y setParentNode:[aNode parentNode]];
|
||
if ([aNode parentNode] == [self nilNode])
|
||
_contents_root = y;
|
||
else
|
||
{
|
||
if (NODE_IS_LEFTCHILD(aNode))
|
||
[[aNode parentNode] setLeftNode:y];
|
||
else
|
||
[[aNode parentNode] setRightNode:y];
|
||
}
|
||
[y setLeftNode:aNode];
|
||
[aNode setParentNode:y];
|
||
return self;
|
||
}
|
||
|
||
- rightRotateAroundNode: aNode
|
||
{
|
||
id y;
|
||
|
||
/* Make sure we actually own the aNode. */
|
||
NSAssert([aNode binaryTree] == self, NSInternalInconsistencyException);
|
||
|
||
y = [aNode leftNode];
|
||
if (y == [self nilNode])
|
||
return self;
|
||
[aNode setLeftNode:[y rightNode]];
|
||
if ([y rightNode] != [self nilNode])
|
||
[[y rightNode] setParentNode:aNode];
|
||
[y setParentNode:[aNode parentNode]];
|
||
if ([aNode parentNode] == [self nilNode])
|
||
_contents_root = y;
|
||
else
|
||
{
|
||
if (NODE_IS_RIGHTCHILD(aNode))
|
||
[[aNode parentNode] setRightNode:y];
|
||
else
|
||
[[aNode parentNode] setLeftNode:y];
|
||
}
|
||
[y setRightNode:aNode];
|
||
[aNode setParentNode:y];
|
||
return self;
|
||
}
|
||
|
||
- objectAtIndex: (unsigned)index
|
||
{
|
||
id ret;
|
||
|
||
CHECK_INDEX_RANGE_ERROR(index, _count);
|
||
ret = [self firstObject];
|
||
// Not very efficient; Should be rewritten;
|
||
while (index--)
|
||
ret = [self successorOfObject: ret];
|
||
return ret;
|
||
}
|
||
|
||
- (void) sortAddObject: newObject
|
||
{
|
||
id theParent, tmpChild;
|
||
|
||
/* Make sure no one else already owns the newObject. */
|
||
NSAssert([newObject binaryTree] == NO_OBJECT, NSInternalInconsistencyException);
|
||
|
||
/* Claim ownership of the newObject. */
|
||
[newObject retain];
|
||
[newObject setBinaryTree: self];
|
||
|
||
[newObject setLeftNode:[self nilNode]];
|
||
[newObject setRightNode:[self nilNode]];
|
||
theParent = [self nilNode];
|
||
tmpChild = _contents_root;
|
||
while (tmpChild != [self nilNode])
|
||
{
|
||
theParent = tmpChild;
|
||
if ([newObject compare: theParent] < 0)
|
||
tmpChild = [tmpChild leftNode];
|
||
else
|
||
tmpChild = [tmpChild rightNode];
|
||
}
|
||
[newObject setParentNode:theParent];
|
||
if (theParent == [self nilNode])
|
||
_contents_root = newObject;
|
||
else
|
||
{
|
||
if ([newObject compare: theParent] < 0)
|
||
[theParent setLeftNode:newObject];
|
||
else
|
||
[theParent setRightNode:newObject];
|
||
}
|
||
_count++;
|
||
}
|
||
|
||
- (void) addObject: newObject
|
||
{
|
||
// By default insert in sorted order.
|
||
[self sortAddObject: newObject];
|
||
}
|
||
|
||
- (void) removeObject: oldObject
|
||
{
|
||
id x, y;
|
||
|
||
/* Make sure we actually own the aNode. */
|
||
NSAssert([oldObject binaryTree] == self, NSInternalInconsistencyException);
|
||
|
||
/* Extract the oldObject and sew up the cut. */
|
||
if ([oldObject leftNode] == [self nilNode]
|
||
|| [oldObject rightNode] == [self nilNode])
|
||
y = oldObject;
|
||
else
|
||
y = [self successorOfObject: oldObject];
|
||
|
||
if ([y leftNode] != [self nilNode])
|
||
x = [y leftNode];
|
||
else
|
||
x = [y rightNode];
|
||
|
||
if (x != [self nilNode])
|
||
[x setParentNode: [y parentNode]];
|
||
|
||
if ([y parentNode] == [self nilNode])
|
||
_contents_root = x;
|
||
else
|
||
{
|
||
if (y == [[y parentNode] leftNode])
|
||
[[y parentNode] setLeftNode: x];
|
||
else
|
||
[[y parentNode] setRightNode: x];
|
||
}
|
||
|
||
if (y != oldObject)
|
||
{
|
||
/* put y in the place of oldObject */
|
||
[y setParentNode: [oldObject parentNode]];
|
||
[y setLeftNode: [oldObject leftNode]];
|
||
[y setRightNode: [oldObject rightNode]];
|
||
if (oldObject == [[oldObject parentNode] leftNode])
|
||
[[oldObject parentNode] setLeftNode: y];
|
||
else
|
||
[[oldObject parentNode] setRightNode: y];
|
||
[[oldObject leftNode] setParentNode: y];
|
||
[[oldObject rightNode] setParentNode: y];
|
||
}
|
||
_count--;
|
||
|
||
/* Release ownership of the object. */
|
||
#if 0
|
||
[oldObject setRightNode: [self nilNode]];
|
||
[oldObject setLeftNode: [self nilNode]];
|
||
[oldObject setParentNode: [self nilNode]];
|
||
#else
|
||
[oldObject setLeftNode: NO_OBJECT];
|
||
[oldObject setRightNode: NO_OBJECT];
|
||
[oldObject setParentNode: NO_OBJECT];
|
||
#endif
|
||
[oldObject setBinaryTree: NO_OBJECT];
|
||
[oldObject release];
|
||
}
|
||
|
||
|
||
// ENUMERATING;
|
||
|
||
- nextObjectWithEnumState: (void**)enumState
|
||
{
|
||
if (!(*enumState))
|
||
*enumState = [self leftmostNodeFromNode:_contents_root];
|
||
else
|
||
*enumState = [self successorOfObject:*enumState];
|
||
return (id) *enumState;
|
||
}
|
||
|
||
- prevObjectWithEnumState: (void**)enumState
|
||
{
|
||
if (!(*enumState))
|
||
*enumState = [self rightmostNodeFromNode:_contents_root];
|
||
else
|
||
*enumState = [self predecessorObject:*enumState];
|
||
return (id) *enumState;
|
||
}
|
||
|
||
- (unsigned) count
|
||
{
|
||
return _count;
|
||
}
|
||
|
||
|
||
/* replace this with something better eventually */
|
||
- _tmpPrintFromNode: aNode indent: (int)count
|
||
{
|
||
printf("%-*s", count, "");
|
||
printf("%s\n", [[aNode description] cString]);
|
||
printf("%-*s.", count, "");
|
||
if ([aNode leftNode] != [self nilNode])
|
||
[self _tmpPrintFromNode:[aNode leftNode] indent:count+2];
|
||
else
|
||
printf("\n");
|
||
printf("%-*s.", count, "");
|
||
if ([aNode rightNode] != [self nilNode])
|
||
[self _tmpPrintFromNode:[aNode rightNode] indent:count+2];
|
||
else
|
||
printf("\n");
|
||
return self;
|
||
}
|
||
|
||
- binaryTreePrintForDebugger
|
||
{
|
||
[self _tmpPrintFromNode:_contents_root indent:0];
|
||
return self;
|
||
}
|
||
|
||
@end
|
||
|
||
|
||
|
||
/* These methods removed because they belong to an
|
||
OrderedCollection implementation, not an IndexedCollection
|
||
implementation. */
|
||
|
||
#if 0
|
||
// NOTE: This gives you the power to put elements in unsorted order;
|
||
- insertObject: newObject before: oldObject
|
||
{
|
||
id tmp;
|
||
|
||
/* Make sure no one else already owns the newObject. */
|
||
NSAssert([newObject linkedList] == NO_OBJECT, NSInternalInconsistencyException);
|
||
|
||
/* Claim ownership of the newObject. */
|
||
[newObject retain];
|
||
[newObject setBinaryTree: self];
|
||
|
||
[newObject setRightNode:[self nilNode]];
|
||
[newObject setLeftNode:[self nilNode]];
|
||
if ((tmp = [oldObject leftNode]) != [self nilNode])
|
||
{
|
||
[(tmp = [self rightmostNodeFromNode:tmp]) setRightNode:newObject];
|
||
[newObject setParentNode:tmp];
|
||
}
|
||
else if (newObject != [self nilNode])
|
||
{
|
||
[oldObject setLeftNode:newObject];
|
||
[newObject setParentNode:oldObject];
|
||
}
|
||
else
|
||
{
|
||
_contents_root = newObject;
|
||
[newObject setParentNode:[self nilNode]];
|
||
}
|
||
_count++;
|
||
RETAIN_ELT(newObject);
|
||
return self;
|
||
}
|
||
|
||
// NOTE: This gives you the power to put elements in unsorted order;
|
||
- insertObject: newObject after: oldObject
|
||
{
|
||
id tmp;
|
||
|
||
/* Make sure no one else already owns the newObject. */
|
||
NSAssert([newObject linkedList] == NO_OBJECT, NSInternalInconsistencyException);
|
||
|
||
/* Claim ownership of the newObject. */
|
||
[newObject retain];
|
||
[newObject setBinaryTree: self];
|
||
|
||
[newObject setRightNode:[self nilNode]];
|
||
[newObject setLeftNode:[self nilNode]];
|
||
if ((tmp = [oldObject rightNode]) != [self nilNode])
|
||
{
|
||
[(tmp = [self leftmostNodeFromNode:tmp]) setLeftNode:newObject];
|
||
[newObject setParentNode:tmp];
|
||
}
|
||
else if (newObject != [self nilNode])
|
||
{
|
||
[oldObject setRightNode:newObject];
|
||
[newObject setParentNode:oldObject];
|
||
}
|
||
else
|
||
{
|
||
_contents_root = newObject;
|
||
[newObject setParentNode:[self nilNode]];
|
||
}
|
||
_count++;
|
||
RETAIN_ELT(newObject);
|
||
return self;
|
||
}
|
||
|
||
// NOTE: This gives you the power to put elements in unsorted order;
|
||
- insertObject: newObject atIndex: (unsigned)index
|
||
{
|
||
CHECK_INDEX_RANGE_ERROR(index, _count+1);
|
||
|
||
if (index == _count)
|
||
[self appendObject:newObject];
|
||
else
|
||
[self insertObject:newObject before:[self ObjectAtIndex:index]];
|
||
return self;
|
||
}
|
||
|
||
// NOTE: This gives you the power to put elements in unsorted order;
|
||
- appendObject: newObject
|
||
{
|
||
if (_count == 0)
|
||
{
|
||
/* Make sure no one else already owns the newObject. */
|
||
NSAssert([newObject linkedList] == NO_OBJECT, NSInternalInconsistencyException);
|
||
|
||
/* Claim ownership of the newObject. */
|
||
[newObject retain];
|
||
[newObject setBinaryTree: self];
|
||
|
||
_contents_root = newObject;
|
||
_count = 1;
|
||
[newObject setLeftNode:[self nilNode]];
|
||
[newObject setRightNode:[self nilNode]];
|
||
[newObject setParentNode:[self nilNode]];
|
||
}
|
||
else
|
||
[self insertObject:newObject after:[self lastObject]];
|
||
return self;
|
||
}
|
||
#endif
|