add these
This commit is contained in:
parent
514b8325d2
commit
a22880ca8e
4 changed files with 265 additions and 0 deletions
84
misc/data_structures/binheap.nim
Normal file
84
misc/data_structures/binheap.nim
Normal 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()
|
56
misc/data_structures/graph.nim
Normal file
56
misc/data_structures/graph.nim
Normal 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
|
104
misc/data_structures/trie.nim
Normal file
104
misc/data_structures/trie.nim
Normal 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
21
misc/partial.lua
Normal 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))
|
Loading…
Add table
Reference in a new issue