From a22880ca8ec7d7be543a6845f5e25c9849ef3b27 Mon Sep 17 00:00:00 2001 From: tocariimaa Date: Fri, 24 Jan 2025 16:23:45 -0300 Subject: [PATCH] add these --- misc/data_structures/binheap.nim | 84 +++++++++++++++++++++++++ misc/data_structures/graph.nim | 56 +++++++++++++++++ misc/data_structures/trie.nim | 104 +++++++++++++++++++++++++++++++ misc/partial.lua | 21 +++++++ 4 files changed, 265 insertions(+) create mode 100644 misc/data_structures/binheap.nim create mode 100644 misc/data_structures/graph.nim create mode 100644 misc/data_structures/trie.nim create mode 100644 misc/partial.lua diff --git a/misc/data_structures/binheap.nim b/misc/data_structures/binheap.nim new file mode 100644 index 0000000..9831b32 --- /dev/null +++ b/misc/data_structures/binheap.nim @@ -0,0 +1,84 @@ +## Generalized min/max binary heap implementation +## 2023/01/24 +type BinHeap*[T] = ref object + items: seq[T] + size: int + puCmp: proc (lhs, rhs: T): bool {.noSideEffect.} + pdCmp: proc (lhs, rhs: T): bool {.noSideEffect.} + +func lt[T](lhs, rhs: T): bool = lhs < rhs +func gt[T](lhs, rhs: T): bool = rhs < lhs + +## Find the smallest children of a parent node +## Knowing the parent node, we can its children with this formula: +## If P = 2, then its children are 2P and 2P + 1 respectively. +proc minChild[T](self: BinHeap[T], parent: int): int = + let (lc, rc) = (parent * 2, parent * 2 + 1) + # If the computed right child of the parent is bigger than + # the heap list, it doesn't exist. + if (rc >= self.items.len) or (self.items[lc] < self.items[rc]): + return lc + return rc + +## Swaps the inserted element with its parent until the element is +## bigger than its parent, towards the root +proc propagateUp[T](self: BinHeap[T]; parent, child: var int) = + while parent > 0: + if self.puCmp(self.items[child], self.items[parent]): + swap(self.items[parent], self.items[child]) + child = parent + parent = parent div 2 + +## Swaps the node with its smallest children until the node is bigger +## than its parent, towards the leaves +proc propagateDown[T](self: BinHeap[T], node: int) = + var i = node + while i * 2 < self.items.len: + let mc = self.minChild(i) + if self.pdCmp(self.items[i], self.items[mc]): + swap(self.items[i], self.items[mc]) + i = mc + +proc newBinHeap*[T](minh: bool): BinHeap[T] = + new(result) + result.items = newSeqOfCap[T](32) + result.items.add(0) + result.puCmp = lt + result.pdCmp = gt + if not minh: + swap(result.puCmp, result.pdCmp) + +## Adds a new element to the heap, keeping the heap property. +proc add*[T](self: BinHeap[T], e: T) = + self.items.add(e) + inc self.size + var + child = self.items.len - 1 # the inserted element + parent = child div 2 # parent of the element + self.propagateUp(parent, child) + +## Pops the min or max element (the root, index 1 in a min heap) +## keeping the heap property. +## Whether the popped element is min or max depends if the heap is a +## minumum or maximum one. +proc popMinOrMax*[T](self: BinHeap[T]): T = + result = self.items[1] + self.items[1] = self.items[self.items.len - 1] + discard self.items.pop() + self.propagateDown(1) + +## Builds a heap from the given list +proc heapify*[T](self: BinHeap[T], lst: openArray[T]) = + self.items &= lst + for i in countdown(self.items.len div 2, 1): + self.propagateDown(i) + +func len*(self: BinHeap): int = self.size + +when isMainModule: + var bh = newBinHeap[int](false) + bh.heapify([9, 6, 5, 2, 3]) + bh.add(23) + for e in bh.items: + echo e + echo "min element: ", bh.popMinOrMax() diff --git a/misc/data_structures/graph.nim b/misc/data_structures/graph.nim new file mode 100644 index 0000000..741ad34 --- /dev/null +++ b/misc/data_structures/graph.nim @@ -0,0 +1,56 @@ +import tables +from strformat import fmt + +type + VertexKey = string + Graph*[T] = ref object + vertices: Table[VertexKey, Vertex[T]] + vertexCount: int + Vertex*[T] = ref object + key*: VertexKey + payload*: T + adj: seq[Edge] + Edge* = tuple + toVert: VertexKey + weight: int + +proc addVertex[T](this: Graph, vx: Vertex[T]) = + this.vertices[vx.key] = vx + +proc addEdge(this: Graph, fromVert: VertexKey, eg: Edge) = + this.vertices[fromVert].adj.add(eg) + +proc addEdge(this: Graph, fromVert: VertexKey, edges: varargs[Edge]) = + for edge in edges: + this.vertices[fromVert].adj.add(edge) + +proc contains(this: Graph, vx: VertexKey): bool = + vx in this.vertices + +proc `$`(this: Graph): string = + for vkey, vval in this.vertices.pairs: + result &= fmt"v{vkey} -> {{" + for i, edge in vval.adj: + result &= fmt"v{edge.toVert} (w{edge.weight})" + if i + 1 < vval.adj.len: + result &= ", " + result &= "} " + + +var g = Graph[int]() +g.addVertex(Vertex[int](key: "0", payload: 20)) +g.addVertex(Vertex[int](key: "1", payload: 39)) +g.addVertex(Vertex[int](key: "2", payload: 2983)) +g.addVertex(Vertex[int](key: "3", payload: 19380)) +g.addVertex(Vertex[int](key: "4", payload: 947)) +g.addVertex(Vertex[int](key: "5", payload: 947)) + +g.addEdge("0", (toVert: "1", weight: 5), (toVert: "5", weight: 0)) +g.addEdge("1", (toVert: "2", weight: 0)) +g.addEdge("2", (toVert: "3", weight: 4)) +g.addEdge("3", (toVert: "4", weight: 0), (toVert: "5", weight: 0)) +g.addEdge("4", (toVert: "0", weight: 7)) +g.addEdge("5", (toVert: "4", weight: 0)) + +echo g +assert "2" in g diff --git a/misc/data_structures/trie.nim b/misc/data_structures/trie.nim new file mode 100644 index 0000000..8746cb6 --- /dev/null +++ b/misc/data_structures/trie.nim @@ -0,0 +1,104 @@ +# Trie implementation - 2023/02/08, toomaa +import options + +const + AlphabetSize = 26 +type + NodeValue = char # array[4, uint8] + Trie* = object + root: TrieNode + size: int # number of words on the trie + TrieNode = ref object + nodes: seq[TrieNode] + value: NodeValue + isTerminal: bool # true if this node is the end of a word + + +proc add(self: TrieNode, value: NodeValue): TrieNode = + result = TrieNode( + nodes: newSeqOfCap[TrieNode](AlphabetSize), + value: value, + ) + self.nodes.add(result) + +proc getNode(self: TrieNode, value: NodeValue): Option[TrieNode] = + assert self != nil + for n in self.nodes: + if n.value == value: + return some(n) + return none(TrieNode) + +proc followPath(self: Trie, str: string): Option[TrieNode] = + var node = self.root + for c in str: + # echo "path: ", c + let tmp = node.getNode(c) + if tmp.isNone: + return none(TrieNode) + node = tmp.get() + return some(node) + +func len*(self: Trie): int = self.size + +proc insert*(self: var Trie, word: string): var Trie {.discardable.} = + result = self + var node = self.root + for c in word: + let nextNode = node.getNode(c) + if nextNode.isNone: + node = node.add(c) + else: + node = nextNode.get() + node.isTerminal = true + inc self.size + +proc delete*(self: var Trie, word: string): var Trie {.discardable.} = + result = self + let terminalNode = self.followPath(word) + if terminalNode.isNone: + return + terminalNode.get.isTerminal = false + dec self.size + +proc prefixExists*(self: Trie, prefix: string): bool = + self.followPath(prefix).isSome + +proc searchWord*(self: Trie, str: string): bool = + let nodeOpt = self.followPath(str) + if nodeOpt.isNone: + return false + return nodeOpt.get.isTerminal + +proc getWordsByPrefix*(self: Trie, prefix: string): seq[TrieNode] = + let nodeOpt = self.followPath(prefix) + if nodeOpt.isNone: + return @[] + for child in nodeOpt.unsafeGet.nodes: + result.add(child) + +when isMainModule: + var t = Trie(root: new(TrieNode)) + let words = [ + "gnome", + "gnostic", + "genetics", + "genome", + "geek", + "greek", + "general", + "generalist", + "generator", + "thomas", + "though", + "through" + ] + + for w in words: + t.insert(w) + assert t.searchWord(w) + + for w in ["general", "gno", "th", "agact"]: + echo "'", w, "' ", "exists? ", t.prefixExists(w) + + for n in t.getWordsByPrefix("gen"): + echo "child value: ", n.value diff --git a/misc/partial.lua b/misc/partial.lua new file mode 100644 index 0000000..fc28065 --- /dev/null +++ b/misc/partial.lua @@ -0,0 +1,21 @@ +function partial(fn, arg1) + return function(...) + return fn(arg1, ...) + end +end + +function add(n1, n2) + return n1 + n2 +end + +function mul(n1, n2) + return n1 * n2 +end + +local s5 = partial(add, 5) +print(s5(5)) +assert(s5(5) == 10) + +local doubler = partial(mul, 2) +print('32 * 2 =', doubler(32)) +print('14 * 2 =', doubler(14))