C言語による二分木のチェーン構造 - トラバーサル - 再帰実装

プリオーダー、インオーダー、ポストオーダーのトラバーサル
        二分木走査 (Traversal) は、 二分木の、各ノードは 1 回だけ操作されます
ルールによれば、バイナリ ツリー トラバーサルには次のものが含まれます。 事前順序/順序内/事後 再帰構造のトラバーサル :
  • 1.プレオーダー トラバーサル(プレオーダー トラバーサルとも呼ばれます) -ルート ノードにアクセスする操作は、左右のサブツリーをトラバースする前に発生します。
  • 2.インオーダー トラバーサル(Inorder Traversal) -ルート ノードにアクセスする操作は、その左右のサブツリー (中間) のトラバース中に発生します。
  • 3.ポストオーダー トラバーサル-ルート ノードにアクセスする操作は、その左右のサブツリーをトラバースした後に発生します。
        訪問したノードは特定のサブツリーのルートでなければならない ため、 N (ノード )、 L (左サブツリー )、および R (右サブツリー) はルート、ルートの左サブツリー、およびルートの右サブツリー として解釈できます NLR LNR LRN はそれぞれ、最初のルート トラバーサル、中間のルート トラバーサル、最後のルート トラバーサルとも呼ばれます
// 二叉树前序遍历
void PreOrder(BTNode* root);
// 二叉树中序遍历
void InOrder(BTNode* root);
// 二叉树后序遍历
void PostOrder(BTNode* root);
プレオーダートラバーサル再帰図

 //................................................................ .上記の概念的な内容はすべてビット科学技術からのものです。 ……………………

より直感的に理解するには、まず二分木を手でこすります

#include<stdio.h>
#include<assert.h>
#include<stdlib.h>


typedef int BTDataType;
typedef struct BinaryTreeNode
{
	struct BinaryTreeNode* left;
	struct BinaryTreeNode* right;
	BTDataType data;
}BTNode;


BTNode* BuyNode(BTDataType x)
{
	BTNode* node = (BTNode*)malloc(sizeof(BTNode));
	assert(node);

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

	return node;
}

BTNode* CreatBinaryTree()
{
	BTNode* node1 = BuyNode(1);
	BTNode* node2 = BuyNode(2);
	BTNode* node3 = BuyNode(3);
	BTNode* node4 = BuyNode(4);
	BTNode* node5 = BuyNode(5);
	BTNode* node6 = BuyNode(6);

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

	return node1;
}

次に、前/中/後の順序を使用して以下にアクセスします。

コード:

プロローグ:

//前序
void PreOrder(BTNode* root){
	if (root == NULL)
	{
		printf("# ");
		return;
	}
	printf("%d ", root->data);
	PreOrder(root->left);
	PreOrder(root->right);
}

中程度の注文:

//中序
void InOrder(BTNode* root){
	if (root == NULL)
	{
		printf("# ");
		return;
	}
	InOrder(root->left);
	printf("%d ", root->data);
	InOrder(root->right);
}

その後:

//后序
void PostOrder(BTNode* root)
{
	if (root == NULL)
	{
		printf("# ");
		return;
	}

	PostOrder(root->left);
	PostOrder(root->right);
	printf("%d ", root->data);
}

形が崩れて

アイデア: 分割統治アルゴリズム、分割統治、大きな問題を同じサイズの小さな問題に変換します。(通常は再帰を使用します)

1. 二分木のノードの数を見つける

         方法は2つあり、 ① グローバル変数を定義し、再帰するたびに変数を1回ずつ++します。

         ② 最初に左側のサブツリー ノードの数を求め、右側のサブツリー ノードの数を追加し、最後にルートを追加します。これは再帰的であるため、NULL ツリーに遭遇すると分割されなくなるまで、左と右のサブツリーに分割できます。以下の例のほとんどはこの考えを持っています。

//求二叉树结点的个数

int count = 0;
int TreeSize1(BTNode* root)
{
	if (root == NULL)
	{
		return;
	}

	count++;//注:这里需要定义全局变量,因为是递归,所以不能使用局部变量

	TreeSize1(root->left);
	TreeSize1(root->right);
}

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

}

