1. 程式人生 > >C語言二叉樹的層序遍歷

C語言二叉樹的層序遍歷

上一篇中我記錄了二叉樹的先序,中序,後序的遞迴和非遞迴遍歷方法,這一篇會接著上一篇的,記錄二叉樹的層序遍歷方法,層序遍歷用到了佇列的資料結構,下面直接上程式碼:

1、首先是鏈佇列的資料結構定義,LinkQueue.h檔案:

#pragma once
#include "BinaryTree.h"

/** 鏈佇列的節點定義,包含一個數據域和下一個節點的指標 */
typedef struct QueueNode {
	BiTreeNode* data;
	struct QueueNode* next;
}QueueNode;

/**  鏈佇列的定義,包含隊頭和隊尾指標*/
typedef struct {
	QueueNode* front;
	QueueNode* rear;
}LinkQueue;

LinkQueue* InitQueue();/** 鏈佇列的初始化 */
void DestoryQueue(LinkQueue*);/** 銷燬佇列 */
void EnQueue(LinkQueue*, BiTreeNode*);/** 入隊 */
BiTreeNode* DeQueue(LinkQueue*);/** 出隊 */

2、LinkQueue.c檔案:
#include <stdio.h>
#include <stdlib.h>
#include "LinkQueue.h"

/** 鏈佇列的初始化 */
LinkQueue* InitQueue()
{
	LinkQueue* queue = (LinkQueue*)malloc(sizeof(LinkQueue));
	if (!queue)
	{
		printf("init queue error!\n");
		exit(0);
	}
	queue->front = (QueueNode*)malloc(sizeof(QueueNode));
	queue->front->next = NULL;
	queue->rear = queue->front;
	return queue;
}

/** 鏈佇列的銷燬,注意先進去的是佇列頭,後進去的是佇列尾 */
void DestoryQueue(LinkQueue* queue)
{
	while (queue->front)
	{
		queue->rear = queue->front->next;
		free(queue->front);
		queue->front = queue->rear;
	}
}

/** 入隊 */
void EnQueue(LinkQueue* queue, BiTreeNode* node)
{
	QueueNode* queueNode = (QueueNode*)malloc(sizeof(QueueNode));
	queueNode->data = node;
	queueNode->next = NULL;
	queue->rear->next = queueNode;
	queue->rear = queueNode;
}

/** 出隊 */
BiTreeNode* DeQueue(LinkQueue* queue)
{
	if (queue->front == queue->rear)//佇列為空
		return NULL;
	QueueNode* p = queue->front->next;
	BiTreeNode* node = p->data;
	queue->front = p;
	return node;
}

3、層序遍歷的主要程式碼

void LayerOrderBiTree(struct BiTreeNode* root)
{
	int curLayerCount = 0; //當前層中的節點數
	int nextLayerCount = 0; //下一層中的節點數
	struct Queue* queue = InitQueue();
	EnQueue(queue, root);
	curLayerCount++;
	struct BiTreeNode* p;
	while (p = DeQueue(queue))
	{
		curLayerCount--;
		printf("%c ", p->val);
		if (p->left)
		{
			EnQueue(queue, p->left);
			nextLayerCount++;
		}
		if (p->right)
		{
			EnQueue(queue, p->right);
			nextLayerCount++;
		}
		if (curLayerCount == 0)//一層已經遍歷完畢
		{
			curLayerCount = nextLayerCount;
			nextLayerCount = 0;
			printf("\n");
		}
	}
}


4、測試程式碼
#include<stdio.h>
#include <stdlib.h>
#include "Stack.h"

void printResult(char *msg, void(*p)(BiTreeNode*), BiTreeNode* node)
{
	printf("\n---------%s---------\n", msg);
	p(node);
	printf("\n---------%s---------\n", msg);
}

