我的编程空间,编程开发者的网络收藏夹
学习永远不晚

Python算法之图的遍历

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

Python算法之图的遍历

本节主要介绍图的遍历算法BFS和DFS,以及寻找图的(强)连通分量的算法

Traversal就是遍历,主要是对图的遍历,也就是遍历图中的每个节点。对一个节点的遍历有两个阶段,首先是发现(discover),然后是访问(visit)。遍历的重要性自然不必说,图中有几个算法和遍历没有关系?!

[算法导论对于发现和访问区别的非常明显,对图的算法讲解地特别好,在遍历节点的时候给节点标注它的发现节点时间d[v]和结束访问时间f[v],然后由这些时间的一些规律得到了不少实用的定理,本节后面介绍了部分内容,感兴趣不妨阅读下算法导论原书]

图的连通分量是图的一个最大子图,在这个子图中任何两个节点之间都是相互可达的(忽略边的方向)。我们本节的重点就是想想怎么找到一个图的连通分量呢?

一个很明显的想法是,我们从一个顶点出发,沿着边一直走,慢慢地扩大子图,直到子图不能再扩大了停止,我们就得到了一个连通分量对吧,我们怎么确定我们真的是找到了一个完整的连通分量呢?可以看下作者给出的解释,类似上节的Induction,我们思考从i-1到i的过程,只要我们保证增加了这个节点后子图仍然是连通的就对了。

Let'slookatthefollowingrelatedproblem.Showthatyoucanorderthenodesinaconnectedgraph,V1,V2,…Vn,sothatforanyi=1…n,thesubgraphoverV1,…,Viisconnected.Ifwecanshowthisandwecanfigureouthowtodotheordering,wecangothroughallthenodesinaconnectedcomponentandknowwhenthey'reallusedup.

Howdowedothis?Thinkinginductively,weneedtogetfromi-1toi.Weknowthatthesubgraphoverthei-1firstnodesisconnected.Whatnext?Well,becausetherearepathsbetweenanypairofnodes,consideranodeuinthefirsti-1nodesandanodevintheremainder.Onthepathfromutov,considerthelastnodethatisinthecomponentwe'vebuiltsofar,aswellasthefirstnodeoutsideit.Let'scallthemxandy.Clearlytheremustbeanedgebetweenthem,soaddingytothenodesofourgrowingcomponentkeepsitconnected,andwe'veshownwhatwesetouttoshow.

经过上面的一番思考,我们就知道了如何找连通分量:从一个顶点开始,沿着它的边找到其他的节点(或者说站在这个节点上看,看能够发现哪些节点),然后就是不断地向已有的连通分量中添加节点,使得连通分量内部依然满足连通性质。如果我们按照上面的思路一直做下去,我们就得到了一棵树,一棵遍历树,它也是我们遍历的分量的一棵生成树。在具体实现这个算法时,我们要记录“边缘节点”,也就是那些和已得到的连通分量中的节点相连的节点,它们就像是一个个待办事项(to-dolist)一样,而前面加入的节点就是标记为已完成的(checkedoff)待办事项。

这里作者举了一个很有意思的例子,一个角色扮演的游戏,如下图所示,我们可以将房间看作是节点,将房间的门看作是节点之间的边,走过的轨迹就是遍历树。这么看的话,房间就分成了三种:(1)我们已经经过的房间;(2)我们已经经过的房间附近的房间,也就是马上可以进入的房间;(3)“黑屋”,我们甚至都不知道它们是否存在,存在的话也不知道在哪里。

查看图片

根据上面的分析可以写出下面的遍历函数walk,其中参数S暂时没有用,它在后面求强连通分量时需要,表示的是一个“禁区”(forbidden zone),也就是不要去访问这些节点。

注意下面的difference函数的使用,参数可以是多个,也就是说调用后返回的集合中的元素在各个参数中都不存在,此外,参数也不一定是set,也可以是dict或者list,只要是可迭代的(iterables)即可。可以看下python docs


# Walking Through a Connected Component of a Graph Represented Using Adjacency Sets
def walk(G, s, S=set()):            # Walk the graph from node s
  P, Q = dict(), set()            # Predecessors + "to do" queue
  P[s] = None                 # s has no predecessor
  Q.add(s)                  # We plan on starting with s
  while Q:                  # Still nodes to visit
    u = Q.pop()               # Pick one, arbitrarily
    for v in G[u].difference(P, S):     # New nodes?
      Q.add(v)              # We plan to visit them!
      P[v] = u              # Remember where we came from
  return P

