Esempio n. 1
0
/**
 * Rotate the nodes in an AVL tree
 * Direction specifies the direction to rotate (ie: the direction away from the heavy node)
 *
 * @param[in] tree  The tree
 * @param[in] walk  The root of the tree to search
 * @param[in] direction  The direction to rotate
 * @param[in|out] heightChange  The height change
 *
 * @return  The heavy node
 */
static J9AVLTreeNode *
rotate(J9AVLTree *tree, J9AVLTreeNode *walk, intptr_t direction, intptr_t *heightChange)
{
	J9WSRP *heavyNodePtr;
	J9WSRP *graftNodePtr;
	J9AVLTreeNode *heavyNode;

	Trc_AVL_rotate_Entry(tree, walk, direction, heightChange);

	if (tree->genericActionHook) {
		tree->genericActionHook(tree, (J9AVLTreeNode *)walk, J9AVLTREE_ACTION_SINGLE_ROTATE);
	}

	if (direction < 0) {
		heavyNodePtr = &walk->rightChild;
		heavyNode    = AVL_NNSRP_GETNODE(*heavyNodePtr);
		graftNodePtr = &heavyNode->leftChild;
	} else {
		heavyNodePtr = &walk->leftChild;
		heavyNode    = AVL_NNSRP_GETNODE(*heavyNodePtr);
		graftNodePtr = &heavyNode->rightChild;
	}

	AVL_SRP_PTR_SETNODE(heavyNodePtr, AVL_SRP_GETNODE(*graftNodePtr));
	AVL_NNSRP_PTR_SETNODE(graftNodePtr, walk);

	if (AVL_GETBALANCE(heavyNode) != AVL_BALANCED) {
		/* this rotation reduces the amount the tree is growing by one */

		/* if the height was growing, it is no longer growing */
		if (*heightChange > 0) {
			*heightChange = 0;
		}

		AVL_SETBALANCE(heavyNode, AVL_BALANCED);
		AVL_SETBALANCE(walk, AVL_BALANCED);
	} else {
		/* the only way that the heavy node can be balanced is via deletion
		 * otherwise a single or double rotation will have already occured */
		*heightChange = 0;
		if (direction < 0) {
			AVL_SETBALANCE(heavyNode, AVL_LEFTHEAVY);
			AVL_SETBALANCE(walk, AVL_RIGHTHEAVY);
		} else {
			AVL_SETBALANCE(heavyNode, AVL_RIGHTHEAVY);
			AVL_SETBALANCE(walk, AVL_LEFTHEAVY);
		}
	}

	Trc_AVL_rotate_Exit(heavyNode);

	return heavyNode;
}
Esempio n. 2
0
/*
 * Insert a new node into an AVL tree at the specified (from avl_find()) place.
 *
 * Newly inserted nodes are always leaf nodes in the tree, since avl_find()
 * searches out to the leaf positions.  The avl_index_t indicates the node
 * which will be the parent of the new node.
 *
 * After the node is inserted, a single rotation further up the tree may
 * be necessary to maintain an acceptable AVL balance.
 */
