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