ディレクトリ
新しく、より包括的な「データ構造とアルゴリズム、」更新サイトは、より多くのpythonは、あなたが人工知能を教えるのを待っている、行く:https://www.cnblogs.com/nickchen121/p/11407287.html
まず、ハフマンものです(ハフマン木)
我々は場合パーセンタイルにテストの点数を変換する5点満点達成の以下に示すように、我々はプログラムを使用することができます。
/* c语言实现 */
if( score < 60 ) grade =1;
else if( score < 70 ) grade =2;
else if( score < 80 ) grade =3;
else if( score < 90 ) grade =4;
else grade =5;
上記のコードは、私たちは、次の図に示す決定木を構築することができます。
上記の5点尺度の結果ならば、私たちは、学生の達成を検討確率分布を以下に示すように、:
学生レコード分布によって確率と決定木を言った、私たちは生徒の成績を得ることができ、検索効率がある:
[0.05×1 + 0.15×2 + 0.4×3 + 0.3×4 + 0.1×4 = 3.15 \。。。] \
生徒の成績から確率分布、我々はしかし、その効率は本当に低いです見つける、学生の分布で70〜79より80から89を見ることができるので、私たちは、次の方法に従うことができるコードや意思決定ツリーを変更すると:
/* c语言实现 */
if( score < 80 )
{
if( score < 70 );
if( score < 60 ) {
grade =1;
} else grade = 2;
else grad=3;
}
else if( score < 90 ) grade =4;
else grade =5;
この変更では、学生のパフォーマンスの探索効率は次のとおりです。
\ [×0.05 + 0.15×3.3 + 0.4×2 + 0.3×2 + 0.1×2 = 2.2 \。]
上記の例を通じて、我々は問題を考えることができますどのようにより効率的な探索木を構築するための別のノードの周波数を探しますか?
1.1定義ハフマン木
加重経路長(WPL):バイナリツリー設けられた有するリーフノードN個の、正しい値を有する各葉ノード\(W_k \) 、各リーフノードまでのルートの長さである\(L_Kを\) 、加重経路長の各リーフノードは、の和である:\(] WPL = \ sum_ K = {} 1 nw_kl_k ^ \)
最適なバイナリやハフマン木:WPL最小のバイナリツリー
例:バイナリ重みのこの複数の値のシーケンスは、異なる形状で構成することができるで5つのリーフノードがあり、その重量は、{1、2、3、4、5}です。
第二に、ハフマンツリー構造
毎回2社の最小重量バイナリ合併
/* c语言实现 */
typedef struct TreeNode *HuffmanTree;
struct TreeNode{
int Weight;
HuffmanTree Left, Right;
}
HuffmanTree Huffman( MinHeap H )
{
// 假设H->Size个权值已经存在H->Elements[]->Weight里
int i; HuffmanTree T;
BuildMinHeap(H); // 将H->Elements[]按权值调整为最小堆
for (i = 1; i < H->Size; i++)
{
// 做H->Size-1次合并
T = malloc(sizeof(struct TreeNode)); // 建立新结点
T->Left = DeleteMin(H); // 从最小堆中删除一个结点,作为新T的左子结点
T->Right = DeleteMin(H); // 从最小堆中删除一个结点,作为新T的右子结点
T->Weight = T->Left->Weight+T->Right->Weight; // 计算新权值
Insert(H, T); // 将新T插入最小堆
}
T = DeleteMin(H);
return T;
}
# python语言实现
# 节点类
class Node(object):
def __init__(self, name=None, value=None):
self._name = name
self._value = value
self._left = None
self._right = None
# 哈夫曼树类
class HuffmanTree(object):
# 根据Huffman树的思想:以叶子节点为基础,反向建立Huffman树
def __init__(self, char_weights):
self.a = [Node(part[0], part[1]) for part in char_weights] # 根据输入的字符及其频数生成叶子节点
while len(self.a) != 1:
self.a.sort(key=lambda node: node._value, reverse=True)
c = Node(value=(self.a[-1]._value + self.a[-2]._value))
c._left = self.a.pop(-1)
c._right = self.a.pop(-1)
self.a.append(c)
self.root = self.a[0]
self.b = list(range(10)) # self.b用于保存每个叶子节点的Haffuman编码,range的值只需要不小于树的深度就行
# 用递归的思想生成编码
def pre(self, tree, length):
node = tree
if (not node):
return
elif node._name:
print(node._name + '的编码为:')
for i in range(length):
print(self.b[i])
print()
return
self.b[length] = 0
self.pre(node._left, length + 1)
self.b[length] = 1
self.pre(node._right, length + 1)
# 生成哈夫曼编码
def get_code(self):
self.pre(self.root, 0)
if __name__ == '__main__':
# 输入的是字符及其频数
char_weights = [('a', 5), ('b', 4), ('c', 10), ('d', 8), ('f', 15), ('g', 2)]
tree = HuffmanTree(char_weights)
tree.get_code()
上記プロセスの時間複雑である:O(logN個N)
2.1ハフマンツリー機能
- ノード1の何度ありません。
- Nの2N-1ハフマンツリーノードのリーフノードの合計
- ハフマン木の任意の非リーフノードの左と右のサブツリー交換まだハフマン木の後に、
- 重みの同一のセット\({W_1、W_2、\ cdots、W_N} \)の存在2本のハフマン木の異なる構成、それ?
- {1、2、3、3}、以下に示すように重みのセットを有することができる異なる構成 2本のハフマン木の:
第三に、ハフマンコーディング
文字列を考えると、どのようにエンコードするための文字をエンコードすることができるので、文字列の少なくとも収納スペース?
例:假设有一段文本,包含58个字符,并由以下7个字符构成:a,e,i,s,t,空格(sp),换行(nl)。这7个字符出现的次数不同。如何对这7个字符进行编码,使得总编码空间最少?
分析:
- 用等长ASCCII编码:58*8 = 464位;
- 用等长3位编码:58*3 = 174位;
- 不等长编码:出现频率高的字符用的编码短些,出现频率低的字符可以编码长些?
对于上述问题,我们如果使用下图所示方式进行不等长编码:
很明显,可以发现上图所示的不等长编码具有二义性,因此我们可以使用前缀码的方式解决二义性问题。
前缀码(prefix code):任何字符的编码都不是另一字符编码的前缀。
3.1 使用二叉树编码
使用二叉树编码,我们需要注意以下两个问题:
- 左右分支:0、1
- 字符只在叶结点上
假设四个字符的频率为:a:4,u:1,x:2,z:1;那么我们可以使用最普通的二叉树对这四个字符进行编码,如下图所示:
通过上图可以发现,我们使用最偷懒的方式,把四个字符放在上述二叉树的四个叶子结点上,因此我们可以考虑使用如下所示的方法,降低二叉树的编码代价:
综上:哈夫曼编码需要解决的一个问题为——如何构造一颗编码代价最小的二叉树。
3.2 使用哈夫曼树编码
对于我们提出来的7个字符的例子,如果我们得知这7个字符的分布概率为如下图所示:
我们可以使用构造哈夫曼树的方式,进行哈夫曼编码,编码流程如下:
最终结果如下图所示: