2 中序遍历对下面这棵树进行前序遍历。
采用递归思想,先遍历这个结点的数据,然后先序遍历左孩子,然后右孩子
//前序遍历 void preOrder(BiTree p) { if (p != NULL) { putchar(p->data);//等价于visit函数 preOrder(p->lchild); preOrder(p->rchild); } }
3 后序遍历对下面这棵树进行中序遍历。
采用递归思想,先 先序遍历这个结点的左孩子,然后遍历结点的数据,然后先序遍历这个结点的右孩子
//中序遍历 void InOrder(BiTree p) { if (p != NULL) { InOrder(p->lchild); putchar(p->data); InOrder(p->rchild); } }
4 中序遍历非递归对下面这棵树进行后序遍历。
采用递归思想,先 后序遍历这个结点的左孩子,然后 后序遍历这个结点的右孩子,最后遍历这个结点的数据
//后序遍历 void PostOrder(BiTree p) { if (NULL != p) { PostOrder(p->lchild); PostOrder(p->rchild); putchar(p->data); } }
(1) 原理步骤在考研中考察的几率不大。如果大题考察这个问题难度会很大;小题考察这个问题分值有可能会很高
非递归执行效率高
在这个实现过程中需要使用栈的数据结构点击查看栈相关笔记。
- 构建一个栈 S ,用来接收树的结点。前提是已经层序建好了一棵树
- 每次遍历之前都要从树根开始,用一个新的变量 p 来接收树根的地址(后续会接收其他树结点的地址)。判断p存在或者栈s不为空即可继续。此时栈为空,但是树根存在所以p就存在,所以继续。
- 如果P存在,就将p压入栈s中,然后p指向自己的左孩子。
- 重复第2步的判断。判断p存在或者栈s不为空即可继续。此时,P既存在、栈S又不为空,继续。因为P存在,所以将P压入栈S中,然后P指向自己的左孩子
- 重复第2步的判断。判断p存在或者栈s不为空即可继续。此时,P既存在、栈S又不为空,继续。因为P存在,所以将P压入栈S中,然后P指向自己的左孩子
重复第2步的判断。判断p存在或者栈s不为空即可继续。此时,P不存在,但是栈S不为空,继续。
因为这里p不存在,执行的操作是:栈S执行出栈操作(这里可以加上控制台输出操作),并且将出栈元素赋值给p
- p指向自己的右孩子。
重复第2步的判断。判断p存在或者栈s不为空即可继续。此时,P不存在,但是栈S不为空,继续。
因为这里p不存在,执行的操作是:栈S执行出栈操作(这里可以加上控制台输出操作),并且将出栈元素赋值给p
- p指向自己的右孩子。
- 重复第2步的判断。判断p存在或者栈s不为空即可继续。此时,P既存在、栈S又不为空,继续。因为P存在,所以将P压入栈S中,然后P指向自己的左孩子
重复第2步的判断。判断p存在或者栈s不为空即可继续。此时,P不存在,但是栈S不为空,继续。
因为这里p不存在,执行的操作是:栈S执行出栈操作(这里可以加上控制台输出操作),并且将出栈元素赋值给p
- p指向自己的右孩子。
重复第2步的判断。判断p存在或者栈s不为空即可继续。此时,P不存在,但是栈S不为空,继续。
因为这里p不存在,执行的操作是:栈S执行出栈操作(这里可以加上控制台输出操作),并且将出栈元素赋值给p
- p指向自己的右孩子。
重复第2步的判断。判断p存在或者栈s不为空即可继续。此时,虽然栈S是空的,但是P存在,所以继续。
因为P存在,所以将P压入栈S中,然后P指向自己的左孩子。
(2) 代码实现
- 重复上面的操作即可得到最终的队列为:dbeafcg
#include5 层序遍历(广度遍历)using namespace std; //构建树的结构 typedef char BiElemType; typedef struct BiTNode { BiElemType data; BiTNode* lchild;//树的左孩子结点 BiTNode* rchild;//树的右孩子结点 }BiTNode,*BiTree; //栈的相关数据结构 #define MaxSize 50 typedef BiTree ElemType; typedef struct SqStack { ElemType data[MaxSize]; int top; }; void InitStack(SqStack& S) { S.top = -1; } bool Push(SqStack& S, ElemType e) { if (S.top == MaxSize - 1) { return false; } S.top++; S.data[S.top] = e; return true; } bool Pop(SqStack& S, ElemType& x) { if (S.top == -1) { return false; } x = S.data[S.top]; S.top--; return true; } bool GetTop(SqStack S, ElemType& x) { if (S.top == -1) { return false; } x = S.data[S.top]; return true; } bool StackEmpty(SqStack S) { if (S.top == -1) { return true; } return false; } //中序遍历非递归 void InOrder2(BiTree T) {//传入的参数是树根的地址 SqStack S; InitStack(S); BiTree p = T;//用一个遍历的变量p,先等于树根 while (p || !StackEmpty(S)) { if (p) { //不断压栈的过程找到了最左边的左孩子 Push(S, p); p = p->lchild; } else { Pop(S, p); putchar(p->data); p = p->rchild; } } }
- 在建好一棵树的前提下,需要建一个辅助队列Q
- 用一个变量 p 来进行遍历,遍历到谁谁就入队。从树根开始遍历。所以树根入队
判断队列是否为空。空就结束,不空的话执行出队操作(也就是第一个结点),然后让p指向出队的结点。p指向的结点左孩子是否为空,不空的话左孩子入队,空的话跳过。然后判断p指向的右孩子是否为空,不空的话右孩子入队,空的话跳过。然后p指向的结点出队
在这个例子里。a是第一个结点,出队,p指向a,a的左右孩子都存在,所以按顺序入队。随后a出队
- 重复第3步进行判断,直至队列为空
#includeusing namespace std; //构建树的结构 typedef char BiElemType; typedef struct BiTNode { BiElemType data; BiTNode* lchild;//树的左孩子结点 BiTNode* rchild;//树的右孩子结点 }BiTNode, * BiTree; //辅助队列结构体 typedef struct tag { BiTree p; tag* pnext; }tag_t, * ptag_t; #define MaxSize 50 typedef BiTree ElemType; //定义结点结构体 struct LinkNode { ElemType data; LinkNode* next; }; //定义队列结构体 struct LinkQueue { LinkNode* front;//链表头 LinkNode* rear;//链表尾 }; //初始化 void InitQueue(LinkQueue& Q) { Q.front = Q.rear = (LinkNode*)malloc(sizeof(LinkNode));//头和尾指向同一个结点 Q.front->next = NULL; } //入队 尾插法 void EnQueue(LinkQueue& Q, ElemType x) { LinkNode* s = (LinkNode*)malloc(sizeof(LinkNode)); s->data = x; s->next = NULL; //开始尾插,尾指针的下一个结点指向s Q.rear->next = s; //再让尾指针指向s Q.rear = s; } //出队 头部删除法 bool DeQueue(LinkQueue& Q, ElemType& x) { //判断是不是空的队列 if (Q.front == Q.rear) { return false; } LinkNode* p = Q.front->next;//front是头指针,没有数据,下一个结点才是有数据的第一个结点 x = p->data;//获取到要删除的元素的数据值 Q.front->next = p->next;//断链 //判断删除的是不是最后一个元素 if (p == Q.rear) { Q.front = Q.rear; } //释放p free(p); return true; } bool IsEmpty(LinkQueue Q) { if (Q.front == Q.rear) { return true; } return false; } //层次遍历,层序遍历,广度优先遍历 void LevelOrder(BiTree T) { LinkQueue Q;//辅助队列 InitQueue(Q);//初始化队列 BiTree p; EnQueue(Q, T); while (!IsEmpty(Q)) { DeQueue(Q, p); putchar(p->data); if (p->lchild != NULL) { EnQueue(Q, p->lchild); } if (p->rchild != NULL) { EnQueue(Q, p->rchild); } } } int main() { BiTree pnew;//用来接收新加入的树的结点 int i, j, pos; char c;//新加入树的数据 BiTree tree = NULL;//树根 ptag_t phead = NULL, ptail = NULL;//辅助队列的 队列头 队列尾 ptag_t listpnew, pcur;//辅助队列 和 遍历队列的指针,pcur始终指向要插入的结点 //输入abcdefghij cout << "输入建树的元素:" << endl; while (scanf("%c", &c) != EOF) { if (c == 'n') { break; } pnew = (BiTree)calloc(1, sizeof(BiTNode)); pnew->data = c; listpnew = (ptag_t)calloc(1, sizeof(tag_t));//给辅助队列结点申请空间 listpnew->p = pnew; if (NULL == tree) {//树根是空的 tree = pnew;//树的根 phead = listpnew;//队列头 ptail = listpnew;//队列尾 pcur = listpnew; continue; } else { ptail->pnext = listpnew;//新结点放入队列,通过尾插法 ptail = listpnew;//ptail 指向队列尾部 } //如何把新结点放入树中 if (NULL == pcur->p->lchild) {//如果遍历指针指向的结点的左孩子是空的 pcur->p->lchild = pnew;//让 新的结点 赋值给 遍历指针所在的结点 的 左孩子 } else if (NULL == pcur->p->rchild) { pcur->p->rchild = pnew; pcur = pcur->pnext;//该结点右孩子也有数据了,证明该结点满了,遍历指针指向队列中的下一个结点 } } cout << "层序遍历:" << endl; LevelOrder(tree); cout << endl; }
点击获取项目文件
暑期编程PK赛 得CSDN机械键盘等精美礼品!


