Chapter 6: Tree Part IV

Chapter 6: Tree Part IV

14. AVL (Adelson-Velskii and Landis) Trees

An AVL tree is a binary search tree with a balance condition : the difference between left subtree height and right subtree height is at most 1 for any node.

Min / Max Number of Nodes in AVL Tree

Assume that the height of an AVL tree is h and N(k) indicates the number of nodes in AVL tree with height h. To get the minimum number of nodes with height h, we should fill the tree with the minimum number of nodes possible which means if we fill the left subtree with height h-1 then we should fill the right subtree with height h-2.

As a result, the minimum number of nodes with height h is:
N ( h ) = N ( h − 1 ) + N ( h − 2 ) + 1 N(h)=N(h-1)+N(h-2)+1 N(h)=N(h1)+N(h2)+1.
We can give N(h-1) either for left subtree or right subtree. Solving the above recurrence gives:
N ( h ) = O ( 1.61 8 h )    ⟹    h = 1.44 l o g N ≈ O ( l o g n ) N(h)=O(1.618^h) \implies h=1.44logN \approx O(logn) N(h)=O(1.618h)h=1.44logNO(logn)
Similarly, to get maximum number of nodes, we need to fill both left and right subtrees with height h-1 :
N ( h ) = N ( h − 1 ) + N ( h − 1 ) + 1 N(h)=N(h-1)+N(h-1)+1 N(h)=N(h1)+N(h1)+1
The above expression defines the case of full binary tree. Solving the recurrence we get:
N ( h ) = O ( 2 h )    ⟹    h = l o g N ≈ O ( l o g n ) N(h)=O(2^h) \implies h=logN \approx O(logn) N(h)=O(2h)h=logNO(logn)

∴ \therefore In both the cases, AVL tree property is ensuring that the height of an AVL tree with n nodes is O(logn).

Declaration

struct AVLTreeNode{
	struct AVLTreeNode *left;
	struct AVLTreeNode *right;
	int data;
	int height;
};

Find the Heigh

int Height(struct AVLTreeNode *root){
	if(!root) return -1;
	else return root->height;
}

Rotations

When the tree structure changes with insertion or deletion which lead to violation of AVL tree property at a certain node X where the difference in heights of left(X) and right(X) differ by exactly 2, we need to modify the tree to restore the AVL property by applying the single rotations or double rotations technique.

One important observation is that, after an insertion, only nodes that are on the path from the insertion point to the root might have their balances alterd, because only those nodes have their subtree altered. To restore the AVL tree property, we start at the insertion point and keep going to the root of the tree.If we fix the issue for the first node which is not satisfying the AVL property, then all other nodes on the path to the root will automatically satisfy the property.

Types of Violation

Assume the node that must be rebalanced is X. Since any node has at most two children, and a height imbalance requires that X’s two subtree heights differ by two, we can observe that a violation might occur in four cases:

  1. An insertion into the left subtree of the left child of X.
  2. An insertion into the right subtree of the left child of X.
  3. An insertion into the left subtree of the right child of X.
  4. An insertion into the right subtree of the right child of X.

Cases 1 and 4 are symmetric and easily solved with single rotations. Similarly, case 2 and 3 are also symmetric and can be solved with double rotations (need two single rotations).

Single Rotations
  • Left Left Rotation (LL) [case 1]在这里插入图片描述
struct AVLTreeNode *SingleLL(struct AVLTreeNode *x){
	struct AVLTreeNode *w=x->left;
	x->left=w->right;
	w->right=x;
	x->height=max(Height(x->left), Height(x->right))+1;
	w->height=max(Height(w->left), x->height)+1;
	return w; 								//new root
}	

Time Complexity: O(1), Space Complexity: O(1).

  • Right Right Rotation (RR) [case 4]在这里插入图片描述
struct AVLTreeNode *SingleRR(struct AVLTreeNode *w){
	struct AVLTreeNode *x=w->right;
	w->right=x->left;
	x->left=w;
	w->height=max(Height(w->right), Height(w->left))+1;
	x->height=max(Heihgt(x->right), w->height)+1;
	return x; 					//new node
}

Time Complexity: O(1), Space Complexity: O(1).