void
avl_insert(avl_tree_t *tree, void *new_data, avl_index_t where)
{
	avl_node_t *node;
	avl_node_t *parent = AVL_INDEX2NODE(where);
	int old_balance;
	int new_balance;
	int which_child = AVL_INDEX2CHILD(where);
	size_t off = tree->avl_offset;

	if (tree == NULL) {
		filebench_log(LOG_ERROR, "No Tree Supplied");
		return;
	}
#if defined(_LP64) || (__WORDSIZE == 64)
	if (((uintptr_t)new_data & 0x7) != 0) {
		filebench_log(LOG_ERROR, "Missaligned pointer to new data");
		return;
	}
#endif

	node = AVL_DATA2NODE(new_data, off);

	/*
	 * First, add the node to the tree at the indicated position.
	 */
	++tree->avl_numnodes;

	node->avl_child[0] = NULL;
	node->avl_child[1] = NULL;

	AVL_SETCHILD(node, which_child);
	AVL_SETBALANCE(node, 0);
	AVL_SETPARENT(node, parent);
	if (parent != NULL) {
		if (parent->avl_child[which_child] != NULL)
			filebench_log(LOG_DEBUG_IMPL,
			    "Overwriting existing pointer");

		parent->avl_child[which_child] = node;
	} else {
		if (tree->avl_root != NULL)
			filebench_log(LOG_DEBUG_IMPL,
			    "Overwriting existing pointer");

		tree->avl_root = node;
	}
	/*
	 * Now, back up the tree modifying the balance of all nodes above the
	 * insertion point. If we get to a highly unbalanced ancestor, we
	 * need to do a rotation.  If we back out of the tree we are done.
	 * If we brought any subtree into perfect balance (0), we are also done.
	 */
	for (;;) {
		node = parent;
		if (node == NULL)
			return;

		/*
		 * Compute the new balance
		 */
		old_balance = AVL_XBALANCE(node);
		new_balance = old_balance + avl_child2balance[which_child];

		/*
		 * If we introduced equal balance, then we are done immediately
		 */
		if (new_balance == 0) {
			AVL_SETBALANCE(node, 0);
			return;
		}

		/*
		 * If both old and new are not zero we went
		 * from -1 to -2 balance, do a rotation.
		 */
		if (old_balance != 0)
			break;

		AVL_SETBALANCE(node, new_balance);
		parent = AVL_XPARENT(node);
		which_child = AVL_XCHILD(node);
	}

	/*
	 * perform a rotation to fix the tree and return
	 */
	(void) avl_rotation(tree, node, new_balance);
}
Esempio n. 3
0
/*
 * Perform a rotation to restore balance at the subtree given by depth.
 *
 * This routine is used by both insertion and deletion. The return value
 * indicates:
 *	 0 : subtree did not change height
 *	!0 : subtree was reduced in height
 *
 * The code is written as if handling left rotations, right rotations are
 * symmetric and handled by swapping values of variables right/left[_heavy]
 *
 * On input balance is the "new" balance at "node". This value is either
 * -2 or +2.
 */
