この記事では、Python の二分探索木について詳しく紹介 (コード例) しています。一定の参考価値があります。困っている友人は参考にしてください。お役に立てれば幸いです。
1. 二分探索ツリー
**二分探索ツリー (BST 二分探索) Tree)** は特殊なバイナリ ツリーです。任意のノードの値は、左の子の値より大きく、右の子の値以下です。BST (バイナリ) が順番に走査されます。 Search Tree) はソートされた要素のセットを取得でき、挿入と削除の消費時間も比較的妥当ですが、メモリのオーバーヘッドが少し大きいことが欠点です。
二分探索ツリーのプロパティ
1. 任意のノード x について、その左側のサブツリーのキーは x.key より大きくなく、右側のサブツリーのキーは x より小さくありません。 。鍵。 ###2、異なる二分探索ツリーが同じ値のセットを表すことができます。
3. 二分探索木の基本演算は木の高さに比例するため、完全な二分木であれば最悪の実行時間は Θ(lgn) ですが、次の線形木であればn ノードの場合、最悪の実行時間は Θ(n) になります。 ###4、ルートノードは、親ポインタがNILノードを指す唯一のノードである。
5. 各ノードには少なくとも 4 つの属性 (キー、左、右、親) が含まれています。二分探索木を構築するときは、キーの比較アルゴリズムが必要です。
1.
ツリーのノードを定義します:
class TreeNode: def __init__(self,key,val,left=None,right=None,parent=None): self.key = key self.payload = val self.leftChild = left self.rightChild = right self.parent = parent class BinarySearchTree: def __init__(self): self.root = None self.size = 0
2. 挿入
BinarySearchTree シェルと TreeNode を用意したので、バイナリ検索ツリーを構築できる put メソッドを作成します。 putメソッドはBinarySearchTreeクラスのメソッドです。このメソッドは、ツリーにすでにルートがあるかどうかを確認します。ルートがない場合、put は新しい TreeNode を作成し、それをツリーのルートにします。ルート ノードがすでに配置されている場合、put はプライベート再帰ヘルパー関数 _put を呼び出し、次のアルゴリズムに従ってツリーを検索します。
- ツリーのルートから開始してバイナリ ツリーを検索します。を検索し、新しいキーを現在のノード キーと照合して比較します。新しいキーが現在のノードより小さい場合は、左側のサブツリーが検索されます。新しいキーが現在のノードより大きい場合は、右側のサブツリーが検索されます。
- 検索する左 (または右) の子がない場合は、新しいノードを確立する必要があるツリー内の位置を見つけます。
- ノードをツリーに追加するには、新しい TreeNode オブジェクトを作成し、そのオブジェクトを前の手順で検出したノードに挿入します。
-
挿入する場合、常にリーフ ノードとしてツリーに挿入されます。
二分探索木を順番に構築するシーケンスが与えられると、二分探索木は一意になります。このツリーのすべてのキーが一致する場合、二分探索木は一意になります。シーケンスが使用される 単語は、一般に一意ではない、可能なバイナリ ツリー (任意の順序で配置) を構築するために使用されます。def put(self,key,val): if self.root: self._put(key,val,self.root) else: self.root = TreeNode(key,val) self.size = self.size + 1 def _put(self,key,val,currentNode): if key < currentNode.key: if currentNode.hasLeftChild(): self._put(key,val,currentNode.leftChild) else: currentNode.leftChild = TreeNode(key,val,parent=currentNode) else: if currentNode.hasRightChild(): self._put(key,val,currentNode.rightChild) else: currentNode.rightChild = TreeNode(key,val,parent=currentNode)
上記は、ツリーに新しいノードを挿入する Python コードを示しています。 _put 関数は、上記の手順に従って再帰的に記述されます。新しい子ノードがツリーに挿入されると、currentNode が親ノードとして新しいツリー ノードに渡されることに注意してください。
3. Find
ツリーが構築されたら、次のタスクは、指定されたキーの値の取得を実装することです。 get メソッドは、一致しないリーフ ノードに到達するか、一致するキーが見つかるまでツリーを再帰的に検索するだけなので、put メソッドよりも簡単です。一致するキーが見つかると、ノードのペイロードに格納されている値が返されます。
二分探索木が空でない場合:
- まず与えられた値とルートノードのキーワードを比較し、等しければ検索成功
- ルート ノードのキー値より小さい場合は、左のサブツリーを再帰的に検索します。
- #ルート ノードのキー値より大きい場合は、左のサブツリーを再帰的に検索します。ルート ノードで、正しいサブツリー サブツリー
- #サブツリーが空の場合、検索は失敗します
-
def get(self,key): if self.root: res = self._get(key,self.root) if res: return res.payload else: return None else: return None def _get(self,key,currentNode): if not currentNode: return None elif currentNode.key == key: return currentNode elif key < currentNode.key: return self._get(key,currentNode.leftChild) else: return self._get(key,currentNode.rightChild) def __getitem__(self,key): return self.get(key)
4。削除
def delete(self,key):
if self.size > 1:
nodeToRemove = self._get(key,self.root)
if nodeToRemove:
self.remove(nodeToRemove)
self.size = self.size-1
else:
raise KeyError('Error, key not in tree')
elif self.size == 1 and self.root.key == key:
self.root = None
self.size = self.size - 1
else:
raise KeyError('Error, key not in tree')
def __delitem__(self,key):
self.delete(key)
削除するキーのノードを見つけたら、次の 3 つの状況を考慮する必要があります。
削除するノードには子ノードがありません。 #削除するノードには子ノードが 1 つだけあります。
- #削除対象のノードには 2 つの子ノードがあります。
第一种情况:
如果当前节点没有子节点,我们需要做的是删除节点并删除对父节点中该节点的引用。
第二种情况:
如果一个节点只有一个孩子,那么我们可以简单地促进孩子取代其父。此案例的代码展示在下一个列表中。当你看这个代码,你会看到有六种情况要考虑。由于这些情况相对于左孩子或右孩子对称,我们将仅讨论当前节点具有左孩子的情况。决策如下:
如果当前节点是左子节点,则我们只需要更新左子节点的父引用以指向当前节点的父节点,然后更新父节点的左子节点引用以指向当前节点的左子节点。
如果当前节点是右子节点,则我们只需要更新左子节点的父引用以指向当前节点的父节点,然后更新父节点的右子节点引用以指向当前节点的左子节点。
如果当前节点没有父级,则它是根。在这种情况下,我们将通过在根上调用replaceNodeData 方法来替换 key,payload,leftChild 和 rightChild 数据。
第三种情况:
最难处理的情况。 如果一个节点有两个孩子,那么我们不太可能简单地提升其中一个节点来占据节点的位置。 然而,我们可以在树中搜索可用于替换被调度删除的节点的节点。 我们需要的是一个节点,它将保留现有的左和右子树的二叉搜索树关系。 执行此操作的节点是树中具有次最大键的节点。 我们将这个节点称为后继节点,我们将看一种方法来很快找到后继节点。 继承节点保证没有多于一个孩子,所以我们知道使用已经实现的两种情况删除它。 一旦删除了后继,我们只需将它放在树中,代替要删除的节点。
找到后继的代码如下所示,是 TreeNode 类的一个方法。此代码利用二叉搜索树的相同属性,采用中序遍历从最小到最大打印树中的节点。在寻找接班人时,有三种情况需要考虑:如果节点有右子节点,则后继节点是右子树中的最小的键。
如果节点没有右子节点并且是父节点的左子节点,则父节点是后继节点。
如果节点是其父节点的右子节点,并且它本身没有右子节点,则此节点的后继节点是其父节点的后继节点,不包括此节点。
def findSuccessor(self): succ = None if self.hasRightChild(): succ = self.rightChild.findMin() else: if self.parent: if self.isLeftChild(): succ = self.parent else: self.parent.rightChild = None succ = self.parent.findSuccessor() self.parent.rightChild = self return succ def findMin(self): current = self while current.hasLeftChild(): current = current.leftChild return current def spliceOut(self): if self.isLeaf(): if self.isLeftChild(): self.parent.leftChild = None else: self.parent.rightChild = None elif self.hasAnyChildren(): if self.hasLeftChild(): if self.isLeftChild(): self.parent.leftChild = self.leftChild else: self.parent.rightChild = self.leftChild self.leftChild.parent = self.parent else: if self.isLeftChild(): self.parent.leftChild = self.rightChild else: self.parent.rightChild = self.rightChild self.rightChild.parent = self.parent
三、平衡二叉搜索树(AVL树)
1. 概念
二叉搜索树的深度越小,那么搜索所需要的运算时间越小。一个深度为log(n)的二叉搜索树,搜索算法的时间复杂度也是log(n)。然而,我们在二叉搜索树中已经实现的插入和删除操作并不能让保持log(n)的深度。如果我们按照8,7,6,5,4,3,2,1的顺序插入节点,那么就是一个深度为n的二叉树。那么,搜索算法的时间复杂度为n。
在上一节中我们讨论了建立一个二叉搜索树。我们知道,当树变得不平衡时get和put操作会使二叉搜索树的性能降低到O(n)。
如何减少树的深度呢?
一种想法是先填满一层,再去填充下一层,这样就是一个完全二叉树(complete binary tree)。这样的二叉树实现插入算法会比较复杂。另一种比较容易实现的树状数据结构——AVL树,其搜索算法复杂度为log(n)。
在这一节中我们将看到一种特殊的二叉搜索树,它可以自动进行调整,以确保树随时都保持平衡。这种树被称为AVL树,命名源于其发明者:G.M. Adelson-Velskii 和 E.M. Landis。
AVL ツリーの実装 Map 抽象データ型は通常の二分探索ツリーとまったく同じで、唯一の違いはツリーの実行方法です。 AVL ツリーを実装するには、ツリー内の各ノードの バランス係数 を追跡する必要があります。これは、各ノードの左右のサブツリーの高さを調べることによって行われます。より正式には、ノードのバランス係数を、左側のサブツリーの高さと右側のサブツリーの高さの差 として定義します。
balanceFacto#r##=##height(leftSubTree)##−height(rightSub# ##木######)################## ###上記のバランス係数の定義を使用すると、バランス係数がゼロより大きい場合、サブツリーは左に重いと言えます。バランス係数がゼロより小さい場合、サブツリーは右重みになります。バランス係数がゼロの場合、ツリーは完全にバランスが取れています。 AVL ツリーを実装し、バランスの取れたツリーの利点を得るには、バランス係数が -1、0、または 1 の場合にツリーのバランスを定義します。ツリー内のノードのバランス係数がこの範囲外になると、ツリーのバランスを戻す手順が必要になります。 高さ h の木のノード数 (Nh) は次のとおりです: Nh=1 Nh−1 Nh−2 この式はフィボナッチ数列に非常に似ています。この式を使用して、ツリー内のノードの数から AVL ツリーの高さを推定できます。フィボナッチ数列の数がどんどん大きくなるにつれて、Fi / Fi−1 は黄金比 Φ にどんどん近づきます。いつでも、AVL ツリーの高さは、AVL ツリーの高さの対数である定数に等しくなります。ツリー内のノード数 (1.44) 倍。検索が O(logN) に制限されるため、これは AVL ツリーの検索にとって朗報です。 2. 実装新しいノードを追加すると二分木のバランスが崩れるため、回転により修正する必要があります。 単一回転正しい右回転を実行するには、次のことを行う必要があります: 左ノードを作成します。サブツリーのルートになります。
注: 新しいルートは古いルートの左ノードであるため、移動後の古いルートの左ノードは空でなければなりません。この時点で、移動した古いルートに左側のノードを直接追加できます。
同様に、左回転を実行するには、次のことを行う必要があります:
右のノード (B) をサブツリーのルートにします。
古いルート ノード (A) を新しいルートの左側のノードに移動します。
新しいルート (B) にもともと左ノードがある場合、元の B の左ノードを新しいルートの左ノード (A) の右ノードにします。
二重回転
図に示すように、子ノードが 2 ではなく 4 の場合、単一回転を試してみると、問題が解決できないことがわかります。
この問題を解決するには、次のルールを使用する必要があります:
バランスをとるためにサブツリーを左に回転する必要がある場合は、まず右側のノードのバランス係数を確認します。右のノードが左に多い場合、右のノードが右に回転されてから、元のノードが左に回転されます。
サブツリーのバランスをとるためにサブツリーを右に回転する必要がある場合は、まず左側のノードのバランス係数を確認します。左側のノードが右寄りの場合、左側のノードが左に回転されてから、元のノードが右に回転されます。
現時点での解決策は二重回転です。
二重回転は実際には 2 回の単一回転です。ルート ノード 4 を持つサブツリーは最初に左への 1 回転を実行し、次にルート ノード 5 を持つサブツリーは右方向への 1 回転を実行します。これにより、ツリーの ACL プロパティが復元されます。
AVL ツリーの場合、新しいノードが追加されると、AVL ツリーのプロパティは 1 回の回転を通じて常に復元できることが証明できます。
回転ルール
新しいノードを挿入すると、どこが回転するのでしょうか?単一回転または二重回転を使用する必要がありますか?
次の基本手順に従います。
二分探索ツリー法に従ってノードを追加し、新しいノード名はリーフノードです。
新しいノードから開始して、最初の不平衡ノード (5) まで遡ります。
(ルート ノードまで遡って不均衡なノードが存在しない場合は、ツリーがすでに AVL プロパティに準拠していることを意味します。)- ##壊れたエッジを見つけます (5- >3)、切れた文字列の方向(5の左側)を決定します
- 切れたエッジ(3)の下端をルートノードとして、どちらを決定しますか2 つのサブツリーのうち、深さが大きい方 (左側のサブツリーまたは右側のサブツリー) があります。
(2 つのサブツリーの深さを等しくすることはできません。深さが深いサブツリーには新しいノードが含まれます。)
- 手順 2 と 3 の方向が同じ場合 (両方左または両方右) では、アンバランス ノードをルート ノードとしてサブツリーを 1 回回転する必要があります。
- それ以外の場合は、不均衡ノードをルートとするサブツリーを二重回転します。
赤黒ツリーは、非常に興味深いバランスの取れた検索ツリーです。赤黒ツリーはバランス二分木 (AVL-tree) よりも統計的なパフォーマンスが優れているため、多くの場所で使用されます。 C STL では、多くの部分 (現在
set、multiset、map、multimap を含む) で赤黒ツリーのバリエーションが適用されます (SGI STL の赤黒ツリーにはいくつかの変更があり、これらの変更により、パフォーマンスが向上するだけでなく、セット操作もサポートされます)。 赤黒ツリーの主なルール:
赤黒ツリーの主なルールは次のとおりです:
- ノードは赤または黒です。 #根元は黒いです。
- すべての葉は黒です (葉は NIL ノードです)。
- #各赤いノードには 2 つの黒い子ノードが必要です。 (各リーフからルートまでのパス上に 2 つの連続する赤いノードは存在できません。)
- 任意のノードから各リーフまでのすべての単純なパスには、同じ番号の黒いノードが含まれます。
赤黒ツリーに挿入されたノードはすべて赤です。赤いノードを挿入する方が黒のノードを挿入するよりも赤黒ルールに違反する可能性が低いため、これは偶然ではありません。その理由は、黒のノードを挿入すると常に黒の高さが変更される (ルール 4 に違反) が、赤のノードを挿入するとルール 3 に違反する可能性は半分しかないためです。さらに、ルール 3 の違反は、ルール 4 の違反よりも修正が簡単です。
新規ノードを挿入するとこのバランスが崩れる場合がありますが、赤黒ツリーでは主にノードの色の変更、左回転、右回転の3つの方法でバランスを修正します。 (具体的なルールは省略)
各赤黒ツリーも特殊な二分探索木であるため、赤黒ツリーに対する読み取り専用操作は通常の二分探索木に対する読み取り専用操作と同じです。ただし、赤黒ツリーに対する挿入および削除操作は、赤黒ツリーのプロパティに準拠しなくなります。赤黒ツリーのプロパティを復元するには、わずかな (O(logn)) 色の変更 (実際には非常に高速) と 3 回以内のツリー回転 (挿入操作の場合は 2 回) が必要です。挿入と削除は複雑ですが、操作時間は O(logn) 回に抑えることができます。
n 個の内部ノードを持つ赤黒ツリーの高さは、最大 2lg(n 1) です。
以上がPython の二分探索ツリーの詳細な紹介 (コード例)の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

