下面以一棵二叉查找树为例说明中序遍历的程序实现及其转化为双向链表的方法。二叉查找树的性质是:每个结点对应的值都大于其左子树中任意结点的值且小于右子树中任意结点的值,如下例所示。
可以明显地看出,该二叉树经历中序遍历后,值会从小到大输出,即4→6→8→10→12→14→16,我们最终要实现的目标是将这个二叉树转化为双向链表,即4⇆6⇆8⇆10⇆12⇆14⇆16。
首先定义一个结构体BinTree,它有三个成员,一个成员val存放结点的值,两个指针分别指向左子树和右子树。
struct BinTree {
int val;
BinTree *left, *right;
BinTree(int v) : val(v), left(NULL), right(NULL) {}
};
使用递归法来遍历二叉树是非常简洁明了的,这个无需多言。
void traverse(BinTree *root)
{
if(root == NULL) return;
traverse(root->left);
cout << root->val << endl;
traverse(root->right);
}
下面使用循环的方式来实现中序遍历,这会用到“栈”,不断将前面的结点压入栈中,代码如下。
void treeTraverse(BinTree *root)
{
stack<BinTree*> s;
BinTree *p = root;
while (p || !s.empty()) {
while (p) {
s.push(p);
p = p->left;
}
p = s.top();
s.pop();
cout << p->val << endl;
p = p->right;
}
}
可以看到,中序遍历时,cout的先后顺序正是双向链表从左到右的顺序,故只需将cout部分替换为指针指向代码即可,具体实现如下。
BinTree* treeToList(BinTree *root)
{
stack<BinTree*> s;
BinTree *p = root, *prev = NULL, *head = NULL;
while (p || !s.empty()) {
while (p) {
s.push(p);
p = p->left;
}
p = s.top();
s.pop();
if(head == NULL) head = p;
if (prev) prev->right = p;
p->left = prev;
prev = p;
p = p->right;
}
return head;
}