↑↑↑↑↑全文使用的示例二叉树↑↑↑↑↑
首先要搞懂的几个概念:
1.前驱节点和后继节点:
即打印顺序的前一个和后一个,例如打印出来是:4 2 6 5 7 1 3
对于2,前驱节点就是4,后继节点就是6
除了4,其余每一个节点都有前驱节点。除了3,其余每一个节点都有后继驱节点
2.线索二叉树
在二叉树的基础上增加线索,所谓线索就是加上前驱节点或者后继节点或者都加上。
Morris前序 (前中后总的代码在最后)
public class alg3132morrisPreMid {
public static class TreeNode{
int val;
TreeNode left;
TreeNode right;
public TreeNode() {}
public TreeNode(int val) { this.val = val; }
public TreeNode(int val, TreeNode left, TreeNode right) {
this.val = val;
this.left = left;
this.right = right;
}
}
public static void main(String[] args) {
TreeNode node7 = new TreeNode(7,null,null);
TreeNode node6 = new TreeNode(6,null,null);
TreeNode node5 = new TreeNode(5, node6, node7);
TreeNode node4 = new TreeNode(4, null, null);
TreeNode node3 = new TreeNode(3, null, null);
TreeNode node2 = new TreeNode(2, node4, node5);
TreeNode node1 = new TreeNode(1, node2, node3);
morrisPre(node1);
}
private static void morrisPre(TreeNode cur) {
if(cur == null){
return;
}
TreeNode mostRight = null;//当前节点左子树的最右节点
while (cur != null){
mostRight = cur.left;//mostRight变成当前节点的左节点
if(mostRight != null){//mostRight不为空,即cur节点有左子树
while(mostRight.right != null && mostRight.right != cur){//找到cur节点左子树的最右节点
mostRight = mostRight.right;
}
if(mostRight.right == null){//建立线索指针
mostRight.right = cur;//建立线索指针
System.out.print(cur.val+" ");//输出有左子树的节点
cur = cur.left;
continue;
}else {//mostRight.right == cur 删除线索指针
mostRight.right = null;
}
}else {//cur节点没有左子树
System.out.print(cur.val+" ");//输出没有左子树的节点
}
cur = cur.right;
}
}
}
总的打印步骤(根左右):
cur为1 ,找到7,建立线索7->1 并打印 cur 输出为1
cur为2 ,找到4,建立线索4->2 并打印 cur 输出为1 2
cur为4 ,没有左子树,直接打印cur 输出为1 2 4
cur为2 ,找到4,删除线索4->2 ,cur = cur.right
cur为5 , 找到6,建立线索6->5,并打印 cur 输出为1 2 4 5
cur为6 ,没有左子树,直接打印cur 输出为1 2 4 5 6
cur为5 ,找到6,删除线索6->5 ,cur = cur.right
cur为7 ,没有左子树,直接打印cur 输出为1 2 4 5 6 7
cur为1,找到7,删除线索7->1 ,cur = cur.righ
cur为3 ,没有左子树,直接打印cur 输出为1 2 4 5 6 7 3
Morris中序
private static void morrisMid(TreeNode cur) {
if(cur == null){
return;
}
TreeNode mostRight = null;//当前节点左子树的最右节点
while (cur != null){
mostRight = cur.left;//mostRight变成当前节点的左节点
if(mostRight != null){//mostRight不为空,即cur节点有左子树
while(mostRight.right != null && mostRight.right != cur){//找到cur节点左子树的最右节点
mostRight = mostRight.right;
}
if(mostRight.right == null){//建立线索指针
mostRight.right = cur;
cur = cur.left;
continue;
}else {//mostRight.right == cur 删除线索指针
mostRight.right = null;
}
}
System.out.print(cur.val+" ");
cur = cur.right;
}
}
与前序唯一唯一的区别只有System.out.print()语句的位置,
只有删除线索或者判断cur节点左子树为空才执行到打印语句
总的打印步骤(左根右):
cur为1 ,找到7,建立线索7->1 continue
cur为2 ,找到4,建立线索4->2 continue
cur为4 ,没有左子树,打印cur 输出为4
cur为2 ,找到4,删除线索4->2 ,打印cur 输出为4 2
cur为5 , 找到6,建立线索6->5 continue
cur为6 ,没有左子树,打印cur 输出为4 2 6
cur为5 ,找到6,删除线索6->5 ,打印cur 输出为4 2 6 5
cur为7 ,没有左子树,打印cur 输出为4 2 6 5 7
cur为1,找到7,删除线索7->1 ,打印cur 输出为4 2 6 5 7 1
cur为3 ,没有左子树,打印cur 输出为4 2 6 5 7 1 3
Morris后序
private static void morrisPost(TreeNode cur) {
if(cur == null){
return;
}
TreeNode root = cur;
TreeNode mostRight = null;//当前节点左子树的最右节点
while (cur != null){
mostRight = cur.left;//mostRight变成当前节点的左节点
if(mostRight != null){//mostRight不为空,即cur节点有左子树
while(mostRight.right != null && mostRight.right != cur){//找到cur节点左子树的最右节点
mostRight = mostRight.right;
}
if(mostRight.right == null){//建立线索指针
mostRight.right = cur;
cur = cur.left;
continue;
}else {//mostRight.right == cur 删除线索指针
mostRight.right = null;
printNode(cur.left);
}
}
cur = cur.right;
}
printNode(root);
}
private static void printNode(TreeNode head) {
TreeNode tail = reverse(head);
while (tail != null){
System.out.print(tail.val + " ");
tail = tail.right;
}
reverse(tail);//翻转第一次后破坏了二叉树的结构,所以要翻回去
}
private static TreeNode reverse(TreeNode node) {//链表翻转代码
if(node == null){
return null;
}
TreeNode pre = null, cur, next;
cur = node;
while(cur != null){
next = cur.right;
cur.right = pre;
pre = cur;
cur = next;
}
return pre;
}
与Mid区别在打印的语句变成了打印的方法printNode(),并且保留了全树的根节点--root
总的打印步骤(左右根):
cur为1 ,找到7,建立线索7->1 continue
cur为2 ,找到4,建立线索4->2 continue
cur为4 ,没有左子树 continue
cur为2 ,找到4,删除线索4->2 ,printNode(cur.left); 输出4
cur为5 , 找到6,建立线索6->5 continue
cur为6 ,没有左子树 continue
cur为5 ,找到6,删除线索6->5 ,printNode(cur.left); 输出为 4 6
cur为7 ,没有左子树 continue
cur为1,找到7,删除线索7->1 ,printNode(cur.left); 输出为4 6 7 5 2
cur为3 ,没有左子树,跳出while
printNode(root); 输出为4 6 7 5 2 3 1
总代码
public class alg31_33morris {
public static class TreeNode{
int val;
TreeNode left;
TreeNode right;
public TreeNode() {}
public TreeNode(int val) { this.val = val; }
public TreeNode(int val, TreeNode left, TreeNode right) {
this.val = val;
this.left = left;
this.right = right;
}
}
public static void main(String[] args) {
TreeNode node7 = new TreeNode(7,null,null);
TreeNode node6 = new TreeNode(6,null,null);
TreeNode node5 = new TreeNode(5, node6, node7);
TreeNode node4 = new TreeNode(4, null, null);
TreeNode node3 = new TreeNode(3, null, null);
TreeNode node2 = new TreeNode(2, node4, node5);
TreeNode node1 = new TreeNode(1, node2, node3);
morrisPre(node1);
System.out.println();
morrisMid(node1);
System.out.println();
morrisPost(node1);
}
private static void morrisPre(TreeNode cur) {
if(cur == null){
return;
}
TreeNode mostRight = null;//当前节点左子树的最右节点
while (cur != null){
mostRight = cur.left;//mostRight变成当前节点的左节点
if(mostRight != null){//mostRight不为空,即cur节点有左子树
while(mostRight.right != null && mostRight.right != cur){//找到cur节点左子树的最右节点
mostRight = mostRight.right;
}
if(mostRight.right == null){//建立线索指针
mostRight.right = cur;//建立线索指针
System.out.print(cur.val+" ");//输出有左子树的节点
cur = cur.left;
continue;
}else {//mostRight.right == cur 删除线索指针
mostRight.right = null;
}
}else {//cur节点没有左子树
System.out.print(cur.val+" ");//输出没有左子树的节点
}
cur = cur.right;
}
}
private static void morrisMid(TreeNode cur) {
if(cur == null){
return;
}
TreeNode mostRight = null;//当前节点左子树的最右节点
while (cur != null){
mostRight = cur.left;//mostRight变成当前节点的左节点
if(mostRight != null){//mostRight不为空,即cur节点有左子树
while(mostRight.right != null && mostRight.right != cur){//找到cur节点左子树的最右节点
mostRight = mostRight.right;
}
if(mostRight.right == null){//建立线索指针
mostRight.right = cur;
cur = cur.left;
continue;
}else {//mostRight.right == cur 删除线索指针
mostRight.right = null;
}
}
System.out.print(cur.val+" ");
cur = cur.right;
}
}
private static void morrisPost(TreeNode cur) {
if(cur == null){
return;
}
TreeNode root = cur;
TreeNode mostRight = null;//当前节点左子树的最右节点
while (cur != null){
mostRight = cur.left;//mostRight变成当前节点的左节点
if(mostRight != null){//mostRight不为空,即cur节点有左子树
while(mostRight.right != null && mostRight.right != cur){//找到cur节点左子树的最右节点
mostRight = mostRight.right;
}
if(mostRight.right == null){//建立线索指针
mostRight.right = cur;
cur = cur.left;
continue;
}else {//mostRight.right == cur 删除线索指针
mostRight.right = null;
printNode(cur.left);
}
}
cur = cur.right;
}
printNode(root);
}
private static void printNode(TreeNode head) {
TreeNode tail = reverse(head);
while (tail != null){
System.out.print(tail.val + " ");
tail = tail.right;
}
reverse(tail);//翻转第一次后破坏了二叉树的结构,所以要翻回去
}
private static TreeNode reverse(TreeNode node) {//链表翻转代码
if(node == null){
return null;
}
TreeNode pre = null, cur, next;
cur = node;
while(cur != null){
next = cur.right;
cur.right = pre;
pre = cur;
cur = next;
}
return pre;
}
}