Double Rotations
  • Left Right Rotation (LR) [case 2]
    在这里插入图片描述
struct AVLTreeNode *DoubleLR(struct AVLTreeNode *z){
	z->left=SingleRR(z->left);
	return SingleLL(z);
}
  • Right Left Rotation (RL) [case 3]
    在这里插入图片描述
struct AVLTreeNode *DoubleRL(struct AVLTreeNode *x){
	x->right=SingleLL(x->right);
	return SingleRR(x);
}

Insertion into an AVL tree

struct AVLTreeNode *Insertion(struct AVLTreeNode *node, struct AVLTreeNode *parent, int data){
	if(!root){												//if empty tree, then create
		root=(struct AVLTreeNode *)malloc(sizeof(struct AVLTreeNode));
		if(!root) return NULL; 								//memory error
		else{
			root->data=data;
			root->height=0;
			root->left=root->right=NULL;					//set data, height, left, right
		}
	}
	else if(data < root->data){								//search for a proper position
		root->left=Insertion(root->left, root, data);
		if((Height(root->left)-Height(root->right))==2){	//violate property
			if(data < root->left->data)						
				root=SingleLL(root);						//insert at node x's left child's left subtree
			else
				root=DoubleLR(root);						//insert at node x's left child's right subtree 
		}
	}
	else if (data > root->data){
		root->right=Insertion(root->right, root, data);
		if((Height(root->left)-Height(root->right))==2){
			if(data < root->right->data)
				root=SingleRR(root);						//insert at node x's right child's right subtree
			else
				root=DoubleRL(root);						//insert at node x's right child's left subtree
		}
	}			
	root->height=max(Height(root->left), Height(root->right))+1;		//else data is in the tree already, do nothing				
	return root;													
}	
  • Time Complexity: O(logn), Space Complexity: O(logn).

15. AVL Trees: Problems & Solutions

Pro 1.1: Construct Minimal AVL tree

Construct minimal AVL tree of height 0, 1, 2, 3, 4 and 5. What is the number of nodes in a minimal AVL tree of height 6?

Solution :

Assume N(h) be the number of nodes in a minimal AVL tree with height h.
在这里插入图片描述

Pro 1.2 :How Many Different Shapes

How many different shapes can there be of a minimal AVL tree of height h?

Assume NS(h) be the number of different shapes of a minimal AVL tree of height h. Then,
NS(0)=1
NS(1)=2
NS(3)=2*2*1=4
NS(h)=2*NS(h-1)*NS(h-2)

Pro 2.1: Give an Algorithm to Generate a Full Balance Binary Search Tree

Given a height h, give an algorithm for generating the HB(0).

Solution 1: recursive

  • HB(0) is generating full binary tree with height balance factor equal to zero. In full binary tree the number with height h is 2 h + 1 − 1 2^{h+1}-1 2h+11 (assume the height of tree with one node is zero). As a result the nodes can be numbered as: 1 to 2h+1-1.
struct BinarySearchTreeNode *BuildHB0(int h){
	if(h==0) return NULL;
	struct BinarySearchTreeNode *temp=(struct BinarySearchTreeNode *)malloc(sizeof(struct BinarySearchTreeNode));
	temp->left=BuildHB0(h-1);
	tem->data=count++;						//assume count is a global variable
	temp->right=BuildHB0(h-1);
	return temp;
}
  • Time Complexity: O(n), Space Complexity: O(logn), where logn indicates the maximum stack size which is equal to height of tree.

Solution 2: Merge Sort Logic

  • Instead of working with height, we can take the range. With this approach we do not need any global counter to be maintained.
struct BinarySearchTreeNode *BuildHB0(int l, int r){
	int mid=l+(r-l)/2;
	if(l>r) return NULL;
	struct BinarySearchTreeNode *temp=(struct BinarySearchTreeNode *)malloc(sizeof(struct BinarySearchTreeNode));
	temp->data=mid;
	temp->left=BuildHB0(l, mid-1);
	temp->right=BuildHB0(mid+1, r);
	return temp;
}
/*	
initial call to the BuildHB0(1,1<<h) where 1<<h(=*2) does the shift operation for calculating 2^{h+1}-1 (textbook comment)
*/
  • Time Complexity: O(n), Space Complexity: O(logn), where logn indicates the maximum stack size which is equal to height of tree.

