当前位置: 首页 > news >正文

【算法基础】一篇文章彻底弄懂Dijkstra算法|多图解+代码详解

在这里插入图片描述

  • 博主简介:努力学习的大一在校计算机专业学生,热爱学习和创作。目前在学习和分享:算法、数据结构、Java等相关知识。
  • 博主主页: @是瑶瑶子啦
  • 所属专栏: 算法 ;该专栏专注于蓝桥杯和ACM等算法竞赛🔥
  • 近期目标:写好专栏的每一篇文章

在这里插入图片描述

目录

  • 一、简介
  • 二、基本思想策略
  • 三、代码实现
        • 输入格式
        • 输出格式
        • 数据范围
    • 3.1伪代码详解
    • 3.2源代码详解
    • 3.4:数据结构优化
    • 3.3:算法分析
  • 四、使用小根堆来优化Dijkstra算法
  • 五、深入和反思

一、简介

Dijkstra算法适用于最短路问题中,单源最短路(只有一个起点),并且每条边的权重都是正数的情况

二、基本思想策略

首先假定源点为u(就是起点),顶点集合V被划分为两部分:集合 S 和 V-S。 初始时S中仅含有源点u,其中S中的顶点到源点的最短路径已经确定
集合S 和V-S中所包含的顶点到源点的最短路径的长度待定,称从源点出发只经过S中的点到达V-S中的点的路径为特殊路径(不一定是最短的)
并用dist[]记录当前每个顶点对应的最短特殊路径长度。

红色顶点是S集合中,均已经确定最短路径的点,而绿色的是V-S集合中没有确定该顶点到源点最短路径的点。我们可以看到只经过S中的点到绿色点有两条特殊路径:15+2020+10,但是只有一条最短路径:15+20,那么绿色点就当前情况来看,可以暂时把它的dist[i]更新为25,但是一定是最短特殊路径吗?不一定,为什么呢?我们接下来往下看

在这里插入图片描述
可以看到,V-S集合中假设存在一点T,经过这点到目的点的距离,很有可能是目的点真正的dist!
在这里插入图片描述

可能这里可能有点晕,没错。上面只是一个大概的介绍,我们接下来彻底揭开它的神秘面纱。

选择特殊路径长度最短的路径,将其连接的V-S中的顶点加入到集合S中,同时更新数组dist[](核心)。一旦S包含了所有顶点,dist[]就是从源到所有其他顶点的最短路径长度

数据结构: h[N],e[M],ne[M],w[M]构建带权重的邻接表,来存储图;int dist[N];//dist 数组保存源点到其余各个节点的距离

(1)初始化。令集合S={0},对于集合V-S中的所有顶点x{1,2,3…n};初始化dist数组memset(dist, 0x3f, sizeof(dist));//dist 数组的各个元素为无穷大,

(2)找最小在集合V-S中依照贪心策略来寻找使得dist[j]具有最小值的顶点t,即dist[t]=min,则顶点t就是集合V-S中距离源点u最近的顶点。
(3)加入S战队。将顶点t加入集合S,同时更新V-S
(4)借东风。在(2)中已近找到了源点到t的最短路径,那么对集合V-S中所有与顶点t相邻的顶点j,都可以借助t走捷径。
如果dist[i] = min(dist[i], dist[t] + w[j]);//更新 dist[j],转(2)。

光凭这个好像是这么回事,但是细节值得推敲。这个题的本质还是贪心。
比如只看刚刚的文字,不仔细分析,你能不能解决我开头提出的那个问题?
为什么这么说呢。因为在目前(局部情况)来看,确实找到最短特殊路径了,竟然就直接加入S战队,不太可取,就像我开头提出的,在V-S集合中,万一存在一个点,经过这个点再到目的点,很有可能才是真正的最短距离。
那为什么这个算法是可取的呢?
巧就巧在,最外层循环,遍历了整个顶点,并且并不是说,一旦该顶点加入了S战队,它的dist就不能变了,相反,它在实时更新!。当循环遍历到绿色顶点T时,会更新与它相连节点的dist。
不知道有没有get到我的意思,虽然我没有用公式啥的去推导,我个人也非常讨厌那种不人性化的方式,更喜欢用一种形象的,意会的方式去理解。

