要了解二叉树与树,森林的互转,首先要知道树的存储结构:
一个合理的想法是在结点中存放指向每一个子女结点的指针。但由于各个结点的子女数不同,每个结点设置数目不等的指针,将很难管理。
所以就有了
子女-兄弟表示(也称为树的二叉树表示。结点构造为)
:
firstChild 指向该结点的第一个子女结点。无序树时,可任意指定一个结点为第一个子女。
nextSibling 指向该结点的下一个兄弟。任一结点在存储时总是有顺序的。
若想找某结点的所有子女,可先找firstChild,再反复用 nextSibling 沿链扫描。
代码实现:树的表示(2)--子女兄弟表示法_KRYON!的博客-CSDN博客
template <class T>
struct TreeNode { //树的结点类
T data; //结点数据
TreeNode<T> *firstChild, *nextSibling;
//子女及兄弟指针
TreeNode (T value = 0, TreeNode<T> *fc = NULL,
TreeNode<T> *ns = NULL) //构造函数
: data (value), firstChild (fc), nextSibling (ns) { }
};
template <class T>
class Tree { //树类
private:
TreeNode<T> *root, *current; //根指针及当前指针
int Find (TreeNode<T> *p, T value); //在以p为根的树中搜索value
void RemovesubTree (TreeNode<T> *p); //删除以p为根的子树
bool FindParent (TreeNode<T> *t,
TreeNode<T> *p);
public:
Tree () { root = current = NULL; } //构造函数
bool Root (); //置根结点为当前结点
bool IsEmpty () { return root == NULL; }
bool FirstChild ();
//将当前结点的第一个子女置为当前结点
bool NextSibling ();
//将当前结点的下一个兄弟置为当前结点
bool Parent ();
//将当前结点的双亲置为当前结点
bool Find (T value);
//搜索含value的结点, 使之成为当前结点
…… //树的其他公共操作
};
template <class T>
bool Tree<T>::Root () {
//让树的根结点成为树的当前结点
if (root == NULL) {
current = NULL; return false;
}
else {
current = root; return true;
}
};
template <class T>
bool Tree<T>::Root () {
//让树的根结点成为树的当前结点
if (root == NULL) {
current = NULL; return false;
}
else {
current = root; return true;
}
};
template <class T>
bool Tree<T>::
FindParent (TreeNode<T> *t, TreeNode<T> *p) {
//在根为*t的树中找*p的双亲, 并置为当前结点
TreeNode<T> *q = t->firstChild; //*q是*t长子
bool succ;
while (q != NULL && q != p) { //扫描兄弟链
if ((succ = FindParent (q, p)) == true)
return succ; //递归搜索以*q为根的子树
q = q->nextSibling;
}
if (q != NULL && q == p) {
current = t; return true;
}
else { current = NULL; return false; } //未找到
};
template <class T>
bool Tree<T>::FirstChild () {
//在树中找当前结点的长子, 并置为当前结点
if (current && current->firstChild )
{ current = current->firstChild; return true; }
current = NULL; return false;
};
template <class T>
bool Tree<T>::NextSibling () {
//在树中找当前结点的兄弟, 并置为当前结点
if (current && current->nextSibling) {
current = current->nextSibling;
return true;
}
current = NULL; return false;
};
转换概念有点抽象,我直接放大佬博客了
把二叉树转换成树(代码实现)_追梦少年ML的博客-CSDN博客
树的遍历(通过子女兄弟法)
//算法实现
template <class T>
void Tree<T>::
PreOrder ( void (*visit) (BinTreeNode<T> *t) ) {
//以当前指针current为根, 先根次序遍历
if (!IsEmpty ()) { //树非空
visit (current); //访问根结点
TreeNode<T> *p = current; //暂存当前指针
current = current->firstChild; //第一棵子树
while (current != NULL) {
PreOrder (visit); //递归先根遍历子树
current = current->nextSibling;
}
current = p; //恢复当前指针
}
};
代码实现
template <class T>
void Tree<T> ::
PostOrder (void (*visit) (BinTreeNode<T> *t)) {
//以当前指针current为根, 按后根次序遍历树
if ( ! IsEmpty () ) { //树非空
TreeNode<T> *p = current; //保存当前指针
current = current->firstChild; //第一棵子树
while (current != NULL) { //逐棵子树
PostOrder (visit);
current = current->nextSibling;
}
current = p; //恢复当前指针
visit (current); //访问根结点
}
};
广度优先(树的层次遍历)
template <class T>
void Tree<T>::
LevelOrder(void (*visit) (BinTreeNode<T> *t) ) {
//按广度优先次序分层遍历树, 树的根结点是
//当前指针current。
Queue<TreeNode<T>*> Q;
TreeNode<T> *p;
if (current != NULL) { //树不空
p = current; //保存当前指针
Q.EnQueue (current); //根结点进队列
while (!Q.IsEmpty ()) {
Q.DeQueue (current); //退出队列
visit (current); //访问之
current = current->firstChild;
while (current != NULL) {
Q.EnQueue (current);
current = current->nextSibling;
}
}
current = p; //恢复算法开始的当前指针
}
};
森林的遍历(无代码)