diff --git a/370/.gitignore b/370/.gitignore new file mode 100644 index 0000000..d9568ca --- /dev/null +++ b/370/.gitignore @@ -0,0 +1 @@ +*swp diff --git a/370/notes/1.md b/370/notes/1.md new file mode 100644 index 0000000..a48d448 --- /dev/null +++ b/370/notes/1.md @@ -0,0 +1,6 @@ +# lec1 +> trees & tree heaps +> also: ilearn still busted but theres a survey to fill out + +bin search trees +max/min/heap trees diff --git a/370/notes/2.md b/370/notes/2.md new file mode 100644 index 0000000..6425e74 --- /dev/null +++ b/370/notes/2.md @@ -0,0 +1,13 @@ +# Divide and Conquer + +Make big problem into smaller problems to solve + +## Merge Sort + +_yote_ + +1. find midpoint of list +2. split into two smaller lists +3. keep splitting smaller lists until we have a bunch of 1/2 size lists +4. sort each using the _smaller_ already sorted values against each other into a new sub-list +5. combine and sort each thing diff --git a/370/notes/adj-list.md b/370/notes/adj-list.md new file mode 100644 index 0000000..cbd3ad9 --- /dev/null +++ b/370/notes/adj-list.md @@ -0,0 +1,38 @@ +# Adjacency list + +Imagine 8 nodes with no connections + +To store this data in an _adjacency list_ we need __n__ items to store them. +We'll have 0 __e__dges however so in total our space is (n+e) == (n) + +# Adjacency matrix + +space: O(n^2) +The convention for notation btw is [x,y] meaning: + * _from x to y_ + +# Breadth first search + +add neighbors of current to queue +go through current's neighbors and add their neighbors to queue +add neighbor's neighbors + keep going until there are no more neighbors to add +go through queue and start popping members out of the queue + +# Depth first search + +Here we're going deeper into the neighbors + +_once we have a starting point_ + +_available just means that node has a non-visited neighbor_ +if available go to a neighbor +if no neighbors available visit +goto 1 + +# Kahn Sort + + +# Graph Coloring + +When figuring out how many colors we need for the graph, we should note the degree of the graph diff --git a/370/notes/avl-trees.md b/370/notes/avl-trees.md new file mode 100644 index 0000000..53832ac --- /dev/null +++ b/370/notes/avl-trees.md @@ -0,0 +1,32 @@ +# Self balancing trees aka AVL trees + +_time complexity will be in terms of height_ + +> Height: + distance from nulls after leaves + * impl: _root will typically have the largest height value_ + +> Balance: + | left_height - right_height | + we can discard the || if we want negative balance vals but it really shouldn't matter + basically: we want the balance for each node to be 1 or 0. + +# Self balancing part + +We maintain balance through the tree's lifetime as we insert/delete things into the tree + +> Insertion/Deletion + * just like BST but we balance starting from the new node + +# Restoring balance + +There are 4 special cases when dealing with restoring balance: + + 1. left-left + 2. left-right + 3. right-left + 4. right-right + +# Tries + + diff --git a/370/notes/big-o.md b/370/notes/big-o.md new file mode 100644 index 0000000..a77eff7 --- /dev/null +++ b/370/notes/big-o.md @@ -0,0 +1,60 @@ +# Calculating Big O + +Suppose we have the following function + +``` +func(x): + if cond1 + O(n^2) + elif cond2 + O(n) + else + O(1) +``` + +How do we define the _average_ time complexity: +* any input which isn't setup to be _special_ + 1. linear search which always finds the first elementO(1) + 2. linear search that doen't find anything/last elementO(n) + +With linear searches: finding an average item in the middle(somwhere) we have to cover: + * x% of the n size list + +Since we drop the constants in time complexity expressions we thus end up with O(n). + +## Heap Sort + +Time Complexity Exercise + +* Best: +* Average: +* Worst: +* Space: + +## Insertion Sort + +Time Complexity Exercise + +* Best: + * Already sorted meaning we go through the whole list once + * O(n) - because we'll do the check into our left sub-list but we don't go into it leaving us as constant time spent per item ie c\*n + +* Average: + * Pretty close to n^2 just for the sake of + * O(n^2) + +* Worst: + * Going through the whole list sorting everything(backwards) + * O(n^2) + + * must go through N items for each item +* Space: + +# Notation + +Time Complexity: O(n) + +Space Complexity: OMEGA(n) + +Both Complexity: THETA(n) + * such a complexity only exists if O(n) == OMEGA(n) diff --git a/370/notes/complex.md b/370/notes/complex.md new file mode 100644 index 0000000..1492b96 --- /dev/null +++ b/370/notes/complex.md @@ -0,0 +1,27 @@ +# Complexities + +yote we talkin about space and time complexity + +* Space + +How much space this shit takin up + +* Time + +How fast something it's gonna take + +* Both time/space complexity notation + +_O(?)_: this notation is used for both space and time complexity + +# Scale of Complexity + +O(n) we refer as a linear because the higheset order exponent is /1/ + +The higher the max order of the expression the higher order the overall complexity(duh). + +Non-polynomial expressions are just non-polynomial expressions(yote). + +In other words the part most people care about is the highest order exponential value in the function/expression, since everything else _will_ be faster than that. + +If you want to jam jargon in there go ahead but don't overthink this tbh famalamasham. diff --git a/370/notes/graphs.md b/370/notes/graphs.md new file mode 100644 index 0000000..06708cf --- /dev/null +++ b/370/notes/graphs.md @@ -0,0 +1,3 @@ +# Graph + +_First of a few pages on graphs_ diff --git a/370/notes/sorts.md b/370/notes/sorts.md new file mode 100644 index 0000000..ba15ccc --- /dev/null +++ b/370/notes/sorts.md @@ -0,0 +1,20 @@ +# Cheatsheet for sorts + +_using pythonic terminology for these cases_ + +> Bubble + * take the largest value and buble it to the top/front of the list + +> Insertion + +> Selection + * take smallest value and drop it to the front + +> Merge + * split the hell out of things and sort from the inside out + * goes from side to side + +> Heap + * grab max item and append it to a heap + +> Quick diff --git a/370/notes/space.md b/370/notes/space.md new file mode 100644 index 0000000..7e305b4 --- /dev/null +++ b/370/notes/space.md @@ -0,0 +1,16 @@ +# Space complexity + +With function calls there is explicit space used. + +Implicit space used is about how much work is done to take up space + +# Binary recursive search + +> Explicit space: O(c) + +This is the amount of space taken per call. +We know how much space has to be allocated every call so we can say it would likely be constant + +> Implicit: O(log(n)) + +Because again we will likely take up log(n) times to reach our destination an this comes from our rekked stackspace. diff --git a/370/notes/tries.md b/370/notes/tries.md new file mode 100644 index 0000000..2a9442d --- /dev/null +++ b/370/notes/tries.md @@ -0,0 +1,20 @@ +# Tries - Prefix Trees(syntax trees in disguise) + +We can build grammers from symbols where symbols follow a set of rules to build on each other. +Kinda like linguistic sytax trees but, exactly the same. +_Individual syntaxes are combined to build grammers combine to build phrases, etc. etc._ + +Instead of symbols we use _prefixes_ as our terminology, to build _words_. +Terminally sequenced symbols are denoted by a _leaf_ flag. + +# Deletion + +We don't actually remove things for trivial cases. +Instead we turn off the leaf flag in the end target node + +if we have /bathe/ and /bathes/ as valid phrases and wanted to remaove /bathe/ from our language + * All we have to do is set the /e/ to off as a valid leaf. + +If instead we wanted to remove /bathes/ instead we would go to /s/ and then set it to off like before. + * The problem now is that /s/ is hanging and it doesn't have any children so we can remove it entirely + * If a toggled off node has children it means that it necessarily is part of a valid prefix so it can not be removed diff --git a/370/past-midterms/m1.md b/370/past-midterms/m1.md new file mode 100644 index 0000000..689b275 --- /dev/null +++ b/370/past-midterms/m1.md @@ -0,0 +1,57 @@ +# Practice things +_just going through the practice midterm problems_ + + +1. Identifying sorting algorithms based on progression(_conceptual_) + +_bubble sort_: the bigger the value = the bigger the bubble + * compare two values from the start always, bubble up the bigger value + keep compmaring two adjacent values till you get to the end of the list + * kinda like gladiator m&m's + +_insertion sort_: we have the left sublist which maintains a ordered state always + * we walk along the unsorted list and try to drop our current value into the currently sorted left-hand sublist. + * Key points: + left hand ordered sublist + +_quick sort_: here we push things up to the top immediately where they are then sorted against the left hand sub-list + +_heap sort_: make a giant heap(list) and just take the largest/smallest value and prepend/append to the """heap""" + +__reponse__: insertion sort +Left side of progression is always sorted while the right isn't +Left side also get progressively larger + +2. How you know if a graph is undirected given a matrix(_code_) + +_empirically_: check the upper right half of the matrix and check if each coord pair is reflected across the main axis + + 1. Take a coords pair value(_say True_) + 2. Flip the (x,y) so we have /x,y/ + 3. If the /x,y/ value is the same as (x,y) then those two nodes are bidrectional(i.e. undirected) + +The _trick_ here is making sure we don't bother check the divisor axis or below by accident. + +3. Binary tree lookup(_code_) + +Recursion is the smollest way of doing this so just go with that. + +4. Quick sort partition(_code_) + + * Just splitting lists again + * Checking for partition results as well + +5. Graph traversal(_code_) + +DFS/BFS is fair game +List/matrix meme allowed so don't even bother with other trash + +6. Emperical Graph Traversal(_conceptual_) + +Time complexity of either dfs/bfs will be /v\*e/ or something like that + +7. Topological sort(_code_) + +big meme matrix/list allowed + + diff --git a/370/past-midterms/midterm1.pdf b/370/past-midterms/midterm1.pdf new file mode 100644 index 0000000..d7fc03f Binary files /dev/null and b/370/past-midterms/midterm1.pdf differ diff --git a/370/samples/adj-matrix.py b/370/samples/adj-matrix.py new file mode 100644 index 0000000..e69de29 diff --git a/370/samples/graph.py b/370/samples/graph.py new file mode 100755 index 0000000..b62ef1e --- /dev/null +++ b/370/samples/graph.py @@ -0,0 +1,53 @@ +#!/usr/bin/python3 + +import random +class Node: + def __init__(self, data:int): + self.data = data + # empty list o rama + self.refs = [] + + def __str__(self): + return f'{self.data}:{self.refs}' + +def new_node(data): + """ + Provides a new node for a ref list or a basic s + """ + return Node(data) + +def add_node(base, data): + """ + Creates a new node for the base node to hook onto + """ + base.refs.append(new_node(data)) + +def show_children(node): + """ + LMAO @ your life + """ + print(node.refs) + +def populate(node): + """ + Populate our node with some data + """ + for i in range(1,random.randint(2,10)): + new_tmp = new_node(random.randint(0,100)) + node.refs.append(new_tmp) + +def child_count(node): + print(f'{len(node.refs)}') + +if __name__ == "__main__": + root = Node(0) + for i in 'ABCDE': + add_node(root, i) + + print(f'Children count of root: {len(root.refs)}') + for i in root.refs: + populate(i) + child_count(i) + + print('Root node:') + show_children(root) diff --git a/370/samples/tree.py b/370/samples/tree.py new file mode 100644 index 0000000..42e5139 --- /dev/null +++ b/370/samples/tree.py @@ -0,0 +1,37 @@ +#!/usr/bin/python3 +import random # just for some basic population methods + +class Node: + def __init__(self,data): + self.data = data + self.children = [] + + def __str__(self): + return self.data + + def __repr__(self): + return f'{self.__str()}:{self.children}' + +def new_node(data): + return Node(data) + +def add_node(node, lr, val): + node.children.append() + return None + +def lvr(root): + """ + Inorder traversal + """ + # left sequence + if root.left is not None: + lvr(root.left) + + # visit sequence + print(root.data) + + # right sequence + if root.right is not None: + lvr(root.right) + + return diff --git a/370/samples/trie.py b/370/samples/trie.py new file mode 100644 index 0000000..c2135ad --- /dev/null +++ b/370/samples/trie.py @@ -0,0 +1,32 @@ +# Syntax tree in disguise +class Node: + def __init__(self, symbol=None, leaf=False, children={}): + # root node doesn't need any actual data + self.symbol = None + self.leaf = leaf + # {key=char : value=Node} + self.children = children + +class Trie: + def __init__(self): + # root should contain every letter so that we can pick our thing + root = Node() + + #wrapper func + def traverse(self, func, phrase, _node): + # wew lad + def func(_phrase, _node): + + return func(phrase) + + @traverse + def insert(self, phrase, node): + pass + + @traverse + def remove(self, phrase, node): + pass + + @traverse + def checkPhrase(self, phrase): + pass