综上,由局部最优,到全局最优,这种贪心的策略,完全可以保证全部遍历和循环后,dist[]数组中存的就是该点到源点的最短距离!!!(上面是我个人的理解,欢迎一起讨论交流和学习捏!)

三、代码实现

这里是AcWing 849.Dijkstra求最短路 I模板题目

给定一个 n 个点 m 条边的有向图,图中可能存在重边和自环,所有边权均为正值。

请你求出 1 号点到 n 号点的最短距离,如果无法从 1 号点走到 n 号点,则输出 −1。

输入格式

第一行包含整数 n 和 m。

接下来 m 行每行包含三个整数 x,y,z,表示存在一条从点 x 到点 y 的有向边,边长为 z。

输出格式

输出一个整数,表示 1 号点到 n 号点的最短距离。

如果路径不存在,则输出 −1。

数据范围

1≤n≤500,
1≤m≤105,
图中涉及边长均不超过10000。

3.1伪代码详解

int dist[N],state[N];
dist[1] = 0,state = 1;//把源点加入S集合
for (i : 1~n)
{1),t<-找最小,找到只经过S中的点到V-S集合中某一点,距离最小的那个V-S中的那个点2),state[t] = 1;将t加入到S战队3),更新与t顶点相邻点的dist}

3.2源代码详解

#include<iostream>
#include<cstring>
#include<algorithm>using namespace std;//N是顶点数,M是边数
const int N =510,M = 100010;
int h[N],e[M],ne[M],w[M],idx;//邻接表存储图,w[M]存储边的权重
int state[N];//state记录是否找到了源点到该节点的最短距离
int dist[N];//dist保存源点到其余各个顶点的最短特殊距离
int n,m;//图的顶点数和边数void add(int a,int b,int c)//插入边,并给每个边赋值权重
{e[idx] = b, w[idx] = c, ne[idx] = h[a],h[a] = idx++;
}
//key:核心和关键部分!!!
void Dijkstra()
{memset(dist,0x3f,sizeof(dist));// 1)初始化dist数组dist[1] = 0;//源点到源点的距离当然是0for (int i = 0; i < n; i++)//对n个顶点进行n次遍历(一开始V-S集合为n个元素,S集合是0个,肯定是遍历n次,才能完全遍历完{int t = -1;//t存储当前这次遍历到的V-S集合中的点,该点当前局部情况距离源点距离最小的那个点//2)在V-S中 找最小for (int j = 1; j <= n; j++){if(!state[j] && (t == -1 || dist[j] < dist[t]))t = j;}state[t] = 1;//3)加入S 战队//3)借东风for (int j = h[t];j != -1; j = ne[j]){int i = e[j];dist[i] = min(dist[i],dist[t]+w[j]);//更新dist[j]}                                                    }
}int main(){memset (h,-1,sizeof (h));//初始化邻接表cin >> n >>m;while (m--)//读入m条边{int a,b,w;cin >> a >> b >> w;add (a,b,w);}Dijkstra();if (dist[n] != 0x3f3f3f3f)//如果dist[n]被更新了,那么一定存在从1号节点到n号节点的最短距离路径cout << dist[n];elsecout << "-1";
}

关于存储图的适合,没有考虑重边和自环的影响?

因为在第三步更新的时候,即使邻接表那条单链上有两个一样编号的节点,但是第三步更新的时候,还是会让对应编号节点的dist为最小。所以即使有重边也不影响

3.4:数据结构优化

上面我们是采用邻接表来存储图,邻接表的原理如下。邻接表是适合稀疏图,当边比较多,也就是稠密图时,我们采用邻接矩阵来存储图。即g[a][b]的值为编号为a的节点a到编号为b的节点b之间的距离。

在这里插入图片描述
在这里插入图片描述

使用邻接矩阵,注意去重边,因为邻接矩阵只允许a→b的距离唯一。

