地铁两站之间最短路径查询(python实现)
基于图结构实现北京地铁乘坐线路查询( python)
问题描述
编写一个程序实现北京地铁最短乘坐(站)线路查询,输入为起始站名和目的站名,输出为从起始站到目的站的最短乘坐站换乘线路。
- 采用Dijkstra算法实现;
- 如果两站间存在多条最短路径,找出其中的一条就行
数据输入形式
文件bgstations.txt为数据文件,包含了北京地铁的线路及车站信息。其格式如下:
<地铁线路总条数><线路1> <线路1站数><站名1> <换乘状态><站名2> <换乘状态>...<线路2> <线路2站数><站名1> <换乘状态><站名2> <换乘状态>...
例如演示代码输入的数据形式:
121 23苹果园 0古城 0八角游乐园 0八宝山 0玉泉路 0五棵松 0万寿路 0公主坟 1军事博物馆 1木樨地 0南礼士路 0复兴门 1西单 1...2 19西直门 1积水潭 0鼓楼大街 1...西直门 1...该文件表明当前北京地铁共有12条线路(不含郊区线路),接着为每条线路信息。
打开当前目录下文件bgstations.txt,读入地铁线路信息,并从标准输入中读入起始站和目的站名(均为字符串,各占一行)。
数据输出形式
输出从起始站到目的站的乘坐信息,要求乘坐站数最少。换乘信息格式如下:SSN-n1(m1)-S1-n2(m2)-...-ESN其中:SSN和ESN分别为起始站名和目的站名;n为乘坐的地铁线路号,m为乘坐站数。
代码结构以及重难点分析
- 站名是中文字符,对于不同的编译器或者不同的操作系统,可能会导致乱码的形式出现
# try except部分代码用于修改python runtime的标准输入输出的编码格式
try:import ioimport syssys.stdin = io.TextIOWrapper(sys.stdin.detach(), encoding='utf-8')sys.stdout = io.TextIOWrapper(sys.stdout.detach(), encoding='utf-8')
except:pass
# 读取地铁线路信息的函数
def read_file(filename):# 打开文件时指定编码为"utf-8"f = open(filename, 'r', encoding="utf-8")# 读取总线路数目total = int(f.readline())for _ in range(total):# 读取线路id和线路站数id, n = (int(x) for x in f.readline().split())for j in range(n):# 读取站名和换乘站信息name, is_transfer = f.readline().split()return subway_info
- 环线、直线、换乘
从bgstations.txt中可以看见如下数据输入:从bgstations.txt中可以看见如下数据输入:
2 19
西直门 1
积水潭 0
鼓楼大街 1
…
车公庄 1
西直门 1
这说明2号线是环路,所以要在建立地铁站连线图结构的时候对环线的最短路径加以考虑。我们来看图想一下
譬如,从鼓楼大街到复兴门,沿安定门方向和沿积水潭方向都可以到达,比较两者路径长度显然是后者是更优解。当然这样一想一脸懵逼 ,要怎么做呢?
我们就要来看看图结构的表达形式
简单介绍一下图
图(Graph)是一种比线性表和树更为复杂的数据结构。
图结构:是研究数据元素之间的多对多的关系。在这种结构中,任意两个元素之间可能存在关系。即结点之间的关系可以是任意的,图中任意元素之间都可能相关。 图的应用极为广泛,已渗入到诸如语言学、逻辑学、物理、化学、电讯、计算机科学以及数学的其它分支。
图的基本术语:
1.弧(Arc) :表示两个顶点v和w之间存在一个关系,用顶点偶对<v,w>表示。通常根据图的顶点偶对将图分为有向图和无向图。
2.有向图(Digraph): 若图G的关系集合E(G)中,顶点偶对<v,w>的v和w之间是有序的,称图G是有向图。 在有向图中,若 <v,w>∈E(G) ,表示从顶点v到顶点w有一条弧。 其中:v称为弧尾(tail)或始点(initial node),w称为弧头(head)或终点(terminal node) 。
3.无向图(Undigraph): 若图G的关系集合E(G)中,顶点偶对<v,w>的v和w之间是无序的,称图G是无向图。
4.完全无向图:对于无向图,若图中顶点数为n ,用e表示边的数目,则e ∈[0,n(n-1)/2] 。具有n(n-1)/2条边的无向图称为完全无向图。
5.完全有向图:对于有向图,若图中顶点数为n ,用e表示弧的数
目,则e∈[0,n(n-1)] 。具有n(n-1)条边的有向图称为完全有向图。
6.权(Weight):与图的边和弧相关的数。权可以表示从一个顶点到另一个顶点的距离或耗费
7.子图和生成子图:设有图G=(V,E)和G’=(V’,E’),若V’=V且E’∈E ,则称图G’是G的子图;若V’=V且E’∈E,则称图G’是G的一个生成子图。顶点的邻接(Adjacent):对于无向图G=(V,E),若边(v,w)∈E,则称顶点v和w 互为邻接点,即v和w相邻接。边(v,w)依附(incident)与顶点v和w 。
图的存储结构
邻接矩阵
∞ 6 2 ∞ ∞
6 ∞ 3 4 3
2 3 ∞ 1 ∞
∞ 4 3 ∞ 5
∞ 3 ∞ 5 ∞
# 定义邻接矩阵图类
class Graph:def __init__(self,mat,unconn=0):vnum=len(mat)for x in mat:if len(x)!=vnum:#检查是否是方阵raise ValueError("Argument for 'Graph'.")self._mat=[mat[i][:] for i in range(vnum)]#赋值mat到self._matself._unconn=unconnself._vnum=vnumdef vertex_num(self):return self._vnumdef _invalid(self,v):return 0>v or v>=self._vnumdef add_vertex(self):#并未计划支持增加顶点,所以直接定义为错误,要增加顶点需要增加一行矩阵一列raise GraphError("Adj-Matrix does not support 'add_vertex'.")def add_edge(self,vi,vj,val=1):if self._invalid(vi) or self._invalid(vj):raise GraphError(str(vi)+' or '+str(vj)+" is not a valid vertex.")self._mat[vi][vj]=valdef get_edge(self,vi,vj):if self._invalid(vi) or self._invalid(vj):raise GraphError(str(vi)+' or '+str(vj)+" is not a valid vertex.")return self._mat[vi][vj]#记录已经构造的表#用静态方法构造结点表def out_edges(self,vi):if self._invalid(vi):raise GraphError(str(vi)+" is not a valid vertex.")return self._out_edges(self._mat[vi],self._unconn)@staticmethoddef _out_edges(row,unconn):edges=[]for i in range(len(row)):if row[i]!=unconn:edges.append((i,row[i]))return edges
邻接矩阵 对于大型数据的处理很鸡肋!!
(对于本次讨论的地铁图结构来说,你会发现二百多个点,一个200*200数量极的大二维列表,每一行就几个有数,其他都是inf,对于数据处理没有卵用!!)
所有的线索都指向==》当当当当
- 邻接表(可以理解为字典形式,每一个顶点可以指到连接它的所有点)
# 基于邻接表定义图,继承图类,也可以直接写
class GraphAL(Graph):def __init__(self,mat=[],unconn=0):vnum=len(mat)for x in mat:if len(x)!=vnum:raise ValueError("Argument for 'GraphAL'.")self._mat=[Graph._out_edges(mat[i],unconn) for i in range(vnum)]self._vnum=vnumself._unconn=unconndef add_vertex(self):#增加新节点时安排一个新编号self._mat.append([])self._vnum+=1return self._vnum-1def add_edge(self,vi,vj,val=1):if self._vnum==0:raise GraphError("cannot add edge to empty graph")if self._invalid(vi) or self._invalid(vj):raise GraphError(str(vi) + ' or ' + str(vj) + " is not a valid vertex.")row=self._mat[vi]i=0while i<len(row):if row[i][0]==vj:#更新mat[vi][vj]的值self._mat[vi][i]=(vj,val)returnif row[i][0]>vj:#原来如果没有到vj的边,退出循环,加入边breaki+=1self._mat[vi].insert(i,(vj,val))def get_edge(self,vi,vj):if self._invalid(vi) or self._invalid(vj):raise GraphError(str(vi) + ' or ' + str(vj) + " is not a valid vertex.")for i,val in self._mat[vi]:if i==vj:return valreturn self._unconndef out_edges(self,vi):if self._invalid(vi):raise GraphError(str(vi)+" is not a valid vertex.")return self._mat[vi]
代码实现
#这里我可以直接读取并显示中文,大家不行的自己修改LINEDATA=['1','2','4','5','6','7','8','9','10','13','14','15']
STATION_NUM={}#字典,站名到数字编号的对应
data={}
datanum={} #邻接表,啊哈就先这么叫他吧
STATIO={}#字典,对应数字到站名的对应
with open("routedata.txt","r") as f:TOTAL=f.readline()for line in f.readlines():if line!='\n':line = line.rstrip('\n')line=line.split(' ')if line[0] in LINEDATA:linei=line[0]continueline[1]=lineiline0=line[0]intline=int(line[1])if intline not in data.keys():data[intline]=[line0]else:data[intline].append(line0)if line0 not in datanum.keys():datanum[line0]=[intline]else:datanum[line0].append(intline)for datai in datanum.keys():STATION_NUM[datai]=iSTATIO[i]=dataii+=1I=i # 顶点个数#判断是否为环线
def iscircle(mlist):if mlist[0]==mlist[-1]:return Truereturn False
data:{1: ['苹果园', '古城', '八角游乐园', '八宝山', '玉泉路', '五棵松', '万寿路', '公主坟'...
datanum:{'苹果园': [1], '古城': [1], '八角游乐园': [1], '八宝山': [1], '玉泉路': [1], '五棵松': [1], '万寿路': [1], '公主坟': [1, 10]...
STATION-NUM:{'苹果园': 0, '古城': 1, '八角游乐园': 2, '八宝山': 3, '玉泉路': 4, '五棵松': 5, '万寿路': 6, '公主坟': 7...
最短路径搜索
如题,采用Dijkstra算法实现
#基于优先队列的dijkstra算法
def dijkstra_shortest_pathS(graph,v0,endpos):vnum=0for i in pathss.keys():vnum+=1# print(vnum)# vnum=graph.vertex_num()assert 0<=v0<vnumpaths=[None]*vnum#长为vnum的表记录路径count=0cands=PrioQueue([(0,v0,v0)])#求解最短路径的候选边集记录在优先队列cands中(p,v,v')v0经过v到v'的最短路径长度为p,根据p的大小排序,保证选到最近的未知距离顶点while count<vnum and not cands.is_empty():plen,u,vmin=cands.dequeue()#取路径最短顶点# print(u,vmin)if paths[vmin]:#如果这个点的最短路径已知,则跳过continuepaths[vmin]=(u,plen)#新确定最短路径并记录for v in graph[vmin]:#遍历经过新顶点组的路径if not paths[v]:#如果还不知道最短路径的顶点的路径,则记录cands.enqueue((plen+1,vmin,v))count+=1# print(paths)return paths
我注释的挺清楚了,具体了解的话可以看这篇
https://www.cnblogs.com/jason2003/p/7222182.html
注意的是这里输入的graph参数如下定义:
pathss={}
for i in range(I):for j in range(I):if RouteGraph.get_edge(i,j)==1:start=STATIO[i]end=STATIO[j]if i not in pathss.keys():pathss[i]=[j]else:pathss[i].append(j)
【样例输入】
西土城
北京西站
【样例输出】
西土城-10(1)-知春路-13(2)-西直门-4(2)-国家图书馆-9(4)-北京西站
(或西土城-10(1)-知春路-13(2)-西直门-2(1)-车公庄-6(2)-白石桥南-9(3)-北京西站)
源代码放在评论里了,欢迎大家讨论与优化
完整代码:
import sys
import io
sys.stdout=io.TextIOWrapper(sys.stdout.detach(),encoding='utf-8')
sys.stdin=io.TextIOWrapper(sys.stdin.detach(),encoding='utf-8')
LINEDATA=['1','2','4','5','6','7','8','9','10','13','14','15']
STATION_NUM={}
data={}
datanum={}
# with open("routedata.txt","rb") as f:
# for line in f.readlines():
# print(line.decode('utf-8'))
with open("routedata.txt","r") as f:TOTAL=f.readline()for line in f.readlines():if line!='\n':line = line.rstrip('\n')line=line.split(' ')if line[0] in LINEDATA:linei=line[0]continueline[1]=lineiline0=line[0]intline=int(line[1])if intline not in data.keys():data[intline]=[line0]else:data[intline].append(line0)if line0 not in datanum.keys():datanum[line0]=[intline]else:datanum[line0].append(intline)
i=0
STATIO={}
for datai in datanum.keys():STATION_NUM[datai]=iSTATIO[i]=dataii+=1
# print(STATION_NUM)#对应到邻接矩阵的引索上
I=i
#判断是否为环线
def iscircle(mlist):if mlist[0]==mlist[-1]:return Truereturn False# print(data)
# print(datanum)
# print(STATION_NUM)#判断是否为换乘点
def istransport(station):if len(datanum[station])>1:return Truereturn False
#得到换线路
def destransport(station):return datanum[station]
# print(datanum)
def changeline(p1,p2):line1=datanum[p1]line2=datanum[p2]a=[]# print(data[line1[0]])for i1 in data[line1[0]]:if istransport(i1):ways=destransport(i1)for i2 in line2:if i2 in ways:a.append(i1)return i1return None
class GraphError(ValueError):pass
class Graph:def __init__(self,mat,unconn=0):vnum=len(mat)for x in mat:if len(x)!=vnum:#检查是否是方阵raise ValueError("Argument for 'Graph'.")self._mat=[mat[i][:] for i in range(vnum)]#赋值mat到self._matself._unconn=unconnself._vnum=vnumdef vertex_num(self):return self._vnumdef _invalid(self,v):return 0>v or v>=self._vnumdef add_vertex(self):#并未计划支持增加顶点,所以直接定义为错误,要增加顶点需要增加一行矩阵一列raise GraphError("Adj-Matrix does not support 'add_vertex'.")def add_edge(self,vi,vj,val=1):if self._invalid(vi) or self._invalid(vj):raise GraphError(str(vi)+' or '+str(vj)+" is not a valid vertex.")self._mat[vi][vj]=valdef get_edge(self,vi,vj):if self._invalid(vi) or self._invalid(vj):raise GraphError(str(vi)+' or '+str(vj)+" is not a valid vertex.")return self._mat[vi][vj]#记录已经构造的表#用静态方法构造结点表def out_edges(self,vi):if self._invalid(vi):raise GraphError(str(vi)+" is not a valid vertex.")return self._out_edges(self._mat[vi],self._unconn)@staticmethoddef _out_edges(row,unconn):edges=[]for i in range(len(row)):if row[i]!=unconn:edges.append((i,row[i]))return edges
class GraphAL(Graph):def __init__(self,mat=[],unconn=0):vnum=len(mat)for x in mat:if len(x)!=vnum:raise ValueError("Argument for 'GraphAL'.")self._mat=[Graph._out_edges(mat[i],unconn) for i in range(vnum)]self._vnum=vnumself._unconn=unconndef add_vertex(self):#增加新节点时安排一个新编号self._mat.append([])self._vnum+=1return self._vnum-1def add_edge(self,vi,vj,val=1):if self._vnum==0:raise GraphError("cannot add edge to empty graph")if self._invalid(vi) or self._invalid(vj):raise GraphError(str(vi) + ' or ' + str(vj) + " is not a valid vertex.")row=self._mat[vi]i=0while i<len(row):if row[i][0]==vj:#更新mat[vi][vj]的值self._mat[vi][i]=(vj,val)returnif row[i][0]>vj:#原来如果没有到vj的边,退出循环,加入边breaki+=1self._mat[vi].insert(i,(vj,val))def get_edge(self,vi,vj):if self._invalid(vi) or self._invalid(vj):raise GraphError(str(vi) + ' or ' + str(vj) + " is not a valid vertex.")for i,val in self._mat[vi]:if i==vj:return valreturn self._unconndef out_edges(self,vi):if self._invalid(vi):raise GraphError(str(vi)+" is not a valid vertex.")return self._mat[vi]
import numpy as np
# mat=np.zeros([i,i])
mat=np.full([i,i],np.inf)
RouteGraph=Graph(mat)
# print(data)
# print(STATION_NUM)
# print(datanum)
routee={}
for key in data.keys():datai=data[key]# print(datai)for i in range(1,len(datai)-1):# RouteGraph.add_vertex()v1=STATION_NUM[datai[i]]v2=STATION_NUM[datai[i+1]]v3=STATION_NUM[datai[i-1]]RouteGraph.add_edge(v1, v2, 1)RouteGraph.add_edge(v2, v1, 1)RouteGraph.add_edge(v3, v1, 1)RouteGraph.add_edge(v1, v3, 1)if iscircle(datai):# RouteGraph.add_vertex()v1=STATION_NUM[datai[0]]v2=STATION_NUM[datai[-2]]RouteGraph.add_edge(v1, v2, 1)RouteGraph.add_edge(v2, v1, 1)def all_shortest_path(graph):import numpy as npvnum=graph.vertex_num()a=[[graph.get_edge(i,j) for j in range(vnum)]for i in range(vnum)]nvertex=[[-1 if a[i][j]==np.inf else j for j in range(vnum)]for i in range(vnum)]for k in range(vnum):for i in range(vnum):for j in range(vnum):if a[i][j]>a[i][k]+a[k][j]:a[i][j] = a[i][k] + a[k][j]nvertex[i][j]=nvertex[i][k]return(a,nvertex)
def find_shortest_path(graph, start, end, path=[]):'查找最短路径'path = path + [start]if start == end:return pathif not start in graph.keys():return Noneshortest = Nonefor node in graph[start]:if node not in path:newpath = find_shortest_path(graph, node, end, path)if newpath:if not shortest or len(newpath) < len(shortest):shortest = newpathreturn shortest
def find_all_paths(graph, start, end, path):'查找所有的路径'path = path + [start]if start == end:return [path]if not start in graph.keys():return []paths = []for node in graph[start]:if node not in path:newpaths = find_all_paths(graph, node, end, path)for newpath in newpaths:paths.append(newpath)return pathsclass PrioQueueError(ValueError):pass
#基于堆的优先队列类,在尾端加入元素,首端作为堆顶,见peek等
class PrioQueue:def __init__(self,elist=[]):self._elems=list(elist)if elist:self.buildheap()def buildheap(self):end=len(self._elems)for i in range(end//2,-1,-1):self.siftdown(self._elems[i],i,end)def is_empty(self):return not self._elemsdef peek(self):if self.is_empty():raise PrioQueueError("in peek")return self._elems[0]def enqueue(self,e):self._elems.append(None)self.siftup(e,len(self._elems)-1)def siftup(self,e,last):elems,i,j=self._elems,last,(last-1)//2while i>0 and e<elems[j]:elems[i]=elems[j]i,j=j,(j-1)//2elems[i]=edef dequeue(self):if self.is_empty():raise PrioQueueError("in dequeue")elems=self._elemse0=elems[0]e=elems.pop()if len(elems)>0:self.siftdown(e,0,len(elems))return e0def siftdown(self,e,begin,end):elems,i,j=self._elems,begin,begin*2+1while j<end:if j+1<end and elems[j+1]<elems[j]:j+=1if e<elems[j]:breakelems[i]=elems[j]i,j=j,2*j+1elems[i]=e
#Dijkstra算法实现最短路径查找
pathss={}
for i in range(I):for j in range(I):if RouteGraph.get_edge(i,j)==1:start=STATIO[i]end=STATIO[j]if i not in pathss.keys():pathss[i]=[j]else:pathss[i].append(j)
print(pathss)
def dijkstra_shortest_pathS(graph,v0,endpos):vnum=0for i in pathss.keys():vnum+=1# print(vnum)# vnum=graph.vertex_num()assert 0<=v0<vnumpaths=[None]*vnum#长为vnum的表记录路径count=0cands=PrioQueue([(0,v0,v0)])#求解最短路径的候选边集记录在优先队列cands中(p,v,v')v0经过v到v'的最短路径长度为p,根据p的大小排序,保证选到最近的未知距离顶点while count<vnum and not cands.is_empty():plen,u,vmin=cands.dequeue()#取路径最短顶点# print(u,vmin)if paths[vmin]:#如果这个点的最短路径已知,则跳过continuepaths[vmin]=(u,plen)#新确定最短路径并记录for v in graph[vmin]:#遍历经过新顶点组的路径if not paths[v]:#如果还不知道最短路径的顶点的路径,则记录cands.enqueue((plen+1,vmin,v))count+=1# print(paths)return pathsstartpos=input()
endpos=input()
s1=STATION_NUM[startpos]
e1=STATION_NUM[endpos]
# print(s1,e1)
paths=dijkstra_shortest_pathS(pathss,s1,e1)
# print(paths)
b=[]
p=paths[e1][0]
b.append(STATIO[p])
while True:p1=paths[p][0]p=p1b.append(STATIO[p])if p==s1:break
b.reverse()
# print(b)
if len(datanum[b[0]])==1:lines=datanum[b[0]][0]
else:for i in datanum[b[0]]:for j in datanum[b[1]]:if i==j:lines=i
# print(lines)
ways=[]
ways.append([b[0],lines])
# print(STATION_NUM)
for i in range(len(b)-1):li=datanum[b[i]]if len(li)>1:for j in li:if j!=lines and j in datanum[b[i+1]]:lines=jways.append([b[i],lines])
ways.append([STATIO[e1]])
for i in range(len(ways)-1):length=paths[STATION_NUM[ways[i+1][0]]][1]-paths[STATION_NUM[ways[i][0]]][1]print(ways[i][0],end='')print('-', end='')print(ways[i][1], end='')print('(', end='')print(length, end='')print( ')', end='')if i!=len(ways)-1:print('-',end='')
print(ways[-1][0])
地铁两站之间最短路径查询(python实现)相关推荐
- java地铁最短距离_动手构建地铁关系网,实现最短路径查询
一.前言 打开手机'北京地铁'APP,输入起始点:霍营,终点:北京南站,发现系统给我们推荐了两条路线. 最短时间路线与最少换乘路线,并且分别给出了耗时与乘坐里程费.看到这里,不禁开启了靓仔疑问,假如给 ...
- 二叉树中两节点之间最短路径
折腾了一下午,在参考 liuyi1207164339帖子和 ethannnli的帖子的基础上搞定了这个问题.刚开始头真的大了,感觉有点超出能力范围了.分析了他们的思路,求解这个二叉树中两节点的最短路径 ...
- PostgreSQL+PostGIS实现两坐标点之间最短路径查询算法函数(地图工具篇.12)
听老人家说:多看美女会长寿 地图之家总目录(订阅之前建议先查看该博客) 前置博客地址: 11.(地图工具篇)PostgreSQL+PostGIS实现最短路径分析 1.测试验证 select routi ...
- python2.7和3.5相互兼容吗_Python2.7和Python3.5是两个不同版本的Python,它们之间并不相互兼容。...
Python2.7和Python3.5是两个不同版本的Python,它们之间并不相互兼容. 答:错 地铁售票处 (英文):____ 答:subway ticket office;underground ...
- Python计算两日期之间排除节假日与非上班时间的工作时间
Python计算两日期之间排除节假日与非上班时间的工作时间 前言 一.基本思路 二.代码示例 总结 文章目录 前言 一.基本思路 二.代码示例 总结 前言 工作中遇见需要写UDF计算事项办理时间的需求 ...
- 棋盘最短路径 python_Dijkstra 最短路径算法 Python 实现
Dijkstra 最短路径算法 Python 实现 问题描述 使用 Dijkstra 算法求图中的任意顶点到其它顶点的最短路径(求出需要经过那些点以及最短距离). 以下图为例: 算法思想 可以使用二维 ...
- 蜂窝空间两点最短路径的Python实现
昨天和Mcree来一场痛快淋漓的头脑风暴! 叶子为什么是绿色的? 聊起一步步到物理是如何接过生物学家的接力棒深入探索:参考链接:为什么植物是绿色的?为了减少光合作用中的噪音 为什么眼睛能看到绿叶 ...
- 城市交通导航最短路径查询
导航最短路径查询系统 上学期期末老师让写一个课程设计,给了很多课题,选了导航最短路径查询系统,题目如下: 1 项目简介 设计一个交通咨询系统,能让旅客咨询从任一个城市顶点到另一个城市顶点之间的最短路径 ...
- 如何加快城市路网中最短路径查询效率?
一.介绍 最短路查询算法是图论中的经典算法,被广泛地应用在不同场景,例如计算机网络中的路由算法.在时空场景下,最短路算法更是支撑了很多应用,例如在路径规划和推荐中最短路是一种最直接的方案,而目前主流的 ...
最新文章
- bottle+jquery 前后端分离
- 算法与数据结构题目的 PHP 实现:栈和队列 由两个栈组成的队列
- springboot yml怎么建常量_Springboot中加载自定义的yml配置文件
- Linux 设备驱动开发 —— Tasklets 机制浅析
- 微软服务器延迟,经过六个多月的延迟,微软终于推出Hyper-V Server 2019
- 浏览器了解(一)浏览器大概流程
- “微音乐”微信小程序实战开发过程
- PM、PO、PO、PMO、PMP的区别和介绍
- phython学习记录 基础篇
- 移动端的vm vh是什么
- 2.4 深入理解PackageManagerService
- SAP 中Table的使用(一、显示数据)
- SpringCloud H版之Eureka学习
- 洛谷p1307数字反转 c语言
- GeoLite2 City库的基本使用与下载, 通过ip查询地址
- 如何使用U-Net-train进行语义分段,并在Keras中测试您的自定义数据
- Introduction of internet P2P technology
- Spring Boot启动器
- 2017 黑马 C++ 教学视频
- 软件测试-bug详解