[Data Structure Getting Started Guide] Implementation of Binary Tree Chain Structure (interpretation of nanny-level code ideas, very classic)


insert image description here


1. Pre-instructions

Other data structures are different, and the addition, deletion, query, and modification interface of the binary tree is of little significance (only the addition, deletion, query, and modification of the subsequent search tree is meaningful). Ordinary elementary binary trees are more important to learn the control structure, which lays the foundation for subsequent advanced data structures such as AVL trees and red-black trees. At the same time, most of the OJ questions are also here.


Second, the traversal of the binary tree

The so-called binary tree traversal (Traversal) is to perform corresponding operations on the nodes in the binary tree in turn according to certain specific rules, and each node is only operated once. The operations performed by the access nodes depend on the specific application problem.
 
insert image description here
According to the rules, the traversal of the binary tree includes: preorder/inorder/postorder recursive structure traversal:

  • Preorder traversal (Preorder Traversal also known as preorder traversal) - access order: root node -> left subtree -> right subtree
  • Inorder traversal (Inorder Traversal) - access order: left subtree -> root node -> right subtree
  • Postorder Traversal (Postorder Traversal) - access order: left subtree -> right subtree -> root node

2.1 Preorder traversal

【Code ideas】:

  1. If the binary tree is empty, return directly.
  2. Visit the root node.
  3. Recursively traverse the left subtree, that is, call the preorder traversal function and pass in the root node of the left subtree.
  4. Recursively traverse the right subtree, that is, call the preorder traversal function and pass in the root node of the right subtree

code:

void PrevOrder(BTNode* root)
{
    
    
	if (root == NULL)
	{
    
    
		printf("NULL ");
		return;
	}

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

2.2 Inorder traversal

【Code ideas】:

  1. First judge whether the binary tree is empty, and return directly if it is empty.
  2. Perform in-order traversal on the left subtree of the current node, that is, recursively call the in-order traversal function.
  3. Access the value of the current node.
  4. Perform in-order traversal on the right subtree of the current node, that is, recursively call the in-order traversal function.

code:

void InOrder(BTNode* root)
{
    
    
	if (root == NULL)
	{
    
    
		printf("NULL ");
		return;
	}

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

2.3 Post-order traversal

【Code ideas】:

  1. Determine whether the current node is empty, and return if it is empty.
  2. Recursively traverse the left subtree of the current node.
  3. Recursively traverse the right subtree of the current node.
  4. Visit the current node.

code:

void PostOrder(BTNode* root)
{
    
    
	if (root == NULL)
	{
    
    
		printf("N ");
		return;
	}

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

3. Preorder traversal as an example, recursive diagram

Preorder traversal recursive diagram:


insert image description here


insert image description here
The above three traversal results:

  1. Preorder traversal results: 1 2 3 4 5 6
  2. Inorder traversal result: 3 2 1 5 4 6
  3. Post-order traversal results: 3 2 5 6 4 1

Four, layer order traversal

Level-order traversal: In addition to pre-order traversal, in-order traversal, and post-order traversal, level-order traversal of binary trees can also be performed. Assuming that the root node of the binary tree is at 1 layer, the layer order traversal is to start from the root node of the binary tree where it is located, first visit the root node of the first layer, then visit the nodes on the second layer from left to right, and then the third The nodes of the layer, and so on, the process of visiting the nodes of the tree layer by layer from top to bottom and from left to right is layer order traversal.
insert image description here
[Code idea]: (core idea: when the upper layer is out, bring the next layer into the queue, that is, when the root node is out of the stack, the child nodes of the root node are in the stack)

  1. First push the root node onto the stack.
  2. Loop through the following operations until the stack is empty.
    . Pop the top element of the stack and output its value;
    . If the node has a right child, push the right child onto the stack.
    . If the node has a left child, push the left child onto the stack

Check the stack related code by yourself:Stack and queue code implementation

code:

void LevelOrder(BTNode* root)
{
    
    
	Queue q;
	QueueInit(&q);

	if (root)
		QueuePush(&q, root);

	while (!QueueEmpty(&q))
	{
    
    
		BTNode* front = QueueFront(&q);
		QueuePop(&q);

		printf("%d ", front->data);

		if(front->left)
			QueuePush(&q, front->left);

		if (front->right)
			QueuePush(&q, front->right);
	}

	printf("\n");

	QueueDestroy(&q);
}

Five, the number and height of nodes, etc.

5.1 Number of Binary Tree Nodes

【Code ideas】:

  1. If the binary tree is empty, the number of nodes is 0.
  2. Otherwise, the number of nodes is equal to the number of root nodes plus the number of nodes in the left subtree and the number of nodes in the right subtree.
  3. Recursively count the number of nodes in the left subtree.
  4. Recursively calculate the number of nodes in the right subtree.
  5. Returns the number of root nodes plus the number of nodes in the left and right subtrees.

code:

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

5.2 Number of leaf nodes in binary tree

【Code ideas】:

  1. Determine whether the root node is empty, and return 0 if it is empty.
  2. Determine whether the left and right subtrees of the root node are empty. If both are empty, it means that the root node is a leaf node, and return 1.
  3. Calculate the number of leaf nodes in the left subtree and right subtree respectively by recursion, and return the sum of the number of leaf nodes in the left subtree and right subtree.

code:

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);
}

5.3 The number of nodes in the kth layer of the binary tree

【Code ideas】:

  1. Determine whether the binary tree is empty, and return 0 if it is.
  2. Determine whether k is equal to 1, and if so, return 1, indicating that the current layer is the kth layer with only one node.
  3. If none of the above conditions are met, then recursively calculate the number of nodes at the k-1th layer of the left subtree and right subtree of the binary tree, and then add the number of nodes at the k-1th layer of the left and right subtrees to obtain the binary tree at the first The number of k-level nodes.

code:

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);
}