static int
avl_rotation(avl_tree_t *tree, avl_node_t *node, int balance)
{
	int left = !(balance < 0);	/* when balance = -2, left will be 0 */
	int right = 1 - left;
	int left_heavy = balance >> 1;
	int right_heavy = -left_heavy;
	avl_node_t *parent = AVL_XPARENT(node);
	avl_node_t *child = node->avl_child[left];
	avl_node_t *cright;
	avl_node_t *gchild;
	avl_node_t *gright;
	avl_node_t *gleft;
	int which_child = AVL_XCHILD(node);
	int child_bal = AVL_XBALANCE(child);

	/* BEGIN CSTYLED */
	/*
	 * case 1 : node is overly left heavy, the left child is balanced or
	 * also left heavy. This requires the following rotation.
	 *
	 *                   (node bal:-2)
	 *                    /           \
	 *                   /             \
	 *              (child bal:0 or -1)
	 *              /    \
	 *             /      \
	 *                     cright
	 *
	 * becomes:
	 *
	 *              (child bal:1 or 0)
	 *              /        \
	 *             /          \
	 *                        (node bal:-1 or 0)
	 *                         /     \
	 *                        /       \
	 *                     cright
	 *
	 * we detect this situation by noting that child's balance is not
	 * right_heavy.
	 */
	/* END CSTYLED */
	if (child_bal != right_heavy) {

		/*
		 * compute new balance of nodes
		 *
		 * If child used to be left heavy (now balanced) we reduced
		 * the height of this sub-tree -- used in "return...;" below
		 */
		child_bal += right_heavy; /* adjust towards right */

		/*
		 * move "cright" to be node's left child
		 */
		cright = child->avl_child[right];
		node->avl_child[left] = cright;
		if (cright != NULL) {
			AVL_SETPARENT(cright, node);
			AVL_SETCHILD(cright, left);
		}

		/*
		 * move node to be child's right child
		 */
		child->avl_child[right] = node;
		AVL_SETBALANCE(node, -child_bal);
		AVL_SETCHILD(node, right);
		AVL_SETPARENT(node, child);

		/*
		 * update the pointer into this subtree
		 */
		AVL_SETBALANCE(child, child_bal);
		AVL_SETCHILD(child, which_child);
		AVL_SETPARENT(child, parent);
		if (parent != NULL)
			parent->avl_child[which_child] = child;
		else
			tree->avl_root = child;

		return (child_bal == 0);
	}

	/* BEGIN CSTYLED */
	/*
	 * case 2 : When node is left heavy, but child is right heavy we use
	 * a different rotation.
	 *
	 *                   (node b:-2)
	 *                    /   \
	 *                   /     \
	 *                  /       \
	 *             (child b:+1)
	 *              /     \
	 *             /       \
	 *                   (gchild b: != 0)
	 *                     /  \
	 *                    /    \
	 *                 gleft   gright
	 *
	 * becomes:
	 *
	 *              (gchild b:0)
	 *              /       \
	 *             /         \
	 *            /           \
	 *        (child b:?)   (node b:?)
	 *         /  \          /   \
	 *        /    \        /     \
	 *            gleft   gright
	 *
	 * computing the new balances is more complicated. As an example:
	 *	 if gchild was right_heavy, then child is now left heavy
	 *		else it is balanced
	 */
	/* END CSTYLED */
	gchild = child->avl_child[right];
	gleft = gchild->avl_child[left];
	gright = gchild->avl_child[right];

	/*
	 * move gright to left child of node and
	 *
	 * move gleft to right child of node
	 */
	node->avl_child[left] = gright;
	if (gright != NULL) {
		AVL_SETPARENT(gright, node);
		AVL_SETCHILD(gright, left);
	}

	child->avl_child[right] = gleft;
	if (gleft != NULL) {
		AVL_SETPARENT(gleft, child);
		AVL_SETCHILD(gleft, right);
	}

	/*
	 * move child to left child of gchild and
	 *
	 * move node to right child of gchild and
	 *
	 * fixup parent of all this to point to gchild
	 */
	balance = AVL_XBALANCE(gchild);
	gchild->avl_child[left] = child;
	AVL_SETBALANCE(child, (balance == right_heavy ? left_heavy : 0));
	AVL_SETPARENT(child, gchild);
	AVL_SETCHILD(child, left);

	gchild->avl_child[right] = node;
	AVL_SETBALANCE(node, (balance == left_heavy ? right_heavy : 0));
	AVL_SETPARENT(node, gchild);
	AVL_SETCHILD(node, right);

	AVL_SETBALANCE(gchild, 0);
	AVL_SETPARENT(gchild, parent);
	AVL_SETCHILD(gchild, which_child);
	if (parent != NULL)
		parent->avl_child[which_child] = gchild;
	else
		tree->avl_root = gchild;

	return (1);	/* the new tree is always shorter */
}
Esempio n. 4
0
/*
 * Insert a new node into an AVL tree at the specified (from avl_find()) place.
 *
 * Newly inserted nodes are always leaf nodes in the tree, since avl_find()
 * searches out to the leaf positions.  The avl_index_t indicates the node
 * which will be the parent of the new node.
 *
 * After the node is inserted, a single rotation further up the tree may
 * be necessary to maintain an acceptable AVL balance.
 */
