二叉树基础(上):什么样的二叉树适合用数组来存储?
二叉树有哪几种存储方式?什么样的二叉树适合用数组来存储?
树(Tree)
每个元素就是一个节点,用来连线相邻节点之间的关系就是“父子关系”,没有父节点的节点是根结点,没有子节点的节点是叶节点
高度(Height):节点到叶子节点的最长路径(边数)
深度(Depth):根节点到这个节点所经历的边的个数
层数(level):节点的深度+1
树的高度 = 根节点的高度
即高度从下往上度量,深度是从上往下开始度量,层数的起点是1
二叉树(Binary Tree)
满二叉树和完全二叉树
如何存储一颗二叉树?
一种是基于指针或者引用的二叉链式存储法,一种是基于数组的顺序存储法
一:链式存储法,每个节点有三个字段,其中一个存储数据,另外两个是指向左右子节点的指针
二:基于数组的顺序存储法。把根节点存储在下标i=1的位置,左子节点存储在下标为 2 * i = 2 的位置,右子节点存储在2 * i +1 = 3 的位置,根节点的左子节点的的左子节点存储在 2 * i = 4 的位置,其右子节点存储在2 * i + 1 = 5的位置
总结是:节点X存储在数组中下标为i的位置,下标为2 * i的位置存储的是左子节点,下标为 2 * i +1存储的是右子节点,反过来下标为i / 2的位置存储的是其父节点,所以我们只要知道根节点存储的位置,可以通过下标计算,把整棵树串起来
堆和堆排序就是一种完全二叉树,存储方式就是数组
二叉树的遍历
前序遍历、中序遍历和后序遍历,前中后表示的是节点与它的左右子树节点遍历打印的先后顺序
前:对树中任意节点来说,先打印该节点,再打印它左子树,最后打印右子树
中:先打印其节点的左子树,再打印其节点,再打印其右子树
后:先打印左子树,再打印右子树,最后打印其节点
前中后遍历就是递归的过程,递推公式是:
前序遍历的递推公式:
preOrder(r) = print r->preOrder(r->left) ->preOrder(r->right)
中序遍历的递推公式:
inOrder(r) = inOrder(r->left) -> print r->inOder(r->right)
后序遍历的递推公式:
postOrder(r) = postOrder(r->left) ->postOrder(r->right) -> print r
代码为:
void preOrder(Node* root){
if(root == null) return;
print root;//为伪代码,表示打印root节点
preOrder(root->left);
preOrder(root->right);
}
void inOrder(Node* root){
if(root == null) return;
inOrder(root->left);
print root;//打印root节点
inOrder(root->right);
}
void postOrder(Node* root){
if(root == null) return;
postOrder(r->left);
postOrder(r->right);
print root;
}
每个节点最多会被访问两次,所以遍历操作的时间复杂度跟节点n成正比,即时间复杂度是O(n)
1.给定一组数据,1,3,5,6,9,10可以构建出多少种不同的二叉树?
(1)n个数,即n个节点,能构造出多少种不同形态的树
(2)n个数,有多少种不同的排列
(1)*(2)即为最终结果=n! 如果是完全二叉树,可以放在数组中,可以简化为数组中的元素有多少种组合方式
卡特兰数
2.如何实现按层遍历?
层序遍历,借助队列辅助即可,根节点先入队列,然后循环从队列中pop节点,将pop出来的节点的左子节点先入队列,右节点后入队列,依次循环,直到队列为空,遍历结束
vector<vector<int>> levelOrder(TreeNode* root){
vector<vector<int>> vecRes;
if(!root) return vecRes;
vector<int> vecTemp;
quene<TreeNode *> queneT1;
queneT1.push(root);
int nQueneSize = queneT1.size();
while(nQueneSize > 0 ){
for(int i = 0;i < nQueneSize;++i){
TreeNode * pQuene = queneT1.front();
vecTemp.push_back(pQuene->val);
queneT1.pop();
if(pQuene->left){
queneT1.push(pQuene->left);
}
if(pQuene->right){
queneT1.push(pQuene->right);
}
}
nQueneSize = queneT1.size();
vecRes.push_back(vecTemp);
vecTemp.clear();
}
return vecRes;
}