二叉树的遍历之广度优先遍历

 unbelievable😏,小吉我今天又又又更新了,最近更新的频率本人我非常喜欢。如果能做到日更那就好了(还没到睡觉的点又开始做梦了🌒🌒🌒……)
 接下来,就要开始我们今天的学习了,小小期待一下(额,谁学习还期待的啊~)。这篇blog主要讲解二叉树遍历中广度优先遍历。
 在学习广度优先遍历之前,(老规矩)先来认识一下什么是二叉树

二叉树的概述

二叉树的定义:二叉树中每个节点至多只有两个孩子(可以只有一个孩子或者是没有孩子),二叉树的起始节点称为根节点,没有子节点的节点称为叶子节点
二叉树的存储方式:树节点类和数组存储

 有可能有些小伙伴不知道树节点类,其实是非常简单的,小吉在这就不做过多的讲解,直接上代码

class TreeNode
{
public:
	TreeNode(int val):_val(val),_left(nullptr),_right(nullptr) {}//初始化列表

	TreeNode(int val, TreeNode* left, TreeNode* right)
	{
		this->_val = val;
		this->_left = left;
		this->_right = right;
	}
private:
	int _val;
	TreeNode* _left;
	TreeNode* _right;
};

 到这二叉树已经了解完了,接下来就来了解了解广度优先遍历

广度优先遍历

 广度优先遍历:尽可能先访问距离根节点最近的节点,也称之为层序遍历
广度优先遍历
 ⚠️⚠️⚠️注意:1.用队列来层序遍历是针对TreeNode这种方式表示的二叉树
2.如果用数组实现的二叉树,则直接遍历数组即可,自然为层序遍历

 下面,小吉重点给大家讲解一下用队列来层序遍历,还可以顺带复习一下队列的知识

队列层序遍历

二叉树广度优先遍历的算法思路:
1.初始化,将根节点加入队列
2.循环处理队列中每个节点,直至队列为空
3.每次循环内处理节点后,将它的孩子节点(即下一层的节点)加入到队列中

 现在思路也有了,可以进行代码的实现了,下面提供的代码中,队列是自己实现的,与标准队列不同之处是在删除队头操作时还返回了队头的值

👇这是代码中核心部分,实现层序遍历,并把结果打印到屏幕上
void test01()
{
	vector<int> v1;
	for (int i = 1; i <= 7; i++)
	{
		v1.push_back(i);
	}
	TreeNode* root = createBinaryTree(v1, 0);//创建根节点
	LinkedListQueue<TreeNode*> q;//创建队列
	q.myPush(root);
	int c1 = 1;//当前层的节点数
	while (!q.myIsEmpty())
	{
		int c2 = 0;//下一层的节点数
		for (int i = 0; i < c1; i++)
		{
			TreeNode* ret = q.myPop();
			cout << ret->m_Value << ' ';
			if (ret->m_Left != NULL)
			{
				q.myPush(ret->m_Left);
				c2++;
			}
			if (ret->m_Right != NULL)
			{
				q.myPush(ret->m_Right);
				c2++;
			}
		}
		cout << endl;
		c1 = c2;
	}
}
👇二叉树节点类
class TreeNode//二叉树节点类
{
public:
	TreeNode(int value)
	{//有参构造
		this->m_Value = value;
		m_Left = NULL;
		m_Right = NULL;
	}
public:
	int m_Value;
	TreeNode* m_Left;
	TreeNode* m_Right;
};
👇创建二叉树
TreeNode* createBinaryTree(const vector<int>& values,unsigned int index)//创建一个二叉树
{
	if (index >= values.size())
	{//递归的结束条件
		return NULL;
	}
	TreeNode* cur = new TreeNode(values[index]);//创建当前节点
	cur->m_Left = createBinaryTree(values, 2 * index + 1);//创建左子节点
	cur->m_Right = createBinaryTree(values, 2 * index + 2);//创建右子节点
	return cur;
}
👇自己实现的适用于泛型的队列(采用单向环形带哨兵链表实现)
template<class T>
class Node//节点类
{
	template<class E>friend class LinkedListQueue;//类模板声明友元
public:
	Node(T value, Node<T>* next)
	{//有参构造函数,给属性赋初值
		this->m_Value = value;
		this->m_Next = next;
	}
private:
	T m_Value;
	Node<T>* m_Next;
};

template <class T>
class LinkedListQueue//单向环形链表实现队列(没有容量限制)
{
private:
	//m_Head指向头节点
	Node<T>* m_Head = new Node<T>(NULL, NULL);//创建哨兵节点
	Node<T>* m_Tail = m_Head;//指向尾节点
public:
	LinkedListQueue()
	{//无参构造
		m_Tail->m_Next = m_Head;
	}


	bool myPush(T value)//向队列队尾中插入元素
	{
		Node<T>* added = new Node<T>(value, m_Head);
		m_Tail->m_Next = added;
		m_Tail = added;
		return true;
	}

	bool myIsEmpty()//判断队列是否为空
	{
		return m_Head == m_Tail;
	}
	T myPop()//从队头获取值并移除
	{
		if (this->myIsEmpty())
		{
			return NULL;
		}
		Node<T>* first = m_Head->m_Next;
		m_Head->m_Next = first->m_Next;
		if (m_Tail == first)
		{//当链表中只有一个节点时
			m_Tail = m_Head;
		}
		T ret = first->m_Value;
		delete first;//堆区开辟的数据要手动释放
		return ret;
	}

	~LinkedListQueue()//将堆区开辟的数据释放
	{//析构函数,删除链表中所有节点,哨兵置空保留
		while (m_Head->m_Next != m_Head)
		{
			Node<T>* toDelete = m_Head->m_Next;
			m_Head->m_Next = toDelete->m_Next;
			delete toDelete;
		}
		m_Head = NULL;
		m_Tail = NULL;
	}
};
结果预测

二叉树

实际结果

结果
 学习的时间总是短暂的,这篇blog到这里就已经全部结束了(完结撒花🎉🎉🎉)最后再浅浅预告一下,下一篇是讲二叉树的深度优先遍历,可以小小期待一下😘

创作不易,还望各位小可爱们多多支持(点赞收藏关注小吉❤️❤️❤️)

如有错,还望各位大佬们指点一下🌹🌹🌹

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值