Midterm 1 CS 1501
Runtime of BST Search hit
# of comparisons = 1 + d, where d is the depth of the found node
Runtime of BST Add
# of comparisons = d where d is the depth of the new node
Runtime of BST Search miss
# of compassion = d where d is the depth of the node if it were in the tree
Algorithm Analysis
+ determine resource usage as a function of input size. + Measure asymptotic performance --> performance as input size approaches infinity
ST ADT ops
+ insert + search + delete
Ω
- Big Omega - roughly means >=
runtime of BST operations for delete
- Finding node : O(log n) on average - Finding and removing arrest node in subtree: O(log n) on average total is O(log n) on average and O(n) in worst case
ω
- Little Omega - roughly means >
o
- Little o - roughly means <
runtime of BST operations for search miss, search hit, add
- O (depth of node) - worst case --> O(n) - average case --> O(log n)
DST Runtime
- O(b), b is bit length of target or inserted key - on avg b = log n - when branching according to a 0 or 1 is equally likely - in genera b >= (ceiling function)log𝑛 - end up with many equality comparisons against the full key - better than less than/greater than comparison in BST
4 ways to traverse a binary tree
- Pre-order - In-order - Post Order - Level order
Θ
- Theta - roughly means =
Preorder traversal
- Visit root before we visit root's subtrees - Left
In-order traversal
- Visit root of a binary tree between visiting nodes in root's subtrees - left then root then right - down
post order traversal
- Visit root of binary tree after visiting nodes in root's subtrees -right
Level order traversal
- begin at root and visit nodes one level at a time - for implementation see BFS
search space for boggle
- can be modeled as a tree - each node represents one call to traverse excluding the root node - worst-case runtime = number of nodes * work per node (non recursive part of the traverse) -for board n, there are 1 + n * θ (8^(n-1)) nodes - so worst case runtime = O (n * 8^n)
R-way RSt nodes are large
- considering 8 - bit ASCII, each node contains 2^8 references - this is especially problematic as in many cases, a lot of his space is wasted - common paths or prefix are wasted references - at the lower levels of the trie most keys have been sorted out and referenced list will be sparse solution --> De La briandais Trie
in RB BST why use iteration?
- faster than recursion - no function call overhead (stack allocation) - Especially useful for frequently used operations - search is a good example of these operations
Other BST operations
- finding predecessor and successor of an item - find all items within a specific range worst case runtime = Theta (log n )
DST and prefixes
- in a DST, each node shares a common prefix with all nodes in it's subtree - In-order traversal doesn't produce a sorted order of the items + insertion algorithm can be modified to make a DST and BST at the same time
Search tree property
- left.data < root.data < right.data - hold for every subtree - root.data.compareTo(left.data) > 0 && - root.data.compareTo(right.data)< 0
RB tree delete
- make sure you aren't deleting a black node - as you go down tree make sure next node down is red - as you go up tree correct any violations as you'd do with adding -if you're deleting a noe with 2 children + replace with the minimum of right subtree + delete minimum of right subtree + similar trick to delete regular BST
removing largest item in a Bit
- method returns the root of the tree after deleting the largest item - if the largest item is the root of the tree, return its left child
BST delete operation
- need to find node with the item first - we need to return the removed data item so use a wrapper object
deleting in BST, root has two children
- replace root's data by the data of the largest item of its left subtree - remove the largest item from the left subtree - return root
Tilde approximation (~)
- same as theta but keeps constant factors - two factions are Tilda of each other if they have the same order of growth and the same constant of the largest term
How to make nonrecursive work constant (boggle)?
- since we keep adding and deleting a character this is popping and pushing from a string stack - push/pop ops are usually constant - but resisting isn't - since string are immutable, use string builder
cont. boggle search space
- try to make non-recursive work constant
info on Red-Black trees
- two color of edges --> black and red - a node takes the color of the edge to its parent - only left child can be red - at most one red edge connected to each node - each leaf has two balk null edges out of it - all paths from root to null dges gas e the same number of black edges - root node is black
Boggle problem
- uses backtracking - words at least 3 adjacent letters long and must be assembled from a 4x4 grid - Adjacent letters are horizontally, vertically, or diagonally neighboring - any code in the grid can be only used once per word
The three sums algorithm
- would be faster if it is sorted, and the used binary search for the third number - this gives us a O ( n^2 log n ) - there is a O(n^2) - to get that consider hashing or for each number find the missing pair of number in linear time - also it can be O (n log n) under special cases
O
-Big O - roughly means <=
constant
1
How to determine the order of growth?
1) ignore lower order terms 2) ignore multiplicative constants
DlB nodelets
2 ways to implement has private object val and private T character, as well as node sibling and child. --_ if search terminates on a node with non null value key is found ; otherwise not found alternatively => no object val, and has pro vote character character, node sibling and child --> add a sentinel character eg ^ to each key before add and search if search encounters null, key not found otherwise key found.
exponential
2^n
Full Tree
A tree in which every level of the tree is completely full, with no missing nodes.
Complete Tree
A tree in which there are no missing nodes when looking at each level of the tree. The lowest level of tree may not be completely full, but may not have any missing nodes. All other levels are full.
Run time compassions for trees/ tries
BST --> Search hit Θ(n), search miss Θ(log n), insert Θ(n) RB -BST --> search hit Θ(log n), search miss Θ(log n), insert is Θ(log n) DST --> search hit Θ(b), search miss Θ(log n), insert Θ(b) RST --> search hit Θ(b), search miss is Θ(log n), insert Θ(b) R-way RST --> search hit Θ(w), search miss Θ(log r (n)), insert is Θ(w) DLB --> search hit Θ(wr), search miss is Θ(log r (n * r)), insert is Θ(w * r)
deleting in bst
Case #1 --> node to be deleted is leaf, easy, pass back null to the node's parent Case #2 --> node to be deleted has one child, pass back the child to the nodes parent to adopt instead of the node Case #3 --> node has two children, hard to do, replace node's data by successor or predecessor and delete that node we used
ST Implementation hash table
Insert --> O (1) search --> O (1) delete --> O (1)
ST Implementation unsorted Array
Insert --> O (1) search --> O (n) delete --> O (n)
ST Implementation unsorted Linked List
Insert --> O (1) search --> O (n) delete --> O (n)
ST Implementation sorted Array
Insert --> O (n) search --> O (log n) delete --> O (n)
ST Implementation sorted Linked List
Insert --> O (n) search --> O (n) delete --> O (n)
Digital search tree
Instead of looking at less than/greater than (like in a BST), go left or right based on the bits of the key so we have 4 options - current node is null, k not found - k is equal to the current node's key, k is found, return corresponding value - current bit of k is 0, continue to left child - current bit of k is 1, continue to right child
Radix Search Trie
Instead of storing keys as nodes in the tree, store them implicitly as paths down the tree. Values can then be stored at the end of key's bit string path. - interior nodes of the tree only serve to direct us according to the bit string of the key - values can then be stored at the end of key's bit string oath (ie at leaves) - RST uses less space than But and DST
average node depth BST
O (log n)
worst case node depth BST
O (n)
runtime of add and search hit
O (w) where w is the character length of the string
R-way trie
Radix search trie applied to characters in a string instead of bits
De La Briandais trie
Replace the .next array of the R-way trie with a linked-list
Tree terminology
Root --> has no parents, at level 1 edge --> connects two nodes siblings --> children of a node subtree --> portion of the big tree leaves --> childless nodes
rotate left maintains search tree property and perfect balance property T/F
True
Red-Black Tree
a self-balancing binary tree in which nodes are "colored" red or black. The longest path from the root to a leaf is no more than twice the length of the shortest path.
summary of running time for binary RST and Multi-way RST
b RST --> insert Θ(b), search hit Θ(b), search miss Θ(log 2 (n)) on avg Multi RST --> insert Θ(w), search hit Θ(w), search miss Θ(log r (n))
level order traversal
begin at root and visit nodes one level at a time
Tree that is not full and not complete
can have missing nodes
Symbol table ADT
do not assume any implied ordering among the keys and therefore use only equals(and not less) to compare keys, but many of the symbol-table implementations use the ordering relationship among keys implied by less to structure the data and to guide the search.
For asymptotic performance
focus on the order of growth not on exact values
note on order of growth
gross oversimplification, it works but you have to be careful since sometimes the constants can impact the runtime significantly
flip color
h.color = RED; h.right.color = BLACK; h.left.color = BLACK; return h;
preorder traversal implementation
if (root != null) { system.out.println(root.data); traverse (root.left); traverse (root.right); }
in order traversal implementation
if (root != null) { traverse (root.left); system.out.println(root.data); traverse (root.right); }
post order traversal implementation
if (root != null) { traverse (root.left); traverse (root.right); system.out.println(root.data); }
adding to a r way RST
if root is null, set root --> new node current node --> root for each character c in the key -find the cth child --> if child is null create a new node and attach as the cth child, move to child either recursively or by current.child if at last character key, insert value into current node
Adding to DLB trie
if root is nulls et root --> new node current node --> root for each character c in the key -search for c in the linked list headed at currents using sibling links --> if not found creat a new node and attach as a sibling to the linked list -move to child of the found node - either recursively or bu current --> child -if at last character of key, insert vale into current node and return
Compression
input --> a file containing a sequence of characters - n characters - each encoded as an 8-bit extended ASCII - total file size = 8*n Output --> a shorter bit string - of length < 8*n - such that the original sequence can be fully restored from the bit string
searching in RST
input --> key curren node --> root for each bit in the key if current node is null, return key not found if bit == 0 --> move to left child -> either recursively or by setting current --> current.left if bit == 1 --> move to right child -> either recursively or by setting current --> current.right if current node is null or the value inside is null then return key not found else return the value stored in current node
Adding to ReSt
input --> key and corresponding value if root is null, set root --> new node current node --> root -for each bit in the key if bit == 0 --> if left child of current node is null, create new node and attach as the left child. move to left child either recursively or by setting current --> current.left - if bit == 1--> if right child of current node is null, create new node and attach as right child --> either recursively or by setting current --> current.right insert corresponding value into current node
digital searching problem
input :- a large dynamic set of data items in the form of - n (key, value) pairs; key is a string from an alphabet of size R - each key has b bits or w characters (the chars are from the alphabet) - what is the relationship between b and w a target key (k) output:- the corresponding value to if target key found , key not found otherwise
implementation getHeight
int getHeight (BinaryNode<T> root){ int lheight = 0; int rheight = 0; if(root.left != null) Lheight = getHeight(root.left) if(root.right != null) rheight = getHeight(root.right) return Math.max(lheight,rheight) + 1; }
logarithmic
log n
search miss r way rst runtime
log r(n), average tree height with 2^20 keys in an RST is Log 2 (n) = log 2 (2^20) = 20 with 2^20 keys in a large branching factor trie, assuming 8-bits at a time we have log r (n) = log 256 (2^20) = 2.5
do we want low or high order of growth
low
low order of growth
means that when input size increases, the value of the runtime doesn't increase by much
high order of growth
means that when the input size increases, the value of the runtime increase significantly
Linearithmic
n log n
factorial
n!
quadratic
n^2
cubic
n^3
ask yourself as x doubles how does T(x) grow?
options + stays constant + increase by a constant + double as well + quadruple + eightfold +????
iterative postorder traversal
repeat until stack empty && x == null x = leftmost leaf push to stack while moving down visit x if x is right child pop & visit skip left most leaf else x = parent .right
iterative inorder traversal
repeat until stack is empty && x == null x = leftmost node push to stack while moving down pop and visit x = x.right
red black tree basic operations
rotate left rotate right flip color used to preserve the properties of the red black BST
RST Analysis
runtime --> O(b) where b is the length of key reminder that characters are 8 bit ints
Symbol table implementation
unsorted array --> add θ(1), search θ(n) sorted array --> add θ(n), search θ(log n) Binary search --> add θ(n), search θ(log n) unsorted LL --> add θ(1), search θ(n) sorted LL --> add θ(n), search θ(n) BST --> add θ(n), search θ(n) RB - BST --> θ(log n), θ (log n)
Preorder traversal
visit root before we visit root's subtrees
inorder traversal
visit root o f a binary tree between visiting nodes in root's subtrees
postorder traversal
visit root of binary tree after visiting nodes in roots subtrees let then right then root
backtracking frame work
void traverse (current decision, partial solution){ for each choice at the current decision { if choice is valid { apply choice to partial solution if partial solution a valid solution report partial solution as a final solution if more decisions possible traverse(next decision, updated partial solution) undo changed to partial solution } } }
r way rst vs rst
w < b , tree height is reduced
iterative preorder traversal
while (stack not empty) pop visit push right push left
right rotate
x = h.left; h.left = x.right; x.right = h; x.color = h.color; h.color = RED; return x;
left rotate
x = h.right h.right = x.left x.left = h x.color = h.color h.color - red return x
How to make worst case run time of BST O (log n)?
you would need to keep the tree balanced, so the difference in height between left and right subtrees is controlled
Blocks runtime formula
∑ all blocks (Cost * frequency). All statements that have the same frequency can be grouped up
runtime of an algorithm
∑ all statements (Cost * frequency)