Pythonの柔軟性は、マルチパラダイムサポートと動的タイプシステムに反映されていますが、使いやすさはシンプルな構文とリッチ標準ライブラリに由来しています。 1。柔軟性:オブジェクト指向、機能的および手続き的プログラミングをサポートし、動的タイプシステムは開発効率を向上させます。 2。使いやすさ:文法は自然言語に近く、標準的なライブラリは幅広い機能をカバーし、開発プロセスを簡素化します。

Pythonは、初心者から上級開発者までのすべてのニーズに適した、そのシンプルさとパワーに非常に好まれています。その汎用性は、次のことに反映されています。1)学習と使用が簡単、シンプルな構文。 2)Numpy、Pandasなどの豊富なライブラリとフレームワーク。 3)さまざまなオペレーティングシステムで実行できるクロスプラットフォームサポート。 4)作業効率を向上させるためのスクリプトおよび自動化タスクに適しています。

はい、1日2時間でPythonを学びます。 1.合理的な学習計画を作成します。2。適切な学習リソースを選択します。3。実践を通じて学んだ知識を統合します。これらの手順は、短時間でPythonをマスターするのに役立ちます。

Pythonは迅速な開発とデータ処理に適していますが、Cは高性能および基礎となる制御に適しています。 1)Pythonは、簡潔な構文を備えた使いやすく、データサイエンスやWeb開発に適しています。 2)Cは高性能で正確な制御を持ち、ゲームやシステムのプログラミングでよく使用されます。

