您的位置:首页 > 编程语言

【纯代码向】 运用优先队列对拓补排序的实现

2017-10-24 20:07 253 查看
在这篇文章里,我想贴出我的拓补排序代码与分析,讲一讲它是如何从最慢的方法(O(n方))变到理论上最优的方法(O(n))的。

分析

首先,我们需要知道我们面对什么样的问题:我们需要每次找出出度为零(倒序)或者入度为零(正序)的节点,删除这个点后,将这个节点与“父结点”相连的边删除,重复该步骤直到无点可删。
那么第一种方法就出来了。


方案一 逐次检索

每一次我们删除一个点,就去寻找一次图上是否有出度为零的点,这样时间为n方,会浪费大量时间在不必要的搜索上。但相对比较好写,故此不贴出代码,不提倡。

方案二 检查,入队

请大家思考一些问题:有什么点,它原本的出度不为0,然而经过了一次删边之后,出度就变化为0了呢?答案是,那些跟删除的那些点相连,出度为1的点。因为每次删除只会影响到这些点,其他店的出度是不变的,所以我们只需在这中间找即可。

类似于广搜,我们用一个队列(stack[xx])储存出度为零的点。

int stack[20005],be[20005];//be[xx]储存点的出度
vector <int> son[20005];//vector 作为邻接表
int p1=0,p2=0;
for(int i=1;i<=n;i++)
if(be[i]==0) stack[++p2]=i;
while(++p1<=p2){
int h=stack[p1];
for(int i=son[h].size()-1;i>=0;i--)
{
int k=son[h][i];
if(--be[k]==0) stack[++p2]=k;
}
}


不难看出,因为每次操作,我们都可以删去一条边,所以这个算法的时间复杂度是O(m)的,但仍不是我们理想的结果,因为每次都要进行一次判断,常数可能很大。

接下来,就是我们的最终解法。

方案三 优先队列

优先队列真是太好用了!感觉这东西后面会用的很多,而的确是这样,所以请确保你能独立打出优先队列的模板(可以去看我的前一篇博客,)。

数据结构

我们需要这几个东西:

- 出度最小的点队列(有序)——优先队列 因为我们需要优化,所以不能在每次循环后去寻找入度为零的点,而是应当排序。注意,这里的优先队列也得使用结构体,因为我们要记录原先这个点的位置。

- 每个节点的出度

- 每个点的父结点

- 点的访问情况 **运用优先队列,会导致一个点重复进出队列,为了不重复,我们需要用一个数组来判断是否访问过。

using namespace std;
struct node{
int du,pos;
bool operator < (const node& x)const{
if(du>x.du) return true;
return false;
}
};
priority_queue<node> Q;


这里是结构体里的东西,注意重载运算符,这是优先队列的前提。

void readit()
{
memset(vis,0,sizeof(vis));
int n,m;scanf("%d%d",&n,&m);
for(int a,b,i=1;i<=m;i++){
scanf("%d%d",&a,&b);
fa.push_back(a);
chu[a]++;
}
for(int i=1;i<=n;i++)
Q.push((node){chu[i],i});
}


读入数据的过程,我用vector fa
来存储父结点。

while(!Q.empty()){
node x=Q.top();Q.pop();
int k=x.pos;
if(vis[k]) continue;
if(x.du!=0) break;
vis[k]=true;
//doit(k);         放你想做的事吧
for(int i=fa[k].size()-1;i>=0;i--)
{
int p=fa[k][i];
chu[p]--;
Q.push((node){chu[p],p});
}
}


这是主程序的部分。注意的点有两个:首先,要以优先队列非空作为判断的依据,这是为了避免运行错误的基准条件,任何数据结构一定要判断是否超了下界。

其次,是判断这个点的度是否为零:如果不为零,而因为这又是度最小的那一个,那么说明[b]该图有环
,情况错误,退出。剩下的是一些无关紧要的东西了,都可以在我之前的文章里找到。

尾声

这一点内容也结束了,虽然不多,但感觉写起来很累。效率是否过低?我开始理解为什么很多大大们分析完思路就直接贴代码了。下一次我会酌情改进,那么再见,你的支持是我的动力(之一),莫忘评论指出我的不足,谢谢!

2017.10.24
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息