(題目來源於v_JULY_v的整理,微軟公司等數據結構+算法面試100題,July博客http://blog.csdn.net/v_JULY_v)
題目:輸入一顆二元查找樹,將該樹轉換爲它的鏡像,
即在轉換後的二元查找樹中,左子樹的結點都大於右子樹的結點。
用遞歸和循環兩種方法完成樹的鏡像轉換。
例如輸入:
8
/ \
6 10
/ \ / \
5 7 9 11
輸出:
8
/ \
10 6
/ \ /\
11 9 7 5
struct BSTreeNode
{
int m_nValue; // value of node
BSTreeNode *m_pLeft; // left child of node
BSTreeNode *m_pRight; // right child of node
};
typedef BSTreeNode* Tree;
void addNode(Tree &tree, int data)
{
if (tree == NULL)
{
tree = new BSTreeNode;
tree->m_nValue = data;
tree->m_pLeft = NULL;
tree->m_pRight = NULL;
return ;
}
else if ( tree->m_nValue >= data)
{
addNode(tree->m_pLeft, data);
}
else
addNode(tree->m_pRight, data);
}
void Translate(Tree &tree)
{
if (!tree)
{
return ;
}
if (tree->m_pLeft)
{
Translate(tree->m_pLeft);
}
if (tree->m_pRight)
{
Translate(tree->m_pRight);
}
Tree temp = tree->m_pLeft;
tree->m_pLeft = tree->m_pRight;
tree->m_pRight = temp;
}
void PrintTree(Tree &tree)
{
if (!tree)
{
return;
}
PrintTree(tree->m_pLeft);
cout<<tree->m_nValue<<' ';
PrintTree(tree->m_pRight);
}
int _tmain(int argc, _TCHAR* argv[])
{
Tree BinaryTree = NULL;//頭結點
//bool bEnd = false;
//while (!bEnd)
//{
// int data = 0;
// cin>>data;
// if (data == -1)
// {
// bEnd = true;
// }
// else
// addNode(BinaryTree, data);
//}
addNode(BinaryTree, 8);
addNode(BinaryTree, 6);
addNode(BinaryTree, 10);
addNode(BinaryTree, 5);
addNode(BinaryTree, 7);
addNode(BinaryTree, 9);
addNode(BinaryTree, 11);
Translate(BinaryTree);
PrintTree(BinaryTree);
system("pause");
return 0;
}
思路:如果採用循環的的方式,這裏藉助容器,採用採用層序遍歷的思想將遍歷的所有節點保存在容器中,循環遍歷。
int _tmain(int argc, _TCHAR* argv[])
{
Tree BinaryTree = NULL;//頭結點
//bool bEnd = false;
//while (!bEnd)
//{
// int data = 0;
// cin>>data;
// if (data == -1)
// {
// bEnd = true;
// }
// else
// addNode(BinaryTree, data);
//}
addNode(BinaryTree, 8);
addNode(BinaryTree, 6);
addNode(BinaryTree, 10);
addNode(BinaryTree, 5);
addNode(BinaryTree, 7);
addNode(BinaryTree, 9);
addNode(BinaryTree, 11);
//Translate(BinaryTree);
vector<Tree> NodeVct;
NodeVct.push_back(BinaryTree);
int start = 0;
int end = 1;
Tree tree = NULL;
Tree temp = NULL;
while (start<end)
{
tree = NodeVct[start];
if (tree)
{
temp = tree->m_pLeft;
tree->m_pLeft = tree->m_pRight;
tree->m_pRight = temp;
}
if (tree->m_pLeft)
{
NodeVct.push_back(tree->m_pLeft);
++end;
}
if (tree->m_pRight)
{
NodeVct.push_back(tree->m_pRight);
++end;
}
++start;
}
PrintTree(BinaryTree);
system("pause");
return 0;
}
July提供的答案
void Revertsetree(list *root)
{
if(!root)
return;
list *p;
p=root->leftch;
root->leftch=root->rightch;
root->rightch=p;
if(root->leftch)
Revertsetree(root->leftch);
if(root->rightch)
Revertsetree(root->rightch);
}
方法二
由於遞歸的本質是編譯器生成了一個函數調用的棧,
因此用循環來完成同樣任務時最簡單的辦法就是用一個輔助棧來模擬遞歸。
首先我們把樹的頭結點放入棧中。
在循環中,只要棧不爲空,彈出棧的棧頂結點,交換它的左右子樹。
如果它有左子樹,把它的左子樹壓入棧中;
如果它有右子樹,把它的右子樹壓入棧中。
這樣在下次循環中就能交換它兒子結點的左右子樹了。
//再用輔助棧模擬遞歸,改成循環的(有誤之處,望不吝指正):
void Revertsetree(list *phead)
{
if(!phead)
return;
stack<list*> stacklist;
stacklist.push(phead); //首先把樹的頭結點放入棧中。
while(stacklist.size())
//在循環中,只要棧不爲空,彈出棧的棧頂結點,交換它的左右子樹
{
list* pnode=stacklist.top();
stacklist.pop();
list *ptemp;
ptemp=pnode->leftch;
pnode->leftch=pnode->rightch;
pnode->rightch=ptemp;
if(pnode->leftch)
stacklist.push(pnode->leftch); //若有左子樹,把它的左子樹壓入棧中
if(pnode->rightch)
stacklist.push(pnode->rightch); //若有右子樹,把它的右子樹壓入棧中
}
}
看答案後的感悟:
①在使用遞歸方法解決問題時,總是涉及到函數參數的進棧和出棧,我們可以合理的選擇輔助棧來解決這類問題。
②先序遍歷和後序遍歷對結果並無影響。
③採用輔助棧時,遍歷的順序實際是根右左。