144. 二叉树的前序遍历

第一次尝试

  给你二叉树的根节点 root ,返回它节点值的 前序 遍历。LeetCode链接

  • 方法:非递归法,递归的方法在我前面二叉树博客中写过,感兴趣的可以看看,这次主要是使用栈来完成遍历的过程,其实也就是相当于使用栈模拟递归;
  • 主要思想是从头开始遍历二叉树,对于每一个节点,最先访问的是以此结点开始的最左路径,对于每一个树,最先访问的右子树,是在访问路径上最后遇到的右子树;
  • 主要做法为,①首先我们创建一个栈,然后访问每一个节点的最左路径,然后将访问的每一个节点入栈;②最左路径访问完成后,获取栈顶元素,然后继续访问以栈顶元素的右子树为根的子结构,继续执行第①步;③如果栈为空并且走到的节点为空,那么结束遍历;
    在这里插入图片描述
//使用这种方式来重命名数据类型,这样可以很方便的修改后续数据的数据类型,相当于#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* preorderTraversal(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;
    //开始循环遍历
    while(root || !StackEmpty(&s)){
        //只要存在左子树,那么就将其存入数组并保存在栈中
        while(root){
            ret[i++] = root->val;
            StackPush(&s,root);
            root = root->left;
        }
        //直到左子树为空,那么就取栈顶,开始遍历栈顶节点的右子树
        root = StackTop(&s);
        StackPop(&s);
        root = root->right;
    }
    //返回所需的值
    *returnSize = sz;
    return ret;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值