[データ構造] バイナリツリーの連鎖実装とトラバース


ここに画像の説明を挿入します

1. バイナリツリートラバーサル

以下のすべてのコードのバイナリ ツリー ノード:

typedef char BTDataType;
//二叉树结点结构体
typedef struct BinaryTreeNode
{
    
    
	BTDataType data;
	struct BinaryTreeNode* left;
	struct BinaryTreeNode* right;
}BTNode;

1. 事前注文トラバーサル

前順、中間、後順の走査はすべて、分割統治再帰の考え方を使用して解決でき、ルート ノードとその子ノードは個別に処理されます。

// 二叉树前序遍历 
void BinaryTreePrevOrder(BTNode* root)
{
    
    
    if (root == NULL)
    {
    
    
        printf("NULL ");
        return;
    }

    printf("%c ", root->data);
    BinaryTreePrevOrder(root->left);
    BinaryTreePrevOrder(root->right);
}

ここでは、再帰的展開グラフのみを使用して、前順序トラバーサルを分析します。同じ考え方が、順序内および後順序でも使用されます。

ここに画像の説明を挿入します

ここに画像の説明を挿入します

2. 順序どおりの走査

// 二叉树中序遍历
void BinaryTreeInOrder(BTNode* root)
{
    
    
    if (root == NULL)
    {
    
    
        printf("NULL ");
        return;
    }

    BinaryTreeInOrder(root->left);
    printf("%c ", root->data);
    BinaryTreeInOrder(root->right);
}

3. ポストオーダートラバーサル

// 二叉树后序遍历
void BinaryTreePostOrder(BTNode* root)
{
    
    
    if (root == NULL)
    {
    
    
        printf("NULL ");
        return;
    }

    BinaryTreePostOrder(root->left);
    BinaryTreePostOrder(root->right);
    printf("%c ", root->data);
}

4. 層順次走査

レベル順序のトラバーサルはキューを使用して実行する必要があります。バイナリ ツリーとノードが空でない場合は、それへのポインタをキューに入れる次に、キューの先頭ノードを記録し、最初にその値を出力し、次にその左右の子が空でないと判断してからキューに参加し、キューの先頭を削除して次のノードに置き換えて記録を継続します。そして印刷...キューが空になり、走査が完了するまで続きます。

たとえば、次のようなバイナリ ツリーについて考えてみましょう。

レイヤー シーケンス トラバーサルの結果は 12345 です。
ここに画像の説明を挿入します
まず、ルート ノード 1 をキューに入れ、1 を出力します。

ここに画像の説明を挿入します

次に、1 の左右の子 2 と 3 をチームに追加します。
ここに画像の説明を挿入します

キュー 1 の先頭を削除し、先頭を 2 に置き換えて 2 を出力します。
ここに画像の説明を挿入します

次に、左の子 4/2 をチームに追加します。
ここに画像の説明を挿入します

先頭 2 を削除し、先頭を 3 に置き換えて、3 を印刷します。
ここに画像の説明を挿入します

次に、右側の子 5/3 をチームに追加します。
ここに画像の説明を挿入します

… …

次に、このように 4 と 5 を出力して、バイナリ ツリーのレベル順序の走査を完了します。

ここに画像の説明を挿入します

プログラムコードは自身で作成したキューを使用しており、以下のようなコードになります。

//层序遍历
void LevelOrder(BTNode* root)
{
    
    
    //创建队列
    Que q;
    QueueInit(&q);

    //如果根节点不为空,则放进队列
    if (root)
        QueuePush(&q, root);

    while (!QueueEmpty(&q))
    {
    
    
        //将队头打印
        BTNode* front = QueueFront(&q);
        printf("%c ", front->data);
        //判断front左右节点不为空则入队
        if (front->left)
            QueuePush(&q, front->left);

        if (front->right)
            QueuePush(&q, front->right);
        
        QueuePop(&q);
    }
    printf("\n");

    QueueDestroy(&q);
}

