文章目录
二叉树是最常用的树结构
一、二叉树的层次遍历
1、题目描述——LeetCode.102
给定一个二叉树,返回其按层次遍历的节点值。 (即逐层地,从左到右访问所有节点)。
给定二叉树: [3,9,20,null,null,15,7],
返回其层次遍历结果:
2、分析
- 从输出的结果来看,将根节点到叶子节点每层作为一个向量的二维向量中;
- 一般的遍历:将节点存储在队列中,每次从队首输出一个节点并将其左右子节点插入到队列中。
- 此题需要标记每层个数从而可以区分具体是哪层的节点==》nowcount、nextcount
3、实现
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode(int x) : val(x), left(NULL), right(NULL) {}
* };
*/
class Solution {
public:
vector<vector<int>> levelOrder(TreeNode* root) {
// 定义二维向量,存储结果
vector<vector<int>> res;
if(root == NULL)
return res;
// 定义队列 my_queue,存储需要访问的节点
queue<TreeNode*> my_queue;
my_queue.push(root);
TreeNode *temp;
vector<int> lev;
lev.push_back(root->val);
res.push_back(lev);
// nowcount 用于标记本层还有几个未遍历的节点
// nextcount 用于标记下一层的节点的个数
int nowcount = 1, nextcount = 0;
while(!my_queue.empty())
{
vector<int> lev;
while(nowcount > 0){
temp = my_queue.front();
if(temp->left != NULL){
my_queue.push(temp->left);
nextcount++;
lev.push_back(temp->left->val);
}
if(temp->right != NULL){
my_queue.push(temp->right);
nextcount++;
lev.push_back(temp->right->val);
}
my_queue.pop();
nowcount--;
}
if(!lev.empty())
res.push_back(lev);
nowcount = nextcount;
nextcount = 0;
}
return res;
}
};
二、二叉树(Binary Tree)
1、相关概念
二叉树
每个节点最多有两个子节点(左子结点、右子节点)。
满二叉树
叶子节点全都在最底层,除叶子节点外,每个结点都有左右两个子节点。
完全二叉树
叶子节点都在最底下两层,最后一层的叶子节点都靠左排列,并且除了最后一层,其他层的节点个数都要达到最大。
区分
2、二叉树的表示(存储)
两种存储方法:
①基于指针或引用的二叉链式存储法——常用
②基于数组的顺序存储方法。
(1)链式存储法
每个节点有三个字段,分别存储:数据、指向左右子节点的指针。
==》只要通过根节点,就可以通过左右节点的指针,将整棵树串起来。
(2)顺序存储法
一般情况下,为了方便计算子节点,根节点会存储在下标为 1 的位置。
- 将根节点存储在下标
i = 1
的位置,其左节点存储在下标2 * i = 2
的位置,右子节点存储在2 * i + 1 = 3
的位置。 - 依次类推:
- 若结点 X 存储在数组中下标为
i
的位置, - 其左节点下标:
2 * i
- 其右节点下标:
2 * i + 1
- 其父节点下标:
i / 2
- 若结点 X 存储在数组中下标为
(3)分析
若二叉树为完全二叉树,则数组存储是最节省内存的一种方式(不需要存储额外的左右子节点的指针)
3、二叉树遍历
(1)方法
三种方法:前序遍历、中序遍历、后序遍历
==》节点与它的左右子树节点遍历的先后顺序:中代表该节点,左代表其左子树,右代表其右子树。
- 前序遍历:中、左、右
- 中序遍历:左、中、右
- 后序遍历:左、右、中
- 前序遍历:abdefgc
- 中序遍历:debgfac
- 后序遍历:edgfbca
(2)实现
#include<iostream>
#include<string>
#include<stack>
#include<vector>
#include<queue>
using namespace std;
class BiNode{
public:
char data;
BiNode *lchild,*rchild;
};
// 对于二叉树来说,只需要存放指向树根节点的指针
class BiTree{
private:
BiNode * root;
int height;
void pre_Order(BiNode *t);
void in_Order(BiNode *t);
void post_Order(BiNode *t);
BiNode * create(string &s, int &ops);
void get_Height(BiNode *t, int h);
public:
BiTree()
{
root = NULL;
height = 0;
}
// 按照前序遍历序列创建二叉树
void createBiTree(string s);
// 前序遍历二叉树
void preOrder();
// 中序遍历二叉树
void inOrder();
// 后序遍历二叉树(递归方法)
void postOrder();
// 后序遍历二叉树(使用栈的非递归方法)
void postOrder1();
// 层序遍历二叉树
void levelOrder();
// 二叉树的高度
int getHeight();
// 求两个节点的最大公共祖先
void ancestor(char A, char B);
};
// 递归创建二叉树,如果是#表示空节点
// 应用字符串s创建二叉树
BiNode * BiTree::create(string &s, int &pos)
{
++pos;
BiNode *t;
if((unsigned)pos >= s.size())
return NULL;
else{
if(s[pos] == '#')
t = NULL;
else{
t = new BiNode;
t->data = s[pos];
t->lchild = create(s, pos);
t->rchild = create(s, pos);
}
return t;
}
}
// 按照前序遍历序列创建二叉树
void BiTree::createBiTree(string s){
int pos = -1;
root = create(s, pos);
}
// 前序遍历二叉树
void BiTree::preOrder(){
pre_Order(root);
cout<<endl;
}
void BiTree::pre_Order(BiNode *t){
if(t != NULL){
cout<<t->data<<" ";
pre_Order(t->lchild);
pre_Order(t->rchild);
}
}
// 中序遍历二叉树
void BiTree::inOrder(){
in_Order(root);
cout<<endl;
}
void BiTree::in_Order(BiNode *t){
if(t != NULL)
{
in_Order(t->lchild);
cout<<t->data<<" ";
in_Order(t->rchild);
}
}
// 后序遍历二叉树(递归方法)
void BiTree::postOrder()
{
post_Order(root);
cout<<endl;
}
void BiTree::post_Order(BiNode *t){
if(t != NULL)
{
post_Order(t->lchild);
post_Order(t->rchild);
cout<<t->data<<" ";
}
}
// 后序遍历二叉树(使用栈的非递归方法)
// 用r记录右子树是否遍历,若没有遍历,则遍历右子树
void BiTree::postOrder1(){
// p表示当前树节点指针
// r表示最近访问的树节点指针
BiNode *p, *r;
r = NULL;
p = root;
stack<BiNode*> my_stack;
while(p!=NULL || !my_stack.empty())
{
if(p)
{
// 一直走到树的最左边
my_stack.push(p);
p = p->lchild;
}
else
{
p = my_stack.top();
// 如果右子树没有遍历,遍历右子树
if(p->rchild != NULL && p->rchild != r)
{
p = p->rchild;
my_stack.push(p);
// 需要向左转,否则将会遍历右子树节点两边
p = p->lchild;
}
// 否则遍历根节点
else
{
p = my_stack.top();
my_stack.pop();
cout<<p->data<<" ";
// 更新最近遍历的节点
r = p;
// 将遍历后的节点设为NULL,进行下一个节点的遍历
p = NULL;
}
}
}
cout<<endl;
}
// 使用队列进行层序遍历二叉树
void BiTree::levelOrder()
{
if(root == NULL)
return;
queue<BiNode*> my_queue;
my_queue.push(root);
while(!my_queue.empty()){
BiNode *t;
t = my_queue.front();
my_queue.pop();
cout<<t->data<<" ";
if(t->lchild != NULL)
my_queue.push(t->lchild);
if(t->rchild != NULL)
my_queue.push(t->rchild);
}
cout<<endl;
}
int BiTree::getHeight()
{
get_Height(root,0);
return height;
}
void BiTree::get_Height(BiNode *t, int h)
{
if(t != NULL){
++h;
if(h > height)
height = h;
get_Height(t->lchild, h);
get_Height(t->rchild, h);
}
}
int main(int argc, char const *argv[])
{
BiTree a;
string s;
s = "ABD##E#F##C##";
a.createBiTree(s);
cout<<"前序遍历: "<<endl;
a.preOrder();
cout<<"中序遍历: "<<endl;
a.inOrder();
cout<<"后序遍历1: "<<endl;
a.postOrder();
cout<<"后序遍历2: "<<endl;
a.postOrder1();
cout<<"层序遍历: "<<endl;
a.levelOrder();
cout<<"树高:";
cout<<a.getHeight()<<endl;
return 0;
}