145. 二叉树的后序遍历

第一次尝试

  给定一个二叉树,返回它的 后序 遍历。LeetCode链接

  • 方法:非递归法,递归的方法在我前面二叉树博客中写过,感兴趣的可以看看,这次主要是使用栈来完成遍历的过程,其实也就是相当于使用栈模拟递归;
  • 主要操作:①从根节点开始遍历,遍历最左路径,遇到的每一个节点都入栈;②直到左路为空,取栈顶元素并用临时变量保存,如果该节点可以访问并出栈,那么就访问出栈,如果该节点不能访问且出栈,那么就让 root 结点走到栈顶元素的右子树,接着执行第①步;判断是否可以访问出栈的条件是:该节点没有右子树或者右子树已访问完成;③直到结点为空且栈为空结束遍历。
    在这里插入图片描述
//使用这种方式来重命名数据类型,这样可以很方便的修改后续数据的数据类型,相当于#define的作用
typedef struct TreeNode* StackType;
//创建栈
typedef struct Stack {
    //使用指针指向一块动态开辟的内存
    StackType* _date;
    //表示栈中的有效数据,也代表了栈顶
    size_t _size;
    //表示栈的最大容量
    size_t _capacity;
}Stack;
//包含所有函数的声明
//栈初始化
void StackInit(Stack* s1);
//检查栈是否已满
void CheckCapacity(Stack* s1);
//进栈
void StackPush(Stack* s1, StackType val);
//出栈 
void StackPop(Stack* s1);
// 获取栈顶元素
StackType StackTop(Stack* s1);
// 检测栈是否为空,如果为空返回非零结果,如果不为空返回0
int StackEmpty(Stack* s1);
//栈初始化
void StackInit(Stack* s1) {
	//参数合法性检验
	if (s1 == NULL) {
		return;
	}
	s1->_date = NULL;
	s1->_capacity = s1->_size = 0;
}
//检查栈是否已满
void CheckCapacity(Stack* s1) {
	//该函数是在其他函数内部被调用的,所以就不用参数合法性检验了,因为前面已经检查过了
	//如果有效数据等于最大容量,那么需要增容
	if (s1->_capacity == s1->_size) {
		//每次以2倍的空间进行增容
		s1->_capacity = s1->_capacity == 0 ? 1 : 2 * s1->_capacity;
		//用realloc函数进行动态增容
		s1->_date = (StackType*)realloc(s1->_date, sizeof(StackType) * s1->_capacity);
	}
}
//进栈
void StackPush(Stack* s1, StackType val) {
	//参数合法性检验
	if (s1 == NULL) {
		return;
	}
	//检查容量是否够,不够的话就增容
	CheckCapacity(s1);
	s1->_date[s1->_size] = val;
	s1->_size++;
}
//出栈 
void StackPop(Stack* s1) {
	//参数合法性检验,如果没有数据就直接返回
	if (s1 == NULL || s1->_size == 0) {
		return;
	}
	//这是顺序表,所以不用像链表一样,删除一个数据就要释放一个空间,只需有效数据个数减一即可
	s1->_size--;
}
// 获取栈顶元素
StackType StackTop(Stack* s1) {
	//参数合法性检验不好做,因为不能以任何值作为出错的返回值,以后学了抛出异常就可解决
	return s1->_date[s1->_size - 1];
}
// 检测栈是否为空,如果为空返回非零结果,如果不为空返回0
int StackEmpty(Stack* s1) {
	//参数合法性检验
	if (s1 == NULL || s1->_size == 0) {
		return 1;
	}
	return 0;
}
//获取二叉树结点个数,以确定动态开辟的数组大小
int getSize(struct TreeNode* root){
    if(root == NULL){
        return 0;
    }
    return getSize(root->left) + getSize(root->right) + 1;
}
//将遍历结果保存在数组中,并且将参数中的 returnSize 赋值为数组大小
int* postorderTraversal(struct TreeNode* root, int* returnSize){
    //参数合法性检验
    if(root == NULL){
        *returnSize = 0;
        return NULL;
    }
    //创建栈
    Stack s;
    StackInit(&s);
    //获取二叉树大小
    int sz = getSize(root);
    //动态开辟数组,保存遍历结果
    int* ret = (int*)malloc(sizeof(int) * sz);
    int i = 0;
    //用来保存上一次访问的节点;作用是可以判断右子树是否访问过
    struct TreeNode* prve = NULL;
    //开始循环遍历
    while(root || !StackEmpty(&s)){
        //访问左子树,若果不为空,那么就将其入栈
        while(root){
            prve = root;
            StackPush(&s,root);
            root = root->left;
        }
        //设置临时变量保存栈顶元素
        struct TreeNode* top = StackTop(&s);
        //如果栈顶元素满足访问条件,那么就访问并出栈
        if(top->right == NULL || top->right == prve){
            ret[i++] = top->val;
            StackPop(&s);
            //更新变量
            prve = top;
        }
        //如果不能访问,那就继续遍历栈顶右子树
        else{
            root = top->right;
        }
    }
    //返回所需的值
    *returnSize = sz;
    return ret;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值