共通のデータ構造の手がかりバイナリツリーとハフマンツリー

1.スレッドバイナリツリー

        最後のバイナリツリーでは、基本的なバイナリツリー構造を紹介しました。各親ノードは、左の子ノードと右の子ノードの2つの子ノードに対応します。その中で、多くのノードの左右のノードがヌルであることがわかります。より効率的に格納およびトラバースするために、これらのヌルノードを使用する方法を検討します。これは手がかりバイナリツリーのアイデアです。nullの左側の子ノードはトラバーサル中に先行ノードを指し、nullの右側の子ノードはトラバーサル中に後続のノードを指します。このように、トラバーサルの過程で、リーフノードの先行ノードとポストドライブを左右の子ノードから直接見つけ、線を使用してツリー全体を完全につなぎ合わせることができます。

                                                                        

2.コード実装python

          実装の過程で、2つのフラグビットleftTypeとrightTypeを元のNodeクラスに追加する必要があります。これらはそれぞれ、対応するノードが通常の子ノードであるか、先行ノードであるかを示します。実装プロセスは次のとおりです。最初にツリーを構築し、次に中間の順序を使用してツリーをトラバースし、pre変数を使用して前のノードを記録します。現在のノードの左側の子ノードがnullの場合は、左側の子ノードをpreノードにポイントします。preの右側の子ノードもnullの場合は、preの右側の子ノードを現在のノードにポイントします。

          次に、トラバースします。ノードが後続ノードである場合は、最初に左下の子ノードを見つけてから、後続ノードをトラバースし続けます。それ以外の場合は、通常の中次トラバーサルに従って次のノード()を見つけ、ノードが見つからなくなるまでトラバースを続けます。次に、ツリー全体のトラバースを完了します。

#-*- coding:utf-8 -*-
class Node(object):
    def __init__(self,val):
        self.val = val
        self.left = None
        self.right=None
        # 左节点类型 0表示左子节点 1表示后驱
        self.leftType = 0
        # 右节点类型 0表示右子节点 1表示后驱
        self.rightType = 0
    def show(self):
        print("遍历--当前节点为 = {}".format(self.val),end='\t')
        if self.left != None and self.leftType == 0:
            print("左子节点为 = {}".format(self.left.val),end='\t')
        if self.right != None and self.rightType == 0:
            print("右子节点为 = {}".format(self.right.val))
        if self.left != None and self.leftType == 1:
            print("前驱节点为 = {}".format(self.left.val),end='\t')
        if self.right != None and self.rightType == 1:
            print("后驱节点为 = {}".format(self.right.val))
class ThreadTree(object):
    def __init__(self):
        self.root = None
        self.pre = None
    #构建一棵基本的树
    def build(self,values):
        # 将每个元素转换为node节点
        nodes = [None if V is None else Node(V) for V in values]
        # 给根节点添加左右子节点
        for index in range(1, len(nodes)):
            parent_index = (index - 1) // 2
            parent = nodes[parent_index]
            if parent is None:
                raise Exception('parent node missing at index{}'.format(index))
            if index % 2 == 0:
                parent.right = nodes[index]
            else:
                parent.left = nodes[index]
        self.root = nodes[0]
        return nodes[0]
    #在中序遍历的过程中对每个节点中left,right为null的进行复制前驱后驱节点
    def threadedNode(self,node):
        if node == None:
            return
        self.threadedNode(node.left)
        # 处理当前节点的的前驱节点
        if node.left == None:
            node.left = self.pre
            node.leftType = 1
            print("当前节点={}".format(node.val))
            if self.pre != None:
                print("前驱结点为 = {}".format(self.pre.val))
        if self.pre != None and self.pre.right == None:
            # 前驱节点的右指针指向当前节点
            self.pre.right = node
            self.pre.rightType = 1
            print("当前节点={},后驱结点为 = {}".format(self.pre.val, node.val))
        self.pre = node
        self.threadedNode(node.right)
    def mid_order(self,node):
        while node != None:
            while node.leftType == 0:
                node = node.left
            if node != None:
                node.show()
            while node.rightType == 1:
                node = node.right
                node.show()
            node = node.right
threadTree = ThreadTree()
node = threadTree.build([1,2,3,4,5,6,7,8])
threadTree.threadedNode(node)
threadTree.mid_order(node)

3.手がかりバイナリツリーの概要

          この記事では、手がかりのバイナリツリーの原理と、それを実装するためにpythonを使用するプロセスを紹介します。コアとなるアイデアは、バイナリツリーのnullポインタを使用して、これらのポインタが先行ノードと末尾ノードを指すようにすることです。

