算法沉淀——拓扑排序

这篇具有很好参考价值的文章主要介绍了算法沉淀——拓扑排序。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

前言:

首先我们需要知道什么是拓扑排序?

在正式讲解拓扑排序这个算法之前,我们需要了解一些前置知识(和离散数学相关)

1、有向无环图:

指的是一个无回路的有向图。

入度:有向图中某点作为图中边的终点的次数之和

出度:有向图中某点作为图中边的起点的次数之和

2、AOV网:顶点活动图

在有向无环图中,用顶点来表示一个活动,用边来表示活动的先后顺序的图结构。

举个例子:

算法沉淀——拓扑排序,C语言/C++练习题,算法

在下面的这张图中,1这个点的入度就是0,2这个点的入度就是2,因为有两条有向线段指向2这个点。

3、拓扑排序:

简而言之就是找到事情的先后顺,拓扑排序的结果可能不是唯一的。

如何排序?

  1. 找出图中入度为0的点,然后输出
  2. 删除与该点连接的边
  3. 重复1、2操作,直到图中没有点或者没有入度为0点为止。(有可能有环

重要应用:判断有向图中是否有环

4、如何用代码实现拓扑排序呢?(重点)

首先,我们需要根据题意去建图!!!(利用哈希表等容器,会结合题目详细解析)。

接着,建好图后,借助队列,来一次BFS即可。

1、初始化:把所有入度为0的点加入到队列中

2、当队列不为空时:

  1. 拿出队头元素,加入到最终结果中;
  2. 删除与该元素相连的边
  3. 判断:与删除边相连的点,是否入度变成0,如果入度为0,加入到队列中

经典例题1:207. 课程表 - 力扣(LeetCode)

题目描述:

算法沉淀——拓扑排序,C语言/C++练习题,算法

题目解析:

我们可以根据题意,将课程之间的联系抽象成图

算法沉淀——拓扑排序,C语言/C++练习题,算法

而题目所说的判断能否完成所有的课程学习,问的就是这个图有无环!!!

知道本题利用拓扑排序解决,那第一步就是如何建图呢

灵活使用语言提供的容器

邻接表:

我们可以利用哈希表来实现图中点与点之间的关系。

算法沉淀——拓扑排序,C语言/C++练习题,算法

同时我们也需要另一个容器存储每个点的入度。

原码:

class Solution {
public:
    bool canFinish(int numCourses, vector<vector<int>>& prerequisites) {
        unordered_map<int,vector<int>> hash; //邻接表存图
        vector<int> in(numCourses); //标记每个点的入度
        //开始建图
        for(auto& e : prerequisites)
        {
            int a = e[0];
            int b = e[1];
            hash[b].push_back(a);
            in[a]++;
        }
        queue<int> q;
        //将度为0的边存到队列中
        for(int i = 0; i < numCourses; i++)//
        {
            cout << i << endl;
            if(in[i] == 0) q.push(i);
        }
        //进行拓扑排序bfs
        while(q.size())
        {
            int t = q.front();
            q.pop();
            //将这个点删除,并且删除跟他相连的边
            for(int i : hash[t])
            {
                in[i]--;
                if(in[i] == 0) q.push(i);
            }
        }
        //判断是否有环
        for(auto i : in)
        {
            if(i > 0) return false;
        }
        return true;
 
    }
};

例题二:LCR 114. 火星词典 - 力扣(LeetCode)

题目描述:

算法沉淀——拓扑排序,C语言/C++练习题,算法

题目解析:

算法沉淀——拓扑排序,C语言/C++练习题,算法

本题也是拓扑排序的经典例题。

1、如何搜集信息?

两层for循环

2、拓扑排序:

1、建图

hash<char, hash<char>> edges;

注意第一个hash表示map类型,第二个hash表示set。

这就需要我们对容器的灵活使用!

2、统计入度信息

hash<char, int> in; 注意必须要初始化

3、如何收集信息:双指针

4、细节问题:

abc和ab,若abc在前明显不符合要求,需要提前返回空字符串。文章来源地址https://www.toymoban.com/news/detail-845494.html

原码:

class Solution {
public:
    string alienOrder(vector<string>& words) {
        unordered_map<char, unordered_set<char>> edges; // 邻接表来存储图
        unordered_map<char, int> in; // 统计入度
        string ans;

        int n = words.size();
        //必须要对入度进行初始化,不然入度为0的点根本没有存进去
        for(auto& i : words)
        {
            for(auto k : i)
            in[k] = 0;
        }

        for(int i = 0; i < n; i++)
        {
            for(int j = i + 1; j < n; j++)
            {
                string a = words[i];
                string b = words[j];
                int len1 = a.size(), len2 = b.size();
                int len = min(len1, len2);
                int flag = 0;
                for(int k = 0; k < len; k++)
                {
                    //正常情况
                    if(a[k] != b[k])
                    {
                        if(!edges.count(a[k]) || !edges[a[k]].count(b[k]))
                        {
                            edges[a[k]].insert(b[k]);
                            in[b[k]]++;
                        }
                        flag = 1;

                        break;
                    }
                }
                //判断特殊情况
                if(len1 > len2 && !flag)
                {
                    return ans;
                }
            }
        }

        //开始拓扑排序
        queue<char> q;
        //注意map的范围for表示!!!
        for(auto& [a, b]: in)
        {
            if(b == 0)
            {
                q.push(a);
            }
        }
        
        while(q.size())
        {
            char tmp = q.front();
            q.pop();
            ans += tmp;
            cout << ans << endl;
            for(char i : edges[tmp])
            {
                in[i]--;
                if(in[i] == 0) q.push(i);
            }
        }
        //判断是否有环
        for(auto& [a,b] : in)
        {
            if(b != 0) return "";
        }
        return ans;
    } 
};

到了这里,关于算法沉淀——拓扑排序的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • C 语言练习题更新

    目录(先不要看答案,首先自己做才能更好的领悟,做不来没关系) 题目一:有 1、2、3、4 四个数字,能组成多少个互不相同且无重复数字的三位数?都是多少? 程序分析:可填在百位、十位、个位的数字都是 1、2、3、4,组成所有的排列后再去掉不满足条件的排列。 题目

    2024年02月14日
    浏览(45)
  • C语言之练习题

    欢迎来到我的: 世界 希望作者的文章对你有所帮助,有不足的地方还请指正,大家一起学习交流 ! 这期文章由:两题问答题+四道编程题;小孩在文章中写有详细解题思路,感谢大家支持支持。 思路: 首先我们要知道 x=x(x-1) 的含义; 假设x=3;也就是 011 ; 而x-1=2;是 010 ;

    2024年02月10日
    浏览(58)
  • 练习题----顺序栈算法

    ​输入一个包括 \\\'(\\\' 和 \\\')\\\' 的字符串string ,判断字符串是否有效。要求设计算法实现检查字符串是否有效,有效的字符串需满足以下条件: A. 左括号必须用相同类型的右括号闭合。 B. 左括号必须以正确的顺序闭合。 C. 每个右括号都有一个对应的相同类型的左括号。 ​该题需

    2024年04月26日
    浏览(42)
  • C语言习题练习

    首先我们要了解什么是offsetof宏: . 此具有函数形式的宏返回数据结构或联合类型中成员成员的偏移值(以字节为单位)。 . 返回的值是size_t类型的无符号整数值,其字节数位于指定成员与其结构开头之间。 什么意思呢,可以看到下面这张图片: 下面我们来看到这一习题:

    2024年02月15日
    浏览(53)
  • 习题练习 C语言(暑期)

    今天为大家分享我暑假期间所练习的一些小题目! 相信大家看完之后都会有所提升的! 加油! 以下不正确的定义语句是( ) A: double x[5] = {2.0, 4.0, 6.0, 8.0, 10.0}; B: char c2[] = {‘x10’, ‘xa’, ‘8’}; C: char c1[] = {‘1’,‘2’,‘3’,‘4’,‘5’}; D: int y[5+3]={0, 1, 3, 5, 7, 9}; 题目解

    2024年02月10日
    浏览(54)
  • 习题练习 C语言

    首先我们要了解什么是offsetof宏: . 此具有函数形式的宏返回数据结构或联合类型中成员成员的偏移值(以字节为单位)。 . 返回的值是size_t类型的无符号整数值,其字节数位于指定成员与其结构开头之间。 什么意思呢,可以看到下面这张图片: 下面我们来看到这一习题:

    2024年02月14日
    浏览(50)
  • C语言之数组练习题

    第1关:数组插入元素 300 任务要求 参考答案 评论106 任务描述 相关知识 数组 数组元素的表示方法 编程要求 测试说明 任务描述 本关需要你将一个数插入到一组已经排好序的数组并输出。 相关知识 数组在程序设计中,为了处理方便, 把具有相同类型的若干变量按有序的形式

    2024年02月05日
    浏览(54)
  • 【C语言】练习题整理:11

    今天是10道选择题 下面代码段的输出结果是: -12 自右至左的结合方向称为“右结合性”。最典型的右结合 性运算符是赋值运算符。 如x=y=z,由于“=”的右结合性,应先执行y=z,再执行x=(y=z)运算。 C语言运算符中有不少为右结合性,应注意区别,以避免理解错误。 计算顺序是

    2024年02月11日
    浏览(46)
  • C语言/C++练习题

    题目:从键盘输入年份和月份,输出这个月的天数。 【样例输入】2023 1 【样例输出】31 【样例输入】2020 2 【样例输出】29 提示:当输入的月份为2月份时,需要判断该年年份是否为闰年。 判断闰年的条件:年份为4的倍数并且不是100的倍数,或者年份是400的倍数。 ​ 在控制

    2024年02月06日
    浏览(46)
  • <算法学习>动态规划练习题

    本篇文章为初学动态规划时的练习题。参考优质博客学习后根据伪代码描述完成代码。记录一下用于以后复习。 给定一个有n行数字组成的数字三角形. 试设计一个算法, 计算出从三角形的顶至底的一条路径, 使该路径经过的数字和最大. 算法设计: 对于给定的n行数字组成的三角

    2024年01月17日
    浏览(48)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包