二叉树概念,定义,分类与性质
二叉树(binary tree)是一种非线性数据结构,代表“祖先”与“后代”之间的派生关系,体现了“一分为二”的分治逻辑。与链表类似,二叉树的基本单元是节点,每个节点包含值、左子节点引用和右子节点引用。
二叉树的定义:
struct TreeNode {
int val; // 节点值
TreeNode *left; // 左子节点指针
TreeNode *right; // 右子节点指针
TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
};
每个节点都有两个指针,一个指向左子节点,一个指向右子节点,这个节点被称作这两个子节点父节点
二叉树除了叶节点,其他节点都包含子节点与非空子树
下面是Hello算法的图片
二叉树的常见术语:
- 根节点(root node):位于二叉树顶层的节点,没有父节点。
- 叶节点(leaf node):没有子节点的节点,其两个指针均指向
None
。 - 边(edge):连接两个节点的线段,即节点引用(指针)。
- 节点所在的层(level):从顶至底递增,根节点所在层为 1 。
- 节点的度(degree):节点的子节点的数量。在二叉树中,度的取值范围是 0、1、2 。
- 二叉树的高度(height):从根节点到最远叶节点所经过的边的数量。
- 节点的深度(depth):从根节点到该节点所经过的边的数量。
- 节点的高度(height):从距离该节点最远的叶节点到该节点所经过的边的数量。
//以上引自hello算法
二叉树的初始化:
TreeNode* n1 = new TreeNode(1);
TreeNode* n2 = new TreeNode(2);
TreeNode* n3 = new TreeNode(3);
TreeNode* n4 = new TreeNode(4);
TreeNode* n5 = new TreeNode(5);
// 构建节点之间的引用(指针)
n1->left = n2;
n1->right = n3;
n2->left = n4;
n2->right = n5;
删除与插入节点:
/* 插入与删除节点 */
TreeNode* P = new TreeNode(0);
// 在 n1 -> n2 中间插入节点 P
n1->left = P;
P->left = n2;
// 删除节点 P
n1->left = n2;
常见的二叉树类型
完美二叉树:
所有层的节点都被完全填满,若树的高度为 ℎ ,则节点总数为 2的(ℎ+1)次方−1 ,呈现标准的指数级关系,反映了自然界中常见的细胞分裂现象。、
引自Hello算法的图片
完全二叉树:
只有最底层的节点未被填满,且最底层节点尽量靠左填充。
二叉树的迭代遍历(前中后)
图片理解:
代码:前
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode() : val(0), left(nullptr), right(nullptr) {}
* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
* TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
* };
*/
class Solution {
public:
void traversal(TreeNode *cur,vector<int> &vec)
{
if(cur==NULL)return;
vec.push_back(cur->val);
traversal(cur->left,vec);
traversal(cur->right,vec);
}
vector<int> preorderTraversal(TreeNode* root)
{
vector<int> dp;
traversal(root,dp);
return dp;
}
};
中:
class Solution {
public:
void traversal(TreeNode *cur,vector<int> &vec)
{
if(cur==NULL) return;
traversal(cur->left,vec);
vec.push_back(cur->val);
traversal(cur->right,vec);
}
vector<int> inorderTraversal(TreeNode* root) {
vector<int> vec;
traversal(root,vec);
return vec;
}
};
后
class Solution {
public:
void traversal(TreeNode *cur,vector<int> &vec)
{
if(cur==NULL) return;
traversal(cur->left,vec);
traversal(cur->right,vec);
vec.push_back(cur->val);
}
vector<int> inorderTraversal(TreeNode* root) {
vector<int> vec;
traversal(root,vec);
return vec;
}
};
二叉树的层序遍历(模板)
代码:(二维输出)
class Solution {
public:
vector<vector<int>> levelOrder(TreeNode* root) {
//写一个队列,用来对指针进行弹出等操作
queue<TreeNode*> que;
if(root!=NULL)que.push(root);
vector<vector<int>> result;
while(!que.empty()) {
int size=que.size();
vector<int> vec;
for(int i=0;i<size;i++) {
//写一个数指针来对树里的元素进行操作
TreeNode* cur=que.front();
//记忆后就可以弹出了
que.pop();
//放到容器中
vec.push_back(cur->val);
//向下递推,先放左边的。再放右边的,因为队列的性质就是先放入的先弹出
if(cur->left)que.push(cur->left);
if(cur->right)que.push(cur->right);
}
//放到结果容器中
result.push_back(vec);
}
return result;
}
};
代码(一维输出)
vector<int> levelOrder(TreeNode *root) {
// 初始化队列,加入根节点
queue<TreeNode *> queue;
queue.push(root);
// 初始化一个列表,用于保存遍历序列
vector<int> vec;
while (!queue.empty()) {
TreeNode *node = queue.front();
queue.pop(); // 队列出队,当为空的时候,就停止循环了,此时就意味着遍历完了所有的元素
vec.push_back(node->val); // 保存节点值
if (node->left != nullptr)
queue.push(node->left); // 左子节点入队
if (node->right != nullptr)
queue.push(node->right); // 右子节点入队
}
return vec;
}
/*新学二叉树,记得复习,多看看迭代遍历,理解理解,还有层序遍历(递归)思想很重要*/