ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

拓扑排序

2022-06-01 01:02:40  阅读:150  来源: 互联网

标签:int 拓扑 numCourses vector visited 排序 节点 indeg


判断拓扑排序有入度表方式和深度优先(锁路径)无回路方式
其中入度表的能通过栈完成所有无前驱节点访问,也能通过队列广度优先完成访问,本质上只是存储无前驱节点的容器
构建对应拓扑序列序列只能用入度表的方式,按顺序解锁无前驱节点

    bool TopologicalSort(Graph G){
        stack<int> S;//新建一个栈存储无前驱节点(队列效果一样)
        for(int i = 0; i < G.vexnum; i++)
            if(indegree[i]==0) S.push(i);//入度为0顶点入栈
        int count = 0;//对已遍历节点计数
        while(!S.empty()){//开始处理栈中元素,相当于深度优先遍历图,逐渐减少入度
            int point = S.front();S.pop();//出栈
            cout<<point<<endl;//输出该节点
            count++;//计数加一
            for(int p = G.vertices[point].firstarc;p;p->nextarc){//遍历该节点邻接边
                int v = p ->adjvex;//得到邻接节点
                if(!(--dindegree[v])) S.push(v);//减少其入度,若等于0则入栈,即已经无前驱
            }
        }
        if(count<G.vexnum) return false;//排序失败有回路
        return true;//排序成功
    }

1. 课程表

你这个学期必须选修 numCourses 门课程,记为 0 到 numCourses - 1 。
在选修某些课程之前需要一些先修课程。请你判断是否可能完成所有课程的学习?如果可以,返回 true ;否则,返回 false

深度优先锁路径判断有无环
class Solution {
private:
    vector<vector<int>> edges;//邻接表存储图
    vector<int> visited;//记录已经遍历节点,防止重复遍历,同时锁住当前路径
    bool valid = true;

public:
    void dfs(int u) {
        visited[u] = 1;//访问后锁住
        for (int v: edges[u]) {//遍历顶点后继
            if (visited[v] == 0) {
                dfs(v);//继续递归遍历其后继
                if (!valid) return;//剪枝
            }
            else if (visited[v] == 1) {//发现是锁住节点,说有存在闭环
                valid = false;
                return;
            }
        }//无后继节点
        visited[u] = 2;//访问结束解锁
    }

    bool canFinish(int numCourses, vector<vector<int>>& prerequisites) {
        edges.resize(numCourses);
        visited.resize(numCourses);
        for (const auto& info: prerequisites) 
            edges[info[1]].push_back(info[0]);//重构图,存放每个顶点对应后继

        for (int i = 0; i < numCourses && valid; ++i) {
            if (!visited[i]) dfs(i);//深度优先遍历每一个未访问节点
            if(!valid) return valid;//剪枝
        }
        return valid;
    }
};

入度表
class Solution {
private:
    vector<vector<int>> edges;//重构图(邻接表)
    vector<int> indeg;//记录顶点入度t

public:
    bool canFinish(int numCourses, vector<vector<int>>& prerequisites) {
        edges.resize(numCourses);//分配内存
        indeg.resize(numCourses);//分配内存
        for (const auto& info: prerequisites) {
            edges[info[1]].push_back(info[0]);//重构图(邻接表)
            ++indeg[info[0]];//构图时记录入度
        }

        queue<int> q;//栈和队列在这里没有区别,都是用来存储无前驱节点的容器
        for (int i = 0; i < numCourses; ++i) 
            if (indeg[i] == 0) q.push(i); //先存储所有初始化无前驱节点

        int visited = 0;//记录访问数,后面就不用判断入度表有没有清0
        while (!q.empty()) {//当队列不为空
            ++visited;//访问一次加一
            int u = q.front();q.pop();//无前驱节点出队列,该节点移除
            for (int v: edges[u]) {//遍历该节点后继
                --indeg[v];//出队列节点移除,其后继入度都减一
                if (indeg[v] == 0) q.push(v);//削减至无前驱则入队
            }
        }
        return visited == numCourses;//判断是否访问完所有节点
    }
};

2. 外星文字典

请你根据该词典还原出此语言中已知的字母顺序,并 按字母递增顺序 排列。若不存在合法字母顺序,返回 "" 。若存在多种可能的合法字母顺序,返回其中任意一种顺序即可

构建领接矩阵和入度表
class Solution {
public:
    vector<vector<bool>> edges =  vector<vector<bool>>(26,vector<bool>(26));//矩阵
    vector<int> indeg = vector<int>(26);//记录顶点入度,直接从字符转换到下标
    unordered_set<int> s;//记录出现的字符,用于判断最后结果正确性
    bool flag = false;//居然还要判断给的数据是否正确
    string alienOrder(vector<string>& words) {
        //先按逻辑构件图(拓扑序列)
        int count = 0;//记录访问节点数量
        constructgraph(words);//构件好了邻接矩阵图,入度数据和所有节点
        if(flag) return "";
        //准备开始拓扑排序算法
        stack<int> stack_;
        string res;//存储结果
        for (int i = 0; i < 26; ++i) 
            if (s.count(i)!=0&&indeg[i] == 0) //字符出现过且无前驱
                stack_.push(i); //先存储所有初始化无前驱节点
        while(!stack_.empty()){
            count++;//记录一次访问
            int u = stack_.top(); stack_.pop();
            res.push_back(u+'a');
            for(int v = 0; v < 26;++v)
                if(edges[u][v]==1){-
                    --indeg[v];
                if(indeg[v]==0) stack_.push(v);
            }
        }
        if(count==s.size()) return res;
        return "";
    }

    void constructgraph(vector<string>& words){
        //先比较各单词内的,看错了其实不需要,但可以用来记录出现的字符
        for(int i=0;i<words.size();i++){
            s.insert(words[i][0]-'a');
            for(int j=1;j<words[i].size();j++){
                if(words[i][j]==words[i][j-1]) continue;
                s.insert(words[i][j]-'a');}}//记录已有字符
        //比较各单词间的
        for(int i=1;i<words.size();i++){
            int j = 0;
            while(words[i][j]==words[i-1][j]){ 
                j++;
                if(j==words[i].size()||j==words[i-1].size()) break;
            }
            if(j==words[i].size()||j==words[i-1].size()){
                if(words[i].size()<words[i-1].size()) flag=true;  
                continue;}//没从组间得到顺序
            //否则不等的话
            int pre = words[i-1][j]-'a';
            int tail = words[i][j]-'a';
            if(edges[pre][tail]==0){//如果不在则加入
                edges[pre][tail]=1;//加入邻接表
                indeg[tail]++;//入度加一
        }
    }
}
};

标签:int,拓扑,numCourses,vector,visited,排序,节点,indeg
来源: https://www.cnblogs.com/929code/p/16332914.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有