C语言强化(十一)二叉树镜像变化 | 要求:不使用递归
用了这么久的递归,现在不让用递归了,你行么?
通过这道题,你可以学会
- 如何镜像变化一棵二叉树
- 什么是递归的本质
- 如何巧妙地使用辅助栈
题目:
输入一颗二元查找树,将该树转换为它的镜像,
即在转换后的二元查找树中,左子树的结点都大于右子树的结点。
要求:
不使用递归
例如输入:
输出:
将二叉树镜像变化的方法很简单,只要把所有节点的左右节点对调就行了,使用递归可以非常容易的实现。
如下为递归方法实现镜像变化的函数
/** 二叉树镜像变化——递归方法实现 */ void Revertsetree_Recursion(BTreeNode *root) { if(!root) return; BTreeNode *p; p=root->leftNode; root->leftNode=root->rightNode; root->rightNode=p; if(root->leftNode) Revertsetree_Recursion(root->leftNode); if(root->rightNode) Revertsetree_Recursion(root->rightNode); }
现在问题来了,不使用递归,怎么办?
思路:
递归的本质是存储元素为函数的栈,
所以完成同样任务时最简单的办法就是用一个辅助栈来模拟递归,辅之以循环语句
- 首先,把树的头结点放入栈中
- 在循环中,只要栈不为空,弹出栈的栈顶结点,交换它的左右子树
- 如果它有左子树,把它的左子树压入栈中
- 如果它有右子树,把它的右子树压入栈中
- 在下次循环中交换它儿子结点的左右子树
如下为使用循环语句实现镜像变化的函数
/** 二叉树镜像变化——循环方法实现 */ void Revertsetree_Circle(BTreeNode *phead) { if(!phead) return; stack<BTreeNode*> stacklist; stacklist.push(phead); //首先把树的头结点放入栈中。 while(stacklist.size()) //在循环中,只要栈不为空,弹出栈的栈顶结点,交换它的左右子树 { BTreeNode* pnode=stacklist.top(); stacklist.pop(); BTreeNode *ptemp; ptemp=pnode->leftNode; pnode->leftNode=pnode->rightNode; pnode->rightNode=ptemp; if(pnode->leftNode) stacklist.push(pnode->leftNode); //若有左子树,把它的左子树压入栈中 if(pnode->rightNode) stacklist.push(pnode->rightNode); //若有右子树,把它的右子树压入栈中 } }
源代码
/** 题目: 输入一颗二元查找树,将该树转换为它的镜像, 即在转换后的二元查找树中,左子树的结点都大于右子树的结点。 要求: 不使用用递归 思路 把所有节点的左右节点对调 使用递归可以很简单的实现 由于递归的本质是编译器生成了一个函数调用的栈, 因此用循环来完成同样任务时最简单的办法就是用一个辅助栈来模拟递归 首先我们把树的头结点放入栈中。 在循环中,只要栈不为空,弹出栈的栈顶结点,交换它的左右子树。 如果它有左子树,把它的左子树压入栈中; 如果它有右子树,把它的右子树压入栈中。 这样在下次循环中就能交换它儿子结点的左右子树了 */ #include<stdlib.h> #include <iostream> #include<sstream> #include <vector> #include<stack> using namespace std; //创建二叉树结构体 struct BTreeNode{ int value; BTreeNode *leftNode; BTreeNode *rightNode; }; /* 二叉树构造函数 按照二叉排序的算法插入(左小右大) node 二叉树的根结点 value 要插入的结点的值 */ void insertToBTree(BTreeNode * &node,int value){ //结点为空,插入结点为根结点 if(NULL==node){ BTreeNode * btNode=new BTreeNode(); btNode->value=value; btNode->leftNode=NULL; btNode->leftNode=NULL; node=btNode; }else{//结点非空 //值小于根结点,递归左结点 if((node->value)>value) insertToBTree(node->leftNode,value); //值大于根结点,递归右结点 else if(value>(node->value)) insertToBTree(node->rightNode,value); //值与已有结点值相等,提示错误 else printf("结点已经存在,不可以再次插入!"); } } /* 前序遍历二叉排序树 btNode 二叉树根结点 */ void goThroughBTree(BTreeNode * btNode){ //结点为空,返回 if(NULL==btNode) return; cout<<btNode->value<<endl; //左结点不为空,继续向左深入 if(NULL!=btNode->leftNode) goThroughBTree(btNode->leftNode); //右不为空,向右深入 if(NULL!=btNode->rightNode){ goThroughBTree(btNode->rightNode); } } /** 二叉树镜像变化——递归方法实现 */ void Revertsetree_Recursion(BTreeNode *root) { if(!root) return; BTreeNode *p; p=root->leftNode; root->leftNode=root->rightNode; root->rightNode=p; if(root->leftNode) Revertsetree_Recursion(root->leftNode); if(root->rightNode) Revertsetree_Recursion(root->rightNode); } /** 二叉树镜像变化——循环方法实现 */ void Revertsetree_Circle(BTreeNode *phead) { if(!phead) return; stack<BTreeNode*> stacklist; stacklist.push(phead); //首先把树的头结点放入栈中。 while(stacklist.size()) //在循环中,只要栈不为空,弹出栈的栈顶结点,交换它的左右子树 { BTreeNode* pnode=stacklist.top(); stacklist.pop(); BTreeNode *ptemp; ptemp=pnode->leftNode; pnode->leftNode=pnode->rightNode; pnode->rightNode=ptemp; if(pnode->leftNode) stacklist.push(pnode->leftNode); //若有左子树,把它的左子树压入栈中 if(pnode->rightNode) stacklist.push(pnode->rightNode); //若有右子树,把它的右子树压入栈中 } } void main() { BTreeNode *root=NULL;//二叉树根结点 //创建二叉排序树 insertToBTree(root,8); insertToBTree(root,6); insertToBTree(root,10); insertToBTree(root,5); insertToBTree(root,7); insertToBTree(root,9); insertToBTree(root,11); //遍历二叉树 cout<<"原二叉树:"<<endl; goThroughBTree(root); //Revertsetree_Recursion(root); Revertsetree_Circle(root); cout<<"镜像二叉树:"<<endl; goThroughBTree(root); system("pause"); }
运行图
关于辅助栈的用法在C语言强化(二)设计可以求最小元素的栈有介绍过
此次再次使用,相信同学们会对它有更深理解体会。
总结
递归的本质是一个存储了函数的栈