[Data Structure] Level-order traversal of binary trees (4)

 Table of contents

1. Concept of level-order traversal

2. Implementation of level-order traversal

        1. Implementation ideas of layer-order traversal

        2. Create a queue

        Queue.h

        Queue.c

        3. Create a binary tree

        BTree.h

        BTree.c

        4. Implementation of layer-order traversal


1. Concept of level-order traversal

Level-order traversal: In addition to pre-order traversal, in-order traversal, and post-order traversal, level-order traversal can also be performed on binary trees;

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 of nodes, and so on, 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.

2. Implementation of level-order traversal

        1. Implementation ideas of layer-order traversal

Level-order traversal: Visit each node of the binary tree from left to right according to each row.

But, after the access to one layer is over, how to access the next layer? Take the picture above as an example. How to access node (3) after accessing node (4)? (4) The node does not have the information of (3) node;

Algorithm idea:

You can use a queue to first enqueue the root node of the binary tree, then access the dequeue node and dequeue it. If there is a left child node, the left child node will also be enqueued; if there is a right child node, the right child node will be dequeued. Join the team at some point. Then access the dequeue node and dequeue until the queue is empty

Process demonstration: 

(1) Enter the queue, visit the head node (1) , and then ( 1) exit the queue. At this time, the left subtree (2) and the right subtree (4) of (1) enter the queue one after another; at this time, the queue: head < ---- (2) (4) <---Tail

Visit the queue head node (2) , and then (2) dequeue. At this time, the left subtree (3) of (2) enters the queue. At this time, the queue: (4) (3)

Visit the queue head node (4) , and then ( 4 ) is dequeued. At this time, the left subtree (5) and right subtree (6) of (4) are entered into the queue one after another;

Queue at this time: (3) (5) (6)

Visit the queue head node (3) , and then (3) dequeue, because (3) has no left and right subtrees, no data is put into the queue at this time, and the queue at this time is: (5) (6)

Visit the head node (5) , and then (5 ) dequeue, at this time the queue: (6)

Visit the head node (6) , and then (6) dequeue, at this time the queue: NULL, end!

Here is another binary tree traversal to help us understand;

        2. Create a queue

First we have to create a queue. I won’t explain the specific details of the queue. I have introduced it in detail in the previous blog;

The nature of the queue: first in, first out, that is, a singly linked list with tail insertion and head deletion;

        Queue.h

#define _CRT_SECURE_NO_WARNINGS 1
#pragma once
#include<stdio.h>
#include<assert.h>
#include<stdlib.h>
#include"BTree.h"

typedef BTNode* QDataType;
//结点
typedef struct QListNode
{
	struct QListNode* next;
	QDataType data;
}QNode;

// 队列
typedef struct Queue
{
	QNode* front; // 队头
	QNode* rear; //队尾
	int size;
}Queue;

// 初始化队列 
void QueueInit(Queue* q);
// 队头入队列 
void QueuePush(Queue* q, QDataType data);
// 队尾出队列 
void QueuePop(Queue* q);
// 获取队列头部元素 
QDataType QueueFront(Queue* q);
// 获取队列队尾元素 
QDataType QueueBack(Queue* q);
// 获取队列中有效元素个数 
int QueueSize(Queue* q);
// 判空
int QueueEmpty(Queue* q);
// 销毁队列 
void QueueDestroy(Queue* q);

        Queue.c

#define _CRT_SECURE_NO_WARNINGS 1
#define _CRT_SECURE_NO_WARNINGS 1
#include"Queue.h"

// 初始化队列 
void QueueInit(Queue* q)
{
	assert(q);
	q->front = q->rear = NULL;
	q->size = 0;
}

