
题目:
设计一个算法实现二叉树的三种遍历(前序遍历中序遍历后序遍历)。
要求时间复杂度为O(n)空间复杂度为O(1)。
思路:
循环双链表的构造源自双链表,即将终端结点的nnext指针指向链表中第一个结点,将链表中第一个结点的prior指针指向终端结点。malloc返回的指针指向堆中内存,系统中有一个记录空闲内存地址的链表,当有申请请求时,就会遍历链表,寻找第一个空间大于所申请空间的堆结点,然后将该结点从链表中删除,并返回该结点的地址。循环双链表终端结点的next指针指向表头结点,头结点的prior指针指向表尾结点。
/*初始化的时候前驱结点指向头结点,要删除节点指向第一个非头结点的节点即使是空指针(即链表除了头结点没有任何元素)*/。指针后移找到指定位置的前一个节点(n-1)后,将其指针域指向要插入元素的结点(n),然后将插入元素的指针指向下一元素(n+1).。因为题目中已经告知随机指针只会指向链表中的节点或者是空节点,对于这一特性,每次在建立新节点时,将新节点插入到旧链表中相应的节点后面,如旧链表1→2->3→4,在遍历和插入之后就会变成1->1'->2->2'->3->3'->4->4'。
只要将单链表的最后一个指针域(空指针)指向链表中第一个结点即可(这里之所以说第一个结点而不说是头结点是因为,如果循环单链表是带头结点的则最后一个结点的指针域要指向头结点。循环双链表的构造源自双链表,即将终端结点的nnext指针指向链表中第一个结点,将链表中第一个结点的prior指针指向终端结点。(2)、输出单循环链表模块:先判断表是否为空,若不空则输出结点信息,同时指针向后移,指向下一结点,继续输出直到指针再次指向头结点为止,输出完毕。
空闲指针的分配规则如下:
供选择的答案: a:①是特殊的树②不是树的特殊形式③是两棵树的总称④是只有二个根结点的树形结构 b:①左子结点②右子结点③左子结点或者没有右子结点 ④兄弟 c~d: ①最左子结点②最右子结点③最邻近的右兄弟④最邻近的左兄弟⑤最左的兄弟⑥最右的兄弟e:①o(n)②o(n)③o(log2n)④o(log2n) 15、每一棵树都能唯一地转换为它所对应的二叉树,树的这种二叉树表示对树的运算带来很大的好处。按左下键按一次切换一个功能.按住左上不动约三秒,指针转动(不 转按住右下.按右下不动.按一下左下键夏令时dst关闭状态,直到 确认时间及年月日正确,按右上三 下是bjs或bkg,手表显示tyo在闪烁.看小指针指向是不是指到 50(不对按右下一下一下按到) 3,按左上退出,按右下停(如果过了或者是少了按右上或下一下一下加 或减)5。还是对于双向循环链表,要在连续的三个结点s,p,q中删除p结点,只需把s的右链域指针指向q,q的左链域指针指向s,并收回p结点就完成了。
2.从node结点开始通过每个结点的右指针进行移动,并打印结点的值。
假设遍历到的当前结点为curNode,做如下判断:
curNode结点的左子树中最右结点(记为lastRNode)是否指向curNode。
A.是让lastRNode结点的右指针指向null,打印curNode的值。接着通过curNode的右指针遍历下一个结点,重复步骤2。
B.否将curNode为头结点的子树重复步骤1。
下面举例说明上述步骤(先以中序遍历为例),二叉树结构如下图所示:


遍历至结点1发现其没有左子树记为Node。
curNode:1打印1
curNode:2满足A空闲指针由1的右指针指向2将该空闲指针取消掉打印2。通过2的右指针遍历到3。
curNode:3满足B进行步骤1最终打印3。
通过空闲指针遍历至4。
curNode:4满足A空闲指针由3的右指针指向4将该空闲指针取消掉打印4。通过4的右指针遍历到6。
至此左子树和根结点遍历完毕。
curNode:6满足B进行步骤1之后二叉树变为右图。
遍历至结点5其没有左子树记为Node。
curNode:5满足B进行步骤1最终打印5。
通过空闲指针遍历至6。
curNode:6满足A空闲指针由5的右指针指向6将该空闲指针取消掉打印6。
通过6的右指针遍历到7。
curNode:7满足B进行步骤1最终打印7。
3.步骤2最终移动到null结点整个过程结束。
总结:
打印某个结点时,一定是在步骤2开始移动的过程中。
步骤2最开始从子树最左结点开始,在通过右指针移动过程中,只有以下两种移动方式:
①移动到某个结点的右子树【此时左子树和根结点必定已经打印结束】
②移动到某个上层结点(即通过空闲指针移动)【此时该上层结点的左子树整体打印完毕开始处理根结点】
Morris先序遍历只需要将打印顺序稍微调整一下(调整至步骤1中打印)。
Morris后序遍历同样是需要将打印顺序稍微调整一下,即:逆序打印(不能使用额外的数据结构)所有结点的左子树右边界,在满足步骤2中情况A时打印。
注:
二叉树结点定义如下:
typedefintdataType;
structNode
{
dataTypeval;
structNode*left;
structNode*right;

Node(dataType_val):
val(_val),left(NULL),right(NULL){}
};
常规的二叉树遍历方式采用栈实现,比较容易实现,下面直接给出代码。
/*************************Morris遍历二叉树*************************/
#include<iostream>
usingnamespacestd;
typedefintdataType;
structNode
{
dataTypeval;
structNode*left;
structNode*right;
Node(dataType_val):
val(_val),left(NULL),right(NULL){}
};
//Morris中序遍历(左->根->右)
voidMorrisInOrderTraverse(Node*head)
{
if(head==NULL)
{
return;
}
Node*p1=head;
Node*p2=NULL;
while(p1!=NULL)
{
p2=p1->left;
if(p2!=NULL)
{
if (p1=11) and (p1-p2>,'.。if(p1 == null||p2 == null||p3 == null||p4 == null)。for i:=p1+k-1 to p2 do f[p1,p2,k]:=max(f[p1,p2,k],mmax(p1,i-1,k-1)*((((c[p2]-c[i-1]) mod 10)+10) mod 10))。
{
p2=p2->right;
}
if(p2->right==NULL)
{
p2->right=p1;//空闲指针
p1=p1->left;
continue;
}
else
{
p2->right=NULL;
}
}
cout<<p1->val<<"";

p1=p1->right;
}
}
//Morris前序遍历(根->左->右)
voidMorrisPreOrderTraverse(Node*head)
{
if(head==NULL)
{
return;
}
Node*p1=head;
Node*p2=NULL;
while(p1!=NULL)
{
p2=p1->left;
if(p2!=NULL)
{
if (p1=11) and (p1-p2>,'.。if(p1 == null||p2 == null||p3 == null||p4 == null)。for i:=p1+k-1 to p2 do f[p1,p2,k]:=max(f[p1,p2,k],mmax(p1,i-1,k-1)*((((c[p2]-c[i-1]) mod 10)+10) mod 10))。
{
p2=p2->right;
}
if(p2->right==NULL)
{
p2->right=p1;//空闲指针
cout<<p1->val<<"";//打印结点值的顺序稍微调整
p1=p1->left;
continue;
}
else
{
p2->right=NULL;
}
}
else
{
cout<<p1->val<<"";
}
p1=p1->right;
}
}
//逆序右边界
Node*reverseEdge(Node*head)
{
Node*pre=NULL;
Node*next=NULL;
while(head!=NULL)

{
next=head->right;
head->right=pre;
pre=head;
head=next;
}
returnpre;
}
//逆序打印左子树右边界
voidprintEdge(Node*head)
{
Node*lastNode=reverseEdge(head);
Node*cur=lastNode;
while(cur!=NULL)
{
cout<<cur->val<<"";
cur=cur->right;
}
reverseEdge(lastNode);
}
//Morris后序遍历(左->右->根)
voidMorrisPostOrderTraverse(Node*head)
{
if(head==NULL)
{
return;
}
Node*p1=head;
Node*p2=NULL;
while(p1!=NULL)
{
p2=p1->left;
if(p2!=NULL)
{
while(p2->right!=NULL&&p2->right!=p1)
{
p2=p2->right;
}
if(p2->right==NULL)
{
p2->right=p1;//空闲指针
p1=p1->left;
continue;
}
else
{

p2->right=NULL;
printEdge(p1->left);
}
}
p1=p1->right;
}
printEdge(head);
}
voidbuildBinTree(Node**head)
{
dataType_val;
cin>>_val;
if(_val==-1)
{
*head=NULL;
}
else
{
*head=(Node*)malloc(sizeof(Node));
(*head)->val=_val;
buildBinTree(&(*head)->left);
buildBinTree(&(*head)->right);
}
}
intmain(void)
{
Node*head;
buildBinTree(&head);
cout<<"前序遍历序列为:";
MorrisPreOrderTraverse(head);
cout<<endl;
cout<<"中序遍历序列为:";
MorrisInOrderTraverse(head);
cout<<endl;
cout<<"后序遍历序列为:";
MorrisPostOrderTraverse(head);
cout<<endl;
return0;
}
先序递归遍历建立二叉树的方法为:按照先序递归遍历的思想将对二叉树结点的抽象访问具体化为根据接收的数据决定是否产生该结点从而实现创建该二叉树的二叉链表存储结构。常见的综合应用题考点包括:二叉树的遍历算法,遍历基础上针对二叉树的一些统计和操作(比如结点数统计、左右子树对换等等),判断某棵二叉树是否二叉排序树,以上这些都要求能用递归的和非递归的算法解决,特别要重视非递归的算法,线索化后二叉树的遍历算法,如查找某结点线索化后的前驱或后继结点的算法以及给出huffman编码等等。4.二叉树的前序遍历、中序遍历、后序遍历和按层次遍历,重点是二叉树在以二叉链表作为存储结构基础上各种遍历算法(包括非递归算法)的设计与应用。
输入:
1 2 3 -1 -1 4 -1 -1 5 6 8 -1 -1 -1 7 -1 -1
输出:

致谢:
本篇文章参考自左神新书《程序员代码面试指南:IT名企算法与数据结构题目最优解》,在此表示感谢。
本文来自电脑杂谈,转载请注明本文网址:
https://www.pc-fly.com/a/jisuanjixue/article-99238-1.html
最后一笑超赞哎
首先得有
期待小王子