2. 二分木のノードの数と高さ

1. 二分木のノード数

分割統治法を用いて再帰的に実装されており、ルートノードが空の場合は戻り値0、空でない場合は左右のサブツリーのノード数に1を加えた値を返します。

int BinaryTreeSize(BTNode* root)
{
    
    
    return root == NULL ? 0 : BinaryTreeSize(root->left) + BinaryTreeSize(root->right) + 1;
}

2. 二分木の葉ノードの数

分割統治法を用いて再帰的に実装されており、ルートノードが空の場合は0を返し、ルートノードに子ノードがない場合は葉ノードであるため1を返し、それ以外の場合は、左側と右側のサブツリーにリーフ ノードを追加するだけです。

int BinaryTreeLeafSize(BTNode* root)
{
    
    
    if (root == NULL)
    {
    
    
        return 0;
    }
    if (root->left == NULL && root->right == NULL)
    {
    
    
        return 1;
    }
    return BinaryTreeLeafSize(root->left) + BinaryTreeLeafSize(root->right);
}

3. 二分木の k 番目のレベルのノードの数

k が 0 より大きいことを確認する必要があります。ルート ノードが空の場合は 0 が返されます。k が 1 に等しい場合は、1 つのレイヤーにノードが 1 つだけあり、1 が返されます。k>1 の場合、数値はk 番目の層のノードの数は、その左右の子の k 番目の子に相当します - 層 1 のノードの数を合計します。

int BinaryTreeLevelKSize(BTNode* root, int k)
{
    
    
    assert(k > 0);

    if (root == NULL)
    {
    
    
        return 0;
    }
    if (k == 1)
    {
    
    
        return 1;
    }
    return BinaryTreeLevelKSize(root->left, k - 1)
        + BinaryTreeLevelKSize(root->right, k - 1);
}

4. 二分木で値 x を持つノードを見つける

次のノードが空の場合、見つからない場合はNULLを返します ルートノードの値が探している値であればそのノードを返します 等しくない場合はその左右の子ノードを判定します見つかるまでそれぞれ。

BTNode* BinaryTreeFind(BTNode* root, BTDataType x)
{
    
    
    if (root == NULL)
    {
    
    
        return NULL;
    }
    if (root->data == x)
    {
    
    
        return root;
    }
    BTNode* ret = BinaryTreeFind(root->left,x);
    if (ret)
    {
    
    
        return ret;
    }
    return BinaryTreeFind(root->right, x);
}

3. バイナリツリーの作成と破棄

1. 配列を事前順序で走査してバイナリ ツリーを作成する

ユーザーが入力したプレオーダー トラバーサル文字列を読み取り、この文字列に基づいてバイナリ ツリー (ポインタとして保存) を構築します。たとえば、次のような事前注文トラバーサル文字列: ABC##DE#G##F### ここで、「#」はスペースを表し、スペース文字は空のツリーを表します。バイナリ ツリーを確立した後、バイナリ ツリーに対して順序走査を実行し、走査結果を出力します。

#include <stdio.h>
#include<stdlib.h>
typedef char BTDataType;

typedef struct BinaryTreeNode {
    
    
    BTDataType data;
    struct BinaryTreeNode* left;
    struct BinaryTreeNode* right;
} BTNode;
BTNode* BinaryTreeCreate(BTDataType* a, int* pi) {
    
    
    if (a[*pi] == '#') {
    
    
        ++*pi;
        return NULL;
    }

    BTNode* root = (BTNode*)malloc(sizeof(BTDataType));
    root->data = a[*pi];
    ++*pi;

    root->left = BinaryTreeCreate(a, pi);
    root->right = BinaryTreeCreate(a, pi);

    return root;
}
//中序遍历
void InOrder(BTNode* root)
{
    
    
    if(root==NULL)
    {
    
    
        return;
    }
    InOrder(root->left);
    printf("%c ",root->data);
    InOrder(root->right);
}
int main() {
    
    
    char a[100];
    scanf("%s",a);
    int pi=0;
    BTNode* root=BinaryTreeCreate(a, &pi);
    InOrder(root);
    return 0;
}

