sorttable.c

来自「Sun公司Dream项目」· C语言 代码 · 共 1,136 行 · 第 1/3 页

C
1,136
字号
    }
    if (n != NULL) {
	if (sortTable->keyFree != NULL) {
	    (*sortTable->keyFree)((void *)n->item.key);
	}
	sortTableNodeFree(sortTable, t);
    }
#ifdef	ASSERTS
    sortTable->wasModified = TRUE;
#endif	/* ASSERTS */
    return retVal;
}

void        *
_sortTableGet(const SortTable sortTable, const void *key)
{
    return (void *)sortTableFind(sortTable, key)->item.value;
}

/*
 * Returns true if the key is a member of the sorttable.
 */
Boolean
_sortTableIsMember(const SortTable sortTable, const void *key)
{
    return Boolean(sortTableFind(sortTable, key) != &sortTable->head);
}

/*
 * Remove the key-value pair from the sort table. It is not an error if key
 * does not exist. Returns the value associated with the removed key-value.
 * Returns NULL if the key is not found.
 */
void        *
_sortTableRemove(SortTable sortTable, const void *key)
{
    SortNode *s = sortTable->head.link[SORT_NODE_DIR_RIGHT];
    SortNodeDir dir = SORT_NODE_DIR_RIGHT;
    void *valuep = NULL;

    if (sortTable->mode == SORT_TABLE_MODE_MULTIPLE) {
	ABORT("attempt to remove from SORT_TABLE_MODE_MULTIPLE SortTable");
    }
    if (! s->link[SORT_NODE_DIR_LEFT]->isRed
	&& ! s->link[SORT_NODE_DIR_RIGHT]->isRed) {
	s->isRed = TRUE;
    }
    for (;;) {
	SortNodeDir nextDir;

	if (s->link[SORT_NODE_DIR_LEFT] == &sortTable->head) {
	    break;
	}
	nextDir = SortNodeDir((*sortTable->keyCmp)(key, s->item.key) < 0);
	if (! s->isRed && !s->link[nextDir]->isRed) {
	    if (s->link[!nextDir]->isRed) {
		(void) sortTableRotate(s->p, dir, SortNodeDir(!nextDir));
		s->isRed = TRUE;
		s->p->isRed = FALSE;
	    } else {
		SortNode *sib = s->p->link[!dir];

		ASSERT(s->p->isRed);
		ASSERT(! sib->isRed);
		ASSERT(sib->link[SORT_NODE_DIR_LEFT] != &sortTable->head);
		s->isRed = TRUE;
		s->p->isRed = FALSE;
		if (!sib->link[SORT_NODE_DIR_LEFT]->isRed
		    && !sib->link[SORT_NODE_DIR_RIGHT]->isRed) {
		    sib->isRed = TRUE;
		} else {
		    SortNodeDir redKidDir
			= (sib->link[SORT_NODE_DIR_LEFT]->isRed)
			      ? SORT_NODE_DIR_LEFT : SORT_NODE_DIR_RIGHT;
		    SortNode *p = s->p;
		    SortNode *g = p->p;
		    SortNodeDir cDir = (p == g->link[SORT_NODE_DIR_LEFT])
			? SORT_NODE_DIR_LEFT : SORT_NODE_DIR_RIGHT;

		    if (dir != redKidDir) {
			sib->isRed = TRUE;
			sib->link[redKidDir]->isRed = FALSE;
			(void) sortTableRotate(g, cDir, SortNodeDir(!dir));
		    } else {
			(void) sortTableRotate(s->p, SortNodeDir(!dir), redKidDir);
			(void) sortTableRotate(g, cDir, SortNodeDir(!dir));
		    }
		}
	    }
	}
	dir = nextDir;
	s = s->link[dir];
    }
    if (s != &sortTable->head && (*sortTable->keyCmp)(key, s->item.key) == 0) {
	SortNode *p = s->p;
	SortNode *g = p->p;
	SortNode *c = p->link[!dir];
	SortNodeDir gDir = (g == &sortTable->head) ? SORT_NODE_DIR_RIGHT
	     : SortNodeDir((*sortTable->keyCmp)(s->item.key, g->item.key) < 0);

	ASSERT (p->isRed || p == &sortTable->head);
	g->link[gDir] = c;
	c->p = g;
	if (p != &sortTable->head) {
	    if (sortTable->keyFree != NULL) {
		(*sortTable->keyFree)((void *)p->item.key);
	    }
	    sortTableNodeFree(sortTable, p);
	}

	valuep = (void *) s->item.value;
	if (sortTable->keyFree != NULL) {
	    (*sortTable->keyFree)((void *)s->item.key);
	}
	sortTableNodeFree(sortTable, s);
	sortTable->length -= 1;
    }
    sortTable->head.link[SORT_NODE_DIR_RIGHT]->isRed = FALSE;
#ifdef	ASSERTS
    sortTable->wasModified = TRUE;
#endif	/* ASSERTS */
    return valuep;
}