int main()
{
	printf("使用先序建立二叉樹,#表示空節點,請輸入二叉樹的資料:\n");
	BiTreeNode* root = CreateBinaryTree();

	printResult("層序遍歷", LayerOrderBiTree, root);

	return 0;
}
測試用的二叉樹如下圖:


程式碼執行結果如下圖:


下面記錄遇到的坑:

在實現佇列的出隊操作時,程式碼如下:


開始我的程式碼寫錯了,第46行寫成了QueueNode* p = queue->front,結果執行報錯,單步跟蹤後發現出隊不正確,後來檢查原來46行程式碼不對,原因是初始化佇列時,給對頭分配了記憶體空間,然後對頭跟隊尾都指向該空間,但是入隊的時候該空間是沒有用到的,就相當於建立單鏈表時帶了一個頭結點,如下圖所示:


所以出隊的時候,隊頭節點應該是queue->front->next,而不是queue->front!!!

------------------------------這裡是分割線-------------------------------

今天在網上看到一種遞迴輸出層序結果的方法,記錄如下,直接上所有程式碼:

#include<iostream>
#include<stdlib.h>
using namespace std;

typedef struct Node {
	char val;
	struct Node* left = NULL;
	struct Node* right = NULL;
}TreeNode, *Tree;

Tree createTree() {
	char c;
	cin >> c;
	if(c == '#') return NULL;
	Tree tree = (Tree)malloc(sizeof(Tree));
	tree->val = c;
	tree->left = createTree();
	tree->right = createTree();
	return tree;
} 

void preOrder(Tree tree) {
	TreeNode* p = tree;
	if(p) {
		cout << p->val << " ";
		preOrder(p->left);
		preOrder(p->right);
	}
}

//列印第level行的節點,有列印輸出則返回true,否則返回false 
bool printLevel(Tree tree, int level) {
	if(!tree || level < 0) {
		return false;
	}
	if(level == 0) {
		cout << tree->val << " ";
		return true;
	}
	return printLevel(tree->left, level - 1) + printLevel(tree->right, level - 1);
}

//層序遍歷,當某一行沒有列印時break掉迴圈 
void levelOrder(Tree tree) {
	for(int i = 0; ; i++) {
		if(!printLevel(tree, i)) {
			break;
		}
	}
}

int main()
{
	Tree tree = createTree();
	cout << "pre order: " << endl;
	preOrder(tree);
	cout << "\nlevel order: " << endl;
	levelOrder2(tree);
	return 0;
}
所用二叉樹為:



測試結果如下圖:


遞迴的程式碼比非遞迴簡單,但是複雜度可能就沒有非遞迴那麼低了

相關推薦

資料結構實驗-C語言-二叉樹的建立,前、中、後序遍歷的遞迴演算法和非遞迴演算法,求葉子結點數目,求二叉樹深度,判斷二叉樹是否相似,求二叉樹左右子互換,二叉樹層序遍歷的演算法,判斷二叉樹是否是完全二叉樹

1.實驗目的 熟練掌握二叉樹的二叉連結串列儲存結構的C語言實現。掌握二叉樹的基本操作-前序、中序、後序遍歷二叉樹的三種方法。瞭解非遞迴遍歷過程中“棧”的作用和狀態,而且能靈活運用遍歷演算法實現二叉樹的其它操作。 2.實驗內容 (1)二叉樹的二叉連結串列的建立 (2)二叉樹的前、中、後

c++寫法

void LevelOrder(struct node *root)//運用佇列(注意標頭檔案引用) {     queue<struct node*>q;     struct node *p = root;     if(p)     {         q

【LeetCode-面試算法經典-Java實現】【107-Binary Tree Level Order Traversal II(II)】

lin -m length ret itl pub util 實現類 markdown 【107-Binary Tree Level Order Traversal II(二叉樹層序遍歷II)】 【LeetCode-面試算法經典-Java實現】【全

