Esempio n. 1
0
int fwAvlInsert(uint32_t key, void* data, struct FwAvlTree* tree)
{
    int is_left;
    struct FwAvlNode* parent;
    struct FwAvlNode* right;
    struct FwAvlNode* left;
    struct FwAvlNode* unbalanced;
    struct FwAvlNode* node;

    if(do_lookup(key, tree, &parent, &unbalanced, &is_left) != NULL)
        return 1;

    if(!(node = new_node(key, data)))
        return -1;

    tree->count++;
    if(parent == NULL)
    {
        tree->root = node;
        tree->first = node;
        tree->last = node;
        return 0;
    }

    if(is_left != 0)
    {
        if(parent == tree->first)
            tree->first = node;
    }
    else
    {
        if(parent == tree->last)
            tree->last = node;
    }
    set_parent(parent, node);
    set_child(node, parent, is_left);

    while(1)
    {
        if(parent->left == node)
            dec_balance(parent);
        else
            inc_balance(parent);

        if(parent == unbalanced)
            break;

        node = parent;
        parent = get_parent(node);
    }

    switch(get_balance(unbalanced))
    {
        case 1:
        case -1:
            tree->height++;
            break;
        case 0:
            break;
        case 2:
            right = unbalanced->right;

            if(get_balance(right) == 1)
            {
                set_balance(0, unbalanced);
                set_balance(0, right);
            }
            else
            {
                switch(get_balance(right->left))
                {
                    case 1:
                        set_balance(-1, unbalanced);
                        set_balance(0, right);
                        break;
                    case 0:
                        set_balance(0, unbalanced);
                        set_balance(0, right);
                        break;
                    case -1:
                        set_balance(0, unbalanced);
                        set_balance(1, right);
                        break;
                }
                set_balance(0, right->left);
                rotate_right(right, tree);
            }
            rotate_left(unbalanced, tree);
            break;
        case -2:
            left = unbalanced->left;

            if(get_balance(left) == -1)
            {
                set_balance(0, unbalanced);
                set_balance(0, left);
            }
            else
            {
                switch(get_balance(left->right))
                {
                    case 1:
                        set_balance(0, unbalanced);
                        set_balance(-1, left);
                        break;
                    case 0:
                        set_balance(0, unbalanced);
                        set_balance(0, left);
                        break;
                    case -1:
                        set_balance(1, unbalanced);
                        set_balance(0, left);
                        break;
                }
                set_balance(0, left->right);
                rotate_left(left, tree);
            }
            rotate_right(unbalanced, tree);
            break;
    }
    return 0;
}
Esempio n. 2
0
/* Insertion never needs more than 2 rotations */
struct avltree_node *avltree_insert(struct avltree_node *node, struct avltree *tree)
{
	struct avltree_node *key, *parent, *unbalanced;
	int is_left;

	key = do_lookup(node, tree, &parent, &unbalanced, &is_left);
	if (key)
		return key;

	INIT_NODE(node);

	if (!parent) {
		tree->root = node;
		tree->first = tree->last = node;
		tree->height++;
		return NULL;
	}
	if (is_left) {
		if (parent == tree->first)
			tree->first = node;
	} else {
		if (parent == tree->last)
			tree->last = node;
	}
	set_parent(parent, node);
	set_child(node, parent, is_left);

	for (;;) {
		if (parent->left == node)
			dec_balance(parent);
		else
			inc_balance(parent);

		if (parent == unbalanced)
			break;
		node = parent;
		parent = get_parent(parent);
	}