Pythonを学ぶのに必要な時間は、人によって異なり、主に以前のプログラミングの経験、学習の動機付け、学習リソースと方法、学習リズムの影響を受けます。現実的な学習目標を設定し、実用的なプロジェクトを通じて最善を尽くします。

Pythonは、自動化、スクリプト、およびタスク管理に優れています。 1)自動化:OSやShutilなどの標準ライブラリを介してファイルバックアップが実現されます。 2)スクリプトの書き込み:Psutilライブラリを使用してシステムリソースを監視します。 3)タスク管理:スケジュールライブラリを使用してタスクをスケジュールします。 Pythonの使いやすさと豊富なライブラリサポートにより、これらの分野で優先ツールになります。

限られた時間でPythonの学習効率を最大化するには、PythonのDateTime、時間、およびスケジュールモジュールを使用できます。 1. DateTimeモジュールは、学習時間を記録および計画するために使用されます。 2。時間モジュールは、勉強と休息の時間を設定するのに役立ちます。 3.スケジュールモジュールは、毎週の学習タスクを自動的に配置します。

PythonはゲームとGUI開発に優れています。 1)ゲーム開発は、2Dゲームの作成に適した図面、オーディオ、その他の機能を提供し、Pygameを使用します。 2)GUI開発は、TKINTERまたはPYQTを選択できます。 TKINTERはシンプルで使いやすく、PYQTは豊富な機能を備えており、専門能力開発に適しています。


