PAT 1130 Infix Expression——什么才是DFS?由“柳神遍历”写法引发的思考

常见遍历写法

或者说书上一般的范例写法
此处特指王道,天勤等考研递归写法

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可以进行类型转换,在某些题可能有用,其次要注意 “流”传递要用引用

后记

这种写法还是十分值得借鉴与模仿及扩展的,因为更多的题目并不会傻乎乎地只要求你遍历一下,更多的隐含要求会基于叶节点形状来考察

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值