node res queue pop left roo 實現 nod treenode 層序遍歷:用一個隊列保存當前結點的左右孩子以實現層序遍歷,因為先訪問的結點,其左右孩子結點也要先訪問 1 void LevelOrder(TreeNode* root,vector

(關鍵詞:////層次

二叉樹層序遍歷 實現 def levelOrder(self, root): if root is None: return [] res = [] queue = [root]

與獲取深度的應用

不同於中序、前序、和後續遍歷使用棧,層序遍歷使用的是佇列! 程式碼如下: void level_order(tree_pointer ptr){ int front = rear = 0; tree_pointer queue[MAX_QUEUE_SIZE];

LeetCode102

Given a binary tree, return the level order traversal of its nodes’ values. (ie, from left to right, level by level). For example: Given binary

[LeetCode] Binary Tree Level Order Traversal II

Given a binary tree, return the bottom-up level order traversal of its nodes' values. (ie, from left to right, level by level from leaf to root). For ex

[LeetCode] Binary Tree Level Order Traversal

Given a binary tree, return the level order traversal of its nodes' values. (ie, from left to right, level by level). For example:Given binary tree {3,9

劍指Offer——:把列印成多行(

對於二叉樹的最好的解決辦法就是遞迴。遍歷方法無外乎先序遍歷,中序遍歷,後序遍歷方法以及層序遍歷方法。這裡給大家安利一個關於樹的面試題的連結,博主walkinginthewind比較全面且詳細的介紹了二叉樹相關的面試題:對於層序遍歷,最好的方法就是用佇列記錄遍歷節點的值,按層列

Binary Tree Level Order Traversal(-儲存並返回結果集)

題目描述 Given a binary tree, return the level order traversal of its nodes’ values. (ie, from left to right, level by level). For example: Given

LeetCode | Binary Tree Level Order Traversal(

Given a binary tree, return the level order traversal of its nodes' values. (ie, from left to right, level by level). For example: Gi

LeetCode 199 Binary Tree Right Side View(

Given a binary tree, imagine yourself standing on therightside of it, return the values of the node

應用之Binary Tree Right Side View

Given a binary tree, imagine yourself standing on the right side of it, return the values of the nodes you can see ordered from top to b

LeetCode | Binary Tree Level Order Traversal II(II)

Given a binary tree, return the bottom-up level order traversal of its nodes' values. (ie, from left to right, level by level from leaf

BST/

利用佇列的FIFO特性來實現層序遍歷。 初始化:建立佇列q,root入隊。 只要佇列不為空:存隊首元素,把隊首元素pop出來,列印隊首元素。判斷它是否有左孩子,如果有,則左孩子入隊;判斷是否有右孩子,如果有,則右孩子入隊(先判斷左孩子再右孩子是因為這裡一層中

佇列實現

//基本資料結構 template<class T> struct BinaryTreeNode { T _data; BinaryTreeNode<T>* _left;

c++實現、前創建,遞歸非遞歸實現

log ios cst ack ret 出棧 隊列 結點 非遞歸實現 #include <iostream> #include <cstdio> #include <stdio.h> #include <string> #i

(非遞迴)演算法實現--C語言

今天繼續二叉樹的學習。 昨天寫了一遍二叉樹的先序遍歷(非遞迴)演算法,今天寫一下二叉樹的二叉樹的中序遍歷(非遞迴)演算法。中序遍歷的非遞迴演算法有兩種,但是個人覺得只要掌握一種就可以了,只要自己的邏輯清晰,會哪一種又有什麼關係呢~ 首先給出今天的二叉樹的示例圖: 程式碼如下:

(遞迴與非遞迴)演算法及C語言實現

二叉樹後序遍歷的實現思想是:從根節點出發,依次遍歷各節點的左右子樹,直到當前節點左右子樹遍歷完成後,才訪問該節點元素。 圖 1 二叉樹   如圖 1 中,對此二叉樹進行後序遍歷的操作過程為: 從根節點 1 開始,遍歷該節點的左子樹(以節點 2 為根節點); 遍歷節點 2 的左子樹(以節點 4 為根