前提
通过二叉链表建立二叉树,二叉链表的节点结构如下:
template<class T>
struct BiNode {
T data; //节点数据
BiNode<T>* lchild; //左孩子
BiNode<T>* rchild; //右孩子
};
二叉树类的结构如下:
template<class T>
class BiTree {
private:
BiNode<T>* root; //根节点
public:
BiTree(T data[], int n); //构造函数
void PreOrder(); //前序遍历
void InOrder(); //中序遍历
void PostOrder(); //后序遍历
void LevelOrder(); //层序遍历
~BiTree(); //析构函数
int GetDepth(); //获取二叉树的深度
void GetPath(T node); //获取指定节点的路径
void GetPath(BiNode<T>* node); //获取指定节点指针的路径
BiNode<T>* GetNode(T node); //获取指定元素的节点指针
};
基本思想
二叉树建立的过程如下图所示:
可以利用栈来实现非递归建立,另外还需要创建一种栈节点结构,该结构包括:
- 一个
BiNode<T>
类型的指针p
,用于存放指向该二叉树节点的指针; - 一个
int
类型变量i
,用于存放该二叉树节点在顺序存储结构中的位置; - 一个
int
类型变量stage
,用于表示该二叉树节点的创建状态。该节点的创建状态有4种:stage = 0
时,表示p
为NULL
,需要为p
创建空间,并将data
中的相应数据存入p->data
;stage = 1
时,表示还未创建p->lchild
和p->rchild
,需要为p->lchild
创建空间,并将data
中的相应数据存入左孩子中;stage = 2
时,表示已创建p->lchild
,还未创建p->rchild
,需要为p->rchild
创建空间,并将data
中相应数据存入右孩子中;stage = 3
时,表示p->lchild
和p->rchild
均已创建,则该节点可以出栈。
(注意:stage
只表示p
的创建情况,与p
的左孩子和右孩子最后是否为NULL
没有关系。)
C++描述如下:
template<class T>
struct Node {
BiNode<T>* p;
int i; //对应初始化数组中的位置
//访问该节点时的状态。
//0表示需创建该节点,1表示需创建该节点的左孩子,2表示需创建该节点的右孩子,3表示需将该节点出栈
int stage;
};
建立起的二叉树还需要将root
指向根节点,以便通过root
查找该二叉树。通过观察上图中二叉树的建立过程,可以发现,每当栈中只有一个节点时,该节点即为根节点,那么可以在循环的过程中加入判断栈长的语句,进而将root
指向根节点。而且,根节点总是最后一个出栈,不必担心在循环中二叉树发生变化而root
没有变化。
非递归建立二叉树的具体步骤如下:
- [1]将root置空,存入Node中,并设定stage为0,然后入栈;
- [2]判断栈是否为空,若为空,结束;若不为空,执行[3];
- [3]取栈顶元素top;
- [3.1]判断栈中元素个数是否为1,若为1,root=top->p;否则,执行下一步;
- [3.2]判断top->stage的数值:
- [3.2.1]stage=0:初始化top->p,然后将data中第top->i个元素存入top->p中,更改top->stage为1;
- [3.2.2]stage=1:初始化top->p的左孩子,然后将data中第top->i*2个元素存入top->p的左孩子中,其次将该左孩子入栈,其stage设为0,最后更改top->stage为2;
- [3.2.3]stage=2:初始化top->p的右孩子,然后将data中第top->i*2+1个元素存入top->p的右孩子中,其次将该右孩子入栈,其stage设为0,最后更改top->stage为3;
- [3.2.4]stage>2:top出栈;
- [4]返回[2]。
C++描述
构造函数:BiTree(T data[], int n);
参数:data
数组是二叉树的顺序存储结构,n
表示数组的长度;
template<class T>
BiTree<T>::BiTree(T data[], int n) {
root = NULL; //初始化根节点
stack<Node<T>*>st; //栈
Node<T>* no = new Node<T>;
no->p = root; //将根节点存入Node节点中
no->i = 1;
no->stage = 0;
st.push(no); //入栈
while (!st.empty()) {
no = st.top(); //取栈顶元素
if (st.size() == 1) {
root = no->p; //当栈中只剩一个元素时取该元素中存放的节点为根节点
}
if (no->stage == 0) { //stage为0时,创建该节点
BiNode<T>* r = new BiNode<T>;
r->data = data[no->i - 1];
r->lchild = r->rchild = NULL;
no->p = r;
no->stage = 1; //更改stage
}
else if (no->stage == 1) { //stage为1时,创建左孩子
BiNode<T>* r;
int i = no->i * 2;
if ((i <= n) && (data[i - 1] != NULL)) {
r = new BiNode<T>;
r->data = data[i - 1];
r->lchild = r->rchild = NULL;
}
else {
r = NULL;
}
no->p->lchild = r;
no->stage = 2; //更改stage
if (r != NULL) {
no = new Node<T>;
no->p = r;
no->i = i;
no->stage = 1;
st.push(no); //左孩子节点入栈
}
}
else if (no->stage == 2) { //stage为2时,创建右孩子
BiNode<T>* r;
int i = no->i * 2 + 1;
if ((i <= n) && (data[i - 1] != NULL)) {
r = new BiNode<T>;
r->data = data[i - 1];
r->lchild = r->rchild = NULL;
}
else {
r = NULL;
}
no->p->rchild = r;
no->stage = 3; //更改stage
if (r != NULL) {
no = new Node<T>;
no->p = r;
no->i = i;
no->stage = 1;
st.push(no); //右孩子节点入栈
}
}
else { //stage为其余情况时,栈顶元素出栈
st.pop();
}
}
}
这里放上我的完整代码:非递归建立二叉树及测试代码