#include <cstring>
#include <iostream>
#include <algorithm>using namespace std;const int N = 510;int n,m;int g[N][N];//邻接矩阵存储图
int dist[N];
bool st[N];int dijkstra(){memset(dist,0x3f,sizeof(dist)); dist[1] = 0;for(int i = 0; i < n; i++){int t = -1;for (int j = 1; j <= n; j ++)if (!st[j] && (t == -1|| dist[t] > dist[j]))t = j;st[t] = true;for (int j = 1; j <= n; j++)dist[j] = min(dist[j],dist[t] + g[t][j]);}if (dist[n] == 0x3f3f3f3f) return -1;return dist[n];
}int main(){scanf("%d%d",&n,&m);memset(g,0x3f,sizeof g);//初始化邻接矩阵while(m--){int a,b,c;scanf("%d%d%d",&a,&b,&c);g[a][b] = min(g[a][b],c);//去除重边}int t = dijkstra();printf("%d\n",t);return 0;
}

3.3:算法分析

算法时间复杂度:时间复杂是 O(n2+m)O(n2+m), n 表示点数,m表示边数

耗时的主要地方在于第2)步,找最小,每次都需要遍历一遍dist数组,完全没有必要。可以使用小根堆来优化(小根堆的数据结构可以自己来实现(推荐),或者用库中的)

四、使用小根堆来优化Dijkstra算法

这个定义的heap,完全可以看作集合V-S的具体化!通过这个小根堆,可以直接取出(取出+删除)V-S集合的最小值。

#include <cstring>
#include <iostream>
#include <algorithm>
#include <queue>//堆的头文件using namespace std;typedef pair<int, int> PII;//堆里存储距离和节点编号const int N = 1e6 + 10;int n, m;//节点数量和边数
int h[N], w[N], e[N], ne[N], idx;//邻接表存储图
int dist[N];//存储距离
bool st[N];//存储状态void add(int a, int b, int c)
{e[idx] = b, w[idx] = c, ne[idx] = h[a], h[a] = idx ++ ;
}int dijkstra()
{memset(dist, 0x3f, sizeof dist);//距离初始化为无穷大dist[1] = 0;priority_queue<PII, vector<PII>, greater<PII>> heap;//小根堆heap.push({0, 1});//插入距离和节点编号while (heap.size()){auto t = heap.top();//取距离源点最近的点heap.pop();int ver = t.second, distance = t.first;//ver:节点编号,distance:源点距离ver 的距离if (st[ver]) continue;//如果距离已经确定,则跳过该点st[ver] = true;for (int i = h[ver]; i != -1; i = ne[i])//更新ver所指向的节点距离{int j = e[i];if (dist[j] > dist[ver] + w[i]){dist[j] = dist[ver] + w[i];heap.push({dist[j], j});//距离变小,则入堆}}}if (dist[n] == 0x3f3f3f3f) return -1;return dist[n];
}int main()
{scanf("%d%d", &n, &m);memset(h, -1, sizeof h);while (m -- ){int a, b, c;scanf("%d%d%d", &a, &b, &c);add(a, b, c);}cout << dijkstra() << endl;return 0;
}

使用小根堆后,找到 t 的耗时从 O(n^2) 将为了 O(1)。每次更新 dist 后,需要向堆中插入更新的信息。所以更新dist的时间复杂度有 O(e) 变为了 O(elogn)。总时间复杂度有 O(n^2) 变为了 O(n + elongn)。适用于稀疏图。

五、深入和反思

最开始我们说到,Dijkstra算法只适用于边的权重都是正数的情况。为什么负权边不行呢?

看一个Dijkstra算法失效的例子:

在这里插入图片描述
A→B→D→E,确定dist[E]=20,dist[D]=8

然后A→C→D虽然更新了D点的dist,使之正确dist[D]=-1,但是由于D已经被遍历过,无法通过D来更新E,导致最终求出的A→E的最小距离出错。

为什么呢?