// 队尾入队列 
void QueuePush(Queue* q, QDataType data)
{
	assert(q);
	QNode* newnode = (QNode*)malloc(sizeof(QNode));
	if (newnode == NULL)
	{
		perror("malloc");
		exit(-1);
	}
	newnode->next = NULL;
	newnode->data = data;
	if (q->front /*= q->rear*/ == NULL)//谨记判断不要用此等格式
	{
		q->front = q->rear = newnode;
	}
	else
	{
		q->rear->next = newnode;
		q->rear = newnode;
	}
	q->size++;
}
// 队头出队列 
void QueuePop(Queue* q)
{
	assert(q);
	assert(!QueueEmpty(q));
	if (q->front->next == NULL)
	{
		free(q->front);
		q->front = q->rear = NULL;
	}
	else
	{
		QNode* next = q->front->next;
		free(q->front);
		q->front = next;
	}
	q->size--;
}
// 获取队列头部元素 
QDataType QueueFront(Queue* q)
{
	assert(q);
	assert(!QueueEmpty(q));
	return q->front->data;
}
// 获取队列队尾元素 
QDataType QueueBack(Queue* q)
{
	assert(q);
	assert(!QueueEmpty(q));
	return q->rear->data;
}
// 获取队列中有效元素个数 
int QueueSize(Queue* q)
{
	assert(q);
	return q->size;
}
// 检测队列是否为空,如果为空返回非零结果,如果非空返回0 
int QueueEmpty(Queue* q)
{
	assert(q);
	return q->size == 0;
}
// 销毁队列 
void QueueDestroy(Queue* q)
{
	assert(q);

	QNode* cur = q->front;
	QNode* next = NULL;
	while (cur)
	{
		next = cur->next;
		free(cur);
		cur = next;
	}
	cur = NULL;
	q->rear = NULL;
}

This queue has been constructed, we still need a binary tree;

        3. Create a binary tree

We have created binary trees before, so we won’t introduce them too much now, let’s just get started!

        BTree.h

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

typedef int BTDataType;
//二叉链
typedef struct BinaryTreeNode
{
	BTDataType data; // 当前结点值域	
	struct BinaryTreeNode* left; // 指向当前节点左孩子
	struct BinaryTreeNode* right; // 指向当前节点右孩子
}BTNode;

//动态创立新结点
BTNode* BuyNode(BTDataType x);
//创建二叉树
BTNode* GreatBTree();

        BTree.c

#define _CRT_SECURE_NO_WARNINGS 1
#include"BTree.h"
#include"Queue.h"
//动态创立新结点
BTNode* BuyNode(BTDataType x)
{
	BTNode* newnode = (BTNode*)malloc(sizeof(BTNode));
	assert(newnode);
	newnode->data = x;
	newnode->left = NULL;
	newnode->right = NULL;
	return newnode;
}

//创建二叉树
BTNode* GreatBTree()
{
	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;
}

The .c files of this queue and the binary tree  must contain each other's header files to link them;

        4. Implementation of layer-order traversal

Build the code according to the previous analysis ideas;

//层序遍历
void LevelOrder(BTNode* root)
{
	Queue q;
	// 初始化队列 
	QueueInit(&q);
	// 队尾入队列 
	if (root)
	{
		QueuePush(&q, root);
	}
	while (!QueueEmpty(&q))
	{
		printf("%d ", QueueFront(&q)->data);
		BTNode* cur = QueueFront(&q);
		// 队头出队列
		QueuePop(&q);
		if (cur->left)
		{
			QueuePush(&q, cur->left);
		}
		if (cur->right)
		{
			QueuePush(&q, cur->right);
		}
	}
}
int main()
{
	BTNode* root = GreatBTree();
	//层序遍历
	LevelOrder(root);
	return 0;
}

 It is indeed traversed layer by layer;

Previous traversals were recursive, while layer-sequential traversal was implemented in a loop. Currently, if it is implemented in C language, it is particularly cumbersome to implement because there is no queue library. However, it is easy to understand and is not difficult in itself. This is layer-sequence. Implementation of traversal;

The fourth stage will take you through the implementation of layer-order traversal, and in the later stage, you will be taken through classic questions for consolidation;

The blogger will update it one after another later;

If there are any deficiencies, please feel free to supplement and communicate!

end.


Guess you like

Origin blog.csdn.net/m0_71676870/article/details/132921191