Pro 2.2: Give an Algorithm to Generate a Minimal AVL Tree

Given a height h, give an algorithm to generate an AVL tree with minimum number of nodes.

Solution :

  • Fill one level with h-1 and the other with h-2 to get minimum number of nodes.
struct AVLTreeNode *BuildMinAVL(int h){
	if(h==0) return NULL;
	struct AVLTreeNode *temp=(struct AVLTreeNode*)malloc(sizeof(struct AVLTreeNode));
	temp->left=BuildMinAVL(h-1);
	temp->data=count++;								//assume count is a global variable
	temp->right=BuuildMinAVL(h-2);
	temp->height=temp->left->height+1;				//or temp->height=h
	return temp;
}	

Pro 3: Check Whether it is an AVL Tree

Solution :

  • Function IsAVL() returns -1 if the tree is not an AVL tree.During the checks each node sends its height to its parent.
int IsAVL(structBinarySearchTreeNode *root){
	int left, right;
	if(!root) return 0;
	left=IsAVL(root->left);
	if(left==-1) return left;
	right=IsAVL(root->right);
	if(right==-1) return right;
	if(abs(left-right)>1)
		return -1;
	return Max(left,right)+1;
}	
  • Time Complexity: O(n), Space Complexity: O(n).

Pro 4: Count the Number in the Range

Given an AVL Tree with n integer items and two integers a and b can be any integers with a ≤ b a \leq b ab. Implement an algorithm to count the number of nodes in the range [ a , b ] [a,b] [a,b].

Solution :

int RangeCount(struct AVLNode *root, int a, int b){
	if(root==NULL) return 0;
	else if(root->data > b)
		return RangeCount(root->left, a, b);
	else if(root->data < a)
		return RangeCount(root->right, a, b);
	else if(root->data>=a && root->data<=b)
		return RangeCount(root->left, a, b) + RangeCount(root->right, a, b)+  1;
}		
  • In the worst case if the range covers all the nodes in the tree, we need traverse all the n nodes to get the answer which lead to a time complexity in O(n). If the range is small which only covers a few elements in a small subtree at the bottom of the tree, the time complexity will be O(h)=O(logn). This is because only a single path is traversed to reach the small subtree at the bottom and many higher level subtrees have been pruned along the way.

Pro 5: Tree Compression

Given a BST (applicable to AVL trees as well) where each node contains two data elements (its data and the number of nodes in its subtree). Convert the tree to another BST by replacing the second data element with previous node data in inorder traversal. Note that each node is merged with inorder previous node data. Also make sure that conversion happens in-place.
在这里插入图片描述
Solution 1: Level Order Traversal

  • If the number of elements in the left subtree is greater than the number of elements in the right subtree, find the maximum element in the left elements in the left subtree and replace the current node second data element with it. Similarly, if the number of elements in the left subtree is less than the number of elements in the right subtree, find the minimum element in the right subtree and replace the current node second data element with it.
struct BinarySearchTreeNode *TreeCompression(struct BST *root){
	struct BinarySearchTreeNode *temp1, *temp2;
	struct Queue *q=CreateQueue();
	if(!root) return ;
	EnQueue(q, root);
	while(!IsEmptyQueue(q)){
		temp1=DeQueue(q);
		if(temp1->left && temp1->right && temp1->left->data2 > temp1->right->data2)
			temp2=FindMax(temp1);
		else
			temp2=FindMin(temp1);
		temp1->data2=temp2->data2;
		DeleteNodeInBST(temp2);
		if(temp->left)
			EnQueue(q, temp->left);
		if(temp->right)
			EnQueue(q, temp->right);
	}
	DeleteQueue(q);
}
  • Time Complexity: O(nlogn) on average since BST takes O(logn) on average to find the maximum or minimum element. Space Complexity: O(n) since in the worst case, all the nodes on the entire last level could be in the queue simultaneously.

Solution 2: reduce time complexity

  • While traversing the BST in inorder, keep track of the elements visited and merge them.
