张小二求职之 深度搜索和先序遍历 (绝非你想象那样简单)
经过一段时间的闭馆修炼,张小二我又学到了不少东西,准备去会一会那个变态的面试官,我的未来他做主。
M:是你小子。
z:心理说,(是你大爷我),脸上满脸堆笑,连声说,是我是我,
M:我们的大门随时向你打开,只要你达到我们的要求,废话少说,我们开始吧;
3z:so eazy,1 。树有边和点组成,是一种特殊的图,每个点只有一个入度,出了root以外,也就是每个点有且只有一个爹,
树是联通的,无欢的,所以一颗n个节点的树有满足以下三点中的两条就行:
1.联通
2.没有环
3 n-1条边
任意连个都能导出第三个.
M:不过,你觉得如何判断一个图是否是一棵树呢?
z:利用上文中的n-1条边,很好查出来
可以判断是否有环?(有向图可以用topsort,无向图用并查集更方面)
可以判断是否联通(随便搜索一次)
M:功力见长啊,那我问你,深度优先搜索会吧?写出代码吧,递归和非递归两种
z:伪代码行吗?
M:你要人看懂就行
z:我怕你看不懂,我写了,你别盯着我啊,我害羞啊。
void dfs(int v)
{
if()
visited[v]=true;
for(int i=0;i<len;i++)
{
if(dfs(neig[v].i==1)&&!visited[i])
{
dfs(i);
}
}
M:你这个代码有问题呢?
z:是的,他没有考虑这个图是多个联通图,写出来很简单。
M:好吧,写个非递归的出来行吗:
z:小意思(此处STL代码可能出错,我对这些不太熟)这个代码和bfs一样,
void dfs(int *G,int v)
{
stack<int> ;
s.push(v);起始点入队
vistied[v]=true;//该点已经访问
while(!s.IsEmpty())//如果栈不为空
{
int v2=s.top();
cout<<v2<<endl;//输出栈顶元素
q.pop(); //出栈
//孩子入站
for(所有v邻接点且未访问过)
{
s.push(改点);
}
}
}
M:二叉树有三种遍历方式,哪一种是和深度搜索的思想是一样的?
z:应该是先序遍历
M不赖,写出个先序遍历吧
z:非递归的,还是递归的?
M:小伙子,别急,其实我还没有看你的dfs两个版本,你不说两者思想都一样吗?哪里一样了
z:你看,我写个递归方式
void preorder(node *root)
{
if(root!=NULL)
{
cout<<root->data<<endl;
preorder(root->left);
preorder(root->right);
}
}
其实,树的先序是深度搜索的特殊形式,这就意味着我们可以直接使用深度优先搜索来找到先序结果,同时,我们从代码层面思考,树是一种特殊的图,树只有一个父亲,因此树不会重复访问,所以去掉visited访问数组,同时以前的for循环取未访问的邻接点,数中只有两个,因此我们完全可以更改为dfs(左),dfs(右边);
M;你领悟的很好啊,非递归呢?非递归的先序写出来,不对,你改一改,
void dfs(node* v)
{
stack<int> ;
s.push(v);起始点入队
vistied[v]=true;//该点已经访问 visited数组去掉
while(!s.IsEmpty())//如果栈不为空
{
int v2=s.top();
cout<<v2<<endl;//输出栈顶元素
q.pop(); //出栈
//孩子入站
for(所有v邻接点且未访问过)
{
s.push(改点);
}去掉黄色的
改为
if(v->left==NULL) s.push(v->left);
if(v->right==NULL) s.push(v->right);
}
M:你的代码不够精准,但是思想是正确的,深度搜索和回溯的关系知道吗?八皇后能写出来吗,
z:对不起,我现在还不会
M;没关系,你可以回去看看,但是我想告诉你深度搜索是一种具有智能性的算法,他的功能比你想象的多的多,同时你提到拓扑排序,如何用深度搜索实现,深度搜索可以判断是否联通,也可以判断drg是否有环呢。
z:,大哥你好牛逼的
M;心理很得意,但是嘴上说,你一定会超过我的,很年轻
z:最烦的就是这句换,表面谦虚,实际是你现在比我差远了,大