void
sortTableVerify(SortTable sortTable)
{
    /*
     * Verify:
     *	All nodes are either in tree or in free list.
     *  No node appears more than once.
     *  Children have correct parent pointers.
     *  Tree is correctly partitioned.
     *  No consecutive red nodes.
     *  All leaves are black.
     *  All data is in leaves.
     *  Black height is uniform.
     */
    int i;
    SortNode *n;

    sortTable->blackDepth = -1;
    sortTable->head.wasSeen = FALSE;
    for (i = 0; i < sortTable->size; i++) {
	sortTable->nodeArray[i].wasSeen = FALSE;
    }
    for (n = sortTable->freeNodep; n != NULL;
	    n = n->link[SORT_NODE_DIR_RIGHT]) {
	if (! n->isFree || n->wasSeen || n->hasData || n->isRed) {
	    ABORT("free corrupted");
	}
	n->wasSeen = TRUE;
    }
    if (sortTable->head.link[SORT_NODE_DIR_LEFT] != &sortTable->head
	|| sortTable->head.isRed || sortTable->head.isFree
	|| sortTable->head.wasSeen || sortTable->head.hasData
	|| sortTable->head.p != &sortTable->head) {
	ABORT("head corrupted");
    }
    sortTable->head.wasSeen = TRUE;
    if (sortTable->head.link[SORT_NODE_DIR_RIGHT] != &sortTable->head) {
	n = sortTable->head.link[SORT_NODE_DIR_RIGHT];
	if (n->p != &sortTable->head) {
	    ABORT("root parent");
	}
	if (n->link[SORT_NODE_DIR_LEFT] == &sortTable->head
		&& n->link[SORT_NODE_DIR_RIGHT] == &sortTable->head) {
	    /* Single node tree */
	    if (! n->hasData || n->isRed || n->isFree || n->wasSeen) {
		ABORT("single node corrupt");
	    }
	    n->wasSeen = TRUE;
	} else {
	    sortTableTraverse(sortTable, 0, n, NULL, NULL);
	}
    }
    for (i = 0; i < sortTable->size; i++) {
	if (! sortTable->nodeArray[i].wasSeen) {
	    ABORT("lost node");
	}
    }

}

void
sortTablePrint(SortTable sortTable, SortTablePrintFunc pFunc,
	       SortTableItemToStringFunc iFunc, int maxWidth)
{
    SortNode *n = sortTable->head.link[SORT_NODE_DIR_RIGHT];

    if (pFunc != NULL) {
	sortTable->pFunc = pFunc;
    } else {
	pFunc = sortTable->pFunc;
    }
    if (pFunc == NULL) {
	ABORT("no pFunc");
    }
    if (iFunc != NULL) {
	sortTable->iFunc = iFunc;
    } else {
	iFunc = sortTable->iFunc;
    }
    if (iFunc == NULL) {
	ABORT("no iFunc");
    }
    if (maxWidth != 0) {
	sortTable->maxWidth = maxWidth;
    } else {
	maxWidth = sortTable->maxWidth;
    }
    (*pFunc)("SortTable Contents:\n\n");
    if (n == &sortTable->head) {
	(*pFunc)("empty tree\n");
    } else {
	Deque deque = dequeNew(10, 10);
	n->printLow = 0;
	n->printHigh = maxWidth;
	n->level = 0;
	dequeEnqueueTail(deque, n);
	sortTableTraversePrint(sortTable, deque, pFunc, iFunc, 0, maxWidth);
	dequeFree(deque);
    }
    (*pFunc)("\n\n\n\n");
}


/*
 * Frees the sorttable. Does not free the values.
 */
void
sortTableFree(SortTable sortTable)
{
    if (sortTable->keyFree != NULL) {
	SortIter si = sortIterNew(sortTable);
	while (sortIterNext(si)) {
	    (*sortTable->keyFree)((void *)sortIterItem(si)->key);
	}
	sortIterFree(si);
    }
    free(sortTable->nodeArray);
    free(sortTable);
}