4.ハフマンツリー

          免責事項:このブログは、ハフマンツリーとそのpython実装について言及していますハフマンツリーは、最適ツリーおよび最適バイナリツリーとも呼ばれます。最良の実施形態は、すべてのノードの加重パスの合計を最小化することです。図に示すように、値に加えて、各ノードが独自の加重情報を持っていることがわかります。あるノードから別のノードに移動するノードはパスと呼ばれます。たとえば、ルートノードからcに、50、29、14、6を渡す必要があります。加重パスの長さは、次のように定義されます。加重に対応するパスの数を掛けます。たとえば、次の図の加重パス長WPLは、9 * 2 + 12 * 2 + 15 * 2 + 6 * 3 + 3 * 4 + 5 * 4 = 122です。私たちの目標は、加重パスの長さを最小化することです。実際、加重が大きいほどルートノードに近くなり、加重合計が最小になるようにします。

                                         

          次に、実装されたアルゴリズムを紹介します。重みリストを並べ替え、重みが最小の2つのノードが左右の子ノードとして選択されるたびにツリーが生成され、それらの重みの合計がツリーのルートノードとして使用されます。2つのリーフノードが重みリストから削除され、ルートノードの重みが重みリストに追加されます。ルートノードが1つだけになり、ツリー全体の生成が終了するまで、上記のプロセスを繰り返します。

                           

   ハフマンコーディング:ハフマンツリーの加重パス長は最短であり、各ノードからルートノードへのパスは一意であるため、コーディングに使用できます。これは不等長のエンコード方式であり、スペースを大幅に節約します。

           各単語がテキストのどこに現れるかをその重みとして数え、ハフマンツリーを構築し、各サブツリーの左側の分岐パスを0、右側の分岐パスを1に指定します。このようにして、ノードに対応するパスが検出され、パスに沿ってコーディングできます。たとえば、次のaは00としてコーディングでき、bは01としてコーディングできます。

                                      

5.Pythonコードの実装

#-*- coding:utf-8 -*-
#节点类
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):
        #将字典中所有的值 变成node数组
        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()
            c._right=self.a.pop()
            self.a.append(c)
        self.root=self.a[0]
        self.b=list(range(10))          #self.b用于保存每个叶子节点的Haffuman编码,range的值只需要不小于树的深度就行

    #用递归的思想生成编码
    def huffmanEncode(self,tree,length):
        node=tree
        if (not node):
            return
        elif node._name:
            print(node._name + '的编码为:',end='\t')
            for i in range(length):
                print(self.b[i],end='\t')
            print ('\n')
            return
        self.b[length]=0
        self.huffmanEncode(node._left,length+1)
        self.b[length]=1
        self.huffmanEncode(node._right,length+1)
     #生成哈夫曼编码
    def get_code(self):
        self.huffmanEncode(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()

6.ハフマンツリーの概要

         上記では、最適なバイナリツリーとしても知られるハフマンツリーを紹介しました。基本的な考え方は、加重パスの合計を最小化することです。つまり、加重の大きいノードがルートノードに近くなります。アルゴリズムを実装するというアイデアは、重みリストから重みが最小の2つのノードを毎回左右のノードとして選択し、それらの合計をルートノードとして構成することです。次に、これら2つのノードを重みリストから削除し、それらの合計を追加します。ルートノードが1つだけになるまで繰り返します。次に、ハフマンツリーの実用的なアプリケーションの1つであるハフマンコーディングを紹介しました。左側のブランチが0、右側のブランチが1であると指定され、コードはノードのパス上のすべてのブランチの値を介して生成されます。これは長さが等しくないエンコード方法ですが、ノードの一意性を保証できます。スペースを大幅に節約します。

7.ゴシップ

           私はこの天国を守ることができます、そして私はそれを殺すことができます!私は3日2泊し、ついにLiuliを見終えました。それを読んだ後、まるで恋に落ちたように、とても悲しい気持ちになります。私はミスユアンビンギャンがとても好きです、そのようなかわいい笑顔は世界で2番目ではありません。「羅生風」からいくつかの詩を借りて、私の妹、ドラゴンのように優雅なピアンルオ・ジンホンへの称賛を表現させてください。Rong Yao Qiuju、Huamao Chunsong まるで月が明るい雲に覆われているかのようで、雪は流れる風のように羽ばたきます。誰が私に彼女に会わせることができますか、あなたは私の人生で私の最大の恩人です。今日の悪いニュースは、私が4年半好きな女神が結婚しているということです。うーん!もちろん、それは非常に悲しいでしょう。しかし、これは何を示していますか?この期間中、私は自分の考えを満たし、一人の人が考えすぎて涙を残しすぎないようにするために、他の多くのものを使用する必要があるというだけです!彼女が人生の短い数十年の間に私に属していないというだけです。このように考えると、人生はまだ続いていると感じます。私は他人に何も期待していません。今、私はミス・ビンギャンの次のテレビシリーズを楽しみにしています。

Liuli・GodofWar-私はかつてすべての生き物の妄想を運んだ-燃える虐待

 

おすすめ

転載: blog.csdn.net/gaobing1993/article/details/108902921
おすすめ