与二叉树不同的是,n叉树上每个节点可以有任意个孩子节点。由于孩子节点数目不确定,我们不知道该为每个节点分配多大的存储空间,就算可以确定孩子节点的最大数目,也不能保证每个节点拥有相同个数的孩子,这就会导致为孩子节点预留的空间得不到充分利用。
有一种表示法可以避免这些问题,那就是“左孩子-右兄弟”表示法,与二叉树类似,每个节点依然保存除了父亲节点外的两个节点指针,分别表示其左数第一个孩子,和右面第一个兄弟。
这样一来,就可以像遍历二叉树一样地遍历n叉树了。10.4-4具体实现见Traverse方法。
10.4-6要求在Node节点里用“两个指针和一个bool量”取代“三个指针”,实现获取当前节点的父亲和孩子节点的过程,假设当前节点的孩子个数为m,要求过程时间为O(m)。
这道题的思路是,要想从三个指针变成两个指针,应该省略谁呢?仔细观察会发现,一个节点的若干个孩子节点的父亲指针都指向自己,这里有信息的冗余,应该想办法把保存多份父亲指针变成只保存一份,这一份保存在哪里好呢?因为最右面的孩子没有右兄弟,它的“右兄弟”指针的位置刚好空出来可以保存“父亲”指针,而题目中提示的那个bool量自然就是用来表示“当前节点是否为最右面的孩子”。具体实现见GetParent,GetChild方法。
#include <cassert>
#include <iostream>
#include <stack>
using namespace std;
using Index = int;
class ArbitraryRootTree
{
public:
ArbitraryRootTree();
//O(n)-time traverse
void Traverse() const;
Index GetParent(Index nodeIndex) const;
Index GetChild(Index nodeIndex, int rank) const;
private:
struct Node
{
int key;
Index left_child;
Index right_sibling;
bool bLastChild;
};
Node m_array[11];
Index m_root;
};
ArbitraryRootTree::ArbitraryRootTree()
{
/* the tree looks like
* node's key node's index in array
* 12 6
* / | \
* 1 3 5 5 4 3
* / \ | / | \ \
* 7 8 4 2 6 0 11 2 1 0 7 8 9 10
*
* index key left_child right_sibling parent
* 0 4 -1 -1 4
* 1 8 -1 -1 5
* 2 7 -1 1
* 3 5 7 -1 6
* 4 3 0 3
* 5 1 2 4
* 6 12 5 -1
* 7 2 -1 8
* 8 6 -1 9
* 9 0 -1 10
* 10 11 -1 -1 3
*
*/
m_root = 6;
m_array[0] = Node{4, -1, 4, true};
m_array[1] = Node{8, -1, 5, true};
m_array[2] = Node{7, -1, 1, false};
m_array[3] = Node{5, 7, 6, true};
m_array[4] = Node{3, 0, 3, false};
m_array[5] = Node{1, 2, 4, false};
m_array[6] = Node{12, 5, -1, false};
m_array[7] = Node{2, -1, 8, false};
m_array[8] = Node{6, -1, 9, false};
m_array[9] = Node{0, -1, 10, false};
m_array[10] = Node{11, -1, 3, true};
}
void ArbitraryRootTree::Traverse() const
{
stack<Index> indexStack;
indexStack.push(m_root);
Index index, childIndex;
while(!indexStack.empty())
{
index = indexStack.top();
indexStack.pop();
cout << m_array[index].key << "\t";
childIndex = m_array[index].left_child;
if(childIndex != -1)
indexStack.push(childIndex);
childIndex = m_array[index].right_sibling;
if(!m_array[index].bLastChild && childIndex != -1)
indexStack.push(childIndex);
}
}
Index ArbitraryRootTree::GetParent(Index nodeIndex) const
{
while(m_array[nodeIndex].bLastChild == false)
nodeIndex = m_array[nodeIndex].right_sibling;
return m_array[nodeIndex].right_sibling;
}
Index ArbitraryRootTree::GetChild(Index nodeIndex, int rank) const
{
Index childIndex = m_array[nodeIndex].left_child;
while(rank-- != 1)
{
assert(childIndex != -1);
childIndex = m_array[childIndex].right_sibling;
}
return childIndex;
}
void Test()
{
ArbitraryRootTree tree;
tree.Traverse(); //12 1 3 5 2 6 0 11 4 7 8
cout << endl;
cout << tree.GetParent(7) << "\t";
cout << tree.GetParent(8) << "\t";
cout << tree.GetParent(9) << "\t";
cout << tree.GetParent(10) << "\t";//下标为7~10四个节点的父亲节点下标都是3
cout << endl;
cout << tree.GetChild(3,1) << "\t";
cout << tree.GetChild(3,2) << "\t";
cout << tree.GetChild(3,3) << "\t";
cout << tree.GetChild(3,4) << "\t";//依次获取节点3的四个孩子7~10
}
//Test运行结果
//12 1 3 5 2 6 0 11 4 7 8
//3 3 3 3
//7 8 9 10