void
avl_insert(avl_tree_t *tree, void *new_data, avl_index_t where)
{
	avl_node_t *node;
	avl_node_t *parent = AVL_INDEX2NODE(where);
	int old_balance;
	int new_balance;
	int which_child = AVL_INDEX2CHILD(where);
	size_t off = tree->avl_offset;

	node = AVL_DATA2NODE(new_data, off);

	/*
	 * First, add the node to the tree at the indicated position.
	 */
	++tree->avl_numnodes;

	node->avl_child[0] = NULL;
	node->avl_child[1] = NULL;

	AVL_SETCHILD(node, which_child);
	AVL_SETBALANCE(node, 0);
	AVL_SETPARENT(node, parent);
	if (parent != NULL) {
		parent->avl_child[which_child] = node;
	} else {
		tree->avl_root = node;
	}
	/*
	 * Now, back up the tree modifying the balance of all nodes above the
	 * insertion point. If we get to a highly unbalanced ancestor, we
	 * need to do a rotation.  If we back out of the tree we are done.
	 * If we brought any subtree into perfect balance (0), we are also done.
	 */
	for (;;) {
		node = parent;
		if (node == NULL)
			return;

		/*
		 * Compute the new balance
		 */
		old_balance = AVL_XBALANCE(node);
		new_balance = old_balance + avl_child2balance[which_child];

		/*
		 * If we introduced equal balance, then we are done immediately
		 */
		if (new_balance == 0) {
			AVL_SETBALANCE(node, 0);
			return;
		}

		/*
		 * If both old and new are not zero we went
		 * from -1 to -2 balance, do a rotation.
		 */
		if (old_balance != 0)
			break;

		AVL_SETBALANCE(node, new_balance);
		parent = AVL_XPARENT(node);
		which_child = AVL_XCHILD(node);
	}

	/*
	 * perform a rotation to fix the tree and return
	 */
	(void) avl_rotation(tree, node, new_balance);
}
Esempio n. 5
0
/**
 * Delete a node from an AVL tree.
 * This function should always be called externally with walkSRPPtr being NULL.
 * All recursive calls will have walkPtr==NULL and a value for walkSRPPtr.
 *
 * @param[in] tree  The tree
 * @param[in] walkPtr  A pointer to the root of the tree
 * @param[in] walkSRPPtr  Should always be NULL (only used when the function calls itself)
 * @param[in] node  The node to delete (can be a node or an SRP node)
 * @param[in|out] heightChange  The height change
 *
 * @return  The node deleted or NULL
 */
static J9AVLTreeNode *
deleteNode(J9AVLTree *tree, J9AVLTreeNode **walkPtr, J9WSRP *walkSRPPtr, J9AVLTreeNode *node, intptr_t *heightChange)
{
	J9AVLTreeNode *find;
	J9AVLTreeNode *walk;
	intptr_t dir;

	Trc_AVL_deleteNode_Entry(tree, walkPtr, walkSRPPtr, node, heightChange);

	/* Assumption is that if walkSRPPtr is NULL, walkPtr is not */
	if (!walkSRPPtr) {
		walk = AVL_GETNODE(*walkPtr);
	} else {
		walk = AVL_SRP_GETNODE(*walkSRPPtr);
	}
	if (!walk) {
		if (tree->genericActionHook) {
			tree->genericActionHook(tree, walk, J9AVLTREE_ACTION_REMOVE_NOT_IN_TREE);
		}
		Trc_AVL_deleteNode_NotInTree();
		return NULL;
	}

	dir = tree->insertionComparator(tree, node, walk);
	if (!dir) {
		J9AVLTreeNode *walkLeftChild, *walkRightChild;

		walkLeftChild = AVL_SRP_GETNODE(walk->leftChild);
		walkRightChild = AVL_SRP_GETNODE(walk->rightChild);

		if (!walkLeftChild) {
			if (!walkSRPPtr) {
				AVL_SETNODE(*walkPtr, walkRightChild);
			} else {
				AVL_SRP_PTR_SETNODE(walkSRPPtr, walkRightChild);
			}
			AVL_SRP_SET_TO_NULL(walk->rightChild);
			*heightChange = -1;
		} else if (!walkRightChild) {
			if (!walkSRPPtr) {
				AVL_SETNODE(*walkPtr, walkLeftChild);
			} else {
				AVL_SRP_PTR_SETNODE(walkSRPPtr, walkLeftChild);
			}
			AVL_SRP_SET_TO_NULL(walk->leftChild);
			*heightChange = -1;
		} else {
			J9AVLTreeNode *leaf;

			leaf = findRightMostLeaf(tree, &(walk->leftChild), heightChange);

			AVL_SRP_SETNODE(leaf->leftChild, AVL_SRP_GETNODE(walk->leftChild));
			AVL_SRP_SETNODE(leaf->rightChild, AVL_SRP_GETNODE(walk->rightChild));
			AVL_SETBALANCE(leaf, AVL_GETBALANCE(walk));

			AVL_SRP_SET_TO_NULL(walk->leftChild);
			AVL_SRP_SET_TO_NULL(walk->rightChild);

			if (!walkSRPPtr) {
				AVL_SETNODE(*walkPtr, leaf);
			} else {
				AVL_NNSRP_PTR_SETNODE(walkSRPPtr, leaf);
			}
			rebalance(tree, walkPtr, walkSRPPtr, -1, heightChange);
		}

		AVL_SETBALANCE(walk, AVL_BALANCED);

		if (tree->genericActionHook) {
			tree->genericActionHook(tree, walk, J9AVLTREE_ACTION_REMOVE);
		}
		Trc_AVL_deleteNode_Removed(walk);
		return walk;
	}

	if (dir < 0) {
		find = deleteNode(tree, NULL, &(walk->leftChild), node, heightChange);
	} else {
		find = deleteNode(tree, NULL, &(walk->rightChild), node, heightChange);
	}

	/* if we deleted a node */
	if (find) {
		rebalance(tree, walkPtr, walkSRPPtr, dir, heightChange);
	}

	Trc_AVL_deleteNode_Recursive(find);
	return find;
}
Esempio n. 6
0
/**
 * Rebalances an AVL tree.
 * This function should be called with either walkPtr OR walkSRPPtr set.
 * Use walkPtr if you have a direct pointer to the node or walkSRPPtr if you have a pointer to a WSRP
 *
 * @param[in] tree  The tree
 * @param[in] walkPtr  A pointer to the root of the tree to balance (walkSRPPtr is NULL)
 * @param[in] walkSRPPtr  A pointer to an SRP of the root of the tree to balance (walkPtr is NULL)
 * @param[in|out] heightChange  The height change
 */