D的dist的正确性不受负权的影响,是因为负权指向的是D,在更新节点,更新dist的时候,会更新掉D的错误值。但E就不一样了,在当前局部,只有D一个经过它,D一旦遍历过后,更新了E。当经过C到D时,无法再通过正确的D去更新E!

如果全部是正值的话,在A→D时,能一下子确定当前真正的dist[D]!再dist[D]+12,那dist[E]也是正确的!

所以根本原因在于,存在负权边,dist[D]的真值不能在更新dist[E]之前确定。

最后是我个人总结的理解:

💐在Dijkstra算法视角,把B遍历并进行相关更新后,它当前得知了如下情况:dist[A] = 0,dist[B] = 2,dist[D] = 5,dist[C] = 999,dist[D] = 999+C,C>0,Dijkstra当然会放弃A-C-D这条路,可是C其实<0,这条路不该被放弃,反而A-C-D的路径长度很有可能会小于A-B-C的长度,正是由于Dijkstra的这点输入,导致出现负权边时,结果不正确,再说,人家的正确性本来就是建立在所有边的权重都>0的基础上!


在这里插入图片描述

  • Java岛冒险记【从小白到大佬之路】
  • LeetCode每日一题–进击大厂
  • 算法

相关文章:

【算法基础】一篇文章彻底弄懂Dijkstra算法|多图解+代码详解

博主简介&#xff1a;努力学习的大一在校计算机专业学生&#xff0c;热爱学习和创作。目前在学习和分享&#xff1a;算法、数据结构、Java等相关知识。博主主页&#xff1a; 是瑶瑶子啦所属专栏: 算法 &#xff1b;该专栏专注于蓝桥杯和ACM等算法竞赛&#x1f525;近期目标&…...

第二十三天01MySQL多表查询与事务

目录 1. 多表查询 1.1 概述 1.1.1 数据准备 1.1.2 介绍 1.1.3 分类 1.2 内连接 1.2.1 语法 1.2.2 案例演示 1.3 外连接 1.3.1 语法 1.3.2 案例演示 1.4 子查询 1.4.1 介绍 1.4.2 标量子查询 1.4.3 列子查询 1.4.4 行子查询 1.4.5 表子查询 1.5 案例 1.5.1 介…...

TCP协议详解

1.TCP的准备条件在古代的时候&#xff0c;古人们经常写书信进行交流&#xff0c;写书信的前提是你要知道这份信是要寄给谁在网络中&#xff0c;我们通过ip端口号找对目标对象&#xff0c;但是现在网站一般会对ip端口注册一个域名&#xff0c;所以我们一般就是对域名进行查找&am…...

Activiti7与Spring、Spring Boot整合开发

Activiti整合Spring 一、Activiti与Spring整合开发 1.1 Activiti与Spring整合的配置 1)、在pom.xml文件引入坐标 如下 <properties><slf4j.version>1.6.6</slf4j.version><log4j.version>1.2.12</log4j.version> </properties> <d…...

基于SpringBoot实现冬奥会运动会科普平台【源码+论文】

基于SpringBoot实现冬奥会科普平台演示开发语言&#xff1a;Java 框架&#xff1a;springboot JDK版本&#xff1a;JDK1.8 服务器&#xff1a;tomcat7 数据库&#xff1a;mysql 5.7 数据库工具&#xff1a;Navicat11 开发软件&#xff1a;eclipse/myeclipse/idea Maven包&#…...

一文吃透SpringBoot整合mybatis-plus(保姆式教程)

✅作者简介&#xff1a;2022年博客新星 第八。热爱国学的Java后端开发者&#xff0c;修心和技术同步精进。 &#x1f34e;个人主页&#xff1a;Java Fans的博客 &#x1f34a;个人信条&#xff1a;不迁怒&#xff0c;不贰过。小知识&#xff0c;大智慧。 &#x1f49e;当前专栏…...

C++ primer plus(第六版)编程练习答案 第4章 复合类型

一、程序清单 arrayone.cpp // arrayone.cpp -- small arrays of integers #include <iostream> int main() {using namespace std;int yams[3]; // creates array with three elementsyams[0] = 7; // assign value to first elementyams[1] = 8;yams[2] = 6;i…...

