程序员面试金典: 9.4树与图 4.6找出二叉查找树指定结点的下一个结点
2017-01-02 13:07
465 查看
#include <iostream> #include <stdio.h> #include<algorithm> #include <vector> using namespace std; /* 问题:设计一个算法,找出二叉查找树中指定结点的下一个结点(也即中序后继)。可以假定每个结点都含有指向父节点 的连接。 是否解出:否 分析:二叉查找树是,左子树结点值<=结点值<右子树结点值。 中序遍历是: 根左右。显然不符合它的要求。找到结点,肯定是一种遍历方式。如果直接采用当前结点的右孩子作为 下一个结点,这个是符合要求的。 错:前序遍历是:根左右,中序遍历是左根右 题目中说结点有父节点指针,这个条件似乎用不上,除非从下向上遍历这颗树,但是这样做不好。 解决方案:建立二叉查找树,设置左右孩子结点指针,根据给定的结点,从根节点开始向下遍历找到该结点后,然后返回 该结点的右孩子作为结果返回。 建立二叉查找树采用(我们特殊地去建立平衡二叉查找树):给定升序序列,寻找中间值作为根节点,然后对左半部分作为根节点的左子树,递归建立 左子树的根节点,右子树重复上述做法。直到整棵树建立完成。(如果不是升序,先排序) 遍历采用:如果给定值<结点值,则进入结点的左孩子;如果给定值>结点值,进入结点的右孩子。 输入: 12(树的结点个数) 6(给定结点值) 6 3 1 2 4 5 9 7 8 11 10 12 5 3 6 3 1 2 7 9 9 10 6 3 1 2 4 5 9 8 7 9 6 3 1 2 4 5 9 输出: 7(中序后继结点的值) 6 10 NULL 关键; 1 书上解法: 前序遍历是:根左右,中序遍历是左根右。 关键就是: 设当前结点为A,A的父节点为P 情况1:A有右子树,那么就是右子树最左边的结点(因为从当前结点开始遵循左根右的原则) 情况2:A没有右子树,且A是其父节点P的左孩子,则根据左根右的访问原则,访问A的时候,P必然没有访问过, 那么P为其中序后继结点 情况3:A没有右子树,且A是其父节点P的右孩子,根据左根右的访问原则,则访问A的时候,P必然已经访问过, 则以P为根节点的整颗子树都已经访问过,则必须以P结点,向上访问,找到P结点的父节点,如果P结点 是其父节点的左孩子,那么P结点的父节点就是所求;否则,以P结点的父节点重复上述过程。如果发现 最终找到的父结点为空,说明A结点是位于整棵树的最右边,则表示整棵树都遍历完了,因此返回空。 针对这些情况:建二叉查找树的时候,就不能用平衡二叉查找树的建树方式,必须用最原始的建立二叉查找树的 方式。建立二叉查找树。设定当前结点为根节点,小于根节点的作为根节点的左孩子,大于根节点的 座位根节点的右孩子 2 TreeNode* findMiddleOrderNextNode(TreeNode* node) { if(node == NULL ) { return NULL; } //如果当前结点有右子树,那么该结点的中序后继结点就是该右子树中最左边的结点 if( isHasRightChildTree(node) ) { TreeNode* resultNode = findLeftNodeInRightTree(node); return resultNode; } //如果没有右子树,递归遍历当前结点的父节点,如果当前结点是父节点的左孩子,那么此时父节点就是中序后继结点; //否则,如果递归遍历结束,当前结点仍为父节点的右孩子,说明整棵树其实都已经遍历过,中序后继结点为空 else { //当前结点的父节点不空(父节点为空,说明当前结点为根节点),且当前结点为父节点的右孩子 while(node->_pParent && isRightChild(node) ) { node = node->_pParent; } //如果当前结点不为根节点,说明当前结点目前是其父节点的左孩子,那么父节点就是所求 if(node->_pParent) { return node->_pParent; } else { return NULL; } } } 3 找寻当前结点最左边的孩子结点 TreeNode* findLeftNode(TreeNode* node) { if(NULL == node) { return NULL; } //如果有左孩子,那么优先从左孩子向下遍历 if(node->_pLeft) { return findLeftNode(node->_pLeft); } //易错,如果没有左孩子,那么就返回当前结点(根据左根右的遍历顺序) else { return node; } } */ const int MAXSIZE = 10000; typedef struct TreeNode { int _iValue; TreeNode* _pLeft; TreeNode* _pRight; TreeNode* _pParent; }TreeNode; TreeNode g_treeNodeArray[MAXSIZE]; int g_index; TreeNode* createTreeNode() { ++g_index; g_treeNodeArray[g_index]._pLeft = g_treeNodeArray[g_index]._pRight = g_treeNodeArray[g_index]._pParent = NULL; return &g_treeNodeArray[g_index]; } //根据给定值,查询到结点 TreeNode* findNode(TreeNode* head , int value) { if(NULL == head) { return NULL; } if(head->_iValue == value) { return head; } else if(head->_iValue < value) { return findNode(head->_pRight , value); } else { return findNode(head->_pLeft , value); } } void buildTree(TreeNode* head , int value) { if(NULL == head) { return; } if(head->_iValue < value ) { if(head->_pRight != NULL) { buildTree(head->_pRight , value); } else { TreeNode* node = createTreeNode(); node->_iValue = value; head->_pRight = node; //注意要添加父节点指向 node->_pParent = head; } } else { if(head->_pLeft != NULL) { buildTree(head->_pLeft , value); } else { TreeNode* node = createTreeNode(); node->_iValue = value; head->_pLeft = node; node->_pParent = head; } } } void buildBinarySearchTree(TreeNode* head , vector<int>& vecData) { int size = vecData.size(); if(size <= 1) { return ; } if(head == NULL) { return; } for(int i = 1 ; i < size ; i++) { buildTree(head , vecData.at(i)); } } bool isHasRightChildTree(TreeNode* node) { if(node == NULL) { return false; } if(node->_pRight) { return true; } else { return false; } } //找寻当前结点最左边的孩子结点 TreeNode* findLeftNode(TreeNode* node) { if(NULL == node) { return NULL; } //如果有左孩子,那么优先从左孩子向下遍历 if(node->_pLeft) { return findLeftNode(node->_pLeft); } //易错,如果没有左孩子,那么就返回当前结点(根据左根右的遍历顺序) else { return node; } } //找到当前结点右子树中最左边的结点12作为中序后继结点返回 TreeNode* findLeftNodeInRightTree(TreeNode* node) { if(NULL == node) { return NULL; } if(NULL == node->_pRight) { return NULL; } TreeNode* resultNode = findLeftNode(node->_pRight); return resultNode; } //判断当前结点是否为其父节点的右孩子 bool isRightChild(TreeNode* node) { //当前结点为空,不是右孩子 if(NULL == node) { return false; } //当前结点的父节点为空,不是右孩子 if(NULL == node->_pParent) { return false; } if( node->_pParent->_pRight == node ) { return true; } else { return false; } } TreeNode* findMiddleOrderNextNode(TreeNode* node) { if(node == NULL ) { return NULL; } //如果当前结点有右子树,那么该结点的中序后继结点就是该右子树中最左边的结点 if( isHasRightChildTree(node) ) { TreeNode* resultNode = findLeftNodeInRightTree(node); return resultNode; } //如果没有右子树,递归遍历当前结点的父节点,如果当前结点是父节点的左孩子,那么此时父节点就是中序后继结点; //否则,如果递归遍历结束,当前结点仍为父节点的右孩子,说明整棵树其实都已经遍历过,中序后继结点为空 else { //当前结点的父节点不空(父节点为空,说明当前结点为根节点),且当前结点为父节点的右孩子 while(node->_pParent && isRightChild(node) ) { node = node->_pParent; } //如果当前结点不为根节点,说明当前结点目前是其父节点的左孩子,那么父节点就是所求 if(node->_pParent) { return node->_pParent; } else { return NULL; } } } void process() { int nodeNum , nodeValue; int value; while(cin >> nodeNum >> nodeValue) { vector<int> vecData; for(int i = 0 ; i < nodeNum ; i++) { cin >> value; vecData.push_back(value); } if(vecData.empty()) { continue; } g_index = 0; TreeNode* head = createTreeNode(); //注意对根节点赋值 head->_iValue = vecData.at(0); //从根节点下一个结点开始 buildBinarySearchTree(head , vecData); TreeNode* node = findNode(head , nodeValue); TreeNode* nextNode = findMiddleOrderNextNode(node); if(nextNode) { cout << nextNode->_iValue << endl; } else { cout << "Null" << endl; } } } int main(int argc, char* argv[]) { process(); getchar(); return 0; }
相关文章推荐
- 设计一个算法,找出二叉查找树中指定结点的“下一个“结点(也即中序后继)。可以假定每个结点都含有指向父结点的连接。
- 找出二叉查找树中指定结点的”下一个"结点(也即中序后继)
- 找出二叉查找树中指定结点的”下一个"结点(也即中序后继)
- 4.6 找出二叉树中指定节点的下一个节点(中序后继),假定每个节点有父指针。
- 程序员面试金典: 9.4树与图 4.7找出二叉树种某两个结点的第一个共同祖先---O(N)解法
- 找出二叉树中指定结点的下一个结点(中序后继)可以假定每个结点都有指向父节点的连接
- 程序员面试金典--面试22之寻找二叉树中指定结点的下一个结点
- 程序员面试金典: 9.4树与图 4.7找出二叉树种某两个结点的第一个共同祖先---O(N^2)解法
- 程序员面试金典: 9.4树与图 4.5实现一个函数,检查一颗二叉树是否为二叉查找树
- 《剑指offer》-找出中序遍历顺序的下一个结点并且返回
- 给定一个二叉树和其中的一个结点,请找出中序遍历顺序的下一个结点并且返回。注意,树中的结点不仅包含左右子结点,同时包含指向父结点的指针。
- 程序员面试金典: 9.4树与图 4.2给定有向图,设计一个算法,找出两个节点之间是否存在一条路径。
- 程序员面试金典-4.6寻找下一个节点
- 程序员面试金典: 检查是否为BST、 寻找下一个结点
- 程序员面试金典——解题总结: 9.17中等难题 17.9设计一个方法,找出任意指定单词在一本书中的出现频率
- 给定一个二叉树和其中的一个结点,请找出中序遍历顺序的下一个结点并且返回。注意,树中的结点不仅包含左右子结点,同时包含指向父结点的指针。
- 设计一个算法,找出二叉树中某两个结点的第一个公共祖先.。不得将额外的结点存储在另外的数据结构中。注意:这不一定是二叉查找树。
- 找出二叉树的下一个结点(算法)
- 程序员面试金典: 9.4树与图 4.3给定一个有序整数数组,元素各不相同且按升序排列,创建一颗高度最小的二叉查找树。 ---快速解法
- 程序员面试金典: 9.4树与图 4.9在二叉树中,打印结点数值总和等于给定值的所有路径