貪心算法(又稱貪婪算法),基本原理是,遵循某種既定原則,不斷地選取當前條件下最優的選擇來構造每一個子步驟,直到獲得問題最終的求解。即在求解時,總是作出當前看來最好的選擇。也就是說,不從整體最優上加以考慮,僅是求解局部最優解,以期望能找到全局最優解。
貪心算法與動態規劃類似,都是將原來的較大規模的問題拆分為規模較小的問題,依據大問題與小問題之間的遞推關系,通過解決較小規模的問題,最終獲得原始問題的求解。但是動態規劃要通盤考慮各個階段各子問題的求解情況,從全局的角度進行衡量,最終找到解決原始問題的最佳解決方案。貪心算法與動態規劃的不同之處在于,貪心算法利用問題的貪心性質,簡化了分解原始問題的過程,每次只關注在當前狀態下可以獲得的局部最優解,通過拼接各階段的局部最優解獲得最終問題的解。因為貪心選擇可以依賴于以往所做的選擇,但絕不依賴于未來所做的選擇,也不依賴于子問題的解。故而貪心算法往往求解時與動態規劃相反,采用自頂向下的方式,迭代作出貪心選擇,不斷化簡問題規模。
利用貪心算法解題,需要解決兩個問題:
# 硬幣找零問題是給定找零金額,計算如何搭配使得使用的硬幣數量最少def get_change(coins, amount): coins.sort() # 從面值最大的硬幣開始遍歷 i = len(coins) - 1 di = {} while i >= 0: if amount >= coins[i]: n = int(amount // coins[i]) change = n * coins[i] amount -= change di[coins[i]] = n i -= 1 return di
現在有一個包含 5 個字符的字符表 {A,B,C,D,E},各字符出現的頻率A:0.35, B:0.1, C:0.2, D:0.2, E:0.15;
構造一種有效率的編碼類型,使用該編碼表達以上字符表內容時可以產生平均長度最短的位串。在對由 n 個字符組成的文本進行編碼過程中,有兩種編碼方式,即定長編碼和變長編碼。對于定長編碼而言,會為每個字符賦予一個長度固定為 m(m≥log2n) 的位串,我們常用的標準 ASCII 碼就是采用定長編碼策略對字符集進行編碼的。長度各異的編碼,其中出現頻率較高的字符,采用長度較短的編碼表示,出現頻率較低的字符,采用長度較長的編碼表示。
為了對某字母表構造一套二進制的前綴碼,可以借助二叉樹。將樹中所有的左向邊都標記為0,所有的右向邊都標記為 1。通過記錄從根節點到字符所在的葉子節點的簡單路徑上的所有 0-1 標記來獲得表示該字符的編碼。
# 參考文檔: https://www.92python.com/view/354.html# 樹節點定義class Node: def __init__(self, pro): self.left = None self.right = None self.parent = None self.pro = pro def is_left(self): # 判斷左子樹 return self.parent.left == self# create nodes創建葉子節點def create_nodes(pros): return [Node(pro) for pro in pros]# create Huffman-Tree創建Huffman樹def create_huffman_tree(nodes): '''從下向上創建二叉樹''' queue = nodes[:] while len(queue) > 1: queue.sort(key=lambda item: item.pro) node_left = queue.pop(0) node_right = queue.pop(0) node_parent = Node(node_left.pro + node_right.pro) # 二節點值合并 node_parent.left = node_left # 父親認兒子, node_parent.right = node_right node_left.parent = node_parent # 兒子認父親 node_right.parent = node_parent queue.append(node_parent) queue[0].parent = None return queue[0]# Huffman編碼def huffman_encoding(nodes, root): '''根據當前節點為左右子樹進行判斷賦值''' codes = [''] * len(nodes) for i in range(len(nodes)): node_temp = nodes[i] while node_temp != root: if node_temp.is_left(): codes[i] = '0' + codes[i] else: codes[i] = '1' + codes[i] node_temp = node_temp.parent # 當前節點替換為父子節點 return codesif __name__ == '__main__': letters_pros = [('B', 10), ('E', 15), ('C', 20), ('D', 20), ('A', 35)] nodes = create_nodes([item[1] for item in letters_pros]) # 生成樹節點 root = create_huffman_tree(nodes) codes = huffman_encoding(nodes, root) for item in zip(letters_pros, codes): print('Label:%s pro:%-2d Huffman Code:%s' % (item[0][0], item[0][1], item[1]))
哈夫曼樹: