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-私はかつてすべての生き物の妄想を運んだ-燃える虐待