我们可以用下面代码来测试下,得到的结果没有问题


def some_graph():
  a, b, c, d, e, f, g, h = range(8)
  N = [
    [b, c, d, e, f],  # a
    [c, e],       # b
    [d],        # c
    [e],        # d
    [f],        # e
    [c, g, h],     # f
    [f, h],       # g
    [f, g]       # h
  ]
  return N
 
G = some_graph()
for i in range(len(G)): G[i] = set(G[i])
print list(walk(G,0)) #[0, 1, 2, 3, 4, 5, 6, 7]

上面的walk函数只适用于无向图,而且只能找到一个从参数s出发的连通分量,要想得到全部的连通分量需要修改下


def components(G):               # The connected components
  comp = []
  seen = set()                # Nodes we've already seen
  for u in G:                 # Try every starting point
    if u in seen: continue         # Seen? Ignore it
    C = walk(G, u)             # Traverse component
    seen.update(C)             # Add keys of C to seen
    comp.append(C)             # Collect the components
  return comp

用下面的代码来测试下,得到的结果没有问题


G = {
  0: set([1, 2]),
  1: set([0, 2]),
  2: set([0, 1]),
  3: set([4, 5]),
  4: set([3, 5]),
  5: set([3, 4])
  }
 
print [list(sorted(C)) for C in components(G)] #[[0, 1, 2], [3, 4, 5]]

至此我们就完成了一个时间复杂度为Θ(E+V)的求无向图的连通分量的算法,因为每条边和每个顶点都要访问一次。[这个时间复杂度会经常看到,例如拓扑排序,强连通分量都是它]

[接下来作者作为扩展介绍了欧拉回路和哈密顿回路:前者是经过图中的所有边一次,然后回到起点;后者是经过图中的所有顶点一次,然后回到起点。网上资料甚多,感兴趣自行了解]

下面我们看下迷宫问题,如下图所示,原始问题是一个人在公园中走路,结果走不出来了,即使是按照“左手准则”(也就是但凡遇到交叉口一直向左转)走下去,如果走着走着回到了原来的起点,那么就会陷入无限的循环中!有意思的是,左边的迷宫可以通过“左手准则”转换成右边的树型结构。

[注:具体的转换方式我还未明白,下面是作者给出的构造说明]

Here the “keep one hand on the wall” strategy will work nicely. One way of seeing why it works is to observe that the maze really has only one inner wall (or, to put it another way, if you put wallpaper inside it, you could use one continuous strip). Look at the outer square. As long as you're not allowed to create cycles, any obstacles you draw have to be connected to the it in exactly one place, and this doesn't create any problems for the left-hand rule. Following this traversal strategy, you'll discover all nodes and walk every passage twice (once in either direction).

查看图片

上面的迷宫实际上就是为了引出深度优先搜索(DFS),每次到了一个交叉口的时候,可能我们可以向左走,也可以向右走,选择是有不少,但是我们要向一直走下去的话就只能选择其中的一个方向,如果我们发现这个方向走不出去的话,我们就回溯回来,选择一个刚才没选过的方向继续尝试下去。

基于上面的想法可以写出下面递归版本的DFS


def rec_dfs(G, s, S=None):
  if S is None: S = set()           # Initialize the history
  S.add(s)                  # We've visited s
  for u in G[s]:               # Explore neighbors
    if u in S: continue           # Already visited: Skip
    rec_dfs(G, u, S)            # New: Explore recursively
  return S # For testing
 
G = some_graph()
for i in range(len(G)): G[i] = set(G[i])
print list(rec_dfs(G, 0))  #[0, 1, 2, 3, 4, 5, 6, 7]

很自然的我们想到要将递归版本改成迭代版本的,下面的代码中使用了Python中的yield关键字,具体的用法可以看下这里IBM Developer Works


def iter_dfs(G, s):
  S, Q = set(), []              # Visited-set and queue
  Q.append(s)                 # We plan on visiting s
  while Q:                  # Planned nodes left?
    u = Q.pop()               # Get one
    if u in S: continue           # Already visited? Skip it
    S.add(u)                # We've visited it now
    Q.extend(G[u])             # Schedule all neighbors
    yield u                 # Report u as visited
 
G = some_graph()
for i in range(len(G)): G[i] = set(G[i])
print list(iter_dfs(G, 0)) #[0, 5, 7, 6, 2, 3, 4, 1]

