【データ構造】二分木の階層順走査 (4)

 目次

1. レベルオーダートラバーサルの概念

2. レベルオーダートラバーサルの実装

        1. 階層順走査の実装アイデア

        2. キューを作成する

        Queue.h

        Queue.c

        3. バイナリツリーを作成する

        Bツリー.h

        BTree.c

        4. 階層順トラバーサルの実装


1. レベルオーダートラバーサルの概念

レベル順序トラバーサル: 事前順序トラバーサル、順序内トラバーサル、および事後順序トラバーサルに加えて、レベル順序トラバーサルもバイナリ ツリーで実行できます。

バイナリ ツリーのルート ノードのレベル番号が 1 であるとします。レベル順序トラバーサルはバイナリ ツリーのルート ノードから開始され、最初に最初のレベルのルート ノードを訪問し、次に 2 番目のレベルのノードを訪問します。左から右のレベル、次にノードの 3 番目のレベルというように、上から下、左から右にレイヤーごとにツリーのノードにアクセスするプロセスは、レイヤー順序のトラバーサルです。

2. レベルオーダートラバーサルの実装

        1. 階層順走査の実装アイデア

レベル順序トラバーサル: 各行に従って、バイナリ ツリーの各ノードを左から右に訪問します。

しかし、1 つの層へのアクセスが終了した後、次の層にアクセスするにはどうすればよいでしょうか? 上の写真を例にすると、ノード(4)にアクセスした後、ノード(3)にアクセスするにはどうすればよいでしょうか? (4) ノードは、(3) ノードの情報を持っていません。

アルゴリズムのアイデア:

キューを使用して、最初にバイナリ ツリーのルート ノードをキューに登録し、次にデキュー ノードにアクセスしてデキューできます。左側の子ノードがある場合は、左側の子ノードもキューに追加されます。右側の子ノードがある場合は、右側の子ノードがデキューされます。ある時点でチームに参加してください。次に、デキュー ノードにアクセスし、キューが空になるまでデキューします。

プロセスのデモンストレーション: 

(1) キューに入り、ヘッドノード(1)を訪れ、( 1)キューから出る このとき、 ( 1)の左側のサブツリー(2)と右側のサブツリー(4) が1 つずつキューに入ります。別の;このときのキュー: head < ---- (2) (4) <---Tail

キューのヘッド ノード(2)にアクセスし、(2)デキューします。このとき、(2)の左側のサブツリー(3)がキューに入ります。このときのキューは次のとおりです: (4) (3)

キューヘッドノード(4)にアクセスすると、 ( 4 )がデキューされますが、このとき(4) の左側のサブツリー(5)と右側のサブツリー(6) が順番にキューに追加されます。

この時点のキュー: (3) (5) (6)

キュー ヘッド ノード(3)にアクセスし、次に(3)デキューします。(3)には左右のサブツリーがないため、この時点ではキューにデータは置かれません。この時点のキューは次のとおりです。 (5) ( 6)

ヘッド ノードにアクセスし(5)、次に(5 ) デキューします。このときのキューは次のとおりです: (6)

ヘッド ノードにアクセスし(6) 次にデキューします。この時点でキューは NULL、終了です。

ここでは、理解を助ける別のバイナリ ツリーのトラバースを示します。

        2. キューを作成する

まずはキューを作成しますが、キューの詳細については前回のブログで詳しく紹介しましたので割愛します。

キューの性質: 先入れ先出し、つまり、末尾の挿入と先頭の削除を伴う単一リンクされたリスト。

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

このキューは構築されましたが、バイナリ ツリーがまだ必要です。

        3. バイナリツリーを作成する

バイナリ ツリーは以前に作成したことがあるので、ここではあまり紹介しません。早速始めてみましょう。

        Bツリー.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;
}

このキューとバイナリ ツリーの .c ファイルには、相互にリンクするためのヘッダー ファイルが含まれている必要があります。

        4. 階層順トラバーサルの実装

前の分析のアイデアに従ってコードを構築します。

//层序遍历
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;
}

 実際、層ごとに横断されます。

以前のトラバーサルは再帰的でしたが、層順次トラバーサルはループで実装されていましたが、現在 C 言語で実装すると、キュー ライブラリがないため実装が特に面倒ですが、理解しやすく、難しくはありませんこれ自体がレイヤー シーケンスです。トラバーサルの実装。

4 番目のステージでは、レイヤー順序のトラバーサルの実装を説明し、後のステージでは、統合のための古典的な質問に取り組みます。

後ほどブロガーが順次更新していきますので、よろしくお願いします。

不足がある場合は、お気軽に補足して連絡してください。

終わり。


おすすめ

転載: blog.csdn.net/m0_71676870/article/details/132921191