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到这里就已经全部结束了(完结撒花🎉🎉🎉)最后再浅浅预告一下,下一篇是讲二叉树的深度优先遍历,可以小小期待一下😘
创作不易,还望各位小可爱们多多支持(点赞收藏关注小吉❤️❤️❤️)
如有错,还望各位大佬们指点一下🌹🌹🌹