标签:style blog http color os 文件
看到一个非递归交换一个二叉树的左右孩子的位置,于是想实现之,才发现非递归的先中后序遍历都忘记了……于是杂七杂八的写了一些,抄抄资料就实现了,然后实现非递归交换两个孩子的位置还是相当容易的。先直接上代码吧,其实这东西还是得自己写写过一遍的,印象才会更加深刻:
#include <iostream> #include <fstream> #include <string> #include <stack> using std::cout; using std::endl; using std::cin; using std::ifstream; using std::stack; class BTree { private: struct Node { Node* lChild; char data; Node* rChild; }; Node* m_pRoot; //pointer to tree root void addNode(ifstream& fin, Node** ppNode); void showNode(Node* pNode); //递归中序遍历 void switchLRChild(Node* pNode); public: explicit BTree(void) { m_pRoot = nullptr;} void create(void); void show(void); //这是中序遍历 void switchLR(void); void switchLR2(void); //非递归实现交换节点的左右孩子 void preOrder(void); //写着玩的非递归先序遍历 void inOrder(void); //写着玩的非递归中序遍历 void aftOrder(void); //写着玩的非递归后序遍历 }; void BTree::create(void) { ifstream fin("src.txt"); if(!fin) cout<<"can not open the file!\n"; addNode(fin, &m_pRoot); } void BTree::addNode(ifstream& fin, Node** ppNode) { /* 手工读取 cout<<"Input node‘s value, blank to end:"; char ch; cin.get(ch); if(ch == ‘\n‘) return; while(cin.get() != ‘\n‘) continue; (*ppNode) = new Node; (*ppNode)->data = ch; (*ppNode)->lChild = nullptr; (*ppNode)->rChild = nullptr; cout<<"add left child:"<<endl; addNode(&((*ppNode)->lChild)); cout<<"add right child:"<<endl; addNode(&((*ppNode)->rChild));*/ //文件读取 std::string temp; getline(fin, temp); //这个函数以换行为标志读取一行,但是会丢弃换行符 if(temp.empty()) return; (*ppNode) = new Node; (*ppNode)->data = temp[0]; (*ppNode)->lChild = nullptr; (*ppNode)->rChild = nullptr; addNode(fin, &((*ppNode)->lChild)); addNode(fin, &((*ppNode)->rChild)); } void BTree::show(void) { if(m_pRoot) { showNode(m_pRoot); cout<<endl; } else { cout<<"Empty tree!"<<endl; } } void BTree::showNode(Node* pNode) { if (pNode) { showNode(pNode->lChild); cout<<pNode->data<<" "; showNode(pNode->rChild); } else { return; } } void BTree::switchLR(void) { switchLRChild(m_pRoot); } void BTree::switchLRChild(Node* pNode) { if (pNode && (pNode->lChild != nullptr || pNode->rChild != nullptr)) { Node* temp = pNode->lChild; pNode->lChild = pNode->rChild; pNode->rChild = temp; switchLRChild(pNode->lChild); switchLRChild(pNode->rChild); } } void BTree::switchLR2(void) { struct BNode { Node* pToNode; bool isFirst; }; BNode p = {m_pRoot, true}; stack<BNode> myStack; while(p.pToNode || !myStack.empty()) { while(p.pToNode) { myStack.push(p); p.pToNode = p.pToNode->lChild; p.isFirst = true; //重置 } p = myStack.top(); myStack.pop(); if (p.isFirst) { p.isFirst = false; myStack.push(p); p.pToNode = p.pToNode->rChild; p.isFirst = true; } else //节点第二次在栈顶了,那么此时交换它的左右节点 { Node* temp = p.pToNode->lChild; p.pToNode->lChild = p.pToNode->rChild; p.pToNode->rChild = temp; p.pToNode = nullptr; } } /* 这个和非递归的后序遍历的原理一样:先直接沿着左侧一路向下,把遇到的每个节点都入栈,直到没有了。 然后呢对于栈顶的节点,如果它是第一个出现在栈顶,那么还没有对它的右子树进行处理,所以切换到它的右子树 进行同样的处理。当它的右子树处理完了之后这个节点再次出现在栈顶,这个时候就可以交换它的左右子树了, 并且它的左右子树都已经完成了交换,这不就是递归吗?只不过是循环实现的就是啦。 */ } void BTree::preOrder(void) { stack<Node*> myStack; Node* p = m_pRoot; while(p != nullptr || !myStack.empty()) { while(p != nullptr) //写的时候先写内层循环,再写外层循环 { cout<<p->data<<" "; //先访问数据 myStack.push(p); //指针入栈 p = p->lChild; //指向左孩子 } if (!myStack.empty()) //到这里指针p肯定是空了 { p = myStack.top(); //节点出现在栈顶时,此节点已经访问过,并且其左孩子也被访问过,只有其右孩子还没有 myStack.pop(); p = p->rChild; } } cout<<endl; } void BTree::inOrder(void) { stack<Node*> myStack; Node* p = m_pRoot; while(p || !myStack.empty()) //外层循环相当于实现了递归的作用 { while(p) { myStack.push(p); p = p->lChild; } if (!myStack.empty()) { p = myStack.top(); //节点出现在栈顶,则其左孩子已经被访问过,自己和右孩子都没有被访问过 myStack.pop(); cout<<p->data<<" "; //访问数据 p = p->rChild; //对右子树也用同样的方法,这不是递归的思想吗? } } cout<<endl; } void BTree::aftOrder(void) { struct BNode //这个结构体只多了一个是否是第一次访问的标志 { Node* pToNode; bool isFirst; }; BNode p; p.pToNode = m_pRoot; p.isFirst = true; stack<BNode> myStack; while(p.pToNode || !myStack.empty()) { while(p.pToNode) { myStack.push(p); p.pToNode = p.pToNode->lChild; p.isFirst = true; //注意这里每次切换的时候都要设置true或false,因为就那么一个变量,虽然放到栈里面都有true或false } if (!myStack.empty()) { p = myStack.top(); myStack.pop(); if (p.isFirst) //是第一次出现在栈顶 { p.isFirst = false; myStack.push(p); p.pToNode = p.pToNode->rChild; p.isFirst = true; } else //第二次出现在栈顶了 { cout<<p.pToNode->data<<" "; p.pToNode = nullptr; //这里其实就是让程序直接运行到下次出栈 } } } cout<<endl; /* 非递归后序遍历:先一直沿着左孩子向下,并把指向节点的指针入栈,直到不能继续向下了。 这个时候对于栈顶的节点,让它出栈,但我们还不能访问它,如果这个时候访问了那不就是中序遍历了吗? 也就是一个节点第一次出现在栈顶时不能访问它,这时要继续对它的右子树进行访问。 当结束了对它的右子树访问时,这个时候这个节点又出现在了栈的顶端,这个时候才可以访问它,这才是后序遍历。 */ } int main(void) { BTree myT; myT.create(); myT.show(); //myT.preOrder(); // myT.switchLR(); // myT.show(); //myT.inOrder(); //myT.aftOrder(); myT.switchLR2(); myT.show(); cin.get(); }
1 C 2 T 3 G 4 V 5 6 7 8 W 9 10 11 M 12 S 13 14 15 N
首先是实现它的非递归的三种遍历啦,这个都是抄袭别人的啦,见附。
二叉树非递归先中后序遍历 及 非递归交换二叉树两个孩子的位置,布布扣,bubuko.com
二叉树非递归先中后序遍历 及 非递归交换二叉树两个孩子的位置
标签:style blog http color os 文件
原文地址:http://www.cnblogs.com/jiayith/p/3863621.html