C语言 层序遍历二叉树(递归)

层序遍历意思就是按照从上往下,从左往右的顺序遍历二叉树的元素。
实现二叉树的层序遍历需要用到二叉树和队列。

总体思路:

  1. 判断当前队列是否为空
  2. 队列为空:结束。队列非空:取出队列第一个元素
  3. 将取出的元素的两个子节点依次入队
    C语言 层序遍历二叉树(递归)_第1张图片

用自定义的initQ函数创建一个空队列;

随后我们将二叉树的根节点(比如这里是3)放入队列,这里入队需要使用尾插法来满足队列的“先进先出”的规则;

判断当前队列是否为空,因为我们存入了3,所以现在队列是【3】,不为空,继续下一步;

取出头部第一个元素,也就是3,然后把3的两个子节点(9和20)放入队列,现在的队列是【9、20】

递归:判断队列是否为空,因为有9和20,所以不为空,取出第一个元素也就是9,把9的子节点入队,由于9的子节点都是NULL,所以现在队列是【20】

现在队列不为空,取出20,把20的子节点依次入队,队列变为【15,7】

取出15,存入15的子节点,队列变为【7】

取出7,存入7的子节点,队列为空,结束。

得到层序遍历结果:3,9,20,15,7

3个结构体:

  1. TreeNode:表示二叉树的节点,里面有数据data,指向左右孩子的指针left和right;
  2. QueueNode:表示队列的每个节点,有数据域data和指向下一个节点的指针next;
  3. Queue:表示一条队列,有front和rear,分别指向队列的头和尾。注意:队列包含了一个空的头结点。

5个函数:

  1. initQ:作用是创建一个队列。这个队列只有一个节点,这个节点没有存data,它的next是NULL;
  2. createTree:作用是创建一个二叉树。
    用递归方式创建一个二叉树,需要按照前序手动输入每个节点的元素。如果某个节点没有左右子节点,需要输入*表示NULL;
  3. enqueue:作用是把二叉树的元素取出放入队列。
    这个函数会让之前创建的空队列中新建一个节点接在之前空节点的后面,注意是用尾插法,新的节点是放在最后。新建节点之后把二叉树的元素放入刚刚建好的节点中。更新队列的rear,始终保持rear指向队列的最后一个节点。
    新建节点按照“先右后左”的顺序与其他节点连接,先把新节点的next(右一项)连到NULL,再把新节点的前驱的next连到新节点。
  4. dequeue:作用是删除队列第一个节点。
    要分类讨论,依据队列中节点的数量(不包括initQ建立的空的头结点)分类
    当队列中节点数量大于1时:front右移一位,释放队列中front移动之前节点的内存;
    当队列只有1个节点时:将rear向左移动一位,释放内存。
  5. LevelOrderBiTree:作用是层序输出。通过调用前面的函数实现层序输出,函数的思路就是层序输出整体的思路,写在了文章前面。

整体代码:

#include
#include
#include
//层序遍历二叉树
typedef struct TreeNode//树节点
{
     
	struct TreeNode* left,* right;
	char data;
}TreeNode, * pTreeNode;

typedef struct QueueNode//队列节点
{
     
	pTreeNode data;
	QueueNode* next;
}QueueNode, * pQueueNode;

typedef struct Queue//队列
{
     
	pQueueNode front,rear;
}Queue, * pQueue;

void createTree(pTreeNode& t)//创建树,&引用已经定义的t
{
     
	char ch;
	scanf_s("%c",&ch,sizeof(ch));
	if (ch == '*')//如果输入*则为空
	{
     
		t = NULL;
	}
	else
	{
     
		t = new TreeNode;
		t->data = ch;
		createTree(t->left);//递归
		createTree(t->right);
	}
}

pQueue initQ(pQueue pq)//建立只有头结点的队列
{
     
	pq->front = (pQueueNode)malloc(sizeof(QueueNode));
	if (pq->front==NULL)//判断内存分配是否成功
	{
     
		printf("内存分配不成功!");
	}
	else
	{
     
		pq->front->next = NULL;//队列的front和rear的next初始化为空
		pq->rear = pq->front;
		return pq;
	}
}

void enqueue(pQueue pq, pTreeNode t)//把二叉树的数据取出放入队列
{
     
	pQueueNode pNew = new QueueNode;
	pNew->data = t;//二叉树的数据存入队列
	pNew->next = NULL;
	pq->rear->next = pNew;//尾插法建立连接
	pq->rear = pNew;//rear更新
}

pTreeNode dequeue(pQueue pq)//出队:删除队列第一个元素
{
     
	pQueueNode pTemp= (pQueueNode)malloc(sizeof(QueueNode));
	pTemp = pq->front->next;
	if (pTemp->next == NULL)//只剩下1个节点(不含队列空的头结点)
	{
     
		pq->rear = pq->front;
	}
	else{
     
		pq->front->next = pTemp->next;//front+1(从指向第1个非空节点改为指向第2个节点)
	}
	pTreeNode x;
	x= pTemp->data;//x为队列第一个元素的data
	free(pTemp);
	return x;
}

void LevelOrderBiTree(pTreeNode t)//层序输出
{
     
	pQueue pq= (pQueue)malloc(sizeof(Queue));
	pq = initQ(pq);
	enqueue(pq,t);//取出二叉树的根节点,子节点存入队列
	while (pq->rear != pq->front)//当队列不为空
	{
     
		pTreeNode x = dequeue(pq);//x用于输出队列弹出元素的数据
		printf("%c", x->data);
		if (x->left!=NULL)
		{
     
			enqueue(pq, x->left);//递归左节点
		}
		if (x->right!=NULL)
		{
     
			enqueue(pq, x->right);//递归右节点
		}
	}
}
int main() 
{
     
	pTreeNode t;
	printf("请输入二叉树数据:");
	createTree(t); 
	printf("层序遍历如下:");
	LevelOrderBiTree(t);
	return 0;
}

你可能感兴趣的:(队列,二叉树,数据结构,算法)