Annotation of researchv10no/cmd/odist/pax/src/lib/libodelta/suftree.c, revision 1.1

1.1     ! root        1: #define _IN_SUF_TREE
        !             2: #include       "suftree.h"
        !             3: 
        !             4: /*
        !             5: **     Construct a suffix tree for a source string
        !             6: **     and perform string matching of various input strings.
        !             7: **     This is based on the suffix tree algorithm of E. McCreight.
        !             8: **     I extended the algorithm to remove the restriction that the
        !             9: **     last element of the string has to be different from the rest
        !            10: **     of the string. Note also that since the alphabet is large (256),
        !            11: **     instead of being stored in an array, the children of a node
        !            12: **     are kept in a linked list which is managed by a move-to-front
        !            13: **     heuristic.
        !            14: **
        !            15: **     For details, see the paper:
        !            16: **     "A Space-Economical Suffix Tree Construction Algorithm"
        !            17: **     E.M. McCreight, JACM, v.23, No.2, 1976, pp.262-272.
        !            18: **
        !            19: **     BldSuftree returns either NULL or the pointer to the root of the
        !            20: **     tree. In the latter case, the tree can be destroyed by free()-ing
        !            21: **     the root.
        !            22: **
        !            23: **     Written by Kiem-Phong Vo, 5/20/88.
        !            24: */
        !            25: 
        !            26: /*     Delete a suffix tree */
        !            27: void delsuftree(root)
        !            28: Suftree        *root;
        !            29: {
        !            30:        if(!root)
        !            31:                return;
        !            32:        root -= 1;
        !            33:        while(root)
        !            34:        {
        !            35:                register Suftree *next;
        !            36:                next = NEXT(root);
        !            37:                free(root);
        !            38:                root = next;
        !            39:        }
        !            40: }
        !            41: 
        !            42: /* Find a child whose label string starts with a given character */
        !            43: static Suftree *child_find(node,c)
        !            44: Suftree        *node;          /* the node whose children will be searched */
        !            45: Element        c;              /* the element being looked for */
        !            46: {
        !            47:        register Suftree        *np, *last;
        !            48: 
        !            49:        last = NIL(Suftree);
        !            50:        for(np = CHILD(node); np != NIL(Suftree); np = SIBLING(np))
        !            51:                if(LENGTH(np) > 0 && *LABEL(np) == c)
        !            52:                        break;
        !            53:                else    last = np;
        !            54: 
        !            55:        if(np && last)
        !            56:        {
        !            57:                /* move-to-front heuristic */
        !            58:                SIBLING(last) = SIBLING(np);
        !            59:                SIBLING(np) = CHILD(node);
        !            60:                CHILD(node) = np;
        !            61:        }
        !            62:        return np;
        !            63: }
        !            64: 
        !            65: /* Get space for tree nodes. */
        !            66: static Suftree *getmem(root,n)
        !            67: Suftree        *root;
        !            68: int    n;
        !            69: {
        !            70:        Suftree *list, *malloc(), **realloc();
        !            71: 
        !            72:        if((list = malloc((n+1)*sizeof(Suftree))) == NIL(Suftree))
        !            73:        {
        !            74:                if(root)
        !            75:                        delsuftree(root);
        !            76:                return NIL(Suftree);
        !            77:        }
        !            78: 
        !            79:        /* store where this list is for later deletion */
        !            80:        NEXT(list) = NIL(Suftree);
        !            81:        if(root)
        !            82:        {
        !            83:                for(root -= 1; NEXT(root) != NIL(Suftree); root = NEXT(root))
        !            84:                        ;
        !            85:                NEXT(root) = list;
        !            86:        }
        !            87: 
        !            88:        return list+1;
        !            89: }
        !            90: 
        !            91: /*     Build the tree.
        !            92: **     Following are the meaning of a few important variables:
        !            93: **             clocus: contracted locus, this variable defines the
        !            94: **                     tree node that points to the longest prefix
        !            95: **                     that terminates at a node in the current tree.
        !            96: **             locus:  defines a tree node to be constructed that
        !            97: **                     points to the longest prefix that can be defined.
        !            98: **                     Unless both clocus and locus equal the root,
        !            99: **                     we maintain the invariance that clocus is the
        !           100: **                     parent of locus.
        !           101: **             link:   defines the sublink of the locus of the prefix
        !           102: **                     of the previously inserted suffix.
        !           103: */
        !           104: Suftree        *bldsuftree(src,len)
        !           105: Element                *src;   /* the string to build the tree from */
        !           106: long int       len;    /* the length of the string */
        !           107: {
        !           108:        register Element        *sp, *mp, *rescan, *endmatch, *endsrc;
        !           109:        register Suftree        *match, *clocus, *locus, *link;
        !           110:        register long int       mtlen, relen;
        !           111:        register int            n;
        !           112:        Suftree                 *root, *list, *endlist;
        !           113: 
        !           114:        if(len == 0)
        !           115:                return NIL(Suftree);
        !           116: 
        !           117:        /* get initial space for the tree nodes */
        !           118:        root = NIL(Suftree);
        !           119: 
        !           120:        /* 2*len+1 is the maximum number of nodes that can be created */
        !           121:        n = 2*len+1;
        !           122:        if(n > ALLOCSIZE)
        !           123:                n = ALLOCSIZE;
        !           124:        if(!(list = getmem(root,n)))
        !           125:                return NIL(Suftree);
        !           126:        endlist = list + n;
        !           127: 
        !           128:        /* make root node */
        !           129:        root = list++;
        !           130:        LABEL(root) = NIL(Element);
        !           131:        CHILD(root) = NIL(Suftree);
        !           132:        LINK(root) = root;
        !           133: 
        !           134:        /* locus and contracted locus of the empty substring */
        !           135:        locus = clocus = root;
        !           136: 
        !           137:        /* the current match length */
        !           138:        mtlen = 0;
        !           139: 
        !           140:        /* the end of the source string */
        !           141:        endsrc = src+len;
        !           142: 
        !           143:        /* now build the tree */
        !           144:        for(; src < endsrc; ++src)
        !           145:        {
        !           146:                /* prepare for scanning the current suffix */
        !           147:                if(locus != root)
        !           148:                {
        !           149:                        /* define the string to be rescanned */
        !           150:                        rescan = LABEL(locus);
        !           151:                        relen  = LENGTH(locus);
        !           152: 
        !           153:                        /* minus the first character of the previous prefix */
        !           154:                        if(clocus == root)
        !           155:                        {
        !           156:                                rescan++;
        !           157:                                if(relen > 0)
        !           158:                                        --relen;
        !           159:                        }
        !           160:                        }
        !           161:                else    mtlen = relen = 0;
        !           162: 
        !           163:                /* the length of the known-to-be-matched part */
        !           164:                if(mtlen > 0)
        !           165:                        --mtlen;
        !           166:                /**/ ASSERT(relen <= mtlen)
        !           167: 
        !           168:                /* use sublink to rescan */
        !           169:                link = LINK(clocus);
        !           170: 
        !           171:                /* rescan */
        !           172:                while(relen > 0)
        !           173:                {
        !           174:                        /* find a child of link that starts with the
        !           175:                           first character of rescan. We then know that
        !           176:                           rescan must match a prefix of that child.
        !           177:                        */
        !           178:                        match = child_find(link,*rescan);
        !           179:                        /**/ ASSERT(match != NULL)
        !           180: 
        !           181:                        /* clocus will be the parent of the new link */
        !           182:                        clocus = link;
        !           183: 
        !           184:                        /* rescan contains LABEL(match) */
        !           185:                        if(relen >= LENGTH(match))
        !           186:                        {
        !           187:                                link = match;
        !           188:                                relen -= LENGTH(match);
        !           189:                                rescan += LENGTH(match);
        !           190:                        }
        !           191:                        /* rescan is a proper prefix of LABEL(match) */
        !           192:                        else
        !           193:                        {
        !           194:                                if(list >= endlist)
        !           195:                                {
        !           196:                                        if(!(list = getmem(root,ALLOCSIZE)))
        !           197:                                                return NIL(Suftree);
        !           198:                                        else    endlist = list+ALLOCSIZE;
        !           199:                                }
        !           200: 
        !           201:                                /* make an internal node labeled with rescan */
        !           202:                                LABEL(list) = rescan;
        !           203:                                LENGTH(list) = relen;
        !           204:                                CHILD(list) = match;
        !           205:                                SIBLING(list) = SIBLING(match);
        !           206:                                LINK(list) = root;
        !           207: 
        !           208:                                /* adjust label and pointer of old node */ 
        !           209:                                SIBLING(match) = NIL(Suftree);
        !           210:                                LABEL(match) += relen;
        !           211:                                LENGTH(match) -= relen;
        !           212: 
        !           213:                                CHILD(link) = list;
        !           214:                                link = list++;
        !           215:                                break;
        !           216:                        }
        !           217:                }
        !           218: 
        !           219:                /* define sublink for the prefix of the last suffix */
        !           220:                if(locus != root)
        !           221:                        LINK(locus) = link;
        !           222: 
        !           223:                /* scan to match as much as possible */
        !           224:                locus = link;
        !           225:                sp = src + mtlen;
        !           226:                while(sp < endsrc)
        !           227:                {
        !           228:                        /* see if it matches some child of clocus */
        !           229:                        if(!(match = child_find(locus,*sp)))
        !           230:                                break;
        !           231: 
        !           232:                        /* clocus will be the parent of the new locus */
        !           233:                        clocus = locus;
        !           234: 
        !           235:                        /* find the extend of the match */
        !           236:                        mp = LABEL(match);
        !           237:                        endmatch = mp + LENGTH(match);
        !           238:                        for(; sp < endsrc && mp < endmatch; ++sp, ++mp)
        !           239:                                if(*sp != *mp)
        !           240:                                        break;
        !           241: 
        !           242:                        /* the whole node is matched */
        !           243:                        if(mp >= endmatch)
        !           244:                        {
        !           245:                                locus = match;
        !           246:                                mtlen += LENGTH(match);
        !           247:                        }
        !           248:                        /* found the extended locus of this suffix */
        !           249:                        else
        !           250:                        {
        !           251:                                if(list >= endlist)
        !           252:                                {
        !           253:                                        if(!(list = getmem(root,ALLOCSIZE)))
        !           254:                                                return NIL(Suftree);
        !           255:                                        else    endlist = list+ALLOCSIZE;
        !           256:                                }
        !           257: 
        !           258:                                /* make a new internal node */
        !           259:                                LABEL(list) = LABEL(match);
        !           260:                                LENGTH(list) = mp - LABEL(match);
        !           261:                                CHILD(list) = match;
        !           262:                                SIBLING(list) = SIBLING(match);
        !           263:                                LINK(list) = root;
        !           264: 
        !           265:                                SIBLING(match) = NIL(Suftree);
        !           266:                                LABEL(match) += LENGTH(list);
        !           267:                                LENGTH(match) -= LENGTH(list);
        !           268:                                mtlen += LENGTH(list);
        !           269: 
        !           270:                                /* the new node is the locus for this suffix */
        !           271:                                CHILD(locus) = list;
        !           272:                                locus = list++;
        !           273:                                break;
        !           274:                        }
        !           275:                }
        !           276: 
        !           277:                if(list >= endlist)
        !           278:                {
        !           279:                        if(!(list = getmem(root,ALLOCSIZE)))
        !           280:                                return NIL(Suftree);
        !           281:                        else    endlist = list+ALLOCSIZE;
        !           282:                }
        !           283: 
        !           284:                /* make a new external node for the suffix */
        !           285:                SUFFIX(list) = src;
        !           286:                LABEL(list) = sp;
        !           287:                LENGTH(list) = endsrc-sp;
        !           288:                CHILD(list) = NIL(Suftree);
        !           289: 
        !           290:                /* hook it in as the first child of locus */
        !           291:                SIBLING(list) = CHILD(locus);
        !           292:                CHILD(locus) = list++;
        !           293:        }
        !           294: 
        !           295:        return root;
        !           296: }
        !           297: 
        !           298: /*     Given a raw string and a string represented in a suffix tree,
        !           299:        match the string against the tree to find a longest matching
        !           300:        prefix of the string.
        !           301:        Return the length of the match and where it occurs in the
        !           302:        string represented by the tree.
        !           303: */
        !           304: long   mtchsuftree(tree,str,len,mtchp)
        !           305: Suftree        *tree;          /* the root of the suffix tree */
        !           306: Element        *str;           /* the string to be matched */
        !           307: long   len;            /* the length of the string */
        !           308: Element        **mtchp;        /* to return the address of the match */
        !           309: {
        !           310:        register Suftree        *match;
        !           311:        register Element        *sp, *mp, *endmp, *endstr;
        !           312:        register long           mlen;
        !           313: 
        !           314:        mlen = 0;
        !           315:        endstr = str + len;
        !           316:        while(1)
        !           317:        {
        !           318:                if(!(match = child_find(tree,*str)))
        !           319:                        break;
        !           320: 
        !           321:                /* find the extent of the match */
        !           322:                mp = LABEL(match);
        !           323:                endmp = mp + LENGTH(match);
        !           324:                for(sp = str; sp < endstr && mp < endmp; ++sp, ++mp)
        !           325:                        if(*sp != *mp)
        !           326:                                break;
        !           327: 
        !           328:                /* update the length of the match */
        !           329:                mlen += sp-str;
        !           330: 
        !           331:                /* prepare for next iteration */
        !           332:                tree = match;
        !           333:                str  = sp;
        !           334: 
        !           335:                /* see if we have to work any more */
        !           336:                if(mp < endmp || str >= endstr)
        !           337:                        break; 
        !           338:        }
        !           339: 
        !           340:        if(mlen == 0)   /* no match */
        !           341:                *mtchp = NIL(Element);
        !           342:        else
        !           343:        {
        !           344:                /* find where the match starts */
        !           345:                while(CHILD(tree))
        !           346:                        tree = CHILD(tree);
        !           347:                *mtchp = SUFFIX(tree);
        !           348:        }
        !           349: 
        !           350:        return mlen;
        !           351: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.