Kafka源码分析之Producer(一)

总览 根据kafka的3.1.0的源码example模块进行分析&#xff0c;如下图所示&#xff0c;一般实例代码就是我们分析源码的入口。 可以将produce的发送主要流程概述如下&#xff1a; 拦截器对发送的消息拦截处理&#xff1b; 获取元数据信息&#xff1b; 序列化处理&#xff1b;…...

springboot校友社交系统

050-springboot校友社交系统演示录像开发语言&#xff1a;Java 框架&#xff1a;springboot JDK版本&#xff1a;JDK1.8 服务器&#xff1a;tomcat7 数据库&#xff1a;mysql 5.7&#xff08;一定要5.7版本&#xff09; 数据库工具&#xff1a;Navicat11 开发软件&#xff1a;e…...

python flask项目部署

flask上传服务器pyhon安装下载Anacondasudo wget https://mirrors.tuna.tsinghua.edu.cn/anaconda/archive/Anaconda3-5.3.1-Linux-x86_64.sh可根据需要安装对应的版本https://repo.anaconda.com/archive/解压anaconda压缩包bash Anaconda3-5.3.1-Linux-x86_64.sh解压过程中会…...

常见排序算法(C语言实现)

文章目录排序介绍插入排序直接插入排序希尔排序选择排序选择排序堆排序交换排序冒泡排序快速排序递归实现Hoare版本挖坑法前后指针版本非递归实现Hoare版本挖坑法前后指针版本快排的优化三值取中小区间优化归并排序递归实现非递归实现计数排序排序算法复杂度及稳定性分析不同算…...

基于jsp+ssm+springboot的小区物业管理系统【设计+论文+源码】

摘 要随着科学技术的飞速发展&#xff0c;各行各业都在努力与现代先进技术接轨&#xff0c;通过科技手段提高自身的优势&#xff1b;对于小区物业管理系统当然也不能排除在外&#xff0c;随着网络技术的不断成熟&#xff0c;带动了小区物业管理系统&#xff0c;它彻底改变了过去…...

Elasticsearch 学习+SpringBoot实战教程(三)

需要学习基础的可参照这两文章 Elasticsearch 学习SpringBoot实战教程&#xff08;一&#xff09; Elasticsearch 学习SpringBoot实战教程&#xff08;一&#xff09;_桂亭亭的博客-CSDN博客 Elasticsearch 学习SpringBoot实战教程&#xff08;二&#xff09; Elasticsearch …...

try-with-resource

try-with-resource是Java 7中引入的新特性&#xff0c;它可以方便地管理资源&#xff0c;自动关闭资源&#xff0c;从而避免了资源泄漏的问题。 作用 使用try-with-resource语句可以简化代码&#xff0c;避免了手动关闭资源的繁琐操作&#xff0c;同时还可以保证资源的正确关闭…...

leetcode148_排序链表的3种解法

1. 题目2. 解答 2.1. 解法12.2. 解法22.3. 解法3 1. 题目 给你链表的头结点head&#xff0c;请将其按升序排列并返回排序后的链表。 /*** Definition for singly-linked list.* struct ListNode {* int val;* ListNode *next;* ListNode() : val(0), next(nullp…...

使用stm32实现电机的PID控制

使用stm32实现电机的PID控制 PID控制应该算是非常古老而且应用非常广泛的控制算法了&#xff0c;小到热水壶温度控制&#xff0c;大到控制无人机的飞行姿态和飞行速度等等。在电机控制中&#xff0c;PID算法用的尤为常见。 文章目录使用stm32实现电机的PID控制一、位置式PID1.计…...

数学原理—嵌入矩阵

目录 1.嵌入矩阵的基本作用 2.嵌入矩阵的数学解释 3.嵌入矩阵在联合分布适应中的数学推导主要包括以下几个步骤 4.在JDA中&#xff0c;怎么得到嵌入矩阵 5.联合分布自适应中如何得到嵌入矩阵 &#xff08;另一种解释&#xff09; 1.嵌入矩阵的基本作用 在机器学习中&a…...