ホットAIツール

Undresser.AI Undress
リアルなヌード写真を作成する AI 搭載アプリ

AI Clothes Remover
写真から衣服を削除するオンライン AI ツール。

Undress AI Tool
脱衣画像を無料で

Clothoff.io
AI衣類リムーバー

AI Hentai Generator
AIヘンタイを無料で生成します。

人気の記事

ホットツール

SublimeText3 英語版
推奨: Win バージョン、コードプロンプトをサポート!

SecLists
SecLists は、セキュリティ テスターの究極の相棒です。これは、セキュリティ評価中に頻繁に使用されるさまざまな種類のリストを 1 か所にまとめたものです。 SecLists は、セキュリティ テスターが必要とする可能性のあるすべてのリストを便利に提供することで、セキュリティ テストをより効率的かつ生産的にするのに役立ちます。リストの種類には、ユーザー名、パスワード、URL、ファジング ペイロード、機密データ パターン、Web シェルなどが含まれます。テスターはこのリポジトリを新しいテスト マシンにプルするだけで、必要なあらゆる種類のリストにアクセスできるようになります。

SAP NetWeaver Server Adapter for Eclipse
Eclipse を SAP NetWeaver アプリケーション サーバーと統合します。

VSCode Windows 64 ビットのダウンロード
Microsoft によって発売された無料で強力な IDE エディター

EditPlus 中国語クラック版
サイズが小さく、構文の強調表示、コード プロンプト機能はサポートされていません
