根据线索化二叉树和非递归前序遍历二叉树的算法,对两者进行进行结合
代码设计
线索化二叉树和非递归前序遍历二叉树的算法结合,首先需要建立二叉树:定义二叉树节点,并且构造函数createTree()来建立二叉树,为了方便输入,用前序法进行输入#代表空结点。然后将建立好的二叉树线索化,再对线索化二叉树进行非递归的前序遍历。
代码解析
a.定义二叉树节点,并在里面添加一个bool visit,方便遍历时判断该节点是否被访问过
// 定义二叉树结点
struct TreeNode {
char val;
TreeNode* left;
TreeNode* right;
bool ltag;
bool rtag; // 标志指向线索还是树结构
bool visit; // 判断是否被访问过
TreeNode(char x) : val(x), left(NULL), right(NULL), ltag(false), rtag(false),visit(false) {}
};
b.建立二叉树,通过输入建立二叉树,按照前序输入:如果不输入#,则将不断生成前驱,直到出现#开始生成后继,连续输入两个#则转到上一个没有输入后继的节点继续输入。
// 建立二叉树
TreeNode* createTree() {
char c;
cin >> c;
if (c == '#') {
return nullptr;
}
TreeNode* root = new TreeNode(c);
root->left = createTree();
root->right = createTree();
return root;
}
c.线索化,将建立的二叉树线索化,当结点为空时不会往后进行线索化(直接return),如果前驱/后继为空,则会建立左/右线索。
// 线索化二叉树
void inOrderThreaded(TreeNode* root, TreeNode*& pre) {
if (root == nullptr) {
return;
}
inOrderThreaded(root->left, pre); // 左子树线索化
if (root->left == nullptr) // 建立左线索
{
root->ltag = true;
root->left = pre;
}
if (pre != nullptr && pre->right == nullptr) // 建立右线索
{
pre->rtag = true;
pre->right = root;
}
pre = root; // 要进行右子树线索化前先改变pre为root
inOrderThreaded(root->right, pre); // 右子树线索化
}
d.非递归前序遍历线索化二叉树,需要根据该节点是否被访问过来进行输入和下一步转跳(left or right)。如果没被访问过则直接输出,未被访问并且左指针不是线索就访问前驱,否则访问后继。访问后继时,要么不是线索,指向下一个节点,要么是线索,指向线索(父亲或者爷爷,如果是最后一个则指向空,遍历结束)。
// 非递归前序遍历线索化二叉树
void preOrderTraversal(TreeNode* root) {
while (root) {
if(root->visit==false)
cout << root->val << " ";
if (!root->ltag&&root->visit==false) // 是指针,且没被visit过
{
root->visit=true;
root = root->left;
}
else
root = root->right;
}
}
e.实现,最后用main实现功能
int main() {
// 建立二叉树
cout << "请输入二叉树的节点数据(#表示空节点):" << endl;
TreeNode* root = createTree();
TreeNode* pre = nullptr;
// 线索化二叉树
inOrderThreaded(root, pre);
// 非递归前序遍历线索化二叉树
preOrderTraversal(root);
return 0;
}