5.4 Find the node whose value is x in the binary tree

【Code ideas】:

  1. Returns null if the current node is null.
  2. Returns the current node if its value is equal to x.
  3. Otherwise, recursively search the left subtree, and return the node in the left subtree if found.
  4. Otherwise, recursively search the right subtree, and return the node in the right subtree if found.

code:

BTNode* BTreeFind(BTNode* root, BTDataType x)
{
    
    
	if (root == NULL)
		return NULL;

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

	BTNode* ret1 = BTreeFind(root->left, x);
	if (ret1)
		return ret1;

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

	return NULL;
}

5.5 The height of a binary tree

【Code ideas】:

  1. If the tree is empty, the height is 0.
  2. If the tree is not empty, the height is the greater of the height of the left subtree and the height of the right subtree plus 1.
  3. Recursively calculate the heights of the left and right subtrees and take the larger value.
  4. Returns the greater of the heights of the left and right subtrees plus 1.

code:

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

	int LeftHeight = BinaryTreeHeight(root->left);
	int RightHeight = BinaryTreeHeight(root->right);
	return LeftHeight > RightHeight ? LeftHeight + 1 : RightHeight + 1;
}

Six, the creation and destruction of binary tree

6.1 Building a binary tree

Tips: There are many ways to build a binary tree. Here we use the preorder pass group "ABD##E#H##CF##G##" to build a binary tree. ('#' means empty tree)
[Code ideas]:

  1. If the node is "#" means empty, return empty.
  2. Traverse to create a left subtree, and link with the root node.
  3. Traverse to create a right subtree, and link with the root node.
  4. return root node

code:

typedef int BTDataType;
typedef struct BinaryTreeNode//结构体类型
{
    
    
    BTDataType data;
    struct BinaryTreeNode* left;
    struct BinaryTreeNode* right;
}BTNode;

//创建节点
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;
}

//先序创建二叉树
BTNode* createrroot(char* a, int* pi)
{
    
    
    if (a[*pi] == '#')
    {
    
    
        (*pi)++;
        return NULL;
    }

    BTNode* root = BuyNode(a[*pi]);
    (*pi)++;

    root->left = createrroot(a, pi);
    root->right = createrroot(a, pi);
    return root;
}

6.2 Destruction of binary tree

【Code ideas】:

  1. Starting from the root node, recursively destroy the left subtree.
  2. Starting from the root node, destroy the right subtree recursively.
  3. Remove the root node from memory.

code:

void BinaryTreeDestroy(BTNode* root)
{
    
    
	if (root == NULL)
		return;
	BinaryTreeDestory(root->left);
	BinaryTreeDestory(root->right);
	free(root);
}

6.3 Determine whether a binary tree is a complete binary tree

(The blogger's data structure is initially implemented in C language, so the direct stack code here is copied from the blogger's code warehouse, and readers can use other languages ​​to implement it, similar)

【Code ideas】:

  1. Traversing the binary tree, using the hierarchical traversal method, starts from the root node and traverses each node layer by layer.
  2. Stop traversal when encountering the first empty tree.
  3. Starting from the first empty tree, if the subsequent nodes are non-empty, it is not a complete binary tree, otherwise it is a complete binary tree.

Check the stack related code by yourself:Stack and queue code implementation
code:

int BinaryTreeComplete(BTNode* root)
{
    
    
    Que q;
    QueueInit(&q);

    if (root)
        QueuePush(&q, root);

    while (!QueueEmpty(&q))
    {
    
    
        BTNode* front = QueueFront(&q);
        QueuePop(&q);

        //遇空就跳过
        if (front==NULL)
        {
    
    
            break;
        }

        QueuePush(&q, root->left);
        QueuePush(&q, root->right);
    }

    //检查后续节点是否有非空
    //有非空就不是完全二叉树
    while (!QueueEmpty(&q))
    {
    
    
        BTNode* front = QueueFront(&q);
        QueuePop(&q);
        if (front)
        {
    
    
            QueueDestroy(&q);
            return false;
        }
    }
    QueueDestroy(&q);
    return true;
}

insert image description here
insert image description here
[Data Structure Getting Started Guide] Binary Tree Sequence Structure: Heap and Implementation (with pictures throughout, very classic)

Guess you like

Origin blog.csdn.net/Zhenyu_Coder/article/details/132483203