	switch (get_balance(unbalanced)) {
	case  1: case -1:
		tree->height++;
		/* fall through */
	case 0:
		break;
	case 2: {
		struct avltree_node *right = unbalanced->right;

		if (get_balance(right) == 1) {
			set_balance(0, unbalanced);
			set_balance(0, right);
		} else {
			switch (get_balance(right->left)) {
			case 1:
				set_balance(-1, unbalanced);
				set_balance( 0, right);
				break;
			case 0:
				set_balance(0, unbalanced);
				set_balance(0, right);
				break;
			case -1:
				set_balance(0, unbalanced);
				set_balance(1, right);
				break;
			}
			set_balance(0, right->left);

			rotate_right(right, tree);
		}
		rotate_left(unbalanced, tree);
		break;
	}
	case -2: {
		struct avltree_node *left = unbalanced->left;

		if (get_balance(left) == -1) {
			set_balance(0, unbalanced);
			set_balance(0, left);
		} else {
			switch (get_balance(left->right)) {
			case 1:
				set_balance( 0, unbalanced);
				set_balance(-1, left);
				break;
			case 0:
				set_balance(0, unbalanced);
				set_balance(0, left);
				break;
			case -1:
				set_balance(1, unbalanced);
				set_balance(0, left);
				break;
			}
			set_balance(0, left->right);

			rotate_left(left, tree);
		}
		rotate_right(unbalanced, tree);
		break;
	}
	}
	return NULL;
}
Esempio n. 3
0
/* Deletion might require up to log(n) rotations */
void avltree_remove(struct avltree_node *node, struct avltree *tree)
{
	struct avltree_node *parent = get_parent(node);
	struct avltree_node *left = node->left;
	struct avltree_node *right = node->right;
	struct avltree_node *next;
	int is_left = is_left;

	if (node == tree->first)
		tree->first = avltree_next(node);
	if (node == tree->last)
		tree->last = avltree_prev(node);

	if (!left)
		next = right;
	else if (!right)
		next = left;
	else
		next = get_first(right);

	if (parent) {
		is_left = parent->left == node;
		set_child(next, parent, is_left);
	} else
		tree->root = next;

	if (left && right) {
		set_balance(get_balance(node), next);

		next->left = left;
		set_parent(next, left);

		if (next != right) {
			parent = get_parent(next);
			set_parent(get_parent(node), next);

			node = next->right;
			parent->left = node;
			is_left = 1;

			next->right = right;
			set_parent(next, right);
		} else {
			set_parent(parent, next);
			parent = next;
			node = parent->right;
			is_left = 0;
		}
		assert(parent != NULL);
	} else
		node = next;

	if (node)
		set_parent(parent, node);

	/*
	 * At this point, 'parent' can only be null, if 'node' is the
	 * tree's root and has at most one child.
	 *
	 * case 1: the subtree is now balanced but its height has
	 * decreased.
	 *
	 * case 2: the subtree is mostly balanced and its height is
	 * unchanged.
	 *
	 * case 3: the subtree is unbalanced and its height may have
	 * been changed during the rebalancing process, see below.
	 *
	 * case 3.1: after a left rotation, the subtree becomes mostly
	 * balanced and its height is unchanged.
	 *
	 * case 3.2: after a left rotation, the subtree becomes
	 * balanced but its height has decreased.
	 *
	 * case 3.3: after a left and a right rotation, the subtree
	 * becomes balanced or mostly balanced but its height has
	 * decreased for all cases.
	 */
	while (parent) {
		int balance;
		node   = parent;
		parent = get_parent(parent);

		if (is_left) {
			is_left = parent && parent->left == node;

			balance = inc_balance(node);
			if (balance == 0)		/* case 1 */
				continue;
			if (balance == 1)		/* case 2 */
				return;
			right = node->right;		/* case 3 */
			switch (get_balance(right)) {
			case 0:				/* case 3.1 */
				set_balance( 1, node);
				set_balance(-1, right);
				rotate_left(node, tree);
				return;
			case 1:				/* case 3.2 */
				set_balance(0, node);
				set_balance(0, right);
				break;
			case -1:			/* case 3.3 */
				switch (get_balance(right->left)) {
				case 1:
					set_balance(-1, node);
					set_balance( 0, right);
					break;
				case 0:
					set_balance(0, node);
					set_balance(0, right);
					break;
				case -1:
					set_balance(0, node);
					set_balance(1, right);
					break;
				}
				set_balance(0, right->left);

				rotate_right(right, tree);
			}
			rotate_left(node, tree);
		} else {
			is_left = parent && parent->left == node;

			balance = dec_balance(node);
			if (balance == 0)
				continue;
			if (balance == -1)
				return;
			left = node->left;
			switch (get_balance(left)) {
			case 0:
				set_balance(-1, node);
				set_balance(1, left);
				rotate_right(node, tree);
				return;
			case -1:
				set_balance(0, node);
				set_balance(0, left);
				break;
			case 1:
				switch (get_balance(left->right)) {
				case 1:
					set_balance(0, node);
					set_balance(-1, left);
					break;
				case 0:
					set_balance(0, node);
					set_balance(0, left);
					break;
				case -1:
					set_balance(1, node);
					set_balance(0, left);
					break;
				}
				set_balance(0, left->right);

				rotate_left(left, tree);
			}
			rotate_right(node, tree);
		}
	}
	tree->height--;
}
Esempio n. 4
0
/* Insertion never needs more than 2 rotations */
struct avltree_node *avltree_insert(struct avltree_node *node, struct avltree *tree) {
    struct avltree_node *parent = 0, *unbalanced = tree->root;
    bool is_left;

