⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 dict.c

📁 一些常用的数据结构库
💻 C
📖 第 1 页 / 共 3 页
字号:
/* * Dictionary Abstract Data Type * Copyright (C) 1997 Kaz Kylheku <kaz@ashi.footprints.net> * * Free Software License: * * All rights are reserved by the author, with the following exceptions: * Permission is granted to freely reproduce and distribute this software, * possibly in exchange for a fee, provided that this copyright notice appears * intact. Permission is also granted to adapt this software to produce * derivative works, as long as the modified versions carry this copyright * notice and additional notices stating that the work has been modified. * This source code may be translated into executable form and incorporated * into proprietary software; there is no requirement for such software to * contain a copyright notice related to this source. * * $Id: dict.c,v 1.40.2.7 2000/11/13 01:36:44 kaz Exp $ * $Name: kazlib_1_20 $ */#include <stdlib.h>#include <stddef.h>#include <assert.h>#define DICT_IMPLEMENTATION#include "dict.h"#ifdef KAZLIB_RCSIDstatic const char rcsid[] = "$Id: dict.c,v 1.40.2.7 2000/11/13 01:36:44 kaz Exp $";#endif/* * These macros provide short convenient names for structure members, * which are embellished with dict_ prefixes so that they are * properly confined to the documented namespace. It's legal for a  * program which uses dict to define, for instance, a macro called ``parent''. * Such a macro would interfere with the dnode_t struct definition. * In general, highly portable and reusable C modules which expose their * structures need to confine structure member names to well-defined spaces. * The resulting identifiers aren't necessarily convenient to use, nor * readable, in the implementation, however! */#define left dict_left#define right dict_right#define parent dict_parent#define color dict_color#define key dict_key#define data dict_data#define nilnode dict_nilnode#define nodecount dict_nodecount#define maxcount dict_maxcount#define compare dict_compare#define allocnode dict_allocnode#define freenode dict_freenode#define context dict_context#define dupes dict_dupes#define dictptr dict_dictptr#define dict_root(D) ((D)->nilnode.left)#define dict_nil(D) (&(D)->nilnode)#define DICT_DEPTH_MAX 64static dnode_t *dnode_alloc(void *context);static void dnode_free(dnode_t *node, void *context);/* * Perform a ``left rotation'' adjustment on the tree.  The given node P and * its right child C are rearranged so that the P instead becomes the left * child of C.   The left subtree of C is inherited as the new right subtree * for P.  The ordering of the keys within the tree is thus preserved. */static void rotate_left(dnode_t *upper){    dnode_t *lower, *lowleft, *upparent;    lower = upper->right;    upper->right = lowleft = lower->left;    lowleft->parent = upper;    lower->parent = upparent = upper->parent;    /* don't need to check for root node here because root->parent is       the sentinel nil node, and root->parent->left points back to root */    if (upper == upparent->left) {	upparent->left = lower;    } else {	assert (upper == upparent->right);	upparent->right = lower;    }    lower->left = upper;    upper->parent = lower;}/* * This operation is the ``mirror'' image of rotate_left. It is * the same procedure, but with left and right interchanged. */static void rotate_right(dnode_t *upper){    dnode_t *lower, *lowright, *upparent;    lower = upper->left;    upper->left = lowright = lower->right;    lowright->parent = upper;    lower->parent = upparent = upper->parent;    if (upper == upparent->right) {	upparent->right = lower;    } else {	assert (upper == upparent->left);	upparent->left = lower;    }    lower->right = upper;    upper->parent = lower;}/* * Do a postorder traversal of the tree rooted at the specified * node and free everything under it.  Used by dict_free(). */static void free_nodes(dict_t *dict, dnode_t *node, dnode_t *nil){    if (node == nil)	return;    free_nodes(dict, node->left, nil);    free_nodes(dict, node->right, nil);    dict->freenode(node, dict->context);}/* * This procedure performs a verification that the given subtree is a binary * search tree. It performs an inorder traversal of the tree using the * dict_next() successor function, verifying that the key of each node is * strictly lower than that of its successor, if duplicates are not allowed, * or lower or equal if duplicates are allowed.  This function is used for * debugging purposes.  */static int verify_bintree(dict_t *dict){    dnode_t *first, *next;    first = dict_first(dict);    if (dict->dupes) {	while (first && (next = dict_next(dict, first))) {	    if (dict->compare(first->key, next->key) > 0)		return 0;	    first = next;	}    } else {	while (first && (next = dict_next(dict, first))) {	    if (dict->compare(first->key, next->key) >= 0)		return 0;	    first = next;	}    }    return 1;}/* * This function recursively verifies that the given binary subtree satisfies * three of the red black properties. It checks that every red node has only * black children. It makes sure that each node is either red or black. And it * checks that every path has the same count of black nodes from root to leaf. * It returns the blackheight of the given subtree; this allows blackheights to * be computed recursively and compared for left and right siblings for * mismatches. It does not check for every nil node being black, because there * is only one sentinel nil node. The return value of this function is the * black height of the subtree rooted at the node ``root'', or zero if the * subtree is not red-black. */static unsigned int verify_redblack(dnode_t *nil, dnode_t *root){    unsigned height_left, height_right;    if (root != nil) {	height_left = verify_redblack(nil, root->left);	height_right = verify_redblack(nil, root->right);	if (height_left == 0 || height_right == 0)	    return 0;	if (height_left != height_right)	    return 0;	if (root->color == dnode_red) {	    if (root->left->color != dnode_black)		return 0;	    if (root->right->color != dnode_black)		return 0;	    return height_left;	}	if (root->color != dnode_black)	    return 0;	return height_left + 1;    }     return 1;}/* * Compute the actual count of nodes by traversing the tree and * return it. This could be compared against the stored count to * detect a mismatch. */static dictcount_t verify_node_count(dnode_t *nil, dnode_t *root){    if (root == nil)	return 0;    else	return 1 + verify_node_count(nil, root->left)	    + verify_node_count(nil, root->right);}/* * Verify that the tree contains the given node. This is done by * traversing all of the nodes and comparing their pointers to the * given pointer. Returns 1 if the node is found, otherwise * returns zero. It is intended for debugging purposes. */static int verify_dict_has_node(dnode_t *nil, dnode_t *root, dnode_t *node){    if (root != nil) {	return root == node		|| verify_dict_has_node(nil, root->left, node)		|| verify_dict_has_node(nil, root->right, node);    }    return 0;}/* * Dynamically allocate and initialize a dictionary object. */dict_t *dict_create(dictcount_t maxcount, dict_comp_t comp){    dict_t *new = malloc(sizeof *new);    if (new) {	new->compare = comp;	new->allocnode = dnode_alloc;	new->freenode = dnode_free;	new->context = NULL;	new->nodecount = 0;	new->maxcount = maxcount;	new->nilnode.left = &new->nilnode;	new->nilnode.right = &new->nilnode;	new->nilnode.parent = &new->nilnode;	new->nilnode.color = dnode_black;	new->dupes = 0;    }    return new;}/* * Select a different set of node allocator routines. */void dict_set_allocator(dict_t *dict, dnode_alloc_t al,	dnode_free_t fr, void *context){    assert (dict_count(dict) == 0);    assert ((al == NULL && fr == NULL) || (al != NULL && fr != NULL));    dict->allocnode = al ? al : dnode_alloc;    dict->freenode = fr ? fr : dnode_free;    dict->context = context;}/* * Free a dynamically allocated dictionary object. Removing the nodes * from the tree before deleting it is required. */void dict_destroy(dict_t *dict){    assert (dict_isempty(dict));    free(dict);}/* * Free all the nodes in the dictionary by using the dictionary's * installed free routine. The dictionary is emptied. */void dict_free_nodes(dict_t *dict){    dnode_t *nil = dict_nil(dict), *root = dict_root(dict);    free_nodes(dict, root, nil);    dict->nodecount = 0;    dict->nilnode.left = &dict->nilnode;    dict->nilnode.right = &dict->nilnode;}/* * Obsolescent function, equivalent to dict_free_nodes */void dict_free(dict_t *dict){#ifdef KAZLIB_OBSOLESCENT_DEBUG    assert ("call to obsolescent function dict_free()" && 0);#endif    dict_free_nodes(dict);}/* * Initialize a user-supplied dictionary object. */dict_t *dict_init(dict_t *dict, dictcount_t maxcount, dict_comp_t comp){    dict->compare = comp;    dict->allocnode = dnode_alloc;    dict->freenode = dnode_free;    dict->context = NULL;    dict->nodecount = 0;    dict->maxcount = maxcount;    dict->nilnode.left = &dict->nilnode;    dict->nilnode.right = &dict->nilnode;    dict->nilnode.parent = &dict->nilnode;    dict->nilnode.color = dnode_black;    dict->dupes = 0;    return dict;}/*  * Initialize a dictionary in the likeness of another dictionary */void dict_init_like(dict_t *dict, const dict_t *template){    dict->compare = template->compare;    dict->allocnode = template->allocnode;    dict->freenode = template->freenode;    dict->context = template->context;    dict->nodecount = 0;    dict->maxcount = template->maxcount;    dict->nilnode.left = &dict->nilnode;    dict->nilnode.right = &dict->nilnode;    dict->nilnode.parent = &dict->nilnode;    dict->nilnode.color = dnode_black;    dict->dupes = template->dupes;    assert (dict_similar(dict, template));}/* * Remove all nodes from the dictionary (without freeing them in any way). */static void dict_clear(dict_t *dict){    dict->nodecount = 0;    dict->nilnode.left = &dict->nilnode;    dict->nilnode.right = &dict->nilnode;    dict->nilnode.parent = &dict->nilnode;    assert (dict->nilnode.color == dnode_black);}/* * Verify the integrity of the dictionary structure.  This is provided for * debugging purposes, and should be placed in assert statements.   Just because * this function succeeds doesn't mean that the tree is not corrupt. Certain * corruptions in the tree may simply cause undefined behavior. */ int dict_verify(dict_t *dict){    dnode_t *nil = dict_nil(dict), *root = dict_root(dict);    /* check that the sentinel node and root node are black */    if (root->color != dnode_black)	return 0;    if (nil->color != dnode_black)	return 0;    if (nil->right != nil)	return 0;    /* nil->left is the root node; check that its parent pointer is nil */    if (nil->left->parent != nil)	return 0;    /* perform a weak test that the tree is a binary search tree */    if (!verify_bintree(dict))	return 0;    /* verify that the tree is a red-black tree */    if (!verify_redblack(nil, root))	return 0;    if (verify_node_count(nil, root) != dict_count(dict))	return 0;    return 1;}/* * Determine whether two dictionaries are similar: have the same comparison and * allocator functions, and same status as to whether duplicates are allowed. */int dict_similar(const dict_t *left, const dict_t *right){    if (left->compare != right->compare)	return 0;    if (left->allocnode != right->allocnode)	return 0;    if (left->freenode != right->freenode)	return 0;    if (left->context != right->context)	return 0;    if (left->dupes != right->dupes)	return 0;    return 1;}/* * Locate a node in the dictionary having the given key. * If the node is not found, a null a pointer is returned (rather than  * a pointer that dictionary's nil sentinel node), otherwise a pointer to the * located node is returned. */dnode_t *dict_lookup(dict_t *dict, const void *key){    dnode_t *root = dict_root(dict);    dnode_t *nil = dict_nil(dict);    dnode_t *saved;    int result;    /* simple binary search adapted for trees that contain duplicate keys */    while (root != nil) {	result = dict->compare(key, root->key);	if (result < 0)	    root = root->left;	else if (result > 0)	    root = root->right;	else {	    if (!dict->dupes) {	/* no duplicates, return match		*/		return root;	    } else {		/* could be dupes, find leftmost one	*/		do {		    saved = root;		    root = root->left;		    while (root != nil && dict->compare(key, root->key))			root = root->right;		} while (root != nil);		return saved;	    }	}    }    return NULL;}/* * Look for the node corresponding to the lowest key that is equal to or * greater than the given key.  If there is no such node, return null. */dnode_t *dict_lower_bound(dict_t *dict, const void *key){    dnode_t *root = dict_root(dict);    dnode_t *nil = dict_nil(dict);    dnode_t *tentative = 0;    while (root != nil) {	int result = dict->compare(key, root->key);	if (result > 0) {	    root = root->right;	} else if (result < 0) {	    tentative = root;	    root = root->left;	} else {	    if (!dict->dupes) {	    	return root;	    } else {		tentative = root;		root = root->left;	    }	}     }        return tentative;

⌨️ 快捷键说明

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