二叉树的遍历(递归、非递归)
来源:互联网 发布:乌玛·瑟曼 知乎 编辑:程序博客网 时间:2024/06/16 11:10
二叉树遍历的基本概念
1、二叉树遍历原理:二叉树的遍历是指从根结点出发,按照某种次序依次访问所有结点,使得每个结点被访问一次且仅被访问一次。
2、二叉树遍历方法:
(1)前序遍历:若二叉树为空,则空操作返回,否则先访问根结点,然后前序遍历左子树,再前序遍历右子树。
(2)中序遍历:若树为空,则空操作返回,否则从根结点开始,中序遍历根结点的左子树,然后是访问根结点,最后中序遍历右子树。
(3)后序遍历:若树为空,则空操作返回,否则从左到右先叶子后结点的方式遍历访问左右子树,最后是访问根结点。
(4)层序遍历:若树为空,则空操作返回,否则从树的第一层,也就是根结点开始访问,从上而下逐层遍历,在同一层中,按从左到右的顺序对结点逐个访问。
二叉树遍历举例:
二叉树的前序遍历序列: ABCDEFGH
二叉树的中序遍历序列:CBEDFAGH
二叉树的后续遍历序列:CEFDBHGA
二叉树的层序遍历举例:ABGCDHEF
二叉树遍历算法
1、前序遍历算法
(1)递归算法
void PreOrder(BtNode *ptr){ if (NULL != ptr) { printf("%c ",ptr->data); PreOrder(ptr->leftChild); PreOrder(ptr->rightChild); }}
(2非递归算法
思路1:
对于任一结点pCur:
1)访问结点pCur,并将结点pCur入栈,结点pCur一直左走 ;
2)判断结点pCur的左孩子是否为空,若为空,则取栈顶结点并进行出栈操作,并将栈顶结点的右孩子置为当前的结点pCur,循环至 1);若不为空,则将P的左孩子置为当前的结点pCur;
3)直到pCur为NULL并且栈为空,则遍历结束。
void NicePreOrder(BtNode *ptr){ if (ptr == NULL) { return; } stack<BtNode *> stackTreeNodes; BtNode *pCur = ptr;//指向当前要访问的结点 while(pCur != NULL || !stackTreeNodes.empty()) { while(pCur != NULL)//一直往左走 { printf("%c ",pCur->data); stackTreeNodes.push(pCur); pCur = pCur->leftChild; } if(!stackTreeNodes.empty())//在出栈和访问栈顶元素之前要先检查是否为空 { pCur = stackTreeNodes.top();//pCur刚跳出上面的while循环时值为NULL 故要将其pucr当前的栈顶结点 stackTreeNodes.pop(); pCur = pCur->rightChild; } } }
思路2:
1)先判断树是否为空,若为空则返回空操作,否则将根结点入栈;
2)然后判断栈为不为空,不为空则访问栈顶元素并弹出栈顶元素;
3)判断右子树是否为空,不为空则将右子树根结点压入栈,再判断左子树是否为空,不为空则将左子树根结点压入栈,继续进行2)操作,直到栈为空为止。
void NicePerOrder(BtNode *ptr){ if(NULL == ptr) { return ; } Stack st; Init_Stack(&st); push(&st,ptr); while(!empty(&st)) { ptr = top(&st); pop(&st); printf("%c ",ptr->data); if(ptr->rightchild != NULL) push(&st,ptr->rightchild); if(ptr->leftchild != NULL) push(&st,ptr->leftchild); }}
2、中序遍历算法
(1)递归算法
void InOrder(BtNode *ptr){ if (ptr == NULL) { return; } InOrder(ptr->leftChild); printf("%c ",ptr->data); InOrder(ptr->rightChild);}
(2)非递归算法
思路1:
对于任一结点pCur:
1)将结点pCur入栈,结点pCur一直左走
2)判断结点pCur的左孩子是否为空,若为空,访问结点pCur,则取栈顶结点并进行出栈操作,并将栈顶结点的右孩子置为当前的结点pCur,循环至 1);若不为空,则将P的左孩子置为当前的结点pCur;
3)直到pCur为NULL并且栈为空,则遍历结束。
void NiceInOrder(BtNode *ptr){ if (ptr == NULL) { return; } stack<BtNode *> stackTreeNodes; BtNode *pCur = ptr;//指向当前子树的根结点 while(pCur != NULL || !stackTreeNodes.empty()) { while(pCur != NULL)//一直往左走 { stackTreeNodes.push(pCur); pCur = pCur->leftChild; } if(!stackTreeNodes.empty())//在出栈和访问栈顶元素之前要先检查是否为空 { pCur = stackTreeNodes.top();//pCur刚跳出上面的while循环时值为NULL 故要将其pucr当前的栈顶结点 printf("%c ",pCur->data); stackTreeNodes.pop(); pCur = pCur->rightChild; } } }
3、后序遍历算法
(1)递归算法
void PostOrder(BtNode *ptr){ if (ptr != NULL) { PostOrder(ptr->leftChild); PostOrder(ptr->rightChild); printf("%c ",ptr->data); }}
(2)非递归算法
思路1:
1)设立两个指针pCur (初始指向根结点),和preVisted(指向被访问结点),对于任一结点pCur,将其入栈;
2)然后沿其左子树一直往下搜索,直到搜索到没有左孩子的结点,此时该结点出现在栈顶,此时要判断此结点是否满足输出条件,即:当前结点的右孩子如果为空或者已经被访问,则访问当前结点 ,否则将pCur置为其右结点,直到pCur为NULL并且栈为空,则遍历结束。
void NicePostOrder(BtNode *ptr){ if(ptr == NULL) { return; } stack<BtNode *> stackTreeNodes; BtNode *pCur = ptr;//指向当前子树的根结点 BtNode *preVisted = NULL;//指向前一被访问的结点 while(pCur != NULL || !stackTreeNodes.empty()) { while(pCur != NULL)//一直向左走 { stackTreeNodes.push(pCur); pCur = pCur->leftChild; } if(!stackTreeNodes.empty())//在出栈和访问栈顶元素之前要先检查是否为空 { //pCur刚跳出上面的while循环时值为NULL,故要将pCur指向当前的栈顶结点 pCur = stackTreeNodes.top(); if(pCur->rightChild == NULL || pCur->rightChild==preVisted)//当前节点的右孩子如果为空或者已经被访问,则访问当前节点 { printf("%c ",pCur->data); stackTreeNodes.pop(); preVisted = pCur;//设置当前结点已被访问过 pCur = NULL;//防止当前结点又被压入栈中 } else//如果当前结点的右子结点存在且没被访问过 { pCur = pCur->rightChild; } } } }
思路2:
1)设立标记结点指针,以此来判断右子树是否已被访问过,先将根结点入栈;
2)然后沿其左子树一直往下搜索,直到搜索到没有左孩子的结点,此时该结点出现在栈顶,将该结点出栈,并判断该结点的右孩子是否为空或者已经被访问(即等于标记结点指针),若是则访问该结点 ,并将该结点指针赋值给标记结点,该结点指针置为空,否则将该结点重新压入栈顶,直到当前结点指针和栈都为空,则遍历结束。
void NicePastOrder(BtNode *ptr){ if(ptr == NULL) return ; Stack st; Init_Stack(&st); BtNode *tag = NULL; while(ptr != NULL || !empty(&st)) { while(ptr != NULL) { push(&st,ptr); ptr = ptr->leftchild; } ptr = top(&st); pop(&st); if(ptr->rightchild == NULL || ptr->rightchild == tag) { printf("%c ",ptr->data); tag = ptr; ptr = NULL; } else { push(&st,ptr); ptr = ptr->rightchild; } }}
4、层序遍历算法
思路:
1)先判断树是否为空,不为空则将根结点入队列;
2)然后判断队列是否为空,不为空则出队头元素,并访问此结点;
3)先判断当前结点左子树是否为空,不为空则将左孩子结点入队列,再判断当前结点的右子树是否为空,不为空则将右孩子结点入队列,继续进行2)操作,直到队列为空为止。
void LevelOrder(BtNode *ptr){ assert(ptr != NULL); queue<BtNode *> queueTreeNodes; queueTreeNodes.push(ptr); while(!queueTreeNodes.empty()) { BtNode *pNode=queueTreeNodes.front(); queueTreeNodes.pop(); printf("%c ",pNode->data); if(pNode->leftChild!=NULL) { queueTreeNodes.push(pNode->leftChild); } if(pNode->rightChild!=NULL) { queueTreeNodes.push(pNode->rightChild); } } }
- 二叉树的遍历(递归+非递归+层次遍历)
- 二叉树的递归,非递归遍历
- 二叉树的递归+非递归遍历
- 二叉树的递归非递归遍历
- 二叉树的遍历--递归+非递归
- 二叉树的递归、非递归遍历
- 二叉树的递归非递归遍历
- 二叉树遍历(递归,非递归)
- 二叉树的遍历(非递归)
- 二叉树的遍历(非递归)
- 二叉树的遍历(非递归)
- 二叉树的遍历(递归实现+非递归实现)
- 二叉树的三种遍历(递归+非递归)
- 二叉树的遍历(递归与非递归)
- 二叉树的遍历(递归 and 非递归)
- 二叉树的遍历(递归、非递归)
- 二叉树的遍历(递归、非递归) java
- 二叉树的遍历(递归+非递归)
- ArrayList
- 各国语言简写
- Yarn的JVM重用功能——uber
- 显著性检测(二)Spatio-temporal Saliency Detection Using Phase Spectrum of Quaternion Fourier Transform
- PC制做gif动图超简单教程
- 二叉树的遍历(递归、非递归)
- Linux中的crontab详解
- dhtmlxGrid Cell.getValue()获取带&字符数据问题
- [BZOJ1003][ZJOI2006]物流运输(最短路+dp)
- 机器学习实战【7】(SMO算法实现)
- hihocoder #1584 : Bounce(规律)
- set、env、export——Linux中的环境变量命令
- Spring学习笔记(五) --- 装配Bean之导入和混合配置
- Minimum (ACM-ICPC国际大学生程序设计竞赛北京赛区(2017)网络赛 题9)