Binary Search Tree

  • An ordered binary tree
  • For every node, all elements in its left subtree are less and any elements in its right subtree are greater
  • Used because they can quickly search and sort
  • Height (N is number of nodes)
    • Average:
    • Worst case:

Terminology

  • Predecessor: Left subtree’s rightmost node
  • Successor: Right subtree’s leftmost node-

Operations

OperationBest CaseWorst Case
Searching
Insertion
Deletion

Searching

search(target, root)
	if the tree is empty
		return null
	else if target == root.data
		return root.data
	else if target < root.data
		return seach(root.left)
	else
		return search(root.right)

Time complexity:

  • Worst case: (when tree is basically a linked list)
  • Average case:

Insertion

TreeNode insert(item, root)
	if root == null
		return TreeNode(item)
	else if item < root.data
		root.left = insert(item, root.left)
	else
		root.right = insert(item, root.right)
	return root

Deletion

delete(item, root)
	if root == null
		// item is not in tree
		return null
	if item < root.data
		root.left = delete(item, root.left)
	else if item > root.data
		root.right = delete(item, root.right)
	else //the item is in the local root
		if root has no children
			delete root
			return null
		else if root has one child
			child = root.child // the one that exists
			delete root
			return child
		else // replace with inorder successor
			successor = getMinimum(curr->right);
			val = successor.val
			delete(val, root) // delete successor
			root.val = val
	return root

Traversal

  • Iterating over a tree such that you touch every node
  • Two strategies
    • Depth First: Goes down an entire branch
    • Breadth First: Goes through and entire level

Depth First

traverse(root)
	if root == null
		return
	else
		// order changes depending on type of traveral
		traverse(root.left)  // L
		visit root           // N
		traverse(root.right) // R
  • Uses a stack (through recursion typically)
  • Inorder
    • Order: LNR
    • Uses
      • Returns the sequence in ascending order
      • Is able to get a sorted list in O(n)
  • Preorder
    • Order: NLR
    • Work at a node is done before (pre) its children
    • Uses
      • Printing dictionary listing
      • Making a copy of a tree
    • The true depth first search (goes down an entire branch at a time)
  • Postorder
    • Order: LRN
    • Work at a node is done after (post) its children
    • Uses
      • Deallocating every node in a tree
      • Calculating an accumulated sum for each node and all descendants
  • Strategy for quickly reading
    • invert

Breadth First

  • AKA Level Order
  • Types
    • Spiral approach (always LR or RL)
    • Zig Zag approach (alternates direction for each line)
  • Uses a queue
    • “Queue… I’m out of breadth”
void levelOrder(TreeNode* root) {
	queue<TreeNode*> q;
 
	if(root != nullptr) {
	    q.push(root);
	}
 
	while (!q.empty()) {
		cout << q.front();
		
		if (q.front()->left != nullptr)
			q.push(q.front()->left);
 
		if (q.front()->right != nullptr) 
			q.push(q.front()->right);
 
		q.pop();
	}
}