用栈实现二叉树的非递归遍历与非递归实现快速排序的联系

目录

一、栈与递归的联系

二、二叉树的非递归遍历(前序)

1.  递归解决前序遍历的过程

2. 由递归复刻到非递归

3. 核心代码:144. 二叉树的前序遍历 - 力扣(Leetcode)

三、非递归实现快速排序

一、栈与递归的联系

在调用函数时内存中的栈会为函数开辟函数栈帧,由于栈顶为低地址,栈底为高地址,具体为栈指针寄存器%rsp减去一定大小的值(subq),函数结束再通过addq指令释放函数所开辟的空间,深入理解函数调用的底层实现很有利于我们理解如何用数据结构的栈来模拟递归过程。

递归实际上就是在栈区开辟函数栈帧,同一层递归在栈区上的空间是大概一致的。

所以我们可以用栈这一数据结构来实现一些规律较为明显的递归,同时需要注意栈先进后出的规则。

二、二叉树的非递归遍历(前序)

1.  递归解决前序遍历的过程

① 返回条件:当节点为空指针时返回;

② 处理顺序:前序遍历为中、左、右,所以先处理根节点,再依次递归左右节点;

2. 由递归复刻到非递归


① 返回条件:由与节点为空时返回,所以空节点没有必要加入栈中;最终栈里没有数据,即类似于%rsp回到函数调用前的位置,此时递归结束,循环也结束;

② 处理顺序:首先处理根节点,由于先进后出,先将右节点加入栈,再将左节点加入栈,接下来的下一次循环取栈顶元素,对应于进入下层递归;

3. 核心代码:144. 二叉树的前序遍历 - 力扣(Leetcode)

C语言:

int* preorderTraversal(struct TreeNode* root, int* returnSize){
    struct TreeNode* st[100];   
    int stTop = 0;
    int* res = (int*)malloc(sizeof(int)*100);
    int resTop = 0;
    
    st[stTop++] = root; 
    while(stTop){
        struct TreeNode* node = st[--stTop];
        if(node == NULL){
            continue;
        }
        res[resTop++] = node -> val;    //中
        st[stTop++] = node -> right;    //左
        st[stTop++] = node -> left;     //右
    }
    *returnSize = resTop;
    return res;
}

C++:

class Solution {
public:
    vector<int> preorderTraversal(TreeNode* root) {
        vector<int> res;
        if (root == nullptr) return res;

        stack<TreeNode*> st;
        st.push(root);
        while (!st.empty()) {
            TreeNode* tmp = st.top();
            st.pop();
            res.push_back(tmp->val);

            if (tmp->right != nullptr) st.push(tmp->right);
            if (tmp->left != nullptr) st.push(tmp->left);
        }

        return res;
    }
};

三、非递归实现快速排序

快速排序的三种方法以及递归与非递归在之前的文章中有讲解过,有兴趣的可以去简单阅读一下:

(2条消息) 【数据结构(三)】用C语言实现希尔、堆、快排、归并、三数找中、小区间优化——肝n小时图解进阶排序算法,不信你学不会_算法逻辑gif怎么制作_Dusong_的博客-CSDN博客

快速排序与二叉树的前序遍历有着非常大的相似之处,快速排序是将基准值排到最终位置,再递归左右区间,而二叉树是处理根节点再递归左右子树:

 根据这个相似之处,我们可以照搬非递归遍历二叉树的代码模板实现非递归快速排序:

C语言:

void QuickSortNonR(int* a, int left, int right) {
	int st[10000];
	int stTop = 0;
	st[stTop++] = right;
	st[stTop++] = left;

	while (stTop) {
		int begin = st[--stTop], end = st[--stTop];
		left = begin, right = end;   //保存区间的头尾的位置
		int keyi = begin;   

		while (begin < end) {
			while (begin < end && a[end] >= a[keyi]) end--;
			while (begin < end && a[begin] <= a[keyi]) begin++;
			 
			Swap(&a[begin], &a[end]);   
		}
		                                        
		Swap(&a[keyi], &a[begin]);   //“处理根节点”

		if (right - (begin + 1) > 0) {    //“递归左区间”
			st[stTop++] = right;
			st[stTop++] = begin + 1;
		}
		if ((begin - 1) - left > 0) {     //“递归右区间”
			st[stTop++] = begin - 1;
			st[stTop++] = left;
		}
	}
}

C++:

void QuickSortNonR(int* a, int left, int right) {
	stack<int> st;
	st.push(right);
	st.push(left);

	while (!st.empty()) {
		int begin = st.top();
		st.pop();
		int end = st.top();
		st.pop();
		left = begin, right = end;   //保存区间的头尾的位置
		int keyi = begin;   

		while (begin < end) {
			while (begin < end && a[end] >= a[keyi]) end--;
			while (begin < end && a[begin] <= a[keyi]) begin++;
			 
			Swap(&a[begin], &a[end]);   
		}
		                                        
		Swap(&a[keyi], &a[begin]);   //“处理根节点”

		if (right - (begin + 1) > 0) {    //“递归左区间”
			st.push(right);
			st.push(begin + 1);
		}
		if ((begin - 1) - left > 0) {     //“递归右区间”
			st.push(begin - 1);
			st.push(left);
		}
	}
}

  • 6
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Dusong_

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值