2. バイナリツリーの破壊

void BinaryTreeDestory(BTNode* root)
{
    
    
    if (root == NULL)
    {
    
    
        return;
    }

    BinaryTreeDestory(root->left);
    BinaryTreeDestory(root->right);
    free(root);
}

3. 完全な二分木であるかどうかを判断します。

空のノードもキューに入るようにバイナリ ツリーのレベル順序トラバーサルを変更します。空のノードをトラバースすると、そのノードは終了します。トラバーサルの終了前に空ではないノードがある場合、それは完全なバイナリ ツリーではありません。

int BinaryTreeComplete(BTNode* root)
{
    
    
    //创建队列
    Que q;
    QueueInit(&q);

    //如果根节点不为空,则放进队列
    if (root)
        QueuePush(&q, root);

    while (!QueueEmpty(&q))
    {
    
    
        BTNode* front = QueueFront(&q);
        if (front == NULL)
        {
    
    
            break;
        }
        QueuePush(&q, front->left);
        QueuePush(&q, front->right);
        QueuePop(&q);
    }
    //此时已经遇到空节点,如果再遇到非空节点则不是完全二叉树
    while (!QueueEmpty(&q))
    {
    
    
        BTNode* front = QueueFront(&q);
        if (front)
        {
    
    
            QueueDestroy(&q);
            return false;
        }
        QueuePop(&q);
    }

    QueueDestroy(&q);
    return true;
}

4. テストコード

以下に示すようにバイナリ ツリーを手動で構築し、コードをテストします。
ここに画像の説明を挿入します
テスト結果は次のようになります。

予約注文: 123874569
中間注文: 832715469
予約注文: 837259641

完全な二分木かどうか:0
ノード数:9
リーフノード数:4

BTNode* BuyNode(BTDataType x)
{
    
    
    BTNode* node = (BTNode*)malloc(sizeof(BTNode));
    if (node == NULL)
    {
    
    
        perror("malloc fail");
        exit(-1);
    }

    node->data = x;
    node->left = NULL;
    node->right = NULL;

    return node;
}


int main()
{
    
    
    	// 手动构建
	BTNode* node1 = BuyNode('1');
	BTNode* node2 = BuyNode('2');
	BTNode* node3 = BuyNode('3');
	BTNode* node4 = BuyNode('4');
	BTNode* node5 = BuyNode('5');
	BTNode* node6 = BuyNode('6');
	BTNode* node7 = BuyNode('7');
	BTNode* node8 = BuyNode('8');
	BTNode* node9 = BuyNode('9');

	node1->left = node2;
	node1->right = node4;
	node2->left = node3;
	node4->left = node5;
	node4->right = node6;

	node2->right = node7;
	node3->left = node8;
	node6->right = node9;

    printf("前序遍历:");
    BinaryTreePrevOrder(node1);
	printf("\n");

    printf("中序遍历:");
    BinaryTreeInOrder(node1);
	printf("\n");

    printf("后序遍历:");
    BinaryTreePostOrder(node1);
	printf("\n");

    printf("层序遍历:");
    LevelOrder(node1);
    printf("\n");

    printf("BinaryTreeComplete:%d\n", BinaryTreeComplete(node1));
    printf("BinaryTreeSize:%d\n", BinaryTreeSize(node1));
    printf("BinaryTreeLeafSize:%d\n", BinaryTreeLeafSize(node1));

    BinaryTreeDestory(node1);
	node1 = NULL;

    return 0;
}

操作結果:

ここに画像の説明を挿入します
実行結果は予測結果と一致しています。

おすすめ

転載: blog.csdn.net/zcxyywd/article/details/133107365