常见遍历写法
或者说书上一般的范例写法
此处特指王道,天勤等考研递归写法
void PrintTree(BiTree* T) {
if (T) {
PrintTree(T->lchild);
PrintTree(T->rchild);
printf("%d ", T->key);
}
}
柳神遍历代码
源地址:https://www.liuchuo.net/archives/3798
string ans = dfs(root);
string dfs(int root) {
if (a[root].l == -1 && a[root].r == -1)
return a[root].data;
if (a[root].l == -1 && a[root].r != -1)
return "(" + dfs(a[root].r) + a[root].data + ")";
if (a[root].l != -1 && a[root].r != -1)
return"(" + dfs(a[root].l) + dfs(a[root].r) + a[root].data + ")";
}
何为DFS?
DFS脱胎于图的一种遍历算法,
常见会将其类比于树的先序算法
广义开来甚至类比于中序算法,后序算法
其基本思想是:任选一个结点,检查这个点所有的邻点,递归访问其中未被访问的点
写法剖析——比较柳神与传统写法
传统的写法仅能保证遍历全部的点;并不具备识别点类型的功能
而柳神的写法是以三角形为视角,重视节点形态的写法
原因是这道题有特殊地方,中缀表达式其中对于
1.“-”和“()”的处理 **
2.字符串输出
如果有详细研究的同学会发现要求1都与树的节点形状有关**,因此可以随时变更遍历方法
而要求2.直接导致了可以进行 return ++这种字符串返回拼接时的**“简洁,高端”写法**
以下是我的非字符串的仿写
仿写版1
queue<int> qu;
PrintTree(root,qu);
void PrintTree(BiTree* T,queue<int>& qu) {//左中右
if (T->lchild == NULL && T->rchild == NULL) {
qu.push(T->key);
return ;
}
if (T->lchild == NULL && T->rchild != NULL) {
PrintTree(T->rchild,qu);//哪边不空访问哪边
qu.push(T->key);
return;
}
if (T->lchild != NULL && T->rchild == NULL) {
PrintTree(T->lchild, qu);
qu.push(T->key);
return;
}
if (T->lchild != NULL && T->rchild != NULL) {//此段表明为后序遍历,其他遍历则调整push位置
PrintTree(T->lchild, qu);
PrintTree(T->rchild, qu);
qu.push(T->key);
return;
}
}
结论:简单说,在判断叶节点形态的同时,需要有一个缓存数据的地方。此处用stl—queue缓存
仿写版2
void PrintTree(BiTree* T, stringstream &stream, string &result) {//左中右
if (T->lchild == NULL && T->rchild == NULL) {
stream << T->key<<" ";
//stream>> result;
return ;
}
if (T->lchild == NULL && T->rchild != NULL) {
PrintTree(T->rchild, stream, result);//哪边不空访问哪边
stream << T->key << " ";
//stream >> result;
return;
}
if (T->lchild != NULL && T->rchild == NULL) {
PrintTree(T->lchild, stream, result);
stream << T->key << " ";
//stream >> result;
return;
}
if (T->lchild != NULL && T->rchild != NULL) {//此段表明为后序遍历,其他遍历则调整push位置
PrintTree(T->lchild, stream, result);
PrintTree(T->rchild, stream, result);
stream << T->key << " ";
//stream >> result;
return;
}
}
getline(stream, result);//读取一整行,直到换行符结束,输出时换行符是被吃掉的;endl(换行+刷新流)等价于“\n”;
cout << result << endl;
结论:此处用stringstream缓存,原因在于stringstream可以进行类型转换,在某些题可能有用,其次要注意 “流”传递要用引用
后记
这种写法还是十分值得借鉴与模仿及扩展的,因为更多的题目并不会傻乎乎地只要求你遍历一下,更多的隐含要求会基于叶节点形状来考察