static void
rebalance(J9AVLTree *tree, J9AVLTreeNode **walkPtr, J9WSRP *walkSRPPtr, intptr_t direction, intptr_t *heightChange)
{
	J9AVLTreeNode *walk = NULL;
	uintptr_t walkBalance;

	if (!(*heightChange)) {
		return;
	}

	Trc_AVL_rebalance_Entry(tree, walkPtr, walkSRPPtr, direction, heightChange);

	/* if we shrunk nodes, flip the direction, thus direction points towards heavy direction */
	if (*heightChange < 0) {
		direction = -direction;
	}

	/* Assumption is that if walkSRPPtr is NULL, walkPtr is not */
	if (!walkSRPPtr) {
		walk = AVL_GETNODE(*walkPtr);
	} else {
		walk = AVL_NNSRP_GETNODE(*walkSRPPtr);
	}

	walkBalance = AVL_GETBALANCE(walk);

	if (walkBalance == AVL_BALANCED) {
		AVL_SETBALANCE(walk, (direction < 0) ? AVL_LEFTHEAVY : AVL_RIGHTHEAVY);
		/* if the tree was shrinking, we've just unbalanced a node .. no longer shrinking */
		if (*heightChange < 0) {
			*heightChange = 0;
		}
	} else if ((walkBalance == AVL_LEFTHEAVY) == (direction < 0)) {
		J9AVLTreeNode *rotateResult = NULL;

		/* left heavy adding to the left or right heavy adding to the right */
		if ((direction < 0) && (AVL_GETBALANCE(AVL_NNSRP_GETNODE(walk->leftChild)) == AVL_RIGHTHEAVY)) {
			/* doubleRotate */
			rotateResult = (J9AVLTreeNode *)doubleRotate(tree, walk, -direction, heightChange);
		} else if ((direction > 0) && (AVL_GETBALANCE(AVL_NNSRP_GETNODE(walk->rightChild)) == AVL_LEFTHEAVY)) {
			/* doubleRotate */
			rotateResult = (J9AVLTreeNode *)doubleRotate(tree, walk, -direction, heightChange);
		} else {
			/* single rotate */
			rotateResult = (J9AVLTreeNode *)rotate(tree, walk, -direction, heightChange);
		}

		/* Assumption is that if walkSRPPtr is NULL, walkPtr is not */
		if (!walkSRPPtr) {
			AVL_SETNODE(*walkPtr, rotateResult);
		} else {
			AVL_NNSRP_PTR_SETNODE(walkSRPPtr, rotateResult);
		}
	} else {
		AVL_SETBALANCE(walk, AVL_BALANCED);

		/* added height making node become equal -- no more growing */
		if (*heightChange > 0) {
			*heightChange = 0;
		}
	}

	Trc_AVL_rebalance_Exit(*heightChange);
}
Esempio n. 7
0
/**
 * Double-rotate the nodes in an AVL tree
 * Direction specifies the direction to rotate (ie: the direction away from the heavy node)
 *
 * @param[in] tree  The tree
 * @param[in] walk  The root of the tree to search
 * @param[in] direction  The direction to rotate
 * @param[in|out] heightChange  The height change
 *
 * @return  The new root node
 */