上面迭代版本经过一点点的修改可以得到更加通用的遍历函数


def traverse(G, s, qtype=set):
  S, Q = set(), qtype()
  Q.add(s)
  while Q:
    u = Q.pop()
    if u in S: continue
    S.add(u)
    for v in G[u]:
      Q.add(v)
    yield u

函数traverse中的参数qtype表示队列类型,例如栈stack,下面的代码给出了如何自定义一个stack,以及测试traverse函数


class stack(list):
  add = list.append
 
G = some_graph()
print list(traverse(G, 0, stack)) #[0, 5, 7, 6, 2, 3, 4, 1]

如果还不清楚的话可以看下算法导论中的这幅DFS示例图,节点的颜色后面有介绍

查看图片

上图在DFS时给节点加上了时间戳,这有什么作用呢?

前面提到过,在遍历节点的时候如果给节点标注它的发现节点时间d[v]和结束访问时间f[v]的话,从这些时间我们就能够发现一些信息,比如下图,(a)是图的一个DFS遍历加上时间戳后的结果;(b)是如果给每个节点的d[v]到f[v]区间加上一个括号的话,可以看出在DFS遍历中(也就是后来的深度优先树/森林)中所有的节点 u 的后继节点 v 的区间都在节点 u 的区间内部,如果节点 v 不是节点 u 的后继,那么两个节点的区间不相交,这就是“括号定理”。

查看图片

加上时间戳的DFS遍历还算比较好写对吧


#Depth-First Search with Timestamps
def dfs(G, s, d, f, S=None, t=0):
  if S is None: S = set()           # Initialize the history
  d[s] = t; t += 1              # Set discover time
  S.add(s)                  # We've visited s
  for u in G[s]:               # Explore neighbors
    if u in S: continue           # Already visited. Skip
    t = dfs(G, u, d, f, S, t)        # Recurse; update timestamp
  f[s] = t; t += 1              # Set finish time
  return t                  # Return timestamp

除了给节点加上时间戳之外,算法导论在介绍DFS的时候还给节点进行着色,在节点被发现之前是白色的,在发现之后先是灰色的,在结束访问之后才是黑色的,详细的流程可以参考上面给出的算法导论中的那幅DFS示例图。有了颜色有什么用呢?作用大着呢!根据节点的颜色,我们可以对边进行分类!大致可以分为下面四种:

查看图片

使用DFS对图进行遍历时,对于每条边(u,v),当该边第一次被发现时,根据到达节点 v 的颜色来对边进行分类(正向边和交叉边不做细分):

(1)白色表示该边是一条树边;

(2)灰色表示该边是一条反向边;

(3)黑色表示该边是一条正向边或者交叉边。

下图显示了上面介绍括号定理用时的那个图的深度优先树中的所有边的类型,灰色标记的边是深度优先树的树边

查看图片

那对边进行分类有什么作用呢?作用多着呢!最常见的作用的是判断一个有向图是否存在环,如果对有向图进行DFS遍历发现了反向边,那么一定存在环,反之没有环。此外,对于无向图,如果对它进行DFS遍历,肯定不会出现正向边或者交叉边。

那对节点标注时间戳有什么用呢?其实,除了可以发现上面提到的那些很重要的性质之外,时间戳对于接下来要介绍的拓扑排序的另一种解法和强连通分量很重要!

我们先看下摘自算法导论的这幅拓扑排序示例图,这是某个教授早上起来后要做的事情,嘿嘿

查看图片

不难发现,最终得到的拓扑排序刚好是节点的完成时间f[v]降序排列的!结合前面的括号定理以及依赖关系不难理解,如果我们按照节点的f[v]降序排列,我们就得到了我们想要的拓扑排序了!这就是拓扑排序的另一个解法![在算法导论中该解法是主要介绍的解法,而我们前面提到的那个解法是在算法导论的习题中出现的]

基于上面的想法就能够得到下面的实现代码,函数recurse是一个内部函数,这样它就可以访问到G和res等变量


#Topological Sorting Based on Depth-First Search
def dfs_topsort(G):
  S, res = set(), []             # History and result
  def recurse(u):               # Traversal subroutine
    if u in S: return            # Ignore visited nodes
    S.add(u)                # Otherwise: Add to history
    for v in G[u]:
      recurse(v)             # Recurse through neighbors
    res.append(u)              # Finished with u: Append it
  for u in G:
    recurse(u)               # Cover entire graph
  res.reverse()                # It's all backward so far
  return res
 
