//Tree in 剑指offer
/*
面试题7:重建二叉树
输入某二叉树的前序遍历和中序遍历的结果,请重建
该二叉树。
*/
typedef struct BinaryTreeNode{
int m_nValue;
BinaryTreeNode* m_pLeft;
BinaryTreeNode* m_pRight;
}BinaryTreeNode;
BinaryTreeNode* Construct(int *preorder, int *inorder, int length)
{
if(preorder == NULL || inorder == NULL || (length <= 0))
return NULL;
return ConstructCore(preorder,preorder+length-1,inorder,inorder+length-1);
}
BinaryTreeNode* ConstructCore(int *sPreorder, int* ePreorder, int* sInorder, int* eInorder)
{
int rootValue = sPreorder[0];
BinaryTreeNode* root = (BinaryTreeNode*)malloc(sizeof(struct BinaryTreeNode));
root->m_nValue = rootValue;
root->m_pLeft = root->m_pRight = NULL;
if(sPreorder = eInorder)
{
if(sInorder == eInorder && *sPreorder == *sInorder) return NULL;
else goto;
}
//find the address in Inorder array
int *rootInorder = sInorder;
while(rootInorder <= eInorder && *rootInorder != rootValue)
rootInorder++;
//may the root don't have right subtree
//找遍整个中序序列都无法找到根节点值 error
if(rootInorder == eInorder && *rootInorder != rootValue)
goto;
int leftLength = rootInorder - sInorder;
int *leftPreorderEnd = sPreorder + leftLength;
//if there is a left subtree
if(leftLength > 0)
{
root->left = ConstructCore(sPreorder+1, leftPreorderEnd, sInorder, rootInorder-1);
}
//if there is a right subtree
if(leftLength < ePreorder - sPreorder)
{
root->right = ConstructCore(leftPreorderEnd+1, ePreorder, rootInorder+1, eInorder);
}
return root;
}
/*
面试题8: 二叉树的下一个节点
给定一颗二叉树和其中一个节点,如何找出中序遍历序列的
下一个节点?树中的节点除了有两个分别指向左、右子节点的指针
还有一个指向父节点的指针
*/
/*
1)该节点有右子树 返回右子树最左边的节点
2)该节点无右子树 但该节点是其父节点的左子树
3)但该节点是其父节点的右子树
*/
BinaryTreeNode* GetNext(BinaryTreeNode* pNode)
{
if(pNode == NULL) return NULL;
if(pNode->right)
{
BinaryTreeNode *pRighgt = pNode->right;
while(pRighgt->left)
{
pRighgt = pRighgt->left;
}
return pRight;
}
else if(pNode->m_nParent)
{
BinaryTreeNode *pParent = pNode->m_nParent;
BinaryTreeNode *pCurrent = pNode;
while(pParent != NULL && pCurrent != pParent->right)
{
pCurrent = pParent;
pParent = pParent->m_nParent;
}
return pParent;
}
}
/*
面试题26:树的子结构
输入两棵二叉树A和B,判断B是不是A的子结构。二叉树的节点定义如下:
struct BinaryTreeNode
{
double m_dbvalue;
BinaryTreeNode* m_pLeft;
BinaryTreeNode* m_pRight;
};
*/
bool HasSubtree(BinaryTreeNode* pRoot1,BinaryTreeNode* pRoot2)
{
bool flag = false;
if(pRoot1 != NULL && pRoot2 != NULL)
{
if(Equal(pRoot1->m_dbvalue,pRoot2->m_dbvalue))
flag = DoesTree1HaveTree2(pRoot1,pRoot2);
if(!flag)
flag = HasSubtree(pRoot1->m_pLeft,pRoot2);
if(!flag)
flag = HasSubtree(pRoot1->m_pRight,pRoot2);
}
return flag;
}
bool DoesTree1HaveTree2(BinaryTreeNode* pRoot1,BinaryTreeNode* pRoot2)
{
if(pRoot1 == NULL) return false;
if(pRoot2 == NULL) return true;
if(!Equal(pRoot1->m_dbvalue,pRoot2->m_dbvalue)) return false;
return DoesTree1HaveTree2(pRoot1->m_pLeft,pRoot2->m_pLeft) && DoesTree1HaveTree2(pRoot1->m_pRight,pRoot2->m_pRight);
}
bool Equal(double num1, double num2)
{
if((num1 - num2 > -0.0000001) && (num1 - num2 < 0.0000001))
return true;
else
return false;
}
/*
面试题27:二叉树的镜像
完成一个函数,输入一棵二叉树,该函数输出它的镜像。二叉树
节点定义如下:
struct BinaryTreeNode
{
int m_nValue;
...
...
};
*/
//writer
void MirrorRecursively(BinaryTreeNode* pNode)
{
if(pNode == NULL)
return;
if(pNode->m_pLeft == NULL && pNode->m_pRight == NULL) return;
BinaryTreeNode *pTemp = pNode->m_pLeft;
pNode->m_pLeft = pNode->m_pRight;
pNode->m_pRight = pTemp;
if(pNode->m_pLeft) MirrorRecursively(pNode->m_pLeft);
if(pNode->m_pRight) MirrorRecursively(pNode->m_pRight);
}
//mine
//but didn't be tested
BinaryTreeNode* mine_Mirror(BinaryTreeNode* T)
{
if(!T) return T;
BinaryTreeNode *r = mine_Mirror(T->m_pLeft);
BinaryTreeNode *l = mine_Mirror(T->m_pRight);
T->m_pLeft = r;
T->m_pRight = l;
return T;
}
/*
面试题28:对称的二叉树
实现一个函数,判断它是不是对称的
如果一个二叉树和他的镜像一样,则它是对称的
*/
bool isSymmetrical(BinaryTreeNode* pRoot)
{
return isSymmetrical(pRoot,pRoot);
}
bool isSymmetrical(BinaryTreeNode* pRoot1, BinaryTreeNode* pRoot2)
{
if(pRoot1 == NULL && pRoot2 == NULL) return true;
if(pRoot1 == NULL || pRoot2 == NULL) return false;
if(pRoot1->m_nValue != pRoot2->m_nValue) return false;
return isSymmetrical(pRoot1->m_pLeft, pRoot2->m_pRight) && isSymmetrical(pRoot1->m_pRight,pRoot2->m_pLeft);
}
/*
面试题32:从上到下打印二叉树
思路:层次遍历
*/
/*
扩展一:分行从上到下打印字符串
eg:
8
6 10
5 7 9 11
*/
void Print(BinaryTreeNode* pRoot)
{
if(pRoot == NULL)
{
return;
}
q = CreateQueue();
q.push(pRoot);
int ToBeDeleted = 1;
int nextlevel = 0;
while(!isEmpty(q))
{
BinaryTreeNode *pNode = q.front();
printf("%d ",pNode->m_nValue);
if(pNode->m_pLeft)
{
nextlevel++;
q.push(pNode->m_pLeft);
}
if(pNode->m_pRight)
{
nextlevel++;
q.push(pNode->m_pRight);
}
q.pop();
--ToBeDeleted;
//当这一层节点都printf以后
if(ToBeDeleted == 0)
{
printf("\n");
ToBeDeleted = nextlevel;
nextlevel = 0;
}
}
}
/*
扩展2:之字形打印二叉树
eg:(扩展1)
8
10 6
5 7 9 11
*/
//mine
void Print(BinaryTreeNode* pRoot)
{
if(pRoot == NULL)
return;
s1 = CreateStack(); //奇数层所用的栈
s2 = CreateStack(); //偶数层所用的栈
int k = 1; //当前打印的层数
s1.push(pRoot);
int nextlevel = 0;
int ToBeDeleted = 1;
while(!isEmpty(s1) || !isEmpty(s2))
{
//当前在打印奇数层
//应当把子节点压入偶数栈
if(k % 2 == 1)
{
BinaryTreeNode *pNode = s1.top();
printf("%d ",pNode->m_nValue);
if(pNode->left)
{
s2.push(pNode->left);
nextlevel++;
}
if(pNode->right)
{
s2.push(pNode->right);
nextlevel++;
}
s1.pop();
ToBeDeleted--;
if(ToBeDeleted == 0)
{
k++;
ToBeDeleted = nextlevel;
nextlevel = 0;
}
}
if(k % 2 == 0)
{
BinaryTreeNode *pNode = s2.top();
printf("%d ",pNode->m_nValue);
if(pNode->right)
{
s1.push(pNode->right);
nextlevel++;
}
if(pNode->left)
{
s1.push(pNode->left);
nextlevel++;
}
s2.pop();
ToBeDeleted--;
if(ToBeDeleted == 0)
{
k++;
ToBeDeleted = nextlevel;
nextlevel = 0;
}
}
}
}
//writer
void Print(BinaryTreeNode* pRoot)
{
if(pRoot == NULL)
return;
Stack levels[2];
levels[0] = CreateStack();
levels[1] = CreateStack();
int current = 0;
int next = 1;
levels[current].push(pRoot);
while(!levels[0].empty() || !levels[1].empty())
{
BinaryTreeNode *pNode = levels[current].top();
levels[current].pop();
printf("%d ",pNode->m_nValue);
if(current == 0)
{
if(pNode->m_pLeft)
levels[next].push(pNode->m_pLeft);
if(pNode->m_pRight)
levels[next].push(pNode->m_pRight);
}
else
{
if(pNode->m_pRight)
levels[next].push(pNode->m_pRight);
if(pNode->m_pLeft)
levels[next].push(pNode->m_pLeft);
}
if(levels[current].empty())
{
printf("\n");
current = 1 - current;
next = 1 - next;
}
}
}
/*
面试题33:二叉搜索树的后序遍历
输入一个整数数组,判断该数组是不是某二叉搜索树的
后序遍历结果。如果是则返回true,否则返回false。
假设输入的数组中的任意两个数字都互不相同
*/
bool VerifySquenceOfBST(int sequence[], int length)
{
if(sequence == NULL || length <= 0) return false;
int root = sequence[length-1];
int i=0;
for(;i<length-1;i++)
{
if(sequence[i] > root) break;
}
int j = i;
for(;j<length-1;j++)
{
if(sequence[j] < root)
return false;
}
bool left = true;
if(i>0) left = VerifySquenceOfBST(sequence,i);
bool right = true;
if(length - i - 1 >0) right = VerifySquenceOfBST(sequence+i,length-i-1);
return (left&&right);
}
/*
面试题34:二叉树中和为某一值的路径
题目:输入一棵二叉树和整数,打印出二叉树中节点值
的和为输入整数的所有路径。从树的根节点开始往下一直到
叶节点所经过的节点形成一条路径。
*/
void FindPath(BinaryTreeNode* pRoot, int expectedSum)
{
if(pRoot == NULL) return;
std::vector<int> path;
int currentSum = 0;
FindPath(pRoot, expectedSum, path, currentSum);
}
void FindPath(BinaryTreeNode* pRoot, int expectedSum, std::vector<int>& path, int currentSum)
{
currentSum += pRoot->m_nValue;
path.push_back(pRoot->m_nValue);
bool isLeaf = (pRoot->m_pLeft == NULL && pRoot->m_pRight == NULL);
if(currentSum == expectedSum && isLeaf)
{
printf("a path is found:");
std::vector<int>::iterator iter = path.begin();
for(;iter!=path.end();++iter)
printf("%d\t",*iter);
printf("\n");
}
if(pRoot->m_pLeft != NULL)
FindPath(pRoot->m_pLeft,expectedSum,path,currentSum);
if(pRoot->m_pRight != NULL)
FindPath(pRoot->m_pRight,expectedSum,path,currentSum);
path.pop_back();
}
/*
面试题36:二叉搜索树和双链表
*/
BinaryTreeNode* Convert(BinaryTreeNode* pRootOfTree)
{
BinaryTreeNode* pLastNodeInList = NULL;
Convert(pRootOfTree,&pLastNodeInList);
//返回头节点
BinaryTreeNode* pHeadOfList = pLastNodeInList;
while(pHeadOfList != NULL && pHeadOfList->m_pLeft != NULL)
pHeadOfList = pHeadOfList->m_pLeft;
return pHeadOfList;
}
void ConvertNode(BinaryTreeNode* pNode, BinaryTreeNode** pLastNodeInList)
{
if(pNode == NULL) return;
BinaryTreeNode *pCurrent = pNode;
if(pCurrent->m_pLeft != NULL)
ConvertNode(pCurrent->m_pLeft,pLastNodeInList);
pCurrent->m_pLeft = *pLastNodeInList;
if(*pLastNodeInList != NULL)
(*pLastNodeInList)->m_pRight = pCurrent;
*pLastNodeInList = pCurrent;
if(pCurrent->m_pRight != NULL)
ConvertNode(pCurrent->m_pRight,pLastNodeInList);
}
/*
面试题37:序列化二叉树
请实现两个函数,分别用来序列化和反序列化二叉树
*/
void Serialize(BinaryTreeNode* pRoot, ostream& stream)
{
if(pRoot == NULL)
{
stream<<"%,";
return;
}
stream<<pRoot->m_nValue<<',';
Serialize(pRoot->m_pLeft,stream);
Serialize(pRoot->m_pRight,stream);
}
void Deserialize(BinaryTreeNode* pRoot, istream& stream)
{
int number;
if(ReadStream(stream,&number)) //函数ReadStream每次从流中读取一个数字或其他字符
//读到数字返回true,否则返回false
{
*pRoot = new BinaryTreeNode();
(*pRoot)->m_nValue = number;
(*pRoot)->m_pLeft = NULL;
(*pRoot)->m_pRight = NULL;
Deserialize(&((*pRoot)->m_pLeft),stream);
Deserialize(&((*pRoot)->m_pRight),stream);
}
}
/*
面试题54: 二叉搜索树的第k大节点
给定一棵二叉搜索树,找出其中第k大的节点
*/
BinaryTreeNode* KthNode(BinaryTreeNode* pRoot, unsigned int &k) //注意,此处为k的引用
{
if(pRoot == NULL || k<= 0)
return NULL;
BinaryTreeNode* res = NULL;
//中序遍历
if(pRoot->m_pLeft != NULL)
res = KthNode(pRoot->m_pLeft,k);
/*************************************///左
if(res == NULL)
{
if(k == 1) //找到了
return pRoot;
k--;
}
/************************************///右
if(res == NULL && pRoot->m_pRight != NULL)
res = KthNode(pRoot->m_pRight,k);
return res;
}
/*
面试题55:二叉树的深度
输入一棵二叉树的根节点,求该树的深度
深度:最长路径的长度
*/
int TreeDepth(BinaryTreeNode* pRoot)
{
if(pRoot == NULL)
return 0;
int nLeft = TreeDepth(pRoot->m_pLeft);
int nRight = TreeDepth(pRoot->m_pRight);
return (nLeft > nRight)?(nLeft+1):(nRight+1);
}
/*
扩展:平衡二叉树
输入一棵二叉树的根节点,判断是不是AVL树
*/
bool isBalanced(BinaryTreeNode* pRoot)
{
if(pRoot == NULL) return true;
int left = TreeDepth(pRoot->m_pLeft);
int right = TreeDepth(pRoot->m_pRight);
int diff = left - right;
if(diff > 1 || diff < -1) return false;
return isBalanced(pRoot->m_pLeft) && isBalanced(pRoot->m_pRight);
}
//better solution
bool isBalanced(BinaryTreeNode* pRoot, int *pDepth)
{
if(pRoot == NULL)
{
*pDepth = 0;
return true;
}
int left,right;
if(isBalanced(pRoot->left,&left) && isBalanced(pRoot->right,&right))
{
int diff = left - right;
if(diff <= 1 && diff >= -1)
{
*pDepth = 1+(left>right?left:right);
return true;
}
}
return false;
}