/************************************************************************
 * SortIter Class Interface
 ************************************************************************/

/*
 * Create a list Iterator
 * 
 * BEWARE: A list iterator is invalidated by any non-local-iterator list removal
 * of an item currently referenced by an iterator.  Doing so will cause
 * "undefined" results.
 */
SortIter
sortIterNew(const SortTable sortTable)
{
    SortIter si = NEW_ZEROED(struct _SortIter, 1);
    si->sortTable = sortTable;
    si->curNode = &sortTable->head;
    return si;
}

/************************************************************************
 * SortIter Instance Interface
 ************************************************************************/

/*
 * Position iterator at list head Returns TRUE if list is non-empty; FALSE if
 * list is empty.
 */
Boolean
sortIterHead(SortIter si)
{
    SortTable sortTable = si->sortTable;
    SortNode *n = sortTable->head.link[SORT_NODE_DIR_RIGHT];

    if (n == &sortTable->head) {
	return FALSE;
    }
    while (n->link[SORT_NODE_DIR_LEFT] != &sortTable->head) {
	n = n->link[SORT_NODE_DIR_LEFT];
    }
    si->curNode = n;
#ifdef	ASSERTS
    sortTable->wasModified = FALSE;
#endif	/* ASSERTS */
    return TRUE;
}

/*
 * Position iterator at list tail Returns TRUE if list is non-empty; FALSE if
 * list is empty.
 */
Boolean
sortIterTail(SortIter si)
{
    SortTable sortTable = si->sortTable;
    SortNode *n = sortTable->head.link[SORT_NODE_DIR_RIGHT];

    if (n == &sortTable->head) {
	return FALSE;
    }
    while (n->link[SORT_NODE_DIR_RIGHT] != &sortTable->head) {
	n = n->link[SORT_NODE_DIR_RIGHT];
    }
    si->curNode = n;
#ifdef	ASSERTS
    sortTable->wasModified = FALSE;
#endif	/* ASSERTS */
    return TRUE;
}

/*
 * Position iterator at item.  If duplicates are present, it is unpredictable
 * which of them will be found.
 * Return TRUE if item found.  Return FALSE if item not found. Position of
 * iterator is unchanged if item not found.
 */
extern Boolean
_sortIterFind(SortIter si, const void *key)
{
    SortTable sortTable = si->sortTable;
    SortNode *n = sortTableFind(sortTable, key);
    if (n != &sortTable->head) {
	si->curNode = n;
#ifdef	ASSERTS
	sortTable->wasModified = FALSE;
#endif	/* ASSERTS */
	return TRUE;
    }
    return FALSE;
}

/*
 * Position iterator after item. If item is not found, iterator is positioned
 * at first item that would be after the item if it were present.
 * Returns TRUE if there is an item after key, FALSE otherwise.
 */
extern Boolean
_sortIterAfter(SortIter si, const void *key)
{
    SortTable sortTable = si->sortTable;

    si->curNode = sortTable->head.link[SORT_NODE_DIR_RIGHT];
    for (;;) {
	if (si->curNode->link[SORT_NODE_DIR_RIGHT] == &sortTable->head) {
	    break;
	}
	si->curNode = si->curNode->link[
		(*sortTable->keyCmp)(key, si->curNode->item.key) < 0];
    }
    while (si->curNode != &sortTable->head
	   && (*sortTable->keyCmp)(key, si->curNode->item.key) >= 0) {
	(void) sortIterNext(si);
    }
#ifdef	ASSERTS
    sortTable->wasModified = FALSE;
#endif	/* ASSERTS */
    return Boolean(si->curNode != &sortTable->head);
}

/*
 * Position iterator before item. If item is not found, iterator is
 * positioned at first item that would be before the item if it were present.
 */
extern Boolean
_sortIterBefore(SortIter si, const void *key)
{
    SortTable sortTable = si->sortTable;

    si->curNode = sortTable->head.link[SORT_NODE_DIR_RIGHT];
    for (;;) {
	if (si->curNode->link[SORT_NODE_DIR_RIGHT] == &sortTable->head) {
	    break;
	}
	si->curNode = si->curNode->link[
		(*sortTable->keyCmp)(key, si->curNode->item.key) < 0];

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?