层遍历:从上到下、从左到右,如图所示:
图示为举例进行层遍历顺序
以上图为例,进行分析用栈还是队列?
- 如果用栈: 先进后出,想要输出顺序为先出左孩子后出右孩子的话,需要先进右后进左。
入栈顺序:根 右 左 //必须通过根节点去保存左右孩子
出栈:栈顶元素 //也就是后面入进来的先出
- 举例上面的树图进行思路演绎:
入栈:a
出:a
入:c b
出:b
入:c e d
那么问题来了:此时应该遍历c 但是c被压在栈底出不来,只能先访问d和e,所以无法用栈进行层次遍历,只能用队列进行遍历
- 队:判断队列是否为空,不为空时出队顺序为先出队头
入队顺序:根节点、左孩子、右孩子
出队顺序:出队头元素
- 步骤:
① 将根节点入队
② 判断树是否为空,不为空,则队头元素进行入出队
③ 将刚出队元素的左右孩子进行入队
④ 将①②③循环,直至队列为空时,停止
- 举例上面的树图进行思路演绎:
(说明:灰色字母是已经出队元素,下划线代表目前队尾元素,蓝色是刚入队元素)
入队:a //首先判断树是否为空,不为空,则入树根a
出队:a //队头元素
入:a b c //先入a的左孩子b,再入a的右孩子c
出:b //队头元素
入:a b c d e //c还未出队所以还在,然后入b的左右孩子de
出:c //队头元素
入:a b c d e f g //de还未出队所以还在,然后入c的左右孩子fg
出:d e f //出队头元素d,d无左右孩子,继续出队头元素e,e无左右孩子,继续出队头元素f
入: g h //入f的左右孩子gh
出:g h //出队头元素g,g无左右孩子,继续出队头元素h
此时数组为空,说明入队的数据均已出队,所有节点访问完毕
伪代码:
代码:
typedef struct node
{
char value;//当前节点值
struct node* left;//指向当前节点左孩子指针
struct node* right;//指向当前节点右孩子指针
}Node;
//层次遍历
void LevOrder(Node* root)
{
queue<Node*> qq;//定义队列qq,存储指向每个结点的指针
if(root == NULL)
{
return;
}
Node* front = NULL;//定义指向队头的指针
qq.push(root);//将根节点入队
while(!qq.empty())
{
front = qq.front();//先获取队头,才能在出队后访问其左右孩子
qq.pop();//队头出队
printf("%c", front->value);//输出队头的value
//将当前front的左右孩子入队
if (front->left != NULL)
qq.push(front->left);
//不用输出左右孩子,因为pop出队头后,左右孩子会成为新对头,每次只用输出队头元素
if(front->right != NULL)
qq.push(front->right);
}
printf("%\n");
}
完整代码:
typedef struct node
{
char value;//当前节点值
struct node* left;//指向当前节点左孩子指针
struct node* right;//指向当前节点右孩子指针
}Node;
typedef struct tree
{
Node* root;
}Tree;
void InitTree(Tree* t)
{
t->root = NULL;
}
//先序遍历创建二叉树
Node* Create(const char*& str) //因为要修改字符串就加了引用&
{
if (*str == '*')
return NULL;
else
{
Node* newnode = (Node*)malloc(sizeof(Node));
if (newnode != NULL)
{
newnode->value = *str;
newnode->left = Create(++str);
newnode->right = Create(++str);
return newnode;
}
}
}
//层次遍历
void LevOrder(Node* root)
{
queue<Node*> qq;//定义队列qq,存储指向每个结点的指针
if(root == NULL)
{
return;
}
Node* front = NULL;//定义指向队头的指针
qq.push(root);//将根节点入队
while(!qq.empty())
{
front = qq.front();//先获取队头,才能在出队后访问其左右孩子
qq.pop();//队头出队
printf("%c", front->value);//输出队头的value
//将当前front的左右孩子入队
if (front->left != NULL)
qq.push(front->left);
//不用输出左右孩子,因为pop出队头后,左右孩子会成为新对头,每次只用输出队头元素
if(front->right != NULL)
qq.push(front->right);
}
printf("\n");
}
int main()
{
Tree t;
InitTree(&t);
const char* str = "ABDG**HI****CE*J**F**";
t.root = Create(str);
printf("层次遍历二叉树:\n");
LevOrder(t.root);
printf("\n");
}
说明:上图代码的创建二叉树的思想:创建二叉树
运行结果: