[Data structure] Chain structure and implementation of binary tree

Table of contents

1. Preliminary instructions

2. Binary tree traversal

2.1 Preorder, inorder and postorder traversal

2.2 Layer-order traversal

3. Number and height of nodes, etc.

4. Creation and destruction of binary trees


1. Preliminary instructions

Before learning the basic operations of a binary tree, you need to create a binary tree first, and then you can learn its related basic operations. Since everyone currently does not have a deep enough understanding of the binary tree structure, in order to reduce everyone's learning cost, here we quickly create a simple binary tree manually and quickly enter the binary tree operation learning. When the binary tree structure is almost understood, we will go back to study the real binary tree. Creation method.

typedef int BTDataType;
typedef struct BinaryTreeNode
{
	BTDataType _data;
	struct BinaryTreeNode* _left;
	struct BinaryTreeNode* _right;
}BTNode;

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

Note: The above code is not a way to create a binary tree. The real way to create a binary tree will be explained in detail later.

Before looking at the basic operations of binary trees, let’s review the concept of binary trees. Binary trees are:

  1. empty tree
  2. Non-empty: Root node, the left subtree of the root node, and the right subtree of the root node.

It can be seen from the concept that the definition of binary tree is recursive, so the basic operations of post-order are basically implemented according to this concept.

2. Binary tree traversal

2.1 Preorder, inorder and postorder traversal

The simplest way to learn the binary tree structure is to traverse. The so-calledbinary tree traversal (Traversal) is to perform corresponding operations on the nodes in the binary tree in sequence according to certain specific rules, and each node is only operated once . The operations performed by accessing nodes depend on the specific application problem. Traversal is one of the most important operations on a binary tree and is also the basis for other operations on a binary tree.

According to the rules, the traversal of a binary tree includes:Pre-order/mid-order/post-order recursive structure traversal:

  1. Preorder traversal (also known as preorder traversal) - the operation of accessing the root node occurs before traversing its left and right subtrees.
  2. Inorder Traversal - The operation of accessing the root node occurs during the traversal of its left and right subtrees.
  3. Postorder Traversal - The operation of accessing the root node occurs after traversing its left and right subtrees.

Since the visited node must be the root of a certain subtree, so N (Node), L (Left subtree) and R (Right subtree) can be interpreted as roots , the left subtree of the root and the right subtree of the root. NLR, LNR and LRN are also called first root traversal, middle root traversal and last root traversal respectively.

// 二叉树前序遍历
void PrevOrder(BTNode* root);
// 二叉树中序遍历
void InOrder(BTNode* root);
// 二叉树后序遍历
void PostOrder(BTNode* root);
void PrevOrder(BTNode* root)
{
	if (root == NULL)
	{
		printf("NULL ");
		return;
	}
	printf("%d ", root->val);
	PrevOrder(root->left);
	PrevOrder(root->right);
}

void InOrder(BTNode* root)
{
	if (root == NULL)
	{
		printf("NULL ");
		return;
	}
	InOrder(root->left);
	printf("%d ", root->val);
	InOrder(root->right);
}

void PostOrder(BTNode* root)
{
	if (root == NULL)
	{
		printf("NULL ");
		return;
	}
	PostOrder(root->left);
	PostOrder(root->right);
	printf("%d ", root->val);
}

The following mainly analyzes pre-order recursive traversal. The diagrams of in-order and post-order are similar, and you can draw them yourself.

Preorder traversal recursion diagram:

Preorder traversal result: 1 2 3 4 5 6

In-order traversal result: 3 2 1 5 4 6

Postorder traversal result: 3 2 5 6 4 1

2.2 Layer-order traversal

Level-order traversal: In addition to pre-order traversal, in-order traversal, and post-order traversal, binary trees can also be traversed in level order. Assume that the level number of the root node of the binary tree is 1. The level-order traversal starts from the root node of the binary tree. First, it visits the root node of the first level, then visits the nodes on the second level from left to right, and then the third level. The process of accessing the nodes of the tree layer by layer from top to bottom and from left to right is layer-order traversal.

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

	if (root)
		QueuePush(&q, root);
	while (!QueueEmpty(&q))
	{
		BTNode* front = QueueFront(&q);
		printf("%d ", front->val);
		if (front->left)
			QueuePush(&q, front->left);
		if (front->right)
			QueuePush(&q, front->right);
		QueuePop(&q);
	}
	printf("\n");

	QueueDestroy(&q);
}

3. Number and height of nodes, etc.

// 二叉树节点个数
int TreeSize(BTNode* root);
// 二叉树叶子节点个数
int TreeLeafSize(BTNode* root);
// 二叉树第k层节点个数
int TreeKLevel(BTNode* root, int k);
// 二叉树查找值为x的节点
BTNode* TreeFind(BTNode* root, int x);
// 二叉树的高度
int TreeHeight(BTNode* root);
int TreeSize(BTNode* root)
{
	return root == NULL ? 0 : TreeSize(root->left) + TreeSize(root->right) + 1;
}

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

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

BTNode* TreeFind(BTNode* root, int x)
{
	if (root == NULL)
		return NULL;
	if (root->val == x)
		return root;

	BTNode* ret = NULL;
	ret = TreeFind(root->left, x);
	if (ret)
		return ret;
	ret = TreeFind(root->right, x);
	if (ret)
		return ret;

	return NULL;
}

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

4. Creation and destruction of binary trees

// 手动构建二叉树
BTNode* BuyNode(int x);
// 二叉树销毁
void TreeDestroy(BTNode* root);
// 判断二叉树是否是完全二叉树
int TreeComplete(BTNode* root);
BTNode* BuyNode(int x)
{
	BTNode* node = (BTNode*)malloc(sizeof(BTNode));
	if (node == NULL)
	{
		perror("malloc fail");
		exit(-1);
	}
	node->val = x;
	node->left = NULL;
	node->right = NULL;
	return node;
}

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

int TreeComplete(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);
		QueuePop(&q);
		if (front != NULL)
		{
			QueueDestroy(&q);
			return false;
		}
	}
	QueueDestroy(&q);
	return true;
}

End of article

Guess you like

Origin blog.csdn.net/m0_73156359/article/details/133776442