以 Huffman coding 為例看 Golang 實用主義

不同編程即為不同解決問題的思路

解決一個問題有很多思路,比如:

  1. 過程式(C語言):將解決問題的方式分解成若干步驟來控制數據
  2. 面向對象式 (Java/Ruby):以對象為基本單位,定義其行為控制其內部狀態,通過不同對象之間的協作解決問題
  3. 函數式(Lisp):一切皆為函數,用連貫的思維方式定義過程,常用遞歸
  4. 組合式:將不同的解決方式組合起來,golang 經常會將面向對象與過稱式組合起來

示例: Huffman編碼

用 Golang 組合面向對象式和過程式:

首先我們應該確定整個 package (可視為一個大對象) 的輸入和輸出:

輸入: map[rune]int, 其中 rune 是 golang 中的字符類型,也就是我們要進行編碼的數據類型,int 是這個字符出現的次數

輸出: map[rune]string, 其中 string 對應的01字符串編碼結果。

定義數據結構
type Node struct {
    Value      rune
    Weight     int
    LeftChild  *Node
    RightChild *Node
}

// Nodes 用于 Node 以 weight 排序 
type Nodes []Node

// Tree 就是整棵Huffman樹的根節點
type Tree struct {
    Root *Node
}
定義 package 的對外接口
func Encode(priorityMap map[rune]int) map[rune]string {
    stortedNodes := makeSortedNodes(priorityMap)
    hfmTree := makeFuffManTree(stortedNodes)
    return hfmTree.encode()
}
具體實現思路
// makeSortedNodes 返回排好序的 []Node
func makeSortedNodes(priorityMap map[rune]int) []Node {
    // 實現細節略
    return hfmNodes
}

// makeFuffManTree 將排好序的 Nodes 構造成Huffman樹,
func makeFuffManTree(nodes Nodes) *Tree {
    if len(nodes) < 2 {
        panic("Must contain 2 or more emlments")
    }
    //實現細節略
    return hfmTree
}

// encode 以 tree 根節點開始遍歷,得到最終編碼
func (tree Tree) encode() map[rune]string {
    var initialCode string
    encodeMap := make(map[rune]string)
    tree.Root.traverse(initialCode, func(value rune, code string) {
        encodeMap[value] = code
    })
    return encodeMap
}

// traverse 從當前節點開始向下遍歷,使用遞歸方式
func (n Node) traverse(code string, visit func(rune, string)) {
    if leftNode := n.LeftChild; leftNode != nil {
        leftNode.traverse(code+"0", visit)
    } else {
        visit(n.Value, code)
        return
    }
    n.RightChild.traverse(code+"1", visit)
}

從上面的實現方式上可以看到,既有面向對象的 Node 和 Tree 也有過程式的 makeSortedNodesmakeFuffManTree 還有 func (n Node) traverse(code string, visit func(rune, string)) 的遞歸調用,高階函數參數等。所以 golang 更加注重實用性。

這里僅僅從實現的角度定義了 Huffman編碼 的對外接口,其實還不夠通用和高效,參考 golang 的 io package 我們可以將 Encode 做成 Encode(v []byte, w io.Writer) (int, error) 這樣就可以直接接入標準輸入輸出的package了,當然這里要做一些內部實現的調整。如果想要健壯和高效,還可以結合 buffer 實現緩沖。

項目完整代碼請進:github

相關閱讀:以 Huffman coding 為例看函數式編程

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容

  • 1. Java基礎部分 基礎部分的順序:基本語法,類相關的語法,內部類的語法,繼承相關的語法,異常的語法,線程的語...
    子非魚_t_閱讀 31,766評論 18 399
  • Spring Cloud為開發人員提供了快速構建分布式系統中一些常見模式的工具(例如配置管理,服務發現,斷路器,智...
    卡卡羅2017閱讀 134,948評論 18 139
  • 不同編程即為不同解決問題的思路 解決一個問題有很多思路,比如: 過程式(C語言):將解決問題的方式分解成若干步驟來...
    王諳然閱讀 647評論 0 1
  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 173,353評論 25 708
  • 不容易獲得鍵盤對象的時候可以這樣 [[UIApplication sharedApplication] sendA...
    CyanCricket閱讀 255評論 0 0