struct BinarySearchTreeNode *TreeCompression(struct BinarySearchTreeNode *root, int *prevNodeData){
	if(!root) return NULL;
	TreeCompression(root->left, prevNodeData);
	if(*prevNodeData==INT_MIN){
		*prevNodeData=root->data;
		free(root);
	}
	if(*prevNodeData!=INT_MIN){
		root->data2=prevNodeData;
		*prevNodeData=INT_MIN;
	}
	return TreeCompression(root->right, prevNodeData);
}
  • Time Complexity: O(n), Space Complexity: O(1). Note that we are still having recursive stack space for inorder traversal.

Pro 6: Find the Closest Element

Given a BST and a key, find the element in the BST which is closest to the given key.

Solution 1: level order traversal

  • Use level order traversal and for every element compute the difference between the given key and the element’s value.
struct ClosestInBST(struct BinaryTreeNode *root, int key){
	if(!root) return 0;
	int diff=INT_MAX;
	struct BinaryTreeNode *temp, *ans;
	struct Queue *Q=CreateQueue();
	EnQueue(q, root);
	while(!IsEmptyQUeue(q)){
		temp=DeQueue(q);
		if(diff>(abs(temp->data - key)){
			diff=abs(temp->data - key);
			element=temp;
		}
		if(temp->left)
		 	EnQueue(q, temp->left);
		 if(temp->right)
		 	EnQueue(q, temp->right);
	}
	DeleteQueue(q);
	return element->data;		
}	
  • Time Complexity: O(n), Space Complexity: O(n).

Solution 2: recursive approach

struct BinaryTreeNode *ClosestInBST(struct BinaryTreeNode *root, int key){
	struct BinaryTreeNode *temp;
	if(root==NULL)
		return root;
	if(root->data==key) 
		return root;
	if(key < root->data){
		if(!root->left)
			return root;
		temp=ClosestInBST(root->left, key);
		return abs(temp->data - key) > abs(root->data - key) ? root : temp;
	}
	else{
		if(!root->right)
			return root;
		temp=ClosestInBST(root->right, key);
		return abs(temp->data - key) > abs(root->data - key) ? root : temp;
	}
	return NULL;
}	
  • Time Complexity: O(n) in worst case, O(logn) in average case. Space Complexity: O(n) in worst case, O(logn) in average case.

Pro 7. Median in an Infinite Series of Integer

In a sorted list of number, median is the middle number in a sorted list of numbers if we have odd number of element or the average of two middle numbers if we have even number of elements.

  • We can solve this problem by using a binary search tree with additional information at each node, and the number of children on the left and right subtrees. We also keep the number of total nodes in the tree. Using this additional information we can find the median in O(logn) time, taking the appropriate branch in the tree based on the number of children on the left and right of the currentnode. But, the insertion complexity is O(n) because a standard binary search tree can degenerate in to a linked list if we happen to receive the numbers in sorted order (skew tree).

  • So, let’s use a balanced binary search tree to avoid worst case behavior of standard binary search trees. Insertion and balancing is very similar to AVL trees. Instead of updating the heights, we update the number of nodes information. Only the nodes with a balanced factor of 1 or 0 are considered to be balanced. So the number of nodes on the left subtree is either equal to or one more than the number of nodes on the right subtree but not less. If we ensure this balance factor on every node in the tree, then the root of the tree is the median, if the number of elements is odd; Or the median is the average of the root and its inorder successor which is the leftmost descendant of its right subtree, if number is even. The complexity of insertion maintaining a balanced condition is O(logn) and finding a median operation is O(1).

Pro 8.1: Remove All the Half Nodes

Given a binary tree, how to remove all the half nodes which have only one child? Note that we should not touch leaves.

Solution : PostOrder Traversal

