1.题目描述
给定一个二叉树和其中的一个结点,请找出中序遍历顺序的下一个结点并且返回。注意,树中的结点不仅包含左右子结点,同时包含指向父结点的指针。
二叉树节点的定义:
struct TreeLinkNode {
int val;
struct TreeLinkNode *left;
struct TreeLinkNode *right;
struct TreeLinkNode *next;
TreeLinkNode(int x) :val(x), left(NULL), right(NULL), next(NULL) {
}
};
2.基本思路
如果一个节点p的右子节点存在
- 下一个访问的节点即为p的右子树上的最左边的节点
如果节点p的右子树节点不存在
- 如果节点p为其父节点的左子节点
- 下一个访问的节点是p的父节点
如果节点p为其父节点的右子节点
设该二叉树的根节点为pHead,p位于该二叉树的左子树和右子树上情况是不一样的。做法:则按照如下规则不断回溯
- 令r为p的父节点。 如果节点p是其父节点r的右子节点,则继续回溯,即令
p=r;r=p->next
;反之,则停止。 - r有两种情况
- r为空,说明p节点此时指向的是该二叉树根节点的,则下一个访问的节点为NULL
- 如果p为r的左子节点,则下一个访问的节点为r
- 令r为p的父节点。 如果节点p是其父节点r的右子节点,则继续回溯,即令
- 如果节点p为其父节点的左子节点
特殊情况测试:(就失败在这个地方)
- 空节点
- 二叉树只有一个节点,并且 输入节点即为二叉树的根节点
3.代码
第二写的代码
TreeLinkNode* GetNext(TreeLinkNode* pNode) { TreeLinkNode *res=NULL; if(pNode==NULL) return res; TreeLinkNode *p,*r; p=pNode; if(p->right!=NULL){ p=p->right; while(p->left!=NULL) { p=p->left; } res=p; }else{ if(p->next!=NULL && p->next->left==p) // 如果p没有父节点呢? { res=p->next; }else{ r=p->next; while(r!=NULL && r->right==p) { p=r; r=p->next; } if(r==NULL){ res=NULL; }else{ res=r; } } } return res; }
第一次写的代码
public: TreeLinkNode* GetNext(TreeLinkNode* pNode) { if(pNode==NULL) return NULL; TreeLinkNode *res,*p; res=NULL; if(pNode->right!=NULL ){ p=pNode->right; while(p->left!=NULL) p=p->left; res=p; }else{ if( pNode->next!=NULL && pNode->next->left==pNode) res=pNode->next; if(pNode->next!=NULL && pNode->next->right==pNode){ p=pNode; while( p->next!=NULL && p->next->right==p ) p=p->next; if(p->next!=NULL && p->next->left==p) res=p->next; } } return res; }
感慨:同样功能的代码,代码越写越长,越写越难看