G = {'a': set('bf'), 'b': set('cdf'), 'c': set('d'), 'd': set('ef'), 'e': set('f'), 'f': set()}
print dfs_topsort(G)

[接下来作者介绍了一个Iterative Deepening Depth-First Search,没看懂,貌似和BFS类似]

如果我们在遍历图时“一层一层”式地遍历,先发现的节点先访问,那么我们就得到了广度优先搜索(BFS)。下面是作者给出的一个有意思的区别BFS和DFS的例子,遍历过程就像我们上网一样,DFS是顺着网页上的链接一个个点下去,当访问完了这个网页时就点击Back回退到上一个网页继续访问。而BFS是先在后台打开当前网页上的所有链接,然后按照打开的顺序一个个访问,访问完了一个网页就把它的窗口关闭。

One way of visualizing BFS and DFS is as browsing the Web. DFS is what you get if you keep following links and then use the Back button once you're done with a page. The backtracking is a bit like an “undo.” BFS is more like opening every link in a new window (or tab) behind those you already have and then closing the windows as you finish with each page.

BFS的代码很好实现,主要是使用队列


#Breadth-First Search
from collections import deque
 
def bfs(G, s):
  P, Q = {s: None}, deque([s])        # Parents and FIFO queue
  while Q:
    u = Q.popleft()             # Constant-time for deque
    for v in G[u]:
      if v in P: continue         # Already has parent
      P[v] = u              # Reached from u: u is parent
      Q.append(v)
  return P
 
G = some_graph()
print bfs(G, 0)

Python的list可以很好地充当stack,但是充当queue则性能很差,函数bfs中使用的是collections模块中的deque,即双端队列(double-ended queue),它一般是使用链表来实现的,这个类有extend、append和pop等方法都是作用于队列右端的,而方法extendleft、appendleft和popleft等方法都是作用于队列左端的,它的内部实现是非常高效的。

Internally, the deque is implemented as a doubly linked list of blocks, each of which is an array of individual elements. Although asymptotically equivalent to using a linked list of individual elements, this reduces overhead and makes it more efficient in practice. For example, the expression d[k] would require traversing the first k elements of the deque d if it were a plain list. If each block contains b elements, you would only have to traverse k//b blocks.

最后我们看下强连通分量,前面的分量是不考虑边的方向的,如果我们考虑边的方向,而且得到的最大子图中,任何两个节点都能够沿着边可达,那么这就是一个强连通分量。

下图是算法导论中的示例图,(a)是对图进行DFS遍历带时间戳的结果;(b)是上图的的转置,也就是将上图中所有边的指向反转过来得到的图;(c)是最终得到的强连通分支图,每个节点内部显示了该分支内的节点。

查看图片

上面的示例图自然不太好明白到底怎么得到的,我们慢慢来分析三幅图 [原书的分析太多了,我被绕晕了+_+,下面是我结合算法导论的分析过程]

先看图(a),每个灰色区域都是一个强连通分支,我们想想,如果强连通分支 X 内部有一条边指向另一个强连通分支 Y,那么强连通分支 Y 内部肯定不存在一条边指向另一个强连通分支 Y,否则它们能够整合在一起形成一个新的更大气的强连通分支!这也就是说强连通分支图肯定是一个有向无环图!我们从图(c)也可以看出来

再看看图(c),强连通分支之间的指向,如果我们定义每个分支内的任何顶点的最晚的完成时间为对应分支的完成时间的话,那么分支abe的完成时间是16,分支cd是10,分支fg是7,分支h是6,不难发现,分支之间边的指向都是从完成时间大的指向完成时间小的,换句话说,总是由完成时间晚的强连通分支指向完成时间早的强连通分支!

最后再看看图(b),该图是原图的转置,但是得到强连通分支是一样的(强连通分支图是会变的,刚好又是原来分支图的转置),那为什么要将边反转呢?结合前面两个图的分析,既然强连通分支图是有向无环图,而且总是由完成时间晚的强连通分支指向完成时间早的强连通分支,如果我们将边反转,虽然我们得到的强连通分支不变,但是分支之间的指向变了,完成时间晚的就不再指向完成时间早的了!这样的话如果我们对它进行拓扑排序,即按照完成时间的降序再次进行DFS时,我们就能够得到一个个的强连通分支了对不对?因为每次得到的强连通分支都没有办法指向其他分支了,也就是确定了一个强连通分支之后就停止了。[试试画个图得到图(b)的强连通分支图的拓扑排序结果就明白了]