  • First process the left children, then the right children, and finally the node itself. So we form the new tree bottom up, starting from the leaves towards the root. By the time we process the current node, both its left and right subtrees have already been processed.
struct BinaryTreeNode *RemoveHalfNode(struct BinaryTreeNode *root){
	if(!root) return NULL;
	root->left=RemoveHalfNode(root->left);
	root->right=RemoveHalfNode(root->right);
	if(root->left==NULL && root->right==NULL)
		return root;
	if(root->left==NULL)
		return root->right;
	if(Root->right==NULL)
		return root->left;
	return root;

Pro 8.2: Remove Leaves

Solution : PostOrder Traversal

struct BinaryTreeNode *RemoveLeaves(struct BinaryTreeNode *root){
	if(root){
		if(root->left==NULL && root->right==NULL){
			free(root);
			return NULL;
		}
		else{
		 	root->left=RemoveLeaves(root->left);
		 	root->right=RemoveLeaves(root->right);
		 }
	}
	return root;
}

Pro 9: Prune BST

Given a BST and two integers (minimum and maximum integers) as parameters, how to remove (prune) elements that are not within that range?

Solution : PostOrder Traversal

  • Since we need to check each and every element in the tree, and the subtree changes should be reflected in the parent, we can think about using post order traversal. So we process the nodes starting from the leaves towards the root. As a result, while processing the node itself, both its left and right subtrees are valid pruned BSTs. At each node we will return a pointer based on its value, which will then be assigned to its parent’s left or right child pointer.
struct BinarySearchTreeNode *PruneBST(struct BinarySearchTreeNode *root, int a, int b){
	if(!root) return NULL;
	root->left=PruneBST(root->left, a, b);
	root->right=PruneBST(root->right, a, b);
	if(a<=root->data && b>=root->data)
		return root;
	if(a>root->data)
		return root->right;			//return the reference to right subtree and discard the left(definitely less than a)	
	if(b<root->data)
		return root->left;
}
  • Time Complexity: O(n) in worst case and O(logn) in average case. Note if the given BST is an AVL tree then O(n) is the average time complexity.

Pro 10: Connect All Adjacent Nodes at the Same Level

Given a binary tree, how to connect all the adjacent nodes at the same level? Assume that given binary tree has next pointer along with left and right pointers as show below.

struct BinaryTreeNode{
	int data;
	struct BinaryTreeNode *left, *right;
	struct BinaryTreeNode *next;
};

Solution 1: level order traversal

void LinkNodes(sturct BinaryTreeNode *root){
	struct Queue *q=CreateQueue();
	struct BinaryTreeNode *prev;			//pointer to the previous node of the current level
	struct BinaryTreeNode *temp;
	int CurrLvlNodeCount,NxLvlNodeCount;
	if(!root) return;
	EnQueue(q, root);
	CurrLvlNodeCount=1;
	NxLvlNodeCount=0;
	prev=NULL;
	while(!IsEmptyQueue(q)){
		temp=DeQueue(q);
		if(temp->left){
			EnQueue(q, temp->left);
			NxLvlNodeCount++;
		}
		if(temp->right){
			EnQueue(q, temp->right);
			NxLvlNodeCount++;
		}
		if(prev)
			prev->next=temp;				//link the previous node of the current level to this node
		prev=temp;							//set the previous node to the current
		CurrLvlNodeCount--;
		if(CurrLvlNodeCount==0){			//if this is the last node of the current level
			CurrLvlNodeCount=NxLvlNodeCount;
			NxLvlCount=0;
			prev=NULL;
		}
	}
}		
  • Time Complexity: O(n), Space Complexity: O(n).

Solution 2:

  • Process the tree level by level without a queue.
void LinkNodes(struct BinaryTreeNode *root){
	if(!root) return ;
	struct BinaryTreeNode *rightMost=NULL, *nextHead=NULL, *temp=root;
	while(temp){
		if(temp->left){
			if(rightMost==NULL){
				rightMost=temp->left;
				nextHead=temp->left;
			}
			else{
				rightMost->next=temp->left;
				rightMost=rightMost->next;
			}
		}
		if(temp->right){
			if(rightMost==NULL){
				rightMost=temp->right;
				nextHead=temp->right;
			}
			else{
				rightMost->next=temp->right;
				rightMost=rightMost->next;
			}
		}
		temp=temp->next;
	}
	LinkNodes(nextHead);
}		
  • Time Complexity: O(n), Space Complexity: O(h) for stack space.

Pro 10: Find the Maximum Path Sum

Given a binary tree, find the maximum path sum. The path may start and end at any node in the tree.

Solution :

struct maxPathSum(struct BinaryTreeNode *root){
	int maxValue=INT_MIN;
	return maxPathSumRec(root);
}
int maxPathSumRec(struct BinaryTreeNode *root){
	if(root==NULL) return 0;
	int leftSum=maxPathSumRec(root->left);
	int rightSum=maxPathSumRec(root-.right);
	if(leftSum<0 && rightSum<0){
		maxValue=fmax(maxValue, root->data);
		return root->data;
	}
	if(leftSum>0 && rightSum>0)
		maxValue=fmax(maxValue, root->data+leftSum+rightSum);
	maxValueUp=max(leftSum, rightSum)+root->data;
	maxValue=fmax(maxValue, maxValueUp);
	return maxValue;
}

Pro 11:What does the Algorithm do?

Algorithm TreeTraversal(r):
	if(!r) return 1;
	else{
		a=TreeTraversal(r->left)
		b=TreeTraversal(r->right)
		return a+b
	}

Solution :