2. リーフノードの数を見つける

アイデア: これも 2 つの方法があり、1 つ目は、前の例に基づいてグローバル変数を作成し、if を使用して判断する方法です。

2 番目の方法は、左側のツリーと右側のツリーのリーフ ノードを見つけて追加することです。

//求叶子结点的个数
int TreeLeafSize1(BTNode* root)
{
	if (root == NULL)
	{
		return;
	}

	if (root->left == NULL && root->right == NULL)
	{
		count++;//定义一个全局变量
	}

	TreeLeafSize1(root->left);
	TreeLeafSize1(root->right);
	
}

//方法2
int TreeLeafSize2(BTNode* root)
{
	if (root == NULL)
	{
		return 0;
	}

	if (root->left == NULL && root->right == NULL)
	{
		return 1;
	}

	return TreeLeafSize2(root->left) + TreeLeafSize2(root->right);
}

3. k番目の層のノードの数を見つけます

アイデア: これを部分問題に変換し、左のサブツリーの k-1 レベル + 右のサブツリーの k-1 レベルを見つけます。

//求第k层结点的个数
int TreeKLevel(BTNode* root, int k){
	assert(k >= 1);
	if (root == NULL)
		return 0;

	if (k == 1)
		return 1;

	return TreeKLevel(root->left, k - 1) +
		TreeKLevel(root->right, k - 1);
}

4. 二分木の深さを求める

アイデア: 左側のツリーの深さを見つけて、次に右側のツリーの深さを見つけて、1 を追加してルートを追加し、以下を比較して、大きい/深い方が返されます。

//求二叉树的深度
int TreeDepth(BTNode* root)
{
	if (root == NULL)
		return NULL;

	int leftDepth = TreeDepth(root->left)+1;
	int rightDepth = TreeDepth(root->right)+1;

	return leftDepth > rightDepth ? leftDepth  : rightDepth ;
}

5. 二分木で x ノードの値を見つけます。

注: ここで注目に値するのは、戻り値と再帰からの脱却の問題です。事前注文でそれを横断するだけです。

//二叉树中查找值为x结点的值
BTNode* TreeFind(BTNode* root, BTDataType x)
{
	if (root == NULL)
		return NULL;

	if (root->data == x)
		return root;

	BTNode* ret1 = TreeFind(root->left, x);
	if (ret1) //这里的条件是ret1不为空
		return ret1;

	BTNode* ret2 = TreeFind(root->right, x);
	if (ret2)
		return ret2;

	return NULL;
}


oj 演習 - C 言語の問題解決

1. 単一値の二分木 オージリンク
bool isUnivalTree(struct TreeNode* root){
    if(root == NULL)
         return true;
    
    if(root->left && root->left->val != root->val)
        return false;

     if(root->right && root->right->val != root->val)
          return false;
     
   return  isUnivalTree(root->left)&&
     isUnivalTree(root->right);
    //同时为true 才为true
    //一个为false 就返回false

    //根  和左孩子右孩子比较,如果不相同,就return false
    //如果相同,就继续向下看左子树,再看右子树
    //左子树继续向下划分根 左孩子 右孩子

}
2. 2 つのツリーが同じかどうかを確認します OJリンク
bool isSameTree(struct TreeNode* p, struct TreeNode* q){
    if( p == NULL && q == NULL)//同时为空
          return true;
    
    if(p == NULL  ||  q == NULL)//走到这里必定有一个为空,一个不为空
          return false;

    if(p->val != q->val )
       return false;

    return  isSameTree(p->left,q->left)//左子树跟左子树比较
     && isSameTree(p->right,q->right);//右子树跟右子树比较
 
}

3. 対称二分木 OJリンク
bool isSymmetricSubTree(struct TreeNode* root1,struct TreeNode* root2)
{
    if(root1 == NULL && root2 == NULL)
        return true;

    if(root1 == NULL || root2 == NULL)//走到这里必定一个为空一个不为空
       return false;
    
    if(root1->val != root2->val)//必定同时不为空,比较val值
        return false;
    
    return isSymmetricSubTree(root1->left,root2->right)
    &&isSymmetricSubTree(root1->right,root2->left);
    //左树的左孩子比较右树的右孩子
    //左树的右孩子比较右树的左孩子
}