经过上面略微复杂的分析之后我们知道强连通分支算法的流程有下面四步:

1.对原图G运行DFS,得到每个节点的完成时间f[v];

2.得到原图的转置图GT;

3.对GT运行DFS,主循环按照节点的f[v]降序进行访问;

4.输出深度优先森林中的每棵树,也就是一个强连通分支。

根据上面的思路可以得到下面的强连通分支算法实现,其中的函数parse_graph是作者用来方便构造图的函数


def tr(G):                   # Transpose (rev. edges of) G
  GT = {}
  for u in G: GT[u] = set()          # Get all the nodes in there
  for u in G:
    for v in G[u]:
      GT[v].add(u)            # Add all reverse edges
  return GT
 
def scc(G):
  GT = tr(G)                 # Get the transposed graph
  sccs, seen = [], set()
  for u in dfs_topsort(G):          # DFS starting points
    if u in seen: continue         # Ignore covered nodes
    C = walk(GT, u, seen)          # Don't go "backward" (seen)
    seen.update(C)             # We've now seen C
    sccs.append(C)             # Another SCC found
  return sccs
 
from string import ascii_lowercase
def parse_graph(s):
  # print zip(ascii_lowercase, s.split("/"))
  # [('a', 'bc'), ('b', 'die'), ('c', 'd'), ('d', 'ah'), ('e', 'f'), ('f', 'g'), ('g', 'eh'), ('h', 'i'), ('i', 'h')]
  G = {}
  for u, line in zip(ascii_lowercase, s.split("/")):
    G[u] = set(line)
  return G
 
G = parse_graph('bc/die/d/ah/f/g/eh/i/h')
print list(map(list, scc(G)))
#[['a', 'c', 'b', 'd'], ['e', 'g', 'f'], ['i', 'h']]

[最后作者提到了一点如何进行更加高效的搜索,也就是通过分支限界来实现对搜索树的剪枝,具体使用可以看下这个问题顶点覆盖问题Vertext Cover Problem]

问题5.17 强连通分支

In Kosaraju's algorithm, we find starting nodes for the final traversal by descending finish times from an initial DFS, and we perform the traversal in the transposed graph (that is, with all edges reversed). Why couldn't we just use ascending finish times in the original graph?

问题就是说,我们干嘛要对转置图按照完成时间降序遍历一次呢?干嘛不直接在原图上按照完成时间升序遍历一次呢?

Try finding a simple example where this would give the wrong answer. (You can do it with a really small graph.)

总结

以上就是本文关于Python算法之图的遍历的全部内容,希望对大家有所帮助。感兴趣的朋友可以继续参阅本站:

python先序遍历二叉树问题

python实现报表自动化详解

python绘制铅球的运行轨迹代码分享

如有不足之处,欢迎留言指出。

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

Python算法之图的遍历

下载Word文档到电脑,方便收藏和打印~

下载Word文档

猜你喜欢

Python算法之图的遍历

本节主要介绍图的遍历算法BFS和DFS,以及寻找图的(强)连通分量的算法 Traversal就是遍历,主要是对图的遍历,也就是遍历图中的每个节点。对一个节点的遍历有两个阶段,首先是发现(discover),然后是访问(visit)。遍历的重
2022-06-04

使用Python实现树的遍历算法和类型的树的遍历

树遍历意味着访问树中的每个节点。和线性数据结构单一的遍历方式不同,二叉树是分层式数据结构可以以不同的方式遍历。树遍历结构特点1、每个树的节点都承载一个数据2、每个树下都有2个子树树遍历有三种类型1、中序遍历先遍历左子树所有节点,
使用Python实现树的遍历算法和类型的树的遍历
2024-01-23

Kasaraju算法--强连通图遍历及其

在理解有向图和强连通分量前必须理解与其对应的两个概念,连通图(无向图)和连通分量。连通图的定义是:如果一个图中的任何一个节点可以到达其他节点,那么它就是连通的。例如以下图形:这是最简单的一个连通图,即使它并不闭合。由于节点间的路径是没有方向
2023-01-30

python的os遍历

使用python遍历目录用到方法一:os.path.walk(top, func, arg)模块方法,该方法需要输入3个参数:top为起始路径, func为回调函数(可以对遍历出的目录文件做处理),arg为回调函数func的参数。见下例子:
2023-01-31