  • It computes the number of leves in the tree.

16. Red-Black Trees

(reference from wiki)


A red-black tree is a kind of self-balancing binary search tree. Each node stores an extra bit representing ‘color’, used to ensure that the tree remains balanced during insertions and deletion. When the tree is modified, the new tree is rearranged and repainted to restore the coloring properties that constrain how unbalanced the tree can become in the worst case. The rebalancing is not perfect, but guarantees searching, insert and delete operations along with tree rearrangement and recoloring performed in O(logn) time, where n is the number if entries.

The nodes carrying keys or data are frequently called internal nodes (non-NIL). The leaf nodes (NIL) of red-black trees do not contain keys or data and need not be explicit individuals in computer memory: a NULL pointer can encode the fact that there is no child node at this position in the parent node. The black depth of a node is defined as the number of black nodes from the root to that node. The black height of a red-black tree is the number of black nodes in any path from the root to the leaves and the black height of one node is the black height of the subtree rooted by it. The black height of a NIL node shall be set to zero.

Properties

In addition to the requirements imposed on a binary search tree the following must be satisfied by a red-black tree:

  1. Every node is either red or black.
  2. All NIL nodes are considered black.
  3. A red node does not have a red child.
  4. Every path from a given node to any of its descendant NIL nodes goes through the same number of black nodes.
  5. The root is black.

The requirements enforce a critical property of red-black trees: the path from the root to the farthest leaf is no more than twice as long as the path from the root to the nearest leaf. The result is that the tree is height-balanced. Since operation such as inserting, deleting, and finding values require worst-case time proportional to the height h of the tree, this upper bound on the height allows red-black trees to be efficient in the worst case, namely logarithmic in the number n of entries O(logn), which is not the case for ordinary binary search tree.

Insertion

First, we adopt the approach of binary search tree to insert node at a certain position and mark it in red (if set it to black will lead to one path from the roots to the leaf has one more extra black node that is difficult to adjust the tree). Two consecutive red node conflict could be adjusted by color flips and tree rotation. Next procedure depends on the color of the other neighboring nodes.

/*Assume P=parent node, N=new node, G=granparent node, U=uncle node*/
struct node *Grandparent(struct node *n){
	return n->parent->parent;
}
struct node *Uncle(struct node *n){
	if(n->parent==Grandparent(n)->left)
		return Grandparent(n)->right;
	else
		return Grandparent(n)->left;
}
void insert_case1(node *n){
	/*case1: insert new node at root without P*/
	if(n->parent==NULL)
		n->color=BLACK;			//set root black
	else
		insert_case2;
}
void insert_case2(node *n){
	/*case2: N's P is black*/
	if(n->parent->color==BLACK)
		return;					//tree remain valid
	else
		insert_case3;
}

case 3

case3
void insert_case3(node *n){
	/*case3: N's P & U are both red*/
	if(Uncle(n)!=NULL && Uncle(n)->color==RED){
		n->parent->color=BLACK;
		Uncle(n)->color=BLACK;
		grandparent(n)->color=RED;
		insert_case1(grandparent(n);		//recursively check
	}
	else
		insert_case4(n);
}

在这里插入图片描述

case4
void insert_case4(node *n){
	/*case4: N's P is RED while U is BLACK or NULL and N is P's right child and P is G's left child*/	
	if(n==n->parent->right && n->parent==Grandparent(n)->left){
		rotate_left(n);
		n=n->left;
	}
	else if(n==n->parent->left && n->parent==Grandparent(n)->right){
		rotate_right(n);
		n=n->right;
	}
	insert_case5(5);     		//goto case 5 because two red node is adjoined
}

在这里插入图片描述

case5
void insert_case5(node *n){
	/*case5: N's P is RED while U is BLACK or NULL and N is P's left child and P is G's left child*/	
	n->parent->color=BLACK;
	Grandparent(n)->color=RED;
	if(n==n->parent->left && n->parent==Grandparent(n)->left){
		rotate_right(n->parent);
	}
	else if(n==n->parent->right && n->parent==Grandparent(n)->right){
		rotate_left(n->parent);
	}
}		

Note that insertion is actually an in-place algorithm because all of the above calls use tail recursion.

Deletion

If the node to be deleted has two children, then the problem can be transform into a problem of deleting another node with only one son.

/*Assume S is sibling of new node, SL is S's left child, SR is S's right child*/
struct node *Sibling(struct node *n){
	if(n==n->parent->left)
		return n->parent->right;
	else
		return n->parent->left;
}
void delete_one_child(struct node *n){
	/*Precondition: n has at most one non-null child*/
	struct node *child=is_leaf(n->right) ? n->left : n->right;
	replace_node(n, child);
	if(n->color==BLACK){
		if(child->color==RED)
			child->color=BLACK;
		else
			delete_case1(child);
	}
	free(n);
}
void delete_case1(struct node *n){
	/*case1: N is root, already done*/
	if(n->parent!=NULL)
		delete_case2(n);
}

在这里插入图片描述

case2
void delete_case2(struct node *n){
	/**case2: S is RED*/
	struct node *s=Sibling(n);
	if(s->color==RED){
		n->parent->color=RED;
		s->color=BLACK;
		if(n==n->parent->left)
			rotate_left(n->parent);
		else
			rotate_right(n->parent);
	}
	delete_case3(n);
}

在这里插入图片描述

case3
void delete_case3(struct node *n){
	/*case3: P, N, S, SL, SR are black*/
	struct node *s=Sibling(n);
	if((n->parent->color==BLACK)&&(s->color==BLACK)&&(s->left->color==BLACK)&&(s->right->color==BLACK)){
		s->color=RED;
		delete_case1(n->parent);
	}
	else
		delete_case4(n);
}

在这里插入图片描述

case4
void delete_case4(struct node *n){
	/*case4: S, SL, SR are black; P is red*/
	struct node *s=Sibling(n);
	if((n->parent->color=RED)&&(s->color==BLACK)&&(s->left->color==BLACK)&&(s->right->color==BLACK)){
		s->color=RED;
		n->parent->color=BLACK;
	}
	else
		delete_case5(n);
}	

在这里插入图片描述

case5
void delete_case5(struct node *n){
	/*case5: S, SL are black; SR is black*/
	struct node *s=Sibling(n);
	if(s->color==BLACK){
		if((n==n->parent->left)&&(s->right->color==BLACK)&&(s->left->color==RED)){
			s->color=RED;
			s->left->color=BLACK;
			rotate_right(s);
		}
		else if((n==n->parent->right)&&(s->left->color==BLACK)&&(s->right->color==RED)){
			s->color=RED;
			s->right-.color=BLACK;
			rotate_left(s);
		}
	}
	delete_case6(n);
}

在这里插入图片描述

case6
void delete_case6(struct node *n){
	/*case6: S is black, SR is red*/
	struct node *s=Sibling(n);
	s->color=n->parent->color;
	n->parent->color=BLACK;
	if(n==n->parent->left){
		s->right->color=BLACK;
		rotate_left(n->parent);
	}
	else{
		s->left->color=BLACK;
		rotate_right(n->parent);
	}
}

17. Splay Tree

Splay trees are BSTs with the additional property that recently accessed elements are quick to access again. It cannot guarantee the O(logn) complexity in worst case but gives amortized O(logn) complexity.

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值