代码随想录训练营day13|二叉树理论基础,二叉树的递归,以及迭代

二叉树理论基础

深度:层数
满二叉树:全满,有2^(k-1)个节点。
完全二叉树:只有最下面一层没填慢,而且那一层从左往右有节点的地方连续。
二叉搜索树:
左子树上节点均小于根节点,右子树均大于。
平衡二叉搜索树:
AVL,左右深度差小于等于1.

存储方式

链式存储:左右两指针指向下一节点。
顺序存储:
第i个元素的左孩子是2i+1,右孩子2i+2.

遍历方式

深度优先遍历(前中后序)和广度优先遍历

构造

class Node{
private:
	int val;
	Node* left;
	Node* right;
public:
	Node(int x):val(x),left(NULL),right(NULL){};
	Node(int x,Node* l,Node* r):val(x),left(l),right(r){};
	

二叉树递归

把一个问题拆分为和它相似的子问题,就是递归的思想。
在这里插入图片描述
前序遍历:中左右
有一个函数可以实现这个树的遍历,先记录中节点,再记录它的左子树上的点,再记录它的右子树上的点。
而它的左子树也可以用这个函数来解决,只不过根节点变了而已。
而递归的边界(归)也就是当当前根节点为空的时候

void inorder(TreeNode* root,vector<int> &ans){
	if(root==NULL)
		return;
	ans.push_back(root->val);
	inorder(root->left,ans);
	inorder(root->right,ans);
}

前中后都一样,只不过改写记录根节点的位置。

二叉树迭代

二叉树最后为空的节点先return,这和栈中的后进先出一样,所以可以用栈来实现前中后。
前序:
定义一个stack<TreeNode* > nd;
然后先将根节点放进去,再弹出,如果不为空的话就记录,再先后将它的右子树和左子树加入(因为要先处理左子树)。
后序:
左右中,和前序中的位置刚好反着,如果在前序中先入左,变成中右左,然后reverse一下,就能得到后序。
中序:
先访问的中间结点,但要先处理左边节点,两者不统一,使得它无法像前序一样。
那么在使用迭代法写中序遍历,就需要借用指针的遍历来帮助访问节点,栈则用来处理节点上的元素。

 vector<int> inorderTraversal(TreeNode* root) {
        vector<int> ans;
        stack<TreeNode*> nd;
        TreeNode* cur=root;
        nd.push(cur);
        while(!nd.empty()){
        	cur=nd.top();
            while(cur!=NULL){
                nd.push(cur);
                cur=cur->left;
            }
            if(cur==NULL){
                nd.pop();
                cur=nd.top();
                ans.push_back(cur->val);
                nd.pop();
                nd.push(cur->right);
                
            }
        }
        return ans;

一开始写的时候我想的是即使是空指针也放入,然后再弹出就可以了,但是这样会在一些地方不断地进入根节点,然后向左边循环。
所以应该在空指针时直接处理stack中的节点。

 vector<int> ans;
stack<TreeNode*> nd;
TreeNode* cur=root;
while(!nd.empty()||cur!=NULL){
    while(cur!=NULL){
        nd.push(cur);
        cur=cur->left;
    }
    if(cur==NULL){
        cur=nd.top();
        ans.push_back(cur->val);
        nd.pop();
        cur=cur->right;//这样在cur==null时就能直接处理stack中的元素。
    }
}
return ans;

统一写法

不将空指针的结点加进入,但是用空指针将访问过但还没处理的节点标记出来,
这样到叶子结点时碰到NULL就先弹出NULL,然后cur=top(),处理根节点,再弹出,往回处理。
后序:

vector<int> postorderTraversal(TreeNode* root) {
        vector<int> ans;
        stack<TreeNode*> nd;
        if(root!=NULL)
            nd.push(root);
        while(!nd.empty()){
            TreeNode* cur=nd.top();
            if(cur!=NULL){
                nd.push(NULL);
                if(cur->right!=NULL)//不加入空结点
                    nd.push(cur->right);
                if(cur->left!=NULL)
                    nd.push(cur->left);
            }
            else{
                nd.pop();
                cur=nd.top();
                ans.push_back(cur->val);
                nd.pop();
            }
            
        }
        return ans;

层序遍历

也叫广度优先搜索,用队列来解决。

queue<Node*> dl;
if(root!=NULL){
	dl.push(root);
}

先将根结点加入队列中,
从队列中弹出队首(根节点),分别将其左右节点加入到队列末尾。

Node* cur=dl.front();
dl.pop();
if(cur->left!=NULL) dl.push(cur->left);
....

那可以在每一层开始前先用int size记录一下队列中的节点数,以防把下一层的节点也搞混。

  • 7
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值