English Learning - L2 语音作业打卡 辅音翘舌音 [ʃ] [ʒ] 空气摩擦音 [h] Day31 2023.3.23 周四

English Learning - L2 语音作业打卡 辅音翘舌音 [ʃ] [ʒ] 空气摩擦音 [h] Day31 2023.3.23 周四&#x1f48c;发音小贴士&#xff1a;&#x1f48c;当日目标音发音规则/技巧:翘舌音 [ʃ] [ʒ]空气摩擦音 [h]&#x1f36d; Part 1【热身练习】&#x1f36d; Part2【练习内容】…...

记录springboot+vue+fastdfs实现简易的文件(上传、下载、删除、预览)操作

前言说明&#xff1a;springboot vue FastDFS实现文件上传&#xff08;支持预览&#xff09;升级版 FASTDFS部分 FASTDFS安装过程&#xff1a;基于centos 7安装FastDFS文件服务器 SpringBoot部分 springboot源码实现 package com.core.doc.controller;import com.baomid…...

Java中循环使用Stream应用场景

在JAVA中&#xff0c;涉及到对数组、Collection等集合类中的元素进行操作的时候&#xff0c;通常会通过循环的方式进行逐个处理&#xff0c;或者使用Stream的方式进行处理。例如&#xff0c;现在有这么一个需求&#xff1a;从给定句子中返回单词长度大于5的单词列表&#xff0c…...

中国蚁剑AntSword实战

中国蚁剑AntSword实战1.基本使用方法2.绕过安全狗连接3.请求包修改UA特征伪造RSA流量加密4.插件使用1.基本使用方法 打开蚂蚁宝剑&#xff0c;右键添加数据&#xff1a; 输入已经上传马的路径和连接密码&#xff1a; 测试连接&#xff0c;连接成功&#xff01; GetShell了&…...

C++ 直接初始化和拷贝初始化

首先我们介绍直接初始化&#xff1a;编译器使用普通的函数匹配来选择与我们提供的参数最匹配的构造函数。文字描述可能会让你们云里雾里&#xff0c;那我们直接看代码&#xff1a; //先设计这样的一个类 class A{ public:A(){ cout << "A()" << endl; }A…...

数据迁移工具

1.Kettle Kettle是一款国外开源的ETL工具,纯Java编写,绿色无需安装,数据抽取高效稳定 (数据迁移工具)。 Kettle 中有两种脚本文件,transformation 和 job,transformation 完成针对数据的基础转换,job 则完成整个工作流的控制。 Kettle 中文名称叫水壶,该项目的主程序…...

【C/C++】程序的内存开辟

在C/C语言中&#xff0c;不同的类型开辟的空间区域都是不一样的. 这节我们就简单了解下开辟不同的类型内存所存放的区域在哪里. 文章目录栈区&#xff08;stack&#xff09;堆区&#xff08;heap&#xff09;数据段&#xff08;静态区&#xff09;常量存储区内存开辟布局图栈区…...

全网最完整,接口测试总结彻底打通接口自动化大门,看这篇就够了......

目录&#xff1a;导读前言一、Python编程入门到精通二、接口自动化项目实战三、Web自动化项目实战四、App自动化项目实战五、一线大厂简历六、测试开发DevOps体系七、常用自动化测试工具八、JMeter性能测试九、总结&#xff08;尾部小惊喜&#xff09;前言 所谓接口&#xff0…...

28-flume和kafka为什么要结合使用

一&#xff1a;flume和kafka为什么要结合使用 首先&#xff1a;Flume 和 Kafka 都是用于处理大量数据的工具&#xff0c;但它们的设计目的不同。Flume 是一个可靠地收集、聚合和移动大量日志和事件数据的工具&#xff0c;而Kafka则是一个高吞吐量的分布式消息队列&#xff0c;…...

STM32外设-定时器详解