JavaScript遍历实现DFS算法和BFS算法

DFS(Depth first search)称作「深度优先遍历」,BFS(Breadth first search)称作「广度优先遍历」。本文将通过JavaScript遍历实现这两种算法,需要的可以参考一下
2023-01-14

C语言数据结构与算法图的遍历分析

这篇文章主要介绍“C语言数据结构与算法图的遍历分析”,在日常操作中,相信很多人在C语言数据结构与算法图的遍历分析问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”C语言数据结构与算法图的遍历分析”的疑惑有所帮助!
2023-06-22

怎么理解Java优先遍历和广度优先遍历算法

这篇文章主要讲解了“怎么理解Java优先遍历和广度优先遍历算法”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“怎么理解Java优先遍历和广度优先遍历算法”吧!深度优先遍历主要思路是从图中一个未
2023-06-16

Python Prim算法通过遍历墙实现迷宫的生成

之前,我们在另外一篇文章中使用Prim算法生成了一个完美迷宫,利用的是遍历网格的方法,这一次,我们要教教大家用遍历墙的方法生成,感兴趣的可以收藏一下
2023-01-06

python遍历数组的两种方法

python遍历数组的两种方法第一种,最常用的,通过for in遍历数组[cpp] view plain copycolours = ["red","green","blue"]  for colour in colours:      p
2023-01-31

Python二叉树的定义及常用遍历算法分析

本文实例讲述了Python二叉树的定义及常用遍历算法。分享给大家供大家参考,具体如下: 说起二叉树的遍历,大学里讲的是递归算法,大多数人首先想到也是递归算法。但作为一个有理想有追求的程序员。也应该学学非递归算法实现二叉树遍历。二叉树的非递归
2022-06-04

python遍历目录的方法小结

本文实例总结了python遍历目录的方法。分享给大家供大家参考,具体如下: 方法一使用递归:""" def WalkDir( dir, dir_callback = None, file_callback = None ):for item
2022-06-04

Python数组的遍历

Python的数组是一个好东西啊, 在Python中,我们习惯这样遍历: for item in sequence: process(item) 这样遍历取不到item的序号i,所有就有了下面的遍历方法: for index in
2023-01-31

C++STL中的常用遍历算法分享

这篇文章主要为大家详细介绍了C++STL中两个常用的遍历算法,文中的示例代码讲解详细,具有一定的学习与借鉴价值,感兴趣的小伙伴可以参考一下
2022-12-20

遍历python字典几种方法

脚本:#!/usr/bin/python dict={"a":"apple","b":"banana","o":"orange"}  print "##########dict######################" for i in
2023-01-31

编程热搜

  • Python 学习之路 - Python
    一、安装Python34Windows在Python官网(https://www.python.org/downloads/)下载安装包并安装。Python的默认安装路径是:C:\Python34配置环境变量:【右键计算机】--》【属性】-
    Python 学习之路 - Python
  • chatgpt的中文全称是什么
    chatgpt的中文全称是生成型预训练变换模型。ChatGPT是什么ChatGPT是美国人工智能研究实验室OpenAI开发的一种全新聊天机器人模型,它能够通过学习和理解人类的语言来进行对话,还能根据聊天的上下文进行互动,并协助人类完成一系列
    chatgpt的中文全称是什么
  • C/C++中extern函数使用详解
  • C/C++可变参数的使用
    可变参数的使用方法远远不止以下几种,不过在C,C++中使用可变参数时要小心,在使用printf()等函数时传入的参数个数一定不能比前面的格式化字符串中的’%’符号个数少,否则会产生访问越界,运气不好的话还会导致程序崩溃
    C/C++可变参数的使用
  • css样式文件该放在哪里
  • php中数组下标必须是连续的吗
  • Python 3 教程
    Python 3 教程 Python 的 3.0 版本,常被称为 Python 3000,或简称 Py3k。相对于 Python 的早期版本,这是一个较大的升级。为了不带入过多的累赘,Python 3.0 在设计的时候没有考虑向下兼容。 Python
    Python 3 教程
  • Python pip包管理
    一、前言    在Python中, 安装第三方模块是通过 setuptools 这个工具完成的。 Python有两个封装了 setuptools的包管理工具: easy_install  和  pip , 目前官方推荐使用 pip。    
    Python pip包管理
  • ubuntu如何重新编译内核
  • 改善Java代码之慎用java动态编译

目录