add these

This commit is contained in:
tocariimaa 2025-01-24 16:23:45 -03:00
parent 514b8325d2
commit a22880ca8e
4 changed files with 265 additions and 0 deletions

View file

@ -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()

View file

@ -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

View file

@ -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

21
misc/partial.lua Normal file
View file

@ -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))