基本的な考え方
バイナリ ツリーは、有限のノードのセットで構成されます。
この有限セットは、空のセット、またはルート ノードと、ルートの左右のサブツリーと呼ばれる 2 つの互いに素なバイナリ ツリーで構成されるセットのいずれかです。
二分木の特徴
- 各ノードには最大 2 つのサブツリーがあるため、バイナリ ツリーには次数が 2 を超えるノードはありません。
- 左側のサブツリーと右側のサブツリーには順序があり、順序を自由に逆転させることはできません。
- ツリー内のノードにサブツリーが 1 つしかない場合でも、それが左側のサブツリーか右側のサブツリーかを区別する必要もあります。
二分木の 5 つの基本的な形式
- 空の二分木
- ルートノードは 1 つだけ
- ルートノードには左側のサブツリーしかありません
- ルートノードには右のサブツリーのみがあります
- ルート ノードには左のサブツリーと右のサブツリーの両方があります
関連概念
エッジ: エッジと呼ばれる 2 つのノードの順序付きペア ノードの次数
: ノードに含まれるサブツリーの数がノードの次数になります
リーフ ノード: 次数が 0 です ノードはリーフ
ノードになります パス (パス)
パスの長さ (パスの長さ)
層: ルートは層 0 (他のノードの層番号は、その親ノードの層番号に 1 を加えたものに等しい)
深さ: 最大層数 葉ノードの層数
二分木関連の結論
二分木記憶構造
バイナリ ツリーのシーケンシャル ストレージ構造は、通常、完全なバイナリ ツリーにのみ適用できます。通常、バイナリ ツリーを表すときは、連鎖ストレージ構造を使用します。
バイナリリンクリスト
バイナリ ツリーにはノードごとに最大 2 つの子があるため、1 つのデータ フィールドと 2 つのポインタ フィールドがあります。
このようなリンク リストをバイナリ リンク リストと呼びます。
図に示すように:
子供 | データ | 子供 |
---|
このうち、data はデータ フィールドであり、lchild と rchild は両方ともポインタ フィールドで、それぞれ左の子と右の子へのポインタを格納します。
バイナリツリーのバイナリリンクリスト構造定義
/*定义二叉树的结构*/
typedef struct Node
{
char data; /*数据域*/
struct Node *lchild, *rchild; /*左子树和右子树*/
} * BiTree, BiNode;
/*整棵树和结点名称*/
バイナリツリートラバーサル
トラバーサルは、
各ノードが 1 回だけ訪問されるように、データ構造内のノードを体系的に訪問します。
バイナリ ツリーの深層検索限定トラバーサル:
以下は、3 つの深さ優先トラバーサルの再帰的定義です。
プレオーダートラバーサル
ルール: バイナリ ツリーが空の場合、操作は戻ります。そうでない場合は、最初にルート ノードにアクセスし、次に事前順序で左のサブツリーにアクセスし、次に事前順序で右のサブツリーにアクセスします。
インオーダートラバーサル
左側のサブツリーを順番にトラバースし、ルート ノードにアクセスし、右側のサブツリーを順番にトラバースします。
私は以前、その偉い人による順序トラバーサルの説明を読んだことがあります。各ノードをブドウとして扱い、これらのブドウを同じ平面上に垂直に投影し、次に左から右にアクセスします。これが順序トラバーサルです。
ポストオーダートラバーサル
左側のサブツリーをポストオーダーでトラバースし、右側のサブツリーをポストオーダーでトラバースして、ルート ノードにアクセスします。
小さな要約
前順トラバーサル: 最初にルート、次に左、次に右
順順トラバーサル: 最初に左、次にルート、次に右
事後トラバーサル: 最初に左、次に右、次にルート
このルートは、分岐した各サブツリーのルートを指します (左右のサブツリーのルート ノード) ノードはツリー全体の単なるルート ノードではありません
コード
#include <iostream>
#include <string>
#include <algorithm>
using namespace std;
/*定义二叉树的结构*/
typedef struct Node
{
char data; /*数据域*/
struct Node *lchild, *rchild; /*左子树和右子树*/
} * BiTree, BiNode;
/*整棵树和结点名称*/
/*先需创建二叉树*/
void CreateBiTree(BiTree &T)
{
char ch;
cin >> ch;
if (ch == '#')
T = NULL;
else
{
T = new BiNode; /*创建一个新节点*/
T->data = ch;
CreateBiTree(T->lchild);
CreateBiTree(T->rchild);
}
/*递归创建*/
}
void InOrderTraverse(BiTree T)
{
/*中序遍历*/
if (T)
{
InOrderTraverse(T->lchild);
cout << T->data;
InOrderTraverse(T->rchild);
}
}
void PreOrderTraverse(BiTree T)
{
/*先序遍历*/
if (T)
{
cout << T->data;
PreOrderTraverse(T->lchild);
PreOrderTraverse(T->rchild);
}
}
void PostOrderTraverse(BiTree T)
{
/*后序遍历*/
if (T)
{
PostOrderTraverse(T->lchild);
PostOrderTraverse(T->rchild);
cout << T->data;
}
}
/*统计二叉树中结点的个数*/
int NodeCount(BiTree T)
{
if (T == NULL)
return 0;
else
return NodeCount(T->lchild) + NodeCount(T->rchild) + 1;
}
/*求树的深度*/
int Depth(BiTree T)
{
if (T == NULL)
return 0;
else
{
int i = Depth(T->lchild);
int j = Depth(T->rchild);
return i > j ? i + 1 : j + 1;
}
}
/*复制二叉树*/
void Copy(BiTree T, BiTree &NewT)
{
if (T = NULL)
{
NewT = NULL;
return;
}
else
{
NewT = new BiNode;
NewT->data = T->data;
Copy(T->lchild, NewT->lchild);
Copy(T->rchild, NewT->rchild);
}
}
/*统计二叉树中叶子结点的个数*/
int LeafCount(BiTree T)
{
if (!T)
return 0;
if (!T->lchild && !T->rchild)
return 1;
/*如果二叉树左子树和右子树皆为空,说明该二叉树根节点为叶子结点,结果为1*/
else
return LeafCount(T->lchild) + LeafCount(T->rchild);
}
/*二叉树中从每个叶子结点到跟结点的路径*/
void PrintAllPath(BiTree T, char path[], int pathlen)
{
int i;
if (T != NULL)
{
path[pathlen] = T->data; /*将当前结点放入路径中*/
if (T->lchild == NULL && T->rchild == NULL)
{
/*若这个节点是叶子结点*/
for (i = pathlen; i >= 0; i--)
cout << path[i] << " ";
cout << "\n";
}
else
{
PrintAllPath(T->lchild, path, pathlen + 1);
PrintAllPath(T->rchild, path, pathlen + 1);
}
}
}
/*判断二叉树是否为空*/
int BiTree_empty(BiTree T)
{
if (T)
return 1;
else
return 0;
}
int main()
{
BiTree T;
//测试数据AB#CD##E##F#GH###
cout << "先序遍历输入(以#结束):";
CreateBiTree(T);
cout << "中序遍历输出:";
InOrderTraverse(T);
cout << endl
<< "先序遍历输出:";
PreOrderTraverse(T);
cout << "\n"
<< "后序遍历输出:";
PostOrderTraverse(T);
cout << endl
<< "树的深度:" << Depth(T);
cout << endl
<< "结点的个数:" << NodeCount(T);
cout << endl
<< "二叉树中从每个叶子结点到根结点的所有路径:" << endl;
char path[256];
int pathlen = 0;
PrintAllPath(T, path, pathlen);
return 0;
}
特別な二分木
-
完全なバイナリ ツリー
バイナリ ツリーでは、すべてのブランチ ノードが左右のサブツリーを持ち、左右のサブツリーが同じレベルにある場合、そのようなバイナリ ツリーは図に示すような完全なバイナリ ツリーになります
。
-
すべてのノードには、
左斜木と呼ばれる左サブツリーのみがあります。すべてのノードが右部分木のみを持つ二分木は右斜木と呼ばれます。両方を総称して斜木と呼びます。(これは実際には垂直方向に見ると線形テーブルです) -
完全なバイナリ ツリー
が n 個のノード (シーケンス ルールに従って番号付けされている) を持つバイナリ ツリーである場合、番号 i (1<=i<=n) のノードと、同じ深さの完全なバイナリ ツリー内の番号 i のノードは、バイナリ ツリー内の位置が同じ場合、そのツリーは次の図に示すように完全なバイナリ ツリーになります。
完全な二分木のプロパティ:
1) リーフ ノードは下の 2 つのレイヤーにのみ存在できます。
2) 最下位レイヤーのリーフは左側の連続した位置に集中している必要があります
。 3) ノードの次数が 1 の場合、ノードは左側にしか存在しません。子供たち。
4) 最後から 2 番目の層に葉ノードがある場合は、右側の連続した位置に配置する必要があります。
5) 同じノードのバイナリ ツリー、完全なバイナリ ツリーの深さが最も小さい