0. 概述 本文针对STM32F1系列&#xff0c;主要讲解了其中的8个定时器的原理和功能 1. 定时器分类 STM32F1 系列中&#xff0c;除了互联型的产品&#xff0c;共有 8 个定时器&#xff0c;分为基本定时器&#xff0c;通用定时器和高级定时器基本定时器 TIM6 和 TIM7 是一个 16 位…...

史上最详细的改良顺序表讲解,看完不会你打我

目录 0.什么是顺序表 1.顺序表里结构体的定义 2.顺序表的初始化 3.顺序表的输入 4.增加顺序表的长度 5.1顺序表的元素查找&#xff08;按位查找&#xff09; 5.2顺序表的元素查找&#xff08;按值查找&#xff09;在顺序表进行按值查找&#xff0c;大概只能通过遍历的方…...

【Unity入门】资源包导入和导出

【Unity入门】资源包导入和导出 大家好&#xff0c;我是Lampard~~ 欢迎来到Unity入门系列博客&#xff0c;所学知识来自B站阿发老师~感谢 &#xff08;1&#xff09;资源目录 Unity的资源&#xff08;模型&#xff0c;场景&#xff0c;脚本&#xff09;等都保存在Assert目录下&…...

python条件语句与循环语句

目录 一、条件语句 1.1if 二、循环语句 2.1while 2.2for循环 2.3break和continue 三、test和总结 一、条件语句 1.1if Python条件语句是通过一条或多条语句的执行结果&#xff08;True或者False&#xff09;来决定执行的代码块。 Python程序语言指定&#xff1a; 任…...

电子邮箱怎么申请/上海seo公司排名

pyse 更名为 seldom WebUI automation testing framework based on Selenium and unittest. 基于 selenium 和 unittest 的 Web UI自动化测试框架。 特点 提供更加简单API编写自动化测试。提供脚手架&#xff0c;快速生成自动化测试项目。自动生成HTML测试报告生成。自带断言方…...

贵州省建设项目验收备案网站/哈尔滨seo推广优化

hello&#xff0c;我是apan啊&#xff0c;一位失业已久&#xff0c;正在努力学习python的点点点工程师&#xff0c;近期在努力找工作。 本篇记录并总结下我面试遇到的各种python题目以及相关的知识点&#xff0c;分5大类进行分享&#xff1a;基础问题类、算法问题类、自动化相关…...

东营seo网站推广费用/百度资源提交

总结自己的调试心得&#xff0c;总结如下&#xff1a;   1、Cisco29系列交换机可以做基于2层的端口安全&#xff0c;即mac地址与端口进行绑定。   2、 Cisco3550以上交换机均可做基于2层和3层的端口安全&#xff0c;即mac地址与端口绑定以及mac地址与ip地址绑定。   3、以…...

哪个网站做外贸零售比较好呢/pc优化工具

摘要&#xff1a;世界杯“法阿之战”中帕瓦尔世界波以及姆巴佩梅开二度一定让你印象深刻&#xff0c;而梅西的饮恨离开也让不少球迷碎了心。但你知道&#xff0c;比赛当天的阿里云藏着什么秘密吗&#xff1f;世界杯“法阿之战”中帕瓦尔世界波以及姆巴佩梅开二度一定让你印象深…...

公众号开发主要做什么/搜索引擎优化行业

0.目录 1.前言 2.使用方向键来实现光标左右移动 3.按两下ESC键退出程序 4.移动光标到行首 5.移动光标到行尾 6.总代码 1.前言 之前已经写过一篇文章了&#xff1a;实现一个简单的行编辑器 实现的功能有&#xff1a;1.按下大小写字母或者数字的时候&#xff0c;显示在屏幕上 2.可…...

中国互联网协会12321举报中心/西安网站seo排名优化

Python实战:itertools的排列组合技巧 在Python中,如果想要对列表、元组或字符串进行排列组合等操作,可以使用内置的itertools模块。itertools模块提供了多种排列组合操作函数,如permutations、combinations和product等,可以灵活地组合使用,实现各种复杂的功能。本文将介…...