Data structure -- linked binary tree

Article catalog

catalogue

Article catalog

1, Binary tree

2, Code implementation

1. Node settings

2. Three Traversals

3. Binary tree creation and destruction

4. Calculation of various nodes

5. Sequence traversal

6. Judge whether the binary tree is a complete binary tree

summary



1, Binary tree

         Tree is an important nonlinear data structure. Intuitively, it is a structure organized by data elements (called nodes in the tree) according to the branch relationship, much like the tree in nature.

        Full binary tree: there are no children except the last layer node In addition, all nodes on each layer have two child nodes binary tree.

        Complete binary tree: if the depth of the binary tree is set to h, the node points of all other layers are full except layer h. all nodes of layer h are arranged from the leftmost side, and one node cannot be skipped in the middle.



2, Code implementation



1. Node settings

        The binary tree node structure has three member variables in total. The data field stores data, and the two pointer fields store the nodes of the left and right children.

typedef char BTDataType;

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



2. Three Traversals

        Recursive functions are widely used in chained binary trees. The three traversal methods are actually different in the order of heap root node operations. Traversing a binary tree is the basis of other binary tree operations. Other functions can be realized by using different traversal methods and some specific operations.

// Preorder traversal of binary tree 
void BinaryTreePrevOrder(BTNode* root)
{
	if (!root)
	{
		printf("NULL ");
		return;
	}
	printf("%c ", root->data);
	BinaryTreePrevOrder(root->left);
	BinaryTreePrevOrder(root->right);
}
// Order traversal in binary tree
void BinaryTreeInOrder(BTNode* root)
{
	if (!root)
	{
		printf("NULL ");
		return;
	}
	BinaryTreeInOrder(root->left);
	printf("%c ", root->data);
	BinaryTreeInOrder(root->right);
}
// Postorder traversal of binary tree
void BinaryTreePostOrder(BTNode* root)
{
	if (!root)
	{
		printf("NULL ");
		return;
	}
	BinaryTreePostOrder(root->left);
	BinaryTreePostOrder(root->right);
	printf("%c ", root->data);
}

3. Binary tree creation and destruction

        Here, the binary tree is created by sequential traversal, and the binary tree is destroyed by subsequent traversal.

// The binary tree is constructed through the array "ABD##E#H##CF##G##" traversed in the previous order
BTNode* BinaryTreeCreate(BTDataType* a, int n, int* pi)
{
	if (a[*pi] == '#' || *pi >= n)
	{
		(*pi)++;
		return NULL;
	}
	BTNode* TreeNode = (BTNode*)malloc(sizeof(BTNode));
	TreeNode->data = a[(*pi)++];
	TreeNode->left = BinaryTreeCreate(a, n - 1, *pi);
	TreeNode->right = BinaryTreeCreate(a, n - 1, *pi);
	return TreeNode;
}
// Binary tree destruction
void BinaryTreeDestory(BTNode* root)
{
	if (root == NULL)
		return;
	BinaryTreeDestory(root->left);
	BinaryTreeDestory(root->right);
	free(root);
}

4. Calculation of various nodes

        Using the idea of recursive splitting and the basic knowledge of binary tree, these nodes can be calculated well.

        To find a node with a specific value, first find it in the left subtree, and then find it in the right subtree. If it is found in the left subtree, we can set to return immediately instead of looking in the right subtree. At the same time, you can set variables to record the results found to avoid repeated calculation.

// Number of binary tree nodes
// Number of left subtrees + number of right subtrees + number of current nodes
int BinaryTreeSize(BTNode* root)
{
	return root == NULL ? 0 : 
		BinaryTreeSize(root->left) 
		+ BinaryTreeSize(root->right) + 1;
}
// Number of leaf nodes of binary tree
//Recurse to the leaf node, and then return the number layer by layer
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);
}
// Number of nodes in the k-th layer of binary tree
// The k-th layer of the root node = the sum of the k-1 layers of the left and right subtrees
int BinaryTreeLevelKSize(BTNode* root, int k)
{
	assert(k >= 1);
	if (root == NULL)
		return 0;
	if (k == 1)
		return 1;
	return BinaryTreeLevelKSize(root->left, k - 1)
		+ BinaryTreeLevelKSize(root->right, k - 1);
}
// The binary tree looks for a node with a value of x
BTNode* BinaryTreeFind(BTNode* root, BTDataType x)
{
	if (!root)
	{
		return NULL;
	}
	if (root->data == x)
	{
		return root;
	}
	BTNode* a = BinaryTreeFind(root->right,x);
	if (a)
		return a;
	BTNode* b = BinaryTreeFind(root->left,x);
	if (b)
		return b;
	return NULL;
}

5. Sequence traversal

        The sequence traversal requires a queue structure. At the beginning, the root node is placed in the queue. After each pop-up of a parent node, two child nodes are brought into the queue until there is no data in the queue, and the sequence traversal is completed.

void BinaryTreeLevelOrder(BTNode* root)
{
	if (!root)
	{
		return;
	}
	Queue q;
	QueueInit(&q);
	QueuePush(&q,root);
	while (!QueueEmpty(&q))
	{
		BTNode* front = QueueFront(&q);
		QueuePop(&q);
		printf("%c ", front->data);
		if (front->left)
		{
			QueuePush(&q, front->left);
		}
		if (front->right)
		{
			QueuePush(&q, front->right);
		}
	}
	printf("\n");
	QueueDestroy(&q);
}

6. Judge whether the binary tree is a complete binary tree

        Sequence traversal is used to judge whether a binary tree is a complete binary tree. When the sequence traverses to the empty node, if the binary tree is a complete binary tree, the nodes traversed later will be empty nodes. If a node is not empty, we can conclude that it is not a complete binary tree.

int BinaryTreeComplete(BTNode* root)
{
	Queue q;
	QueueInit(&q);
	QueuePush(&q, root);
	//The sequence traverses until the first empty node is encountered
	while (!QueueEmpty(&q))
	{
		BTNode* front = QueueFront(&q);
		QueuePop(&q);
		if (!front)
		{
			break;
		}
		else
		{
			QueuePush(&q, front->left);
			QueuePush(&q, front->right);
		}
	}
	//Judge whether there is a non empty node after an empty node, that is, it is not a complete binary tree
	while (!QueueEmpty(&q))
	{
		BTNode* front = QueueFront(&q);
		QueuePop(&q);
		if (front)
		{
			QueueDestroy(&q);
			return false;
		}
	}
	return true;
	QueueDestroy(&q);
}

summary

        The operation of binary tree structure is closely related to function recursion, which is a recursive idea of divide and conquer.

Tags: data structure linked list

Posted on Sat, 20 Nov 2021 08:54:45 -0500 by jerryroy