Вы находитесь на странице: 1из 5

AVL Trees:​ A binary tree with n nodes is balanced if it has a height of O(Log n)-> all OPS( O(log n) )

● EX: a complete binary tree with 2^n - 1 nodes has a height of n-1, so is balanced
● AVL Property: heights of left and right subtrees of every node differ by at most 1
○ Maintain height and Balance Factor of each subtree in subtree root node
○ balance factor: Height of right subtree - Height of Left subtree​ -> {-1,0,1} -> computer in O(1)
○ When insert or remove node into AVL, root node BF change by at most 1 or -1
● If BF -2 or 2-> Rebalance and Rotation
○ If root.left has balance factor +1 // CASE 2 perform left rotate on root.left
● Perform right rotate on root // CASE 1
● Else if root’s balance factor is +2, do opposite rotations, applying Case 2 to root.right
● Right Rotate Code (root){ TreeNode ​orph​ = ​root​.​left​.​right​ ​then​ TreeNode ​rotate​ = ​root​.​left​;
○ rotate​.setRight(​root​); ​then​ ​rotate​.​right​.setLeft(​orph​);
○ updateHeight(​rotate​.​right​) ​then​ updateHeight(​rotate​); ​then ​return​ ​rotate​;
● Insert: only 1 rotation needed, Delete: continue to check and rebalance recursively O(logn)
● Cost AVL Maintenance (Rotation O(1) + check & rebalance O(1) per level = ​BST ops ϴ(log n)
2-3-4 Trees (B-Tree) ->​ a complete binary tree-> Each node can hold 1,2, or 3 keys
● Grows bottom-up (not top-down), A non-leaf node with​ t​ keys have ​t + 1​ children
● Every path from root to bottom of tree has the same height h = 2^(h+1) -1 keys
○ If every node has 1 key (min), “same height” property implies that tree is a complete binary
tree of height h-> O (log n) height with n keys
● Insert: insert into existing leaf to maintain same path height ->if full, insert into temp overloaded node
○ Split overloaded node into 2 and push the mid key up to the parent (key #2/4), then
recursively split (splitting takes O(1) so worst case insertion is ​O(log n)​) | Delete: ​O( log n)
Red-Black Tree​ binary rep. of a 234 tree: height O(log n) -> Convert each node in 234 to mini binary tree,
every node map to a black node with 0-2 red children.
Graph Searches​ -> Graph G = (V, E) is a set of V vertices and E Edges | ​A graph has O(n^2) edges
● Directed​ Graph: u->v | asymmetric A -> B does not imply B -> A | has v(v-1) edges
● Undirected ​Graph: u-v | symmetric A - B | has n(n-1)/2 edges
● DENSE​ GRAPH: O(n^2) edges | ​SPARSE​ GRAPH: O(n) edges
● Adjacency Matrix​: M(i,J) -> 1 if edge (i, j) exists, 0 otherwise | undirected: M is symmetric
○ Space:​ ϴ( V^2) | ​Check if Edge exists:​ ϴ(1) | ​Enumerate Al Edges:​ ϴ(V^2)
● Adjacency List:​ ​Array A[1…..n] -> A[i] contains list of edges (i, j)
○ Space: ​ϴ(V+E) | ​Check if Edge exists:​ ϴ(E) | ​Enumerate All Edges:​ϴ(V+E)
Breadth-First-Search (BFS)​-> use FIFO queue that tracks vertices to be searched | ​Cost = ϴ(|V| +|E|)
● Good for: Shortest distances, Bipartite graphs, State-space search in AI
● Initially, Q contains ​only ​starting vertex v, which is marked; v.distance 0; v.parent null
● While Isnotempty ​THEN​ u = Q.dequeue() ​THEN​ for each edge (u,w)
○ if w is not marked ​THEN ​mark w; w.distance = u.distance + 1; w.parent = u ​THEN​ Q.enqueue(w)
● D(v,u) is the smallest # of edges on any path from v to u | Unreachable vertex has distance is infinity.
● Parent pointers from a tree of shortest paths pointing back to the starting vertex
● Remove parent node from Q same time you add its children nodes to the Queue.
Bipartite Graph :​ consists of 2 sets of L and R vertices and edges go ​between ​L and R
● Pick a starting V and label V on side L, run BFS, if we discover vertex w via edge (u,w) label w on opposite
side from u, ​graph is bipartite is BFS never labels both endpoints of an edge (u,w) with the same side.
Depth-First-Search(DFS): ​First Start, Last Finished using a Stack -> ​Cost = ϴ(|V| + |E|)
● POP​ off stack when finished | ​PUSH ​when discovered.
● Good for​: Cycle detection​, Dependency resolution, Reachability Compiler analyses
● Algo:​ each vertex has a start & finish time & time ticks after each assessment of a vertex, if no where to go,
close out end time then back track until can move forward again. If not reach all, start untouched v: +1 time
● DFSVisit(v) ​AND ​v.start = time
○ for each edge (v,u) ​->​ if (u.start is not yet set) ​THEN ​DFSVisit(u) || after for-loop: v.finish = time
● G contains a cycle if DFSVisit(v) ever finds an edge (v,u) where u is started but not finished.
○ Proof: ​If DFSVisit(u) finds adjacent vertex w that is started, not finish, then DFSVisit(w) was called
earlier and is not yet done. Hence, DFS found a path from w to u. But edge (u,w) also exists: cycle.
● Topological Order:​ If a​ directed​ graph does not contain a cycle, we can assign an order to its vertices
○ TOP of directed, acyclic graph (DAG) is total ordering of reverse of finish times
○ If given a TOP order, draw arrows to each letter like in graph, if arrow in opp. Direction: not TOP
○ Proofs: If look at edge (u,v) and v is unstarted vertex, then v has a smaller finishing time than u.
■ V cannot be “in-progress” when (u,v) is traversed because then it would create a cycle in
the graph and the edge (u,v) would not need to be traversed. *****
■ Could start at last vertex then back track because all nodes would end immediately and
first vertex would end at time 1.
○ G=(V,E) has a unique TOP order if has directed path of |V|−1 edges that touch all |V| (Hamiltonian)
Dijkstra's Algorithm​ -> weighted edges and shortest path (length of path is sum of edge weights)
● Problem: ​given a starting vertex v, find path of least total weight from v to each other vertex in the graph.
● D Algo:​ at each step, explore edges out of vertex v with ​smallest v ​ .dist, ​and relax all its adjacent vertices.
Of all vertex.dist, choose the smallest one globally, continue with that vertex. Stop when each vertex has
had its outgoing edges explored once. Parent edges form a shortest path tree
● Relaxation: ​maintain, for each vertex v, the length of the shortest path to v seen so far. Store this shortest
path estimate as v.dist. At each step explore edges out of v and relax adjacent edges before chooses next.
● Starting vertex v gets v.dist=0; all other u get u.dist = ∞, mark all vertices as unfinished
● while (​any vertex unfinished)​ ​->​ V unfinished vertex with smallest v.dist
○ for each edge (v,u)​->​ if (v.dist + w(u,v) < u.dist) ​->​ u.dist = v.dist + w(u,v)​ ->​ mark v ​finished
● Correctness of D Algo: ​when we explore the edges out of vertex v, v has its correct shortest-path distance
D(start, v) stored in current best estimate v.dis
● Use a Priority Queue: PQ of unfinished vertices based on distance, PQ.extractmin() to get next smallest,
and to update Decrease the v.dist
○ v.dist = 0; D[v] = PQ.insert(starting vertex v) | For other vertices u ​->​ U.dist = ∞; D[u]=PQ.insert(u)
○ while (PQ not empty) ​THEN ​V = PQ.extractMin()
■ for each edge (v,u), if (v.dist + w(v,u) < u.dist)​ THEN ​u.dist=v.dist+w(v,u) ​THEN
D[u].dec(u)
● Inner for loop: O(E) | Time of each iteration of for loop: O(logV) | extractmind(): O(logV) caled O(V) times
● Running Time: all PQ take Θ( log V) -> ​DIJ Cost = ​Θ((|V| + |E|) log |V|)
○ Dense: ​Θ(V^2 logV) |​ Sparse: ​Θ(VlogV)
● Run time on Adjacency Matrix: O(V) to find neighbors of each vertex | Overall: O(V^2logV)
○ Inner loop: V takes LogV | Outer loop: V Time | Log v to extractmin() | = V(log v + vlogv)
Fibonacci heap:​ takes Θ(log n) time to do an extractMin() but O(1) for insert or decrease.
● Cost of Fib heap with DIJ is ​Θ(V + E + VlogV) -> Dense: ​Θ(V^2) |​ Sparse: ​Θ(VlogV)
Single-Source Shortest-Paths​ -(SSSP problem): edge weights upper bounded by a constant w.
● The longest path between two vertices in a graph is w(n-1)-To make DIJ run on this graph in O(nW + m)
time
● Use an array of buckets w(n-1), each vertex has a spot in the table and as you perform DIJ algo, you update
the paths stored in each index as appropriate and move to the next smallest distance.
● Find min by starting at left most bucket & scan right till non-empty bucket: Bucket index=pos weight
Negative Edges:​ DIJ fails when about to traverse a (-) edge, can’t​ ​convert graph w/ (-) edges to run properly w/ DIJ.
Greedy Algorithms + Min Spanning Tree​ (min all weights of edges)-min total cost to span tree & connect vertices
● If cycle exists, an edge can be removed w/o disconnecting any vertex-> T is (undirected) acyclic graph: ​tree​.
● A Tree T spans G if it has n-1 vertices and Graph G may not have unique MSTs
● Proof:​ The always chooses the next best greedy edge to create a globally optimal solution and the algo
must terminate. It terminates by not creating cycles, as the cycle would go on forever and never terminate
Prim’s Algo -> cost of Θ((|V| + |E|) log |V|)-> same as Dijkstra-> good for dense graphs -> connect power grid
● Start at arb. vertex, pick edge e of min w(e) that connects a vertex in T to a vertex not yet in T.(undir. graph)
● After any # of edges are chosen, the algo’s current edge set is a subset of some MST for G
● If T has V-1 edges, then it spans G.
● Implementation -> can use a min-first PQ-> like DIJ (total weight of path) vs (weight of last edge on path)
○ Maintain set of unconn vertices->
○ For each unconn v, maintain a v.conn, weight of lowest-weight edge connecting v to any vertex in
T.
○ When add edge (u,v) to T, update connections to each x adjacent to v.
○ If W(v, x) < x.conn, than x.conn = w(v,x)
● Starting vertex v gets v.conn = 0; all other u get u.conn = ∞ | mark all vertices as ​unconnected
● while (​any vertex unconnected)​ -> V = unconnected vertex with smallest v.conn
○ for each edge (v,u) ​-> ​if (uconn > w(u,v)) ​THEN​ uconn = w(u,v) ​THEN​ mark v ​connected
Kruskal’s Algo-> O(ElogE)-> good for sparse graphs
● Algo: Add to T the edge e of minimum w(e) that does not form a cycle when combined with edges already in
T. -> Can’t pick/add an edge that adds a cycle -> First create a sorted array-> maintain list of components
Greedy Decisions
● Dijkstra: Pick the vertex v with minimum v.dist that has not yet been expanded
● Prim: pick the edge e of minimum w(e) that connect a vertex in T to a vertex not in T
● Kruskal: add to T the edge e of min. w(e) that doesn’t form a cycle when combined with edges already in T
Important Algorithm Run-Times
● Binary Search​: ϴ(logn) |​HeapSort: ​ϴ(nlogn) | ​Mergesort: ​ϴ(nlogn) |​Counting Sort:​ ϴ(n+k) -> ϴ(n) | R ​ adix
Sort:​ ϴ(d(n+k)) : d = # of digits, n = # of values, b = base -> base 10 | ​Comparison Sorts: Ω (n logn) |
Array Inserts(Doubling vs. Add One): int [ ] arr = new int [n] = ϴ(n)
Hash Function Design ​(convert h-codes to indices between 0-m) -> use prime number -> Correct and efficient
● Division Mapping​: k mod m | ​Multiplicative Mapping:​ [((c * A)mod 1.0)*m ]:cast int-mod 1.0 take floor of #
● Required ​2 objs that are ​equal​ have ​equal ​hashcodes | ​Optimal​ 2 objs​ not equal​ have ​not equal​ h-codes
● Ideal performance​-> distribute keys ​equally​ and ​independently​ across [0,m)
○ Order​ matters: multiply by primes(tuple) | ​Order not​ matter(set): just add.
● Simple Uniform Hashing: index: ​Assume it is equally likely for any key to map to each value from [0,m)
Master Method: ​T(n) = aT(n/b) + f(n): a = # of recursive calls in an algorithm of size n/b with f(n) work
● Master Method Theorem (Compare f(n) to n^logb(a))-> 1. If f(n) = O (n^logb(a)) -> T(n) = ϴ(n^logb(a))
○ 2. If f(n) = ϴ(n^logb(a) log ^k (n))
■ A.​ k > -1 , T(n) = ϴ( n^logb(a) log^(k+1)n ​B.​ k = -1 , T(n) = ϴ(n^logb(a) log log n)
■ C. k < -1, T(n) = ϴ(n^logb(a))
○ 3. If f(n) = Omega( n^logb(a)) -> T(n) = ϴ (f(n))
● If f(n)​ poly Greater​ g(n): exception-> n^2 log n​ is poly. Equal to ​ n ^2 but n^3 log n ​is​ greater than n ^2
● Master methed not apply if a is not a constant or less than 1 or f(n) is negative

^ L = more buckets = better for time /// v L = less buckets = better for space
○ n/m <= L (upper bound on alpha), when n/m is bigger than L, double array size and re-hashTakes
approx. ϴ(n). To map to a new, larger table when maintaining a load factor

Write in :
1.
ALL OPS
Linked List (No Tail): ϴ(n)- unless insert at head
Linked List (With Tail): search ϴ(n), insert ϴ(1) [ unorder ϴ(n)] ,
Unorder Array: generally ϴ(n), interst at end is ϴ(1), insert could be ϴ(1) with replace, n inserts ϴ(n)
Order Array: Search ϴ(logn), all else ϴ(n)
Min-heap array: search ϴ(n), find mind ϴ(1), all else ϴ(logn), n inserts ϴ(n logn)
Hash table: Average: ϴ(L) 1 + n/m Worst: ϴ(n)-> no load factor
AVL: all ϴ(logn)
BST: Balanced:ϴ(logn) worst-case -Unbalanced: ϴ(n)
2-3-4 and RB : ϴ(logn)

2.

BST Operations -> must be dynamic


● Find()​- start at min value & succ(x) till find value | ​Min/ Max() ​(recursive)-> Min at the far left of tree
● Insert()​-> use find(), Go to where x would be
● Iterate()​-> point to min node & call to iterator.next() move to next largest node->succ(x)
○ X has a right subtree: succ(x) = the left most node of subtree
○ Else, Follow parent pointers from x until some node y is a ​right ​parent -> Return y
● Remove (k)​: X is a leaf: just delete | X has 1 subtree, remove x & link tree’s root to x’s parent
○ Removing a node with two subtrees (steal a key): y=succ(x) | replace x.key by y.key & del. Y.key
3.

● Delete -> also ​O( log n)


○ Case 1: If node with key has at least 2 keys, remove the key
○ Case 2 “rotation”: If the child node (the one being descending into) has only 1 key and has an
immediate sibling with at least 2 keys, move an element down from the parent into the child and
move an element from the sibling into the parent.
■ If both the child node and its immediate siblings have only 1 key each, merge the child
node with one of the siblings and move an element down from the parent into the merged
node. This element will be the middle element in the node. Free the node whose elements
were merged into the other node.
○ Case 3 “hole”: ​If all of these options fail, it creates a hole in the node's parent, then recursively tries
to find a way to fill it using options analogous to C3 and C6 (rotation and "unsplitting", respectively).
If neither option is possible, the hole is pushed up to the next level of the tree, and so forth until it
either reaches the root or disappears. If, as in C8, the hole reaches the roots, the tree shrinks by
one level.

4. Lhopitals rule and important maths

○ Exchange Argument Proof for Prim


■ T is a subset of T* (T* is a MST that spans G) and e is the next greedy edge to select
■ If e is a part of T*, then Inductive hypothesis is proved for T U {e}, otherwise there must be
another spanning tree T’ than contains T U {e}, which is another optimal solution.
■ T* must then have another edge e’ and if you added e to T* you would create a cycle
■ By removing edge e’ you are left with T’
○ Exchange Argument for Kruskal’s
■ T is a subset of T* (T* is a MST that spans G) and e is the next greedy edge to select
● What happens if the next e chosen is not in T*?
■ When e is chosen, it connects to subsets of vertices X and Y. These X and Y are
connected by a path rather than an edge
○ Exchange argument: adding an edge e only creates one cycle because there are none so far on
the first run of the algo. Can’t make 2 cycles with one edge.

Search() Insert() Find Min() / Find() Max() Delete() n Inserts()

Linked List (no ϴ(n) At head: ϴ(1) ϴ(n) ϴ(n) ϴ(n) At Tail: ϴ(n^2)
Tail) At Tail: ϴ(n)
In mid: ϴ(n)

Linked List (with ϴ(n) At Tail: ϴ(1) (no ϴ(n) ϴ(n) At head/tail:ϴ(1) ϴ(n)
Tail) loop) Unorder: ϴ(n) In mid: ϴ(n)
Unorder: ϴ(1) Order: ϴ(1) Order: ϴ(1) after found
Order: ϴ(n)

Unordered Array ϴ(n) At end: ϴ(1) Find: ϴ(n) ϴ(n) From end: ϴ(1) ϴ(n)*
(doubling) Middle: ϴ(n) Extract: remove From mid: ϴ(n) if shift, ϴ(1) if
index, replace last replace
node at index ϴ(1)
+ϴ(n) to find

Ordered ϴ(logn)- binary At end: ϴ(1) Find: ϴ(1) Finds: From end: ϴ(1)
Array(small-big) search Middle: ϴ(n) Extract: ϴ(n)- shift ϴ(1) From mid: ϴ(n)
elements Extract:
K ex() : ϴ(n)** ϴ(1)

Min-Heap Array ϴ(n) ϴ(logn) Find: ϴ(1) ϴ(n) ϴ(logn) ϴ(nlogn)


Extract: ϴ(logn)
k exMi():ϴ(nlogn)
Hash Table Average: ϴ(L) worst: ϴ(n), ... ... double array size
Worst: ϴ(n) average: ϴ(1 + and
n/m), n/m = alpha re-hashTakes
approx. ϴ(n).

AVL Tree ϴ(logn) ϴ(logn) ϴ(logn) ϴ(logn) ϴ(logn) ϴ(nlogn)

BST Balanced:ϴ(logn)
Unbalanced: ϴ(n)

Red-Black Tree ϴ(logn)

● Neg-weights -> ​Bellman-Ford (​ ​Θ(|V||E|)​) | shortest path for every pair ​Floyd-Warshall ​(​Θ(|V|^3)​)

Вам также может понравиться