    // Find a suitable parent.
    for (struct avltree_node *next_parent = tree->root; next_parent != 0;) {
        parent = next_parent;
        if (get_balance(parent) != 0)
            unbalanced = parent;
        int cmp_r = tree->cmp_fn(parent, node);
        if (cmp_r == 0) {
            if (tree->unique_index)
                return parent;
            // For non unique indexes any insert direction is acceptable.
            if (parent->left == 0) {
                is_left = true;
                break;
            } else if (parent->right == 0) {
                is_left = false;
                break;
            } else {
                // Be smart and travel to the least balanced subtree to minimize balancing overhead.
                next_parent = (get_balance(parent) <= 0)? parent->left: parent->right;
            }
        } else {
            is_left = (cmp_r > 0);
            next_parent = is_left? parent->left: parent->right;
        }
    }

    INIT_NODE(node);

    if (!parent) {
        tree->root = node;
        tree->first = tree->last = node;
        tree->height++;
        return 0;
    }
    if (is_left) {
        if (parent == tree->first)
            tree->first = node;
    } else {
        if (parent == tree->last)
            tree->last = node;
    }
    set_parent(parent, node);
    set_child(node, parent, is_left);

    for (;;) {
        if (parent->left == node)
            dec_balance(parent);
        else
            inc_balance(parent);

        if (parent == unbalanced) {
            for (;;) {
                node = parent;
                node->count++;
                if (is_root(node))
                    break;
                parent = get_parent(parent);
            }
            break;
        }
        node = parent;
        node->count++;
        parent = get_parent(parent);
    }

    switch (get_balance(unbalanced)) {
        case 1: case -1:
            tree->height++;
            /* fall through */
        case 0:
            break;
        case 2:
        {
            struct avltree_node *right = unbalanced->right;

            if (get_balance(right) == 1) {
                set_balance(0, unbalanced);
                set_balance(0, right);
            } else {
                switch (get_balance(right->left)) {
                    case 1:
                        set_balance(-1, unbalanced);
                        set_balance(0, right);
                        break;
                    case 0:
                        set_balance(0, unbalanced);
                        set_balance(0, right);
                        break;
                    case -1:
                        set_balance(0, unbalanced);
                        set_balance(1, right);
                        break;
                }
                set_balance(0, right->left);

                rotate_right(right, tree);
            }
            rotate_left(unbalanced, tree);
            break;
        }
        case -2:
        {
            struct avltree_node *left = unbalanced->left;

            if (get_balance(left) == -1) {
                set_balance(0, unbalanced);
                set_balance(0, left);
            } else {
                switch (get_balance(left->right)) {
                    case 1:
                        set_balance(0, unbalanced);
                        set_balance(-1, left);
                        break;
                    case 0:
                        set_balance(0, unbalanced);
                        set_balance(0, left);
                        break;
                    case -1:
                        set_balance(1, unbalanced);
                        set_balance(0, left);
                        break;
                }
                set_balance(0, left->right);

                rotate_left(left, tree);
            }
            rotate_right(unbalanced, tree);
            break;
        }
    }
    return 0;
}