Data commit
This commit is contained in:
parent
7387c8f97b
commit
cb5bb5e222
199093 changed files with 3378972 additions and 0 deletions
96
Task/Huffman-coding/Nim/huffman-coding.nim
Normal file
96
Task/Huffman-coding/Nim/huffman-coding.nim
Normal file
|
|
@ -0,0 +1,96 @@
|
|||
import tables, sequtils
|
||||
|
||||
type
|
||||
|
||||
# Following range can be changed to produce Huffman codes on arbitrary alphabet (e.g. ternary codes)
|
||||
CodeSymbol = range[0..1]
|
||||
|
||||
HuffCode = seq[CodeSymbol]
|
||||
|
||||
Node = ref object
|
||||
f: int
|
||||
parent: Node
|
||||
case isLeaf: bool
|
||||
of true:
|
||||
c: char
|
||||
else:
|
||||
childs: array[CodeSymbol, Node]
|
||||
|
||||
func `<`(a: Node, b: Node): bool =
|
||||
# For min operator.
|
||||
a.f < b.f
|
||||
|
||||
func `$`(hc: HuffCode): string =
|
||||
result = ""
|
||||
for symbol in hc:
|
||||
result &= $symbol
|
||||
|
||||
func freeChildList(tree: seq[Node], parent: Node = nil): seq[Node] =
|
||||
## Constructs a sequence of nodes which can be adopted
|
||||
## Optional parent parameter can be set to ensure node will not adopt itself
|
||||
for node in tree:
|
||||
if node.parent.isNil and node != parent: result.add(node)
|
||||
|
||||
func connect(parent: Node, child: Node) =
|
||||
# Only call this proc when sure that parent has a free child slot
|
||||
child.parent = parent
|
||||
parent.f += child.f
|
||||
for i in parent.childs.low..parent.childs.high:
|
||||
if parent.childs[i] == nil:
|
||||
parent.childs[i] = child
|
||||
return
|
||||
|
||||
func generateCodes(codes: TableRef[char, HuffCode],
|
||||
currentNode: Node, currentCode: HuffCode = @[]) =
|
||||
|
||||
if currentNode.isLeaf:
|
||||
let key = currentNode.c
|
||||
codes[key] = currentCode
|
||||
return
|
||||
|
||||
for i in currentNode.childs.low..currentNode.childs.high:
|
||||
if not currentNode.childs[i].isNil:
|
||||
let newCode = currentCode & i
|
||||
generateCodes(codes, currentNode.childs[i], newCode)
|
||||
|
||||
|
||||
func buildTree(frequencies: CountTable[char]): seq[Node] =
|
||||
|
||||
result = newSeq[Node](frequencies.len)
|
||||
for i in result.low..result.high:
|
||||
let key = toSeq(frequencies.keys)[i]
|
||||
result[i] = Node(f: frequencies[key], isLeaf: true, c: key)
|
||||
|
||||
while result.freeChildList.len > 1:
|
||||
let currentNode = new Node
|
||||
result.add(currentNode)
|
||||
for c in currentNode.childs:
|
||||
currentNode.connect(min(result.freeChildList(currentNode)))
|
||||
if result.freeChildList.len <= 1: break
|
||||
|
||||
when isMainModule:
|
||||
|
||||
import algorithm, strformat
|
||||
|
||||
const
|
||||
SampleString = "this is an example for huffman encoding"
|
||||
SampleFrequencies = SampleString.toCountTable()
|
||||
|
||||
func `<`(code1, code2: HuffCode): bool =
|
||||
# Used to sort the result.
|
||||
if code1.len == code2.len:
|
||||
result = false
|
||||
for (c1, c2) in zip(code1, code2):
|
||||
if c1 != c2: return c1 < c2
|
||||
else:
|
||||
result = code1.len < code2.len
|
||||
|
||||
let
|
||||
tree = buildTree(SampleFrequencies)
|
||||
root = tree.freeChildList[0]
|
||||
|
||||
var huffCodes = newTable[char, HuffCode]()
|
||||
generateCodes(huffCodes, root)
|
||||
|
||||
for (key, value) in sortedByIt(toSeq(huffCodes.pairs), it[1]):
|
||||
echo &"'{key}' → {value}"
|
||||
Loading…
Add table
Add a link
Reference in a new issue