相信大家对树的各种递归的遍历很了解,利用递归使得代码变得简单而且比较好理解,但是利用递归是需要代价的,特别是当递归层次比较深的时候,可能会导致递归栈溢出。而且递归一般运行速度比较慢,那么这种情况下,我们就可以采用非递归来实现,非递归相对递归来说,代码相对比较难理解,而且代码量也一般比较多,可是它的执行效率却是很不错的。
在树的中序非递归遍历中需要用到栈,在层次遍历中需要用到队列,非递归中序遍历的思想如下:
- 先设一个栈st和一个指向树根的指针pVal ,用pVal 指指向结点的m_pLeft(左孩子)并顺其而下直到pVal ==NULL跳出循环,在这一过程中把每个节点入栈,则此时的pVal 指向的是树的最左结点。
- 栈顶元素出栈以访问最左结点。(此步很重要,是为了实现按栈内元素的顺序后入先出访问结点访问最左结点的根结点。栈内元素逐一退栈即为中序遍历的元素顺序。)
- 访问最左结点的根结点。
- 由于将右子树理解为一个子树,对其的遍历也是采用中序遍历的方法,故将右子树的根结点理解为开始遍历树时的根结点,故可用语句pVal = pVal->m_pRight,则又开始了对一个树的遍历,pVal 指针又会走遍右子树的每一个结点。
非递归中序遍历的思想如下:
- 按层次遍历需要一个队列,开始将二叉树的头结点入队
- 然后每次从队列中删除一个节点并输出节点信息,接下来把它的非空
- 左右孩子入队,下一个输出的位它的右面堂兄弟或兄弟节点信息,在把它的
- 左右孩子入队,这两个孩子在上面两个孩子的后面(紧跟其后)
- 这样当队列为空时算法结束
算法实现:
#include <stdio.h> #include <stdlib.h> // Author: 过往记忆 // Email: wyphao.2007@163.com // Blog: // TreeNode ////////////////////////////////////////////////////////////////////////// typedef struct TreeNode { char m_cVal; TreeNode* m_pLeft; TreeNode* m_pRight; TreeNode(char cVal); ~TreeNode(); }; TreeNode::TreeNode(char cVal) { m_cVal = cVal; m_pLeft = 0; m_pRight = 0; } TreeNode::~TreeNode() { } //Stack ////////////////////////////////////////////////////////////////////////// class Stack { public: Stack(int iAmount = 10); ~Stack(); //return 1 means succeeded, 0 means failed. int Pop(TreeNode* &pVal); int Push(TreeNode* pVal); int Top(TreeNode* &pVal); //1 means not null, 0 means null. int NotNull(); private: TreeNode **m_ppData; int m_iCount; int m_iAmount; }; Stack::Stack(int iAmount) { m_ppData = new TreeNode*[iAmount]; m_iCount = 0; m_iAmount = iAmount; } Stack::~Stack() { delete m_ppData; } int Stack::Pop(TreeNode* &pVal) { if(m_iCount>0) { --m_iCount; pVal = m_ppData[m_iCount]; return 1; } return 0; } int Stack::Push(TreeNode* pVal) { if(m_iCount<m_iAmount) { m_ppData[m_iCount] = pVal; ++m_iCount; return 1; } return 0; } int Stack::Top(TreeNode* &pVal) { if(m_iCount>0 && m_iCount<=m_iAmount) { pVal = m_ppData[m_iCount-1]; return 1; } return 0; } int Stack::NotNull() { if(m_iCount!=0) return 1; return 0; } //Queue ////////////////////////////////////////////////////////////////////////// class Queue { public: Queue(int nMounts); ~Queue(); //operator int EnQueue(TreeNode *node); int DeQueue(TreeNode *&node); int IsFull(); int IsEmpty(); private: TreeNode **Q; int front; int rear; int totalNode; }; Queue::Queue(int nMounts = 10){ Q = new TreeNode*[nMounts]; totalNode = nMounts; rear = 0; front = 0; } Queue::~Queue(){ delete Q; } int Queue::EnQueue(TreeNode *node){ if(!IsFull()){ Q[rear] = node; rear = (rear + 1) % totalNode; }else{ //printf("Queue is full!\n"); return 0; } return 1; } int Queue::DeQueue(TreeNode *&node){ if(!IsEmpty()){ node = Q[front]; front = (front + 1) % totalNode; }else{ //printf("Queue is empty!\n"); return 0; } return 1; } int Queue::IsFull(){ if((rear + 1) % totalNode == front){ return 1; } return 0; } int Queue::IsEmpty(){ if(rear == front){ return 1; } return 0; } int main(int argc, char* argv[]) { TreeNode nA('A'); TreeNode nB('B'); TreeNode nC('C'); TreeNode nD('D'); TreeNode nE('E'); TreeNode nF('F'); TreeNode nG('G'); TreeNode nH('H'); TreeNode nI('I'); TreeNode nJ('J'); TreeNode nK('K'); TreeNode nL('L'); nA.m_pLeft = &nB; nA.m_pRight = &nC; nB.m_pRight = &nD; nD.m_pRight = &nG; nC.m_pLeft = &nE; nC.m_pRight = &nF; nF.m_pRight = &nH; nH.m_pLeft = &nI; nH.m_pRight = &nJ; nI.m_pLeft = &nK; nI.m_pRight = &nL; Stack st; //非递归中序遍历 TreeNode *pVal = &nA; int iPopped = 0; while(pVal!=0) { if(pVal->m_pLeft!=0 && iPopped==0) { st.Push(pVal); pVal = pVal->m_pLeft; iPopped = 0; } else if(pVal->m_pRight!=0) { printf("%c ", pVal->m_cVal); pVal = pVal->m_pRight; iPopped = 0; } else { printf("%c ", pVal->m_cVal); if(0==st.Pop(pVal)) break; iPopped = 1; } } printf("\n"); //层次遍历 pVal = &nA; Queue queue; while(pVal != NULL){ if(pVal->m_pLeft != NULL && pVal->m_pRight != NULL){ queue.EnQueue(pVal->m_pLeft); queue.EnQueue(pVal->m_pRight); }else if(pVal->m_pLeft != NULL){ queue.EnQueue(pVal->m_pLeft); }else if(pVal->m_pRight != NULL){ queue.EnQueue(pVal->m_pRight); } printf("%c ", pVal->m_cVal); if(0 == queue.DeQueue(pVal)){ break; } } printf("\n"); return 0; }本博客文章除特别声明,全部都是原创!
原创文章版权归过往记忆大数据(过往记忆)所有,未经许可不得转载。
本文链接: 【树的非递归中序和层次遍历实现】(https://www.iteblog.com/archives/189.html)