/* This file corresponds to orb/gap/avltree.gi, it imlements some of
* its functionality on the C level for better performance. */
static Obj AVLTreeType; /* Imported from the library to be able to check type */ static Obj AVLTreeTypeMutable; /* Imported from the library to be able to check type */ static Obj AVLTree; /* Constructor function imported from the library */ static Obj HTGrow; /* Operation function imported from the library */ static Obj PermList;
/* Note that we have to check the arguments for functions that are called
* by user programs since we do not go through method selection! */
static Obj FuncAVLCmp_C(Obj self, Obj a, Obj b) /* A very fast three-way comparison function. */
{ if (EQ(a,b)) return INTOBJ_INT(0); elseif (LT(a,b)) return INTOBJ_INT(-1); elsereturn INTOBJ_INT(1);
}
/* The following are some internal macros to make the code more readable.
* We always know that these positions are properly initialized! */
/* Last used entry, never shrinks, always = 3 mod 4: */ #define AVLLen(t) INT_INTOBJ(ELM_PLIST(t,1)) #define SetAVLLen(t,i) SET_ELM_PLIST(t,1,INTOBJ_INT(i)) /* Index of first freed entry, if 0, none free: */ #define AVLFree(t) INT_INTOBJ(ELM_PLIST(t,2)) #define AVLFreeObj(t) ELM_PLIST(t,2) #define SetAVLFree(t,i) SET_ELM_PLIST(t,2,INTOBJ_INT(i)) #define SetAVLFreeObj(t,i) SET_ELM_PLIST(t,2,i) /* Number of nodes currently in the tree: */ #define AVLNodes(t) INT_INTOBJ(ELM_PLIST(t,3)) #define SetAVLNodes(t,i) SET_ELM_PLIST(t,3,INTOBJ_INT(i)) /* Highest allocated index, always = 3 mod 4: */ #define AVLAlloc(t) INT_INTOBJ(ELM_PLIST(t,4)) #define SetAVLAlloc(t,i) SET_ELM_PLIST(t,4,INTOBJ_INT(i)) /* Three-way-comparison function: */ #define AVL3Comp(t) ELM_PLIST(t,5) #define SetAVL3Comp(t,f) SET_ELM_PLIST(t,5,f);CHANGED_BAG(t) /* Reference to the top node: */ #define AVLTop(t) INT_INTOBJ(ELM_PLIST(t,6)) #define SetAVLTop(t,i) SET_ELM_PLIST(t,6,INTOBJ_INT(i)) /* Reference to the value plist: */ #define AVLValues(t) ELM_PLIST(t,7) #define SetAVLValues(t,l) SET_ELM_PLIST(t,7,l);CHANGED_BAG(t)
#define AVLmask ((unsignedlong)(3L)) #define AVLmask2 ((unsignedlong)(-4L)) /* Use the following only if you know that the tree object is long enough and
* something is bound to position i! */ #define AVLData(t,i) ELM_PLIST(t,i) #define SetAVLData(t,i,d) SET_ELM_PLIST(t,i,d); CHANGED_BAG(t) #define AVLLeft(t,i) (INT_INTOBJ(ELM_PLIST(t,i+1)) & AVLmask2) #define SetAVLLeft(t,i,n) SET_ELM_PLIST(t,i+1, \
INTOBJ_INT( (INT_INTOBJ(ELM_PLIST(t,i+1)) & AVLmask) + n )) #define AVLRight(t,i) INT_INTOBJ(ELM_PLIST(t,i+2)) #define SetAVLRight(t,i,n) SET_ELM_PLIST(t,i+2,INTOBJ_INT(n)) #define AVLRank(t,i) INT_INTOBJ(ELM_PLIST(t,i+3)) #define SetAVLRank(t,i,r) SET_ELM_PLIST(t,i+3,INTOBJ_INT(r)) #define AVLBalFactor(t,i) (INT_INTOBJ(ELM_PLIST(t,i+1)) & AVLmask) #define SetAVLBalFactor(t,i,b) SET_ELM_PLIST(t,i+1, \
INTOBJ_INT( (INT_INTOBJ(ELM_PLIST(t,i+1)) & AVLmask2) + b ))
staticInt AVLNewNode( Obj t )
{ Int n,a;
n = AVLFree(t); if (n > 0) {
SetAVLFreeObj(t,ELM_PLIST(t,n));
} else {
n = AVLLen(t);
a = AVLAlloc(t); if (n < a) { /* There is already enough allocated! */
SetAVLLen(t,n+4);
n++;
} else { /* We have to allocate new space! */
n++;
a = a*2 + 1; /* Retain congruent 3 mod 4 */
SetAVLAlloc(t,a);
ResizeBag(t,(a+1)*sizeof(Obj));
SetAVLLen(t,n+3);
}
}
SET_ELM_PLIST(t,n,INTOBJ_INT(0));
SET_ELM_PLIST(t,n+1,INTOBJ_INT(0));
SET_ELM_PLIST(t,n+2,INTOBJ_INT(0));
SET_ELM_PLIST(t,n+3,INTOBJ_INT(0)); return n;
}
staticinline Obj AVLFreeNode( Obj t, Int n )
{
Obj v,o;
SET_ELM_PLIST(t,n,AVLFreeObj(t));
SetAVLFree(t,n);
n /= 4;
v = AVLValues(t); if (v != Fail && ISB_LIST(v,n)) {
o = ELM_PLIST(v,n);
UNB_LIST(v,n); return o;
} returnTrue;
}
static Obj FuncAVLLookup_C( Obj self, Obj t, Obj d )
{ if (TNUM_OBJ(t) != T_POSOBJ ||
(TYPE_POSOBJ(t) != AVLTreeType &&
TYPE_POSOBJ(t) != AVLTreeTypeMutable)) {
ErrorQuit( "Usage: AVLLookup(avltree, object)", 0L, 0L ); return0L;
} Int p = AVLFind(t,d); if (p == 0) return Fail; return AVLValue(t,p);
}
staticinlineInt AVLIndex( Obj t, Int i )
{ Int p,offset,r;
if (i < 1 || i > AVLNodes(t)) return0;
p = AVLTop(t);
offset = 0; while (1) { /* will be left by return */
r = offset + AVLRank(t,p); if (i < r) /* go left: */
p = AVLLeft(t,p); elseif (i == r) /* found! */ return p; else { /* go right: */
offset = r;
p = AVLRight(t,p);
}
}
}
static Obj FuncAVLIndexLookup_C( Obj self, Obj t, Obj i )
{ Int p;
Obj vals; if (!IS_INTOBJ(i) ||
TNUM_OBJ(t) != T_POSOBJ ||
(TYPE_POSOBJ(t) != AVLTreeType &&
TYPE_POSOBJ(t) != AVLTreeTypeMutable)) {
ErrorQuit( "Usage: AVLIndexLookup(avltree, integer)", 0L, 0L ); return0L;
}
p = AVLIndex(t,INT_INTOBJ(i)); if (p == 0) return Fail;
vals = AVLValues(t);
p /= 4; if (vals == Fail || !ISB_LIST(vals,p)) returnTrue; else return ELM_LIST(vals,p);
}
staticinlinevoid AVLRebalance( Obj tree, Int q, Int *newroot, int *shrink ) /* the tree starting at q has balanced subtrees but is out of balance: thedepthofthedeepersubtreeis2biggerthanthedepthoftheother tree.Thisfunctionchangesthissituationfollowingtheprocedure describedinKnuth:"TheArtofComputerProgramming". Itreturnsnothingbutstoresthenewstartnodeofthesubtreeinto "newroot"andin"shrink"abooleanvaluewhichindicates,ifthe
depth of the tree was decreased by 1 by this operation. */
{ Int p, l;
if (shrink)
*shrink = 1; /* in nearly all cases this happens */ if (AVLBalFactor(tree,q) == 2) /* was: < 0 */
p = AVLLeft(tree,q); else
p = AVLRight(tree,q); if (AVLBalFactor(tree,p) == AVLBalFactor(tree,q)) { /* we need a single rotation: q++p=q--p= /\/\/\/\ ap+==>q=cORp-c==>aq= /\/\/\/\
b c a b a b b c */ if (AVLBalFactor(tree,q) == 1) { /* was: > 0 */
SetAVLRight(tree,q,AVLLeft(tree,p));
SetAVLLeft(tree,p,q);
SetAVLBalFactor(tree,q,0);
SetAVLBalFactor(tree,p,0);
SetAVLRank(tree,p,AVLRank(tree,p) + AVLRank(tree,q));
} else {
SetAVLLeft(tree,q,AVLRight(tree,p));
SetAVLRight(tree,p,q);
SetAVLBalFactor(tree,q,0);
SetAVLBalFactor(tree,p,0);
SetAVLRank(tree,q,AVLRank(tree,q) - AVLRank(tree,p));
}
} elseif (AVLBalFactor(tree,p) == 3 - AVLBalFactor(tree,q)) { /* was: = - */ /* we need a double rotation: q++q-- /\c=/\c= ap-/\p+e/\ /\==>qpOR/\==>pq ce/\/\ac/\/\ /\abde/\abde
b d b d */ if (AVLBalFactor(tree,q) == 1) { /* was: > 0 */
l = AVLLeft(tree,p);
SetAVLRight(tree,q,AVLLeft(tree,l));
SetAVLLeft(tree,p,AVLRight(tree,l));
SetAVLLeft(tree,l,q);
SetAVLRight(tree,l,p); if (AVLBalFactor(tree,l) == 1) { /* was: > 0 */
SetAVLBalFactor(tree,p,0);
SetAVLBalFactor(tree,q,2); /* was: -1 */
} elseif (AVLBalFactor(tree,l) == 0) {
SetAVLBalFactor(tree,p,0);
SetAVLBalFactor(tree,q,0);
} else { /* AVLBalFactor(tree,l) < 0 */
SetAVLBalFactor(tree,p,1);
SetAVLBalFactor(tree,q,0);
}
SetAVLBalFactor(tree,l,0);
SetAVLRank(tree,p,AVLRank(tree,p) - AVLRank(tree,l));
SetAVLRank(tree,l,AVLRank(tree,l) + AVLRank(tree,q));
p = l;
} else {
l = AVLRight(tree,p);
SetAVLLeft(tree,q,AVLRight(tree,l));
SetAVLRight(tree,p,AVLLeft(tree,l));
SetAVLLeft(tree,l,p);
SetAVLRight(tree,l,q); if (AVLBalFactor(tree,l) == 2) { /* was: < 0 */
SetAVLBalFactor(tree,p,0);
SetAVLBalFactor(tree,q,1);
} elseif (AVLBalFactor(tree,l) == 0) {
SetAVLBalFactor(tree,p,0);
SetAVLBalFactor(tree,q,0);
} else { /* AVLBalFactor(tree,l) > 0 */
SetAVLBalFactor(tree,p,2); /* was: -1 */
SetAVLBalFactor(tree,q,0);
}
SetAVLBalFactor(tree,l,0);
SetAVLRank(tree,l,AVLRank(tree,l) + AVLRank(tree,p));
SetAVLRank(tree,q,AVLRank(tree,q) - AVLRank(tree,l)); /* new value of AVLRank(tree,l)! */
p = l;
}
} else { /* AVLBalFactor(tree,p) = 0 */ /* we need a single rotation: q++p-q--p+ /\/\/\/\ ap===>q+cORp=c==>aq- /\/\/\/\
b c a b a b b c */ if (AVLBalFactor(tree,q) == 1) { /* was: > 0 */
SetAVLRight(tree,q,AVLLeft(tree,p));
SetAVLLeft(tree,p,q);
SetAVLBalFactor(tree,q,1);
SetAVLBalFactor(tree,p,2); /* was: -1 */
SetAVLRank(tree,p,AVLRank(tree,p) + AVLRank(tree,q));
} else {
SetAVLLeft(tree,q,AVLRight(tree,p));
SetAVLRight(tree,p,q);
SetAVLBalFactor(tree,q,2); /* was: -1 */
SetAVLBalFactor(tree,p,1);
SetAVLRank(tree,q,AVLRank(tree,q) - AVLRank(tree,p));
} if (shrink)
*shrink = 0;
}
*newroot = p;
}
static Obj FuncAVLAdd_C( Obj self, Obj tree, Obj data, Obj value )
{ /* Parameters: tree, data, value treeisanAVLtree dataisadatastructuredefinedbytheuser valueisthevaluestoredunderthekeydata,iftrue,nothingisstored Triestoaddthedataasanodeintree.Itisanerror,ifthereis alreadyanodewhichis"equal"todatawithrespecttothecomparison function.Returnstrueifeverythingwentwellorfail,ifanequal
object is already present. */
Obj compare; Int p, new; /* here all steps are recorded: -1:left, +1:right */ int path[64]; /* Trees will never be deeper than that! */ Int nodes[64]; int n; /* The length of the list nodes */ Int q; Int rankadds[64]; int rankaddslen; /* length of list rankadds */ Int c; Int l; Int i;
compare = AVL3Comp(tree);
p = AVLTop(tree); if (p == 0) { /* A new, single node in the tree */ new = AVLNewNode(tree);
SetAVLLeft(tree,new,0);
SetAVLRight(tree,new,0);
SetAVLBalFactor(tree,new,0);
SetAVLRank(tree,new,1);
SetAVLData(tree,new,data); if (value != True)
SetAVLValue(tree,new,value);
SetAVLNodes(tree,1);
SetAVLTop(tree,new); returnTrue;
}
/* let's first find the right position in the tree: but:rememberthelastnodeonthewaywithbal.factor<>0andthepath afterthisnode and:rememberthenodeswheretheRankentryisincrementedincasewe
find an "equal" element */
nodes[1] = p; /* here we store all nodes on our way, nodes[i+1] is reached
from nodes[i] by walking one step path[i] */
n = 1; /* this is the length of "nodes" */
q = 0; /* this is the last node with bal. factor <> 0 */ /* index in "nodes" or 0 for no such node */
rankaddslen = 0; /* nothing done so far, list of Rank-modified nodes */ do { /* do we have to remember this position? */ if (AVLBalFactor(tree,p) != 0)
q = n; /* forget old last node with balance factor != 0 */
/* now one step: */
c = INT_INTOBJ(CALL_2ARGS(compare,data,AVLData(tree,p))); if (c == 0) { /* we did not want this! */ for (p = 1; p <= rankaddslen; p++) {
SetAVLRank(tree,p,AVLRank(tree,rankadds[p]) - 1);
} return Fail; /* tree is unchanged */
}
l = p; /* remember last position */ if (c < 0) { /* data < AVLData(tree,p) */
SetAVLRank(tree,p,AVLRank(tree,p) + 1);
rankadds[++rankaddslen] = p;
p = AVLLeft(tree,p);
} else { /* data > AVLData(tree,p) */
p = AVLRight(tree,p);
}
path[n] = c > 0 ? 1 : 2; /* Internal representation! */
nodes[++n] = p;
} while (p != 0); /* now p is 0 and nodes[n-1] is the node where data must be attached thetreemustbemodifiedbetweennodes[q]andnodes[n-1]alongpath
Ranks are already done */
l = nodes[n-1]; /* for easier reference */
/* a new node: */
p = AVLNewNode(tree);
SetAVLLeft(tree,p,0);
SetAVLRight(tree,p,0);
SetAVLBalFactor(tree,p,0);
SetAVLRank(tree,p,1);
SetAVLData(tree,p,data); if (value != True) {
SetAVLValue(tree,p,value);
} /* insert into tree: */ if (c < 0) { /* left */
SetAVLLeft(tree,l,p);
} else {
SetAVLRight(tree,l,p);
}
SetAVLNodes(tree,AVLNodes(tree)+1);
/* modify balance factors between q and l: */ for (i = q+1;i <= n-1;i++) {
SetAVLBalFactor(tree,nodes[i],path[i]);
}
/* is rebalancing at q necessary? */ if (q == 0) /* whole tree has grown one step */ returnTrue; if (AVLBalFactor(tree,nodes[q]) == 3-path[q]) { /* the subtree at q has gotten more balanced */
SetAVLBalFactor(tree,nodes[q],0); returnTrue; /* Success! */
}
/* now at last we do have to rebalance at nodes[q] because the tree has
gotten out of balance: */
AVLRebalance(tree,nodes[q],&p,0);
/* finishing touch: link new root of subtree (p) to t: */ if (q == 1) { /* q resp. r was First node */
SetAVLTop(tree,p);
} elseif (path[q-1] == 2) {
SetAVLLeft(tree,nodes[q-1],p);
} else {
SetAVLRight(tree,nodes[q-1],p);
}
returnTrue;
}
static Obj FuncAVLIndexAdd_C( Obj self, Obj tree, Obj data, Obj value, Obj ind )
{ /* Parameters: tree, data, value treeisanAVLtree dataisadatastructuredefinedbytheuser valueisthevaluestoredunderthekeydata,iftrue,nothingisstored indexistheindex,wheredatashouldbeinsertedintree1istat firstposition,NumberOfNodes+1afterthelast. Triestoaddthedataasanodeintree.Returnstrueifeverything
went well or fail, if something went wrong, */
Int p, new; /* here all steps are recorded: -1:left, +1:right */ int path[64]; /* Trees will never be deeper than that! */ Int nodes[64]; int n; /* The length of the list nodes */ Int q; Int c; Int l; Int index; Int i; Int offset;
index = INT_INTOBJ(ind); if (index < 1 || index > AVLNodes(tree)+1) return Fail;
p = AVLTop(tree); if (p == 0) { /* A new, single node in the tree */ new = AVLNewNode(tree);
SetAVLLeft(tree,new,0);
SetAVLRight(tree,new,0);
SetAVLBalFactor(tree,new,0);
SetAVLRank(tree,new,1);
SetAVLData(tree,new,data); if (value != True)
SetAVLValue(tree,new,value);
SetAVLNodes(tree,1);
SetAVLTop(tree,new); returnTrue;
}
/* let's first find the right position in the tree: but:rememberthelastnodeonthewaywithbal.factor<>0andthepath afterthisnode and:rememberthenodeswheretheRankentryisincrementedincasewe
find an "equal" element */
nodes[1] = p; /* here we store all nodes on our way, nodes[i+1] is reached
from nodes[i] by walking one step path[i] */
n = 1; /* this is the length of "nodes" */
q = 0; /* this is the last node with bal. factor <> 0 */ /* index in "nodes" or 0 for no such node */
offset = 0; /* number of nodes with smaller index than those in subtree */
do { /* do we have to remember this position? */ if (AVLBalFactor(tree,p) != 0)
q = n; /* forget old last node with balance factor != 0 */
/* now one step: */ if (index <= offset+AVLRank(tree,p))
c = -1; else
c = +1;
l = p; /* remember last position */ if (c < 0) { /* data < AVLData(tree,p) */
SetAVLRank(tree,p,AVLRank(tree,p) + 1);
p = AVLLeft(tree,p);
} else { /* data > AVLData(tree,p) */
offset += AVLRank(tree,p);
p = AVLRight(tree,p);
}
path[n] = c > 0 ? 1 : 2; /* Internal representation! */
nodes[++n] = p;
} while (p != 0); /* now p is 0 and nodes[n-1] is the node where data must be attached thetreemustbemodifiedbetweennodes[q]andnodes[n-1]alongpath
Ranks are already done */
l = nodes[n-1]; /* for easier reference */
/* a new node: */
p = AVLNewNode(tree);
SetAVLLeft(tree,p,0);
SetAVLRight(tree,p,0);
SetAVLBalFactor(tree,p,0);
SetAVLRank(tree,p,1);
SetAVLData(tree,p,data); if (value != True) {
SetAVLValue(tree,p,value);
} /* insert into tree: */ if (c < 0) { /* left */
SetAVLLeft(tree,l,p);
} else {
SetAVLRight(tree,l,p);
}
SetAVLNodes(tree,AVLNodes(tree)+1);
/* modify balance factors between q and l: */ for (i = q+1;i <= n-1;i++) {
SetAVLBalFactor(tree,nodes[i],path[i]);
}
/* is rebalancing at q necessary? */ if (q == 0) /* whole tree has grown one step */ returnTrue; if (AVLBalFactor(tree,nodes[q]) == 3-path[q]) { /* the subtree at q has gotten more balanced */
SetAVLBalFactor(tree,nodes[q],0); returnTrue; /* Success! */
}
/* now at last we do have to rebalance at nodes[q] because the tree has
gotten out of balance: */
AVLRebalance(tree,nodes[q],&p,0);
/* finishing touch: link new root of subtree (p) to t: */ if (q == 1) { /* q resp. r was First node */
SetAVLTop(tree,p);
} elseif (path[q-1] == 2) {
SetAVLLeft(tree,nodes[q-1],p);
} else {
SetAVLRight(tree,nodes[q-1],p);
}
returnTrue;
}
static Obj FuncAVLDelete_C( Obj self, Obj tree, Obj data) /* Parameters: tree, data treeisanAVLtree dataisadatastructuredefinedbytheuser Triestofinddataasanodeinthetree.Iffound,thisnodeisdeleted andthetreerebalanced.Itisanerror,ofthenodeisnotfound.
Returns fail in this case, and true normally. */
{
Obj compare; Int p; int path[64]; /* Trees will never be deeper than that! */ Int nodes[64]; int n; int c; int m,i; Int r,l; Int ranksubs[64]; int ranksubslen; /* length of list randsubs */
Obj old;
/* let's first find the right position in the tree: and:rememberthenodeswheretheRankentryisdecrementedincasewe
find an "equal" element */
nodes[1] = p; /* here we store all nodes on our way, nodes[i+1] is reached
from nodes[i] by walking one step path[i] */
n = 1;
ranksubslen = 0; /* nothing done so far, list of Rank-modified nodes */
do {
/* what is the next step? */
c = INT_INTOBJ(CALL_2ARGS(compare,data,AVLData(tree,p)));
if (c != 0) { /* only if data not found! */ if (c < 0) { /* data < AVLData(tree,p) */
SetAVLRank(tree,p,AVLRank(tree,p) - 1);
ranksubs[++ranksubslen] = p;
p = AVLLeft(tree,p);
} else { /* data > AVLData(tree,p) */
p = AVLRight(tree,p);
}
path[n] = c > 0 ? 1 : 2; /* Internal representation! */
nodes[++n] = p;
}
if (p == 0) { /* error, we did not find data */ for (i = 1; i <= ranksubslen; i++) {
SetAVLRank(tree,ranksubs[i],AVLRank(tree,ranksubs[i]) + 1);
} return Fail;
}
} while (c != 0); /* until we find the right node */ /* now data is equal to AVLData(tree,p) so this node p must be removed. thetreemustbemodifiedbetweenAVLTop(tree)andnodes[n]alongpath
Ranks are already done up there. */
/* now we have to search a neighbour, we modify "nodes" and "path" but
* not n! */
m = n; if (AVLBalFactor(tree,p) == 2) { /* (was: < 0) search to the left */
l = AVLLeft(tree,p); /* must be a node! */
SetAVLRank(tree,p,AVLRank(tree,p) - 1); /* we will delete in left subtree! */
path[m] = 2; /* was: -1 */
nodes[++m] = l; while (AVLRight(tree,l) != 0) {
l = AVLRight(tree,l);
path[m] = 1;
nodes[++m] = l;
}
c = -1; /* we got predecessor */
} elseif (AVLBalFactor(tree,p) > 0) { /* search to the right */
l = AVLRight(tree,p); /* must be a node! */
path[m] = 1;
nodes[++m] = l; while (AVLLeft(tree,l) != 0) {
SetAVLRank(tree,l,AVLRank(tree,l) - 1); /* we will delete in left subtree! */
l = AVLLeft(tree,l);
path[m] = 2; /* was: -1 */
nodes[++m] = l;
}
c = 1; /* we got successor */
} else { /* equal depths */ if (AVLLeft(tree,p) != 0) {
l = AVLLeft(tree,p);
SetAVLRank(tree,p,AVLRank(tree,p) - 1);
path[m] = 2; /* was: -1 */
nodes[++m] = l; while (AVLRight(tree,l) != 0) {
l = AVLRight(tree,l);
path[m] = 1;
nodes[++m] = l;
}
c = -1; /* we got predecessor */
} else { /* we got an end node */
l = p;
c = 0;
}
} /* l points now to a neighbour, in case c = -1 to the predecessor, in case c=1tothesuccessor,ortopitselfincasec=0
"nodes" and "path" is updated, but n could be < m */
/* Copy Data from l up to p: order is NOT modified */
SetAVLData(tree,p,AVLData(tree,l)); /* works for m = n, i.e. if p is end node */
/* Delete node at l = nodes[m] by modifying nodes[m-1]:
Note: nodes[m] has maximal one subtree! */ if (c <= 0)
r = AVLLeft(tree,l); else/* c > 0 */
r = AVLRight(tree,l);
if (path[m-1] == 2) /* was: < 0 */
SetAVLLeft(tree,nodes[m-1],r); else
SetAVLRight(tree,nodes[m-1],r);
SetAVLNodes(tree,AVLNodes(tree)-1);
old = AVLFreeNode(tree,l);
/* modify balance factors: thesubtreenodes[m-1]hasbecomeshorteratitsleft(resp.right) subtree,ifpath[m-1]=-1(resp.+1).Wehavetoreactaccordingto theBalFactoratthisnodeandthenupthetree,ifthewholesubtree hasshrunk:
(we decrement m and work until the corresponding subtree has not shrunk) */
m--; /* start work HERE */ while (m >= 1) { if (AVLBalFactor(tree,nodes[m]) == 0) {
SetAVLBalFactor(tree,nodes[m],3-path[m]); /* we made path[m] shorter*/ return old;
} elseif (AVLBalFactor(tree,nodes[m]) == path[m]) {
SetAVLBalFactor(tree,nodes[m],0); /* we made path[m] shorter */
} else { /* tree is out of balance */ int shorter;
AVLRebalance(tree,nodes[m],&p,&shorter); if (m == 1) {
SetAVLTop(tree,p); return old; /* everything is done */
} elseif (path[m-1] == 2) /* was: = -1 */
SetAVLLeft(tree,nodes[m-1],p); else
SetAVLRight(tree,nodes[m-1],p); if (!shorter) return old; /* nothing happens further up */
}
m--;
} return old;
}
static Obj FuncAVLIndexDelete_C( Obj self, Obj tree, Obj index) /* Parameters: tree, index treeisanAVLtree indexistheindexoftheelementtobedeleted,mustbebetween1and AVLNodes(tree)inclusively
returns fail if index is out of range, otherwise the deleted key; */
{ Int p; int path[64]; /* Trees will never be deeper than that! */ Int nodes[64]; int n; int c; Int offset; int m; Int r,l; Int ind;
Obj x;
p = AVLTop(tree); if (p == 0) /* Nothing to delete or find */ return Fail;
ind = INT_INTOBJ(index); if (ind < 1 || ind > AVLNodes(tree)) /* out of range */ return Fail;
if (AVLNodes(tree) == 1) {
x = AVLData(tree,p);
SetAVLNodes(tree,0);
SetAVLTop(tree,0);
AVLFreeNode(tree,p); return x;
}
/* let's first find the right position in the tree: and:rememberthenodeswheretheRankentryisdecrementedincasewe
find an "equal" element */
nodes[1] = p; /* here we store all nodes on our way, nodes[i+1] is reached
from nodes[i] by walking one step path[i] */
n = 1;
offset = 0; /* number of "smaller" nodes than subtree in whole tree */
do {
/* what is the next step? */ if (ind == offset + AVLRank(tree,p)) {
c = 0; /* we found our node! */
x = AVLData(tree,p);
} elseif (ind < offset + AVLRank(tree,p))
c = -1; /* we have to go left */ else
c = 1; /* we have to go right */
if (c != 0) { /* only if data not found! */ if (c < 0) { /* data < AVLData(tree,p) */
SetAVLRank(tree,p,AVLRank(tree,p) - 1);
p = AVLLeft(tree,p);
} else { /* data > AVLData(tree,p) */
offset += AVLRank(tree,p);
p = AVLRight(tree,p);
}
path[n] = c > 0 ? 1 : 2; /* Internal representation! */
nodes[++n] = p;
}
} while (c != 0); /* until we find the right node */ /* now index is right, so this node p must be removed. thetreemustbemodifiedbetweenAVLTop(tree)andnodes[n]alongpath
Ranks are already done up there. */
/* now we have to search a neighbour, we modify "nodes" and "path" but
* not n! */
m = n; if (AVLBalFactor(tree,p) == 2) { /* (was: < 0) search to the left */
l = AVLLeft(tree,p); /* must be a node! */
SetAVLRank(tree,p,AVLRank(tree,p) - 1); /* we will delete in left subtree! */
path[m] = 2; /* was: -1 */
nodes[++m] = l; while (AVLRight(tree,l) != 0) {
l = AVLRight(tree,l);
path[m] = 1;
nodes[++m] = l;
}
c = -1; /* we got predecessor */
} elseif (AVLBalFactor(tree,p) > 0) { /* search to the right */
l = AVLRight(tree,p); /* must be a node! */
path[m] = 1;
nodes[++m] = l; while (AVLLeft(tree,l) != 0) {
SetAVLRank(tree,l,AVLRank(tree,l) - 1); /* we will delete in left subtree! */
l = AVLLeft(tree,l);
path[m] = 2; /* was: -1 */
nodes[++m] = l;
}
c = 1; /* we got successor */
} else { /* equal depths */ if (AVLLeft(tree,p) != 0) {
l = AVLLeft(tree,p);
SetAVLRank(tree,p,AVLRank(tree,p) - 1);
path[m] = 2; /* was: -1 */
nodes[++m] = l; while (AVLRight(tree,l) != 0) {
l = AVLRight(tree,l);
path[m] = 1;
nodes[++m] = l;
}
c = -1; /* we got predecessor */
} else { /* we got an end node */
l = p;
c = 0;
}
} /* l points now to a neighbour, in case c = -1 to the predecessor, in case c=1tothesuccessor,ortopitselfincasec=0
"nodes" and "path" is updated, but n could be < m */
/* Copy Data from l up to p: order is NOT modified */
SetAVLData(tree,p,AVLData(tree,l)); /* works for m = n, i.e. if p is end node */
/* Delete node at l = nodes[m] by modifying nodes[m-1]:
Note: nodes[m] has maximal one subtree! */ if (c <= 0)
r = AVLLeft(tree,l); else/* c > 0 */
r = AVLRight(tree,l);
/* modify balance factors: thesubtreenodes[m-1]hasbecomeshorteratitsleft(resp.right) subtree,ifpath[m-1]=-1(resp.+1).Wehavetoreactaccordingto theBalFactoratthisnodeandthenupthetree,ifthewholesubtree hasshrunk:
(we decrement m and work until the corresponding subtree has not shrunk) */
m--; /* start work HERE */ while (m >= 1) { if (AVLBalFactor(tree,nodes[m]) == 0) {
SetAVLBalFactor(tree,nodes[m],3-path[m]); /* we made path[m] shorter*/ return x;
} elseif (AVLBalFactor(tree,nodes[m]) == path[m]) {
SetAVLBalFactor(tree,nodes[m],0); /* we made path[m] shorter */
} else { /* tree is out of balance */ int shorter;
AVLRebalance(tree,nodes[m],&p,&shorter); if (m == 1) {
SetAVLTop(tree,p); return x; /* everything is done */
} elseif (path[m-1] == 2) /* was: = -1 */
SetAVLLeft(tree,nodes[m-1],p); else
SetAVLRight(tree,nodes[m-1],p); if (!shorter) return x; /* nothing happens further up */
}
m--;
} return x;
}
staticinlineInt HT_Hash(Obj ht, Obj x)
{
Obj hfd = ElmPRec(ht, RNam_hfd);
Obj hf = ElmPRec(ht, RNam_hf);
Obj res = CALL_2ARGS(hf, x, hfd); if (res == Fail || res == INTOBJ_INT(0))
ErrorMayQuit("hash function not applicable to key of type %s",
(Int)TNAM_OBJ(x), 0); if (!IS_INTOBJ(res))
ErrorMayQuit("hash function should return small integer or the value 'fail', not a %s",
(Int)TNAM_OBJ(res), 0); Int h = INT_INTOBJ(res); Int limit = LEN_LIST(ElmPRec(ht,RNam_els)); if (h <= 0 || h > limit)
ErrorMayQuit("hash value %d not in range 1..%d", h, limit); return h;
}
/* Lookup slot: */
els = ElmPRec(ht,RNam_els);
vals = ElmPRec(ht,RNam_vals);
tmp = ELM_PLIST(els,h); /* Note that hash values are always within
the boundaries of this list */ if (tmp == 0L) { /* Unbound entry! */
SET_ELM_PLIST(els,h,x);
CHANGED_BAG(els); if (v != True) ASS_LIST(vals,h,v);
AssPRec(ht,RNam_nr,INTOBJ_INT(INT_INTOBJ(ElmPRec(ht,RNam_nr))+1)); return INTOBJ_INT(h);
}
/* Now check whether it is an AVLTree or not: */ if (TNUM_OBJ(tmp) != T_POSOBJ ||
(TYPE_POSOBJ(tmp) != AVLTreeTypeMutable &&
TYPE_POSOBJ(tmp) != AVLTreeType)) {
r = NEW_PREC(2); /* This might trigger a garbage collection */
AssPRec(r,RNam_cmpfunc,ElmPRec(ht,RNam_cmpfunc));
AssPRec(r,RNam_allocsize,INTOBJ_INT(3));
t = CALL_1ARGS(AVLTree,r); if (LEN_PLIST(vals) >= h && ELM_PLIST(vals,h) != 0L) {
FuncAVLAdd_C(self,t,tmp,ELM_PLIST(vals,h));
UNB_LIST(vals,h);
} else {
FuncAVLAdd_C(self,t,tmp,True);
}
SET_ELM_PLIST(els,h,t);
CHANGED_BAG(els);
} else t = tmp;
/* Finally add value into tree: */
r = FuncAVLAdd_C(self,t,x,v);
/* Increment accesses entry: */
t = ElmPRec(ht,RNam_accesses);
t = INTOBJ_INT(INT_INTOBJ(t)+1);
AssPRec(ht,RNam_accesses,t);
/* Compute hash value: */
h = HT_Hash(ht, x);
/* Lookup slot: */
els = ElmPRec(ht,RNam_els);
vals = ElmPRec(ht,RNam_vals);
t = ELM_PLIST(els,h); /* Note that hash values are always within
the boundaries of this list */ if (t == 0L) /* Unbound entry! */ return Fail;
/* Now check whether it is an AVLTree or not: */ if (TNUM_OBJ(t) != T_POSOBJ ||
(TYPE_POSOBJ(t) != AVLTreeType &&
TYPE_POSOBJ(t) != AVLTreeTypeMutable)) { if (CALL_2ARGS(ElmPRec(ht,RNam_cmpfunc),x,t) == INTOBJ_INT(0)) { if (LEN_PLIST(vals) >= h && ELM_PLIST(vals,h) != 0L) return ELM_PLIST(vals,h); else returnTrue;
} return Fail;
}
h = AVLFind(t,x); if (h == 0) return Fail; return AVLValue(t,h);
}
/* Lookup slot: */
els = ElmPRec(ht,RNam_els);
vals = ElmPRec(ht,RNam_vals);
t = ELM_PLIST(els,h); /* Note that hash values are always within
the boundaries of this list */ if (t == 0L) /* Unbound entry! */ return Fail;
/* Now check whether it is an AVLTree or not: */ if (TNUM_OBJ(t) != T_POSOBJ ||
(TYPE_POSOBJ(t) != AVLTreeType &&
TYPE_POSOBJ(t) != AVLTreeTypeMutable)) { if (CALL_2ARGS(ElmPRec(ht,RNam_cmpfunc),x,t) == INTOBJ_INT(0)) { if (LEN_PLIST(vals) >= h && ELM_PLIST(vals,h) != 0L) {
v = ELM_PLIST(vals,h);
UNB_LIST(vals,h);
} else v = True;
SET_ELM_PLIST(els,h,0L);
AssPRec(ht,RNam_nr,INTOBJ_INT(INT_INTOBJ(ElmPRec(ht,RNam_nr))-1)); return v;
} return Fail;
}
v = FuncAVLDelete_C(self,t,x); if (v != Fail)
AssPRec(ht,RNam_nr,INTOBJ_INT(INT_INTOBJ(ElmPRec(ht,RNam_nr))-1));
/* Lookup slot: */
els = ElmPRec(ht,RNam_els);
vals = ElmPRec(ht,RNam_vals);
t = ELM_PLIST(els,h); /* Note that hash values are always within
the boundaries of this list */ if (t == 0L) /* Unbound entry! */ return Fail;
/* Now check whether it is an AVLTree or not: */ if (TNUM_OBJ(t) != T_POSOBJ ||
(TYPE_POSOBJ(t) != AVLTreeType &&
TYPE_POSOBJ(t) != AVLTreeTypeMutable)) { if (CALL_2ARGS(ElmPRec(ht,RNam_cmpfunc),x,t) == INTOBJ_INT(0)) { if (LEN_PLIST(vals) >= h && ELM_PLIST(vals,h) != 0L) {
old = ELM_PLIST(vals,h);
SET_ELM_PLIST(vals,h,v);
CHANGED_BAG(vals); return old;
} elsereturnTrue;
} return Fail;
}
h = AVLFind(t,x); if (h == 0) return Fail;
old = AVLValue(t,h);
SetAVLValue(t,h,v); return old;
}
static Obj FuncMappingPermSetSet_C(Obj self, Obj src, Obj dst)
{ Int l; Int d,dd;
Obj out; Int i = 1; Int j = 1; Int next = 1; /* The next candidate, possibly prevented by being in dst */ Int k;
l = LEN_LIST(src); if (l != LEN_LIST(dst)) {
ErrorReturnVoid( "both arguments must be sets of equal length", 0L, 0L, "type 'return;' or 'quit;' to exit break loop" ); return0L;
}
d = INT_INTOBJ(ELM_LIST(src,l));
dd = INT_INTOBJ(ELM_LIST(dst,l)); if (dd > d) d = dd;
out = NEW_PLIST(T_PLIST_CYC,d);
SET_LEN_PLIST(out,d); /* No garbage collection from here on! */
for (k = 1;k <= d;k++) { if (i <= l && k == INT_INTOBJ(ELM_LIST(src,i))) {
SET_ELM_PLIST(out,k,ELM_LIST(dst,i));
i++;
} else { /* Skip things in dst: */ while (j <= l) {
dd = INT_INTOBJ(ELM_LIST(dst,j)); if (next < dd) break; if (next == dd) next++;
j++;
}
SET_ELM_PLIST(out,k,INTOBJ_INT(next));
next++;
}
} return CALL_1ARGS(PermList, out);
}
/* init filters and functions */
InitGVarFuncsFromTable(GVarFuncs);
tmp = NEW_PREC(1);
// In GAP 4.9, the memory layout of T_PERM objects changed, and so the // method for hashing permutations also had to be changed. The following is // used to define the "skip" argument of HASHKEY_BAG, i.e. where in the // bag, containing the permutation, the list of images starts.
Obj p = NEW_PERM2(0);
AssPRec(tmp, RNamName("PERM_HASH_SKIP"),
INTOBJ_INT((UInt) ADDR_PERM2(p) - (UInt) ADDR_OBJ(p)));
CHANGED_BAG(tmp);
gvar = GVarName("ORBC"); AssGVar( gvar, tmp ); MakeReadOnlyGVar(gvar);
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.