static J9AVLTreeNode *
doubleRotate(J9AVLTree *tree, J9AVLTreeNode *walk, intptr_t direction, intptr_t *heightChange)
{
	J9WSRP *heavyNodePtr;
	J9WSRP *graft1NodePtr;
	J9WSRP *graft2NodePtr;
	J9WSRP *newrootNodePtr;
	J9AVLTreeNode *heavyNode;
	J9AVLTreeNode *newrootNode;

	Trc_AVL_doubleRotate_Entry(tree, walk, direction, heightChange);

	if (tree->genericActionHook) {
		tree->genericActionHook(tree, (J9AVLTreeNode *)walk, J9AVLTREE_ACTION_DOUBLE_ROTATE);
	}

	if (direction < 0) {
		heavyNodePtr   = &walk->rightChild;
		heavyNode      = AVL_NNSRP_GETNODE(*heavyNodePtr);

		newrootNodePtr = &heavyNode->leftChild;
		newrootNode    = AVL_NNSRP_GETNODE(*newrootNodePtr);

		graft1NodePtr  = &newrootNode->rightChild;
		graft2NodePtr  = &newrootNode->leftChild;
	} else {
		heavyNodePtr   = &walk->leftChild;
		heavyNode      = AVL_NNSRP_GETNODE(*heavyNodePtr);

		newrootNodePtr = &heavyNode->rightChild;
		newrootNode    = AVL_NNSRP_GETNODE(*newrootNodePtr);

		graft1NodePtr  = &newrootNode->leftChild;
		graft2NodePtr  = &newrootNode->rightChild;
	}

	AVL_SRP_PTR_SETNODE(newrootNodePtr, AVL_SRP_GETNODE(*graft1NodePtr));
	AVL_NNSRP_PTR_SETNODE(graft1NodePtr, heavyNode);

	AVL_SRP_PTR_SETNODE(heavyNodePtr, AVL_SRP_GETNODE(*graft2NodePtr));
	AVL_NNSRP_PTR_SETNODE(graft2NodePtr, walk);

	if (AVL_GETBALANCE(newrootNode) == AVL_BALANCED) {
		AVL_SETBALANCE(heavyNode, AVL_BALANCED);
		AVL_SETBALANCE(walk, AVL_BALANCED);
	} else if (AVL_GETBALANCE(newrootNode) == AVL_LEFTHEAVY) {
		if (direction < 0) {
			AVL_SETBALANCE(heavyNode, AVL_RIGHTHEAVY);
			AVL_SETBALANCE(walk, AVL_BALANCED);
		} else {
			AVL_SETBALANCE(heavyNode, AVL_BALANCED);
			AVL_SETBALANCE(walk, AVL_RIGHTHEAVY);
		}
	} else if (direction < 0) {
		AVL_SETBALANCE(heavyNode, AVL_BALANCED);
		AVL_SETBALANCE(walk, AVL_LEFTHEAVY);
	} else {
		AVL_SETBALANCE(heavyNode, AVL_LEFTHEAVY);
		AVL_SETBALANCE(walk, AVL_BALANCED);
	}

	AVL_SETBALANCE(newrootNode, AVL_BALANCED);

	/* if the height was growing, it is no longer growing */
	if (*heightChange > 0) {
		*heightChange = 0;
	}

	Trc_AVL_doubleRotate_Exit(newrootNode);

	return newrootNode;
}