题目:输入两棵二叉树A和B,判断树B是不是A的子结构
递归判断:如果当前结点值相等,就判断左子树和右子树是否是子结构
- bool IsChildTree(Node * father, Node * son)
- {
- if(father == NULL && son == NULL)
- return true;
- if(father == NULL && son != NULL)
- return false;
- if(father != NULL && son == NULL)
- return true;
- if(father->data == son->data )
- {
- return IsChildTree(father->left, son->left) && IsChildTree(father->right, son->right);
- }
- if(IsChildTree(father->left, son))
- return true;
- if(IsChildTree(father->right, son))
- return true;
- return false;
- }
题目:求二叉树中相距最远的两个节点之间的距离
求两节点的最远距离,实际就是求二叉树的直径。本问题可以转化为求“二叉树每个节点的左右子树高度和的最大值”。
- int TreeHeight(Node* root, int& max_distance)
- {
- if(root == NULL)
- {
- max_distance = 0;
- return 0;
- }
- int left_height,right_height;
- if(root->left)
- left_height = TreeHeight(root->left,max_distance)+1;
- else
- left_height = 0;
- if(root->right)
- right_height = TreeHeight(root->right,max_distance)+1;
- else
- right_height = 0;
- int distance = left_height + right_height;
- if (max_distance < distance) max_distance = distance;
- return (left_height > right_height ? left_height : right_height);
- }
- int TreeDiameter(Node* root)
- {
- int max_distance = 0;
- if(root) TreeHeight(root, max_distance);
- return max_distance;
- }
题目:求二叉树中节点的最大距离:如果我们把二叉树看成一个图,父子节点之间的连线看成是双向的,定义“距离”为两节点之间边的个数。
- //结点的定义
- typedef struct Node
- {
- Node * left;
- Node * right;
- int maxLeft;
- int maxRight;
- char chValue;
- }Node,*pNode;
- //最大距离
- int maxLen = 0;
- //寻找二叉树中节点的最大距离
- void findMaxLength(Node* root)
- {
- if(root == NULL) return;
- //如果左子树为空,则该节点左边最长距离为0
- if(root->left == NULL) root->maxLeft = 0;
- //如果右子树为空,则该节点右边最长距离为0
- if(root->right == NULL) root->maxRight = 0;
- //如果左子树不为空,递归寻找左边最长距离
- if(root->left != NULL) findMaxLength(root->left);
- //如果右子树不为空,递归寻找右边最长距离
- if(root->right != NULL) findMaxLength(root->right);
- //计算左子树最长节点距离
- if(root->left != NULL)
- {
- int tempMax = 0;
- if(root->left->maxLeft > root->left->maxRight)
- tempMax = root->left->maxLeft;
- else tempMax = root->left->maxRight;
- root->maxLeft = tempMax+1;
- }
- //计算右子树最长节点距离
- if(root->right != NULL)
- {
- int tempMax = 0;
- if(root->right->maxLeft > root->right->maxRight)
- tempMax = root->right->maxLeft;
- else tempMax = root->right->maxRight;
- root->maxRight = tempMax+1;
- }
- //更新最长距离
- if(root->maxLeft+root->maxRight > maxLen)
- maxLen = root->maxLeft+root->maxRight;
- }
题目:重建二叉树:通过先序遍历和中序遍历的序列重建二叉树
- //通过先序遍历和中序遍历的序列重建二叉树
- void ReBuild(char* pPreOrder,char* pInOrder,int nTreeLen,Node** pRoot)
- {
- //检查边界条件
- if(pPreOrder == NULL || pInOrder == NULL)
- return ;
- //获得前序遍历的第一个节点
- Node* temp = new Node;
- temp->data = *pPreOrder;
- temp->left = NULL;
- temp->right = NULL;
- //如果节点为空,把当前节点复制到根节点
- if(*pRoot == NULL) *pRoot = temp;
- //如果当前树长为1,那么已经是最后一个节点
- if(nTreeLen == 1) return;
- //寻找子树长度
- char* pOrgInOrder = pInOrder;
- char* pLeftEnd = pInOrder;
- int nTempLen = 0;
- //找到左子树的结尾
- while(*pPreOrder != *pLeftEnd)
- {
- if(pPreOrder == NULL || pLeftEnd == NULL)
- return;
- //记录临时长度,以免溢出
- nTempLen++;
- if(nTempLen > nTreeLen) break;
- pLeftEnd++;
- }
- //寻找左子树长度
- int nLeftLen = (int)(pLeftEnd-pOrgInOrder);
- //寻找右子树长度
- int nRightLen = nTreeLen-nLeftLen-1;
- //重建左子树
- if(nLeftLen > 0)
- ReBuild(pPreOrder+1,pInOrder,nLeftLen,&((*pRoot)->left));
- //重建右子树
- if(nRightLen > 0)
- ReBuild(pPreOrder+nLeftLen+1,pInOrder+nLeftLen+1,nRightLen,&((*pRoot)->right));
- }
题目:寻找最近公共祖先LCA(Lowest Common Ancestor)
- Node* getLCA(Node* root,Node* x,Node* y)
- {
- if(root == NULL) return NULL;
- if(x == root || y == root) return root;
- Node* pleft = getLCA(root->left,x,y);
- Node* pright = getLCA(root->right,x,y);
- if(pleft == NULL) return pright;
- else if(pright == NULL)return pleft;
- else return root;
- }
分别得到根节点root到结点x的路径和到结点y的路径,再比较路径中第一个相同的结点,即是LCA
- //得到根节点pHead到pNode的路径
- bool GetNodePath(Node* pHead, Node* pNode, std::list<Node*>& path)
- {
- if(pHead == pNode)
- return true;
- path.push_back(pHead);
- bool found = false;
- if(pHead->left != NULL)
- found = GetNodePath(pHead->left, pNode, path);
- if(!found && pHead->right)
- found = GetNodePath(pHead->right, pNode, path);
- if(!found)
- path.pop_back();
- return found;
- }
题目:寻找二叉搜索树(BST)的最低公共祖先(LCA)
利用BST的性质:从根结点开始搜索,当第一次遇到当前结点的值介于两个给定的结点值之间时,这个当前结点就是要找的LCA
- Node* FindLCA(Node* root,int x, int y)
- {
- Node * t = root;
- while(1)
- {
- if(t->data > x && t->data > y)
- t = t->left;
- else if(t->data < x && t->data < y)
- t = t->right;
- else return t;
- }
- }
题目:输入一个整数数组,判断该数组是不是某二元查找树的后序遍历的结果。如果是返回true,否则返回false。
例如输入5、7、6、9、11、10、8,由于这一整数序列是如下树的后序遍历结果,因此返回true。
8
/ \
6 10
/ \ / \
5 7 9 11
如果输入7、4、6、5,没有哪棵树的后序遍历的结果是这个序列,因此返回false。
分析:这是一道trilogy的笔试题,主要考查对二元查找树的理解。
在后续遍历得到的序列中,最后一个元素为树的根结点。从头开始扫描这个序列,比根结点小的元素都应该位于序列的左半部分;从第一个大于根节点开始到根结点前面的一个元素为止,所有元素都应该大于根结点,因为这部分元素对应的是树的右子树。根据这样的划分,把序列划分为左右两部分,我们递归地确认序列的左、右两部分是不是都是二元查找树。
参考代码:
- ///
- // Verify whether a squence of integers are the post order traversal
- // of a binary search tree (BST)
- // Input: squence - the squence of integers
- // length - the length of squence
- // Return: return ture if the squence is traversal result of a BST,
- // otherwise, return false
- ///
- bool verifySquenceOfBST(int squence[], int length)
- {
- if(squence == NULL || length <= 0)
- return false;
- // root of a BST is at the end of post order traversal squence
- int root = squence[length - 1];
- // the nodes in left sub-tree are less than the root
- int i = 0;
- for(; i < length - 1; ++ i)
- {
- if(squence[i] > root)
- break;
- }
- // the nodes in the right sub-tree are greater than the root
- int j = i;
- for(; j < length - 1; ++ j)
- {
- if(squence[j] < root)
- return false;
- }
- // verify whether the left sub-tree is a BST
- bool left = true;
- if(i > 0)
- left = verifySquenceOfBST(squence, i);
- // verify whether the right sub-tree is a BST
- bool right = true;
- if(i < length - 1)
- right = verifySquenceOfBST(squence + i, length - i - 1);
- return (left && right);
- }
题目:怎样编写一个程序,把一个有序整数数组放到二叉搜索树中?
分析:本题考察二叉搜索树的建树方法,简单的递归结构。关于树的算法设计一定要联想到递归,因为树本身就是递归的定义。
参考代码:
- Node* array_to_tree(int array[],int start,int end)
- {
- if (start > end) return NULL;
- int m = start+(end-start)/2;
- Node* root = new Node(array[m]);
- root->left = array_to_tree(array,start,m-1);
- root->right = array_to_tree(array,m+1,end);
- return root;
- }
- Node* array2Tree(int array[],int n)
- {
- return array_to_tree(array,0,n-1);
- }
题目:输入一棵二元查找树,将该二元查找树转换成一个排序的双向链表。要求不能创建任何新的结点,只调整指针的指向。
比如将二元查找树
10
/ \
6 14
/ \ / \
4 8 12 16
转换成双向链表 4=6=8=10=12=14=16。
分析:本题是微软的面试题。很多与树相关的题目都是用递归的思路来解决,本题也不例外。下面我们用两种不同的递归思路来分析。
思路一:当我们到达某一结点准备调整以该结点为根结点的子树时,先调整其左子树将左子树转换成一个排好序的左子链表,再调整其右子树转换右子链表。最后链接左子链表的最右结点(左子树的最大结点)、当前结点和右子链表的最左结点(右子树的最小结点)。从树的根结点开始递归调整所有结点。
思路二:我们可以中序遍历整棵树。按照这个方式遍历树,比较小的结点先访问。如果我们每访问一个结点,假设之前访问过的结点已经调整成一个排序双向链表,我们再把调整当前结点的指针将其链接到链表的末尾。当所有结点都访问过之后,整棵树也就转换成一个排序双向链表了。
参考代码:
- //定义二元查找树结点的数据结构如下:
- struct BSTreeNode // a node in the binary search tree
- {
- int m_nValue; // value of node
- BSTreeNode *m_pLeft; // left child of node
- BSTreeNode *m_pRight; // right child of node
- };
- //思路一对应的代码:
- ///
- // Covert a sub binary-search-tree into a sorted double-linked list
- // Input: pNode - the head of the sub tree
- // asRight - whether pNode is the right child of its parent
- // Output: if asRight is true, return the least node in the sub-tree
- // else return the greatest node in the sub-tree
- ///
- BSTreeNode* ConvertNode(BSTreeNode* pNode, bool asRight)
- {
- if(!pNode)
- return NULL;
- BSTreeNode *pLeft = NULL;
- BSTreeNode *pRight = NULL;
- // Convert the left sub-tree
- if(pNode->m_pLeft)
- pLeft = ConvertNode(pNode->m_pLeft, false);
- // Connect the greatest node in the left sub-tree to the current node
- if(pLeft)
- {
- pLeft->m_pRight = pNode;
- pNode->m_pLeft = pLeft;
- }
- // Convert the right sub-tree
- if(pNode->m_pRight)
- pRight = ConvertNode(pNode->m_pRight, true);
- // Connect the least node in the right sub-tree to the current node
- if(pRight)
- {
- pNode->m_pRight = pRight;
- pRight->m_pLeft = pNode;
- }
- BSTreeNode *pTemp = pNode;
- // If the current node is the right child of its parent,
- // return the least node in the tree whose root is the current node
- if(asRight)
- {
- while(pTemp->m_pLeft)
- pTemp = pTemp->m_pLeft;
- }
- // If the current node is the left child of its parent,
- // return the greatest node in the tree whose root is the current node
- else
- {
- while(pTemp->m_pRight)
- pTemp = pTemp->m_pRight;
- }
- return pTemp;
- }
- ///
- // Covert a binary search tree into a sorted double-linked list
- // Input: the head of tree
- // Output: the head of sorted double-linked list
- ///
- BSTreeNode* Convert(BSTreeNode* pHeadOfTree)
- {
- // As we want to return the head of the sorted double-linked list,
- // we set the second parameter to be true
- return ConvertNode(pHeadOfTree, true);
- }
- //思路二对应的代码:
- ///
- // Covert a sub binary-search-tree into a sorted double-linked list
- // Input: pNode - the head of the sub tree
- // pLastNodeInList - the tail of the double-linked list
- ///
- void ConvertNode(BSTreeNode* pNode, BSTreeNode*& pLastNodeInList)
- {
- if(pNode == NULL)
- return;
- BSTreeNode *pCurrent = pNode;
- // Convert the left sub-tree
- if (pCurrent->m_pLeft != NULL)
- ConvertNode(pCurrent->m_pLeft, pLastNodeInList);
- // Put the current node into the double-linked list
- pCurrent->m_pLeft = pLastNodeInList;
- if(pLastNodeInList != NULL)
- pLastNodeInList->m_pRight = pCurrent;
- pLastNodeInList = pCurrent;
- // Convert the right sub-tree
- if (pCurrent->m_pRight != NULL)
- ConvertNode(pCurrent->m_pRight, pLastNodeInList);
- }
- ///
- // Covert a binary search tree into a sorted double-linked list
- // Input: pHeadOfTree - the head of tree
- // Output: the head of sorted double-linked list
- ///
- BSTreeNode* Convert_Solution1(BSTreeNode* pHeadOfTree)
- {
- BSTreeNode *pLastNodeInList = NULL;
- ConvertNode(pHeadOfTree, pLastNodeInList);
- // Get the head of the double-linked list
- BSTreeNode *pHeadOfList = pLastNodeInList;
- while(pHeadOfList && pHeadOfList->m_pLeft)
- pHeadOfList = pHeadOfList->m_pLeft;
- return pHeadOfList;
- }