bool isSymmetric(struct TreeNode* root){
    
    if(root == NULL)
       return true;

    //以根为分割线 -- 镜像二叉树
    
    return isSymmetricSubTree(root->left,root->right);
    //根的左孩子右孩子传过去
}
4. バイナリ ツリーの事前順序走査 OJリンク
//注意:返回的值必须要放进malloc申请的数组空间里面
 //returnSize :默认不给空间大小,也就是我们需要求出数组的大小

//首先求出malloc数组空间的大小
int TreeSize(struct TreeNode* root)
{
    return root == NULL ? 0 : TreeSize(root->left)+TreeSize(root->right)+1;
}

//这里为什么i需要传地址,因为我们需要的是一个i 而不是栈帧空间中的每一个独立的i
//因为下面子树改变i,不会影响上面根的i,这就导致数据可能会重叠,导致后面的空间出现随机数
void prevorder(struct TreeNode* root,int* arr,int* i)
{
    if(root == NULL)
        return;

    arr[(*i)++] = root->val;

    prevorder(root->left,arr,i);
    prevorder(root->right,arr,i);

}

int* preorderTraversal(struct TreeNode* root, int* returnSize){
    
    *returnSize = TreeSize(root);

    int* arr = (int*)malloc(*returnSize * sizeof(int));

    int i = 0;//数组下标
    prevorder(root,arr,&i);
 
    return arr;

}
5. 別のツリーのサブツリー OJリンク
bool isSameTree(struct TreeNode* p, struct TreeNode* q){
    if( p == NULL && q == NULL)//同时为空
          return true;
    
    if(p == NULL  ||  q == NULL)//走到这里必定有一个为空,一个不为空
          return false;

    if(p->val != q->val )
       return false;

    return  isSameTree(p->left,q->left)//左子树跟左子树比较
     && isSameTree(p->right,q->right);//右子树跟右子树比较
 
}

 //思路:把原树中的所有子树都找出来与subRoot进行比较
bool isSubtree(struct TreeNode* root, struct TreeNode* subRoot){

   if(root == NULL)
      return false;


    //遍历所有子树进行比较 ,subroot与root所有的根节点进行比较
    if(isSameTree(root,subRoot))
        return true;
   
    //角度2.
    //先与当前树进行比较,如果不是当前树的子树
    //那么就去与当前树的左子树进行比较
    //如果也不是
    //就与当前树的右子树进行比较
    //只要有一个为true 就可以,所有这里是或|| 
    return isSubtree(root->left,subRoot)
            || isSubtree(root->right,subRoot);

}

6. バイナリ ツリーの構築とトラバース OJリンク
#include<stdio.h>
#include<assert.h>
#include<stdlib.h>


typedef char BTDataType;
typedef struct BinaryTreeNode {
    struct BinaryTreeNode* left;
    struct BinaryTreeNode* right;
    BTDataType data;
} BTNode;


BTNode* BuyNode(BTDataType x) {
    BTNode* node = (BTNode*)malloc(sizeof(BTNode));
    assert(node);

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

    return node;
}

BTNode* CreateTree(char* arr,int* i)//前序构建
{
    if(arr[*i] == '#')
    {
        (*i)++;
        return NULL;
    }

    BTNode* root = BuyNode(arr[(*i)++] );

    root->left = CreateTree(arr,i);//先构建左子树
    root->right = CreateTree(arr,i);//再构建右子树

    return root;//返回根节点
}

//中序遍历
void Inorder(BTNode* root)
{
    if(root == NULL)
        return ;

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

}

int main()
{
    char arr[100]={0};
    scanf("%s",arr);

    int i=0;//数组下标
    BTNode* root = CreateTree(arr,&i);
    Inorder(root);

    return 0;
}





上記はあくまで参考用です

おすすめ

転載: blog.csdn.net/m0_73969113/article/details/131982851