Python数据结构与算法之图的基本实现及迭代器实例详解


Posted in Python onDecember 12, 2017

本文实例讲述了Python数据结构与算法之图的基本实现及迭代器。分享给大家供大家参考,具体如下:

这篇文章参考自《复杂性思考》一书的第二章,并给出这一章节里我的习题解答。

(这书不到120页纸,要卖50块!!,一开始以为很厚的样子,拿回来一看,尼玛。。。。。代码很少,给点提示,然后让读者自己思考怎么实现)

先定义顶点和边

class Vertex(object):
 def __init__(self, label=''):
  self.label = label
 def __repr__(self):
  return 'Vertex(%s)' % repr(self.label)
 # __repr__返回表达式, __str__返回可阅读信息
 __str__=__repr__ # 使其指向同一个函数
class Edge(tuple):
 # 继承自建tuple类型并重写new方法
 def __new__(cls, e1, e2):
  return tuple.__new__(cls, (e1,e2))
 def __repr__(self):
  return "Edge(%s, %s)" % (repr(self[0]), repr(self[1]))
 __str__ = __repr__

创建顶点和边的方法如下

if __name__=="__main__":
 # 创建两个顶点一条边
 v = Vertex('v')
 w = Vertex('w')
 e = Edge(v,w)
#  print e
 # 将顶点和边放入图中
 g = Graph([v,w],[e])
#  print g

创建一个基本的图类:

# 通过字典的字典实现图的结构
class Graph(dict):
 def __init__(self, vs=[], es=[]):
  """ 建立一个新的图,(vs)为顶点vertices列表,(es)为边缘edges列表 """
  for v in vs:
   self.add_vertex(v)
  for e in es:
   self.add_edge(e)
 def add_vertex(self,v):
  """ 添加顶点 v: 使用字典结构"""
  self[v] = {}
 def add_edge(self, e):
  """ 添加边缘 e: e 为一个元组(v,w) 
   在两个顶点 w 和 v 之间添加成员e ,如果两个顶点之间已有边缘,则替换之 """
  v, w = e
  # 由于一条边会产生两个项目,因此该实现代表了一个无向图
  self[v][w] = e
  self[w][v] = e

练习2-2解答:图的一些基本操作

def get_edge(self,v1, v2):
  """ 接收两个顶点,若这两个顶点之间右边则返回这条边,否则返回None """
  try:
   return self[v1][v2]
  except:
   return None
 def remove_edge(self,e):
  """ 接受一条边,并且删除图中该边的所有引用 """
  v, w = e
  self[v].pop(w)
  self[w].pop(v)
 def vertices(self):
  """ 返回图中所有顶点的列表 """
  return self.keys()
 def edges(self):
  """ 返回图中边的列表 """
  es = set()    # 为了避免返回重复的边,设为集合
  for v1 in self.vertices():
   for v2 in self.vertices():
    es.add(self.get_edge(v2, v1))
  es.discard(None)  # 若集合中存在None元素,则删除 
  return list(es)
  """ 利用图的字典结构获得所有边
  es = []
  for v in self.vertices():
   es.extend(self[v].values())
  es = list(set(es))
  return es
  """
 def out_vertices(self,v):
  """ 接受一个Vertex并返回邻近顶点(通过一条边连接到给定节点的节点)的列表 """
  return self[v].keys()
 def out_edges(self,v):
  """ 接受一个Vertex并返回连接到给定节点的边的列表 """
  return self[v].values()
 def add_all_edges(self,vs=None):
  """ 从一个无边的图开始,通过在各个顶点间添加边来生成一个完全图
   输入为目标顶点的列表,如果为None,则对所有的点进行全联结 """
  if vs == None:
   vs = self.vertices()
  for v1 in vs:
   for v2 in vs:
    if v1 is v2 : continue  # 假设不存在单顶点连通
    self.add_edge(Edge(v1,v2))

习题2-3 生成正则图

正则图是指图中每个顶点的度相同,生成正则图需要顶点数和度数满足一定条件,具体算法见注释:

def add_regular_edges(self,k):
  """ 从一个无边的图开始不断添加边,使得每个顶点都有相同的度k
   一个节点的度指的是连接到它的边的数量 """
  n = len(self.vertices())
  assert n > 1
  if k==1:
   vs = self.vertices()
   for i in range(n-1):
    self.add_edge(Edge(vs[i],vs[i+1]))
   return True
  if n < k+1:
   print "Cannot create regular graph"
   return False
  if n == k+1:
   self.add_all_edges()
   return True
  """
   设度数为k,图的阶数(顶点个数)为n
   利用归纳方法生成边的个数
   偶数度 当k=2m,m>=1时
   递归过程:
   0. 假设n>k+1,因为当n=k+1时,只要生成全连接即可,当n<k+1,则不能生成正则图
   1. 当n>k+1时:先从原图中前k+1个顶点(v1,v2,...,v2m-1,v2m, v2m+1)生成完全图
    此时,该k+1个顶点的度数均为k
   2. 现添加一个顶点vx,x=2m+2该顶点的度为0
   3. 删除m条不相连的边,如(v1,v2),(v3,v4),(v5,v6),...,(v2m-1,v2m),这时顶点v1,v2,...v2m的度为k-1
    记录下这m条边的顶点
   4. 联结 (v1,vx),(v2,vx),...,(v2m-1,vx),(v2m,vx),使得v1,v2,...,v2m,v2m+2的度=k
   5. 对新加入的点,重复3,4
   奇数度 当k=2m+1,m>=1时
   递归过程:
   设图G是有n个顶点的k正则图,且k=2m+1,m>=1,按照下面法则生成新图G1
   0. 假设n>k+1,因为当n=k+1时,只要生成全连接即可,当n<k+1,则不能生成正则图
   1. 在图G中任取m条顶点不同的边(x1,x2),(x3,x4),(x5,x6),...,(x2m-1,x2m) 记为组es1
    再另取m条顶点不同的边 (y1,y2),(y3,y4),(y5,y6),...,(y2m-1,y2m) 记为组es2
    其中xi和yj可以存在相同,但是两组中的所有边都不相同
    此时,该k+1个顶点的度数均为k
   2. 在图G中去掉m条边(x1,x2),(x3,x4),(x5,x6),...,(x2m-1,x2m),增加新的顶点v1,并增加2m条新边
    (v1,x1),(v1,x2),...,(v1,x2m-1),(v1,x2m)
   3. 在图G中去掉m条边(y1,y2),(y3,y4),(y5,y6),...,(y2m-1,y2m),增加新的顶点v2,并增加2m条新边
    (v2,y1),(v2,y2),...,(v2,y2m-1),(v2,y2m)
   4. 增加新边 (v1,v2)
   5. 对新的点v3,v4,重复1,2,3,4
   增加的顶点和边保证了v1,v2和x1,x2,...,x2m,y1,y2,...,y2m的度数为2m+1其余顶点度数不变
  """
  if k%2==0:
   # 选取前k+1个点,先构造完全图
   vs = self.vertices()
   self.add_all_edges(vs[:k+1])
   for i in range(k+1,n):   # 对之后的点进行遍历 
    vsdel = []     # 记录删除过边的顶点
    for e in self.edges():      
     # 获得边的两个顶点
     v1,v2 = e[0],e[1]  
     if v1 not in vsdel and v2 not in vsdel:
      vsdel.append(v1)
      vsdel.append(v2)
      # 删除不相连的边
      self.remove_edge(e)
     # 当已删除的边数为k/2,即共k个非邻近点时,退出循环
     if len(vsdel)==k:
      break 
    # 将新的点与记录的点进行连接
    for v in vsdel:
     self.add_edge(Edge(v,vs[i]))
  else:
   if n%2==0 and n>k+1: # 由上述法则可知,n必须为偶数
    # 选取前k+1个偶数点,先构造完全图
    vs = self.vertices()
    self.add_all_edges(vs[:k+1])
    for i in range(k+1,n,2): # 之后的点进行两两遍历
     vsdel1 = []    # 记录第1组删除的点
     edel1 = []    # 记录第1组删除的边
     for e in self.edges():      
      # 获得边的两个顶点
      v1,v2 = e[0],e[1]  
      if v1 not in vsdel1 and v2 not in vsdel1:
       vsdel1.append(v1)
       vsdel1.append(v2)
       # 删除不相连的边
       edel1.append(e)
       self.remove_edge(e)
      # 当已删除的边数为m,即共k-1个非邻近点时,退出循环
      if len(vsdel1)==k-1:
       break
     vsdel2 = []    # 记录第2组删除的点
     edel2 = []    # 记录第2组删除的边
     for e in self.edges():      
      # 获得边的两个顶点
      v1,v2 = e[0],e[1]  
      # 点可以和第一组相同,但边不可以
      if v1 not in vsdel2 and v2 not in vsdel2 and e not in edel1:
       vsdel2.append(v1)
       vsdel2.append(v2)
       # 删除不相连的边
       edel2.append(e)
       self.remove_edge(e)
      # 当已删除的边数为m,即共k-1个非邻近点时,退出循环
      if len(vsdel2)==k-1:
       break
     # 分别连接两组边
     for v in vsdel1:
      self.add_edge(Edge(v,vs[i]))
     for v in vsdel2:
      self.add_edge(Edge(v,vs[i+1]))
     self.add_edge(Edge(vs[i],vs[i+1]))
   else:
    print "Cannot create regular graph"
    return False
  return True

习题2-4:判断一个图是否连通,可以用BFS实现:

def is_connect(self):
  """ 判断一个图是否连通的
   从任意顶点开始进行一次BFS,将所有到达的节点都标记上,然后检查是否所有的节点都被标记上 """
  pass
  vs = self.vertices() # 获得所有顶点
  q, s = [], set()  # 搜索队列,标记集合
  q.append(vs[0])   # 从第1个顶点开始搜索
  while q:    # 当队列非空
   v = q.pop(0)  # 从队列中删除移一个顶点
   s.add(v)   # 并标记当前顶点
   # 搜索当前顶点的连接点,如果这些连接点没有被标记
   # 则将其添加到队列中
   for w in self.out_vertices(v):
    if w not in s:
     q.append(w)
  # 当队列为空时完成搜索,检查标记过的顶点是否等于图的顶点数
  if len(s)==len(vs):
   return True
  else:
   return False

测试代码:需要用到作者书中网页提供的GraphWorld.py实现可视化功能

from GraphWorld import CircleLayout,GraphWorld
from Graph import Graph,Vertex,Edge
import string
def test(n,k):
 # create n Vertices
 labels = string.ascii_lowercase + string.ascii_uppercase
 vs = [Vertex(c) for c in labels[:n]]
 # create a graph and a layout
 g = Graph(vs)
 g.add_regular_edges(k)
 layout = CircleLayout(g)
 # draw the graph
 gw = GraphWorld()
 gw.show_graph(g, layout)
 gw.mainloop()
if __name__ == '__main__':
 test(n=10,k=3)

以下为生成10个结点,度为3的正则图:

Python数据结构与算法之图的基本实现及迭代器实例详解

生成随机图,继承上面的Graph类:

from Graph import Graph,Vertex,Edge
from random import randint
class RandomGraph(Graph):
 """ 随即图 """
 def add_random_edges(self,p):
  """ 从一个·无边图开始随机生成边
   使得任意两个节点间存在边的概率为p (0<=p<=1) """
  for v1 in self.vertices():
   for v2 in self.vertices():
    if v1 is v2: continue
    if randint(0,100) < p*100 :
     self.add_edge(Edge(v1,v2))

测试一下:

from GraphWorld import CircleLayout,GraphWorld
import string
def test(n,p):
 # create n Vertices
 labels = string.ascii_lowercase + string.ascii_uppercase
 vs = [Vertex(c) for c in labels[:n]]
 # create a graph and a layout
 g = RandomGraph(vs)
 g.add_random_edges(p)
 print "connect?:",g.is_connect()
 layout = CircleLayout(g)
 # draw the graph
 gw = GraphWorld()
 gw.show_graph(g, layout)
 gw.mainloop()
if __name__ == '__main__':
 test(p=0.2,n=5)

Python数据结构与算法之图的基本实现及迭代器实例详解

迭代器部分代码:

# 迭代器
class AllTrue(object):
 def next(self):
  return True
 def __iter__(self):
  return self
# 使用AllTrue之类的迭代器可以表现无限序列
print zip('abc',AllTrue())
# 通过编写生成器函数创建一个迭代器
def generate_letters():
 for letter in 'abc':
  yield letter
iter = generate_letters()
import string
# 带有无限循环的生成器会返回一个不会终止的迭代器
def alphabet_cycle():
 while True:
  for i in range(1,10):
   for c in string.lowercase:
    yield c+str(i)
iter_ac = alphabet_cycle()
print iter_ac.next()

希望本文所述对大家Python程序设计有所帮助。

Python 相关文章推荐
python中的对象拷贝示例 python引用传递
Jan 23 Python
Python实现把utf-8格式的文件转换成gbk格式的文件
Jan 22 Python
Python实现LRU算法的2种方法
Jun 24 Python
Python使用redis pool的一种单例实现方式
Apr 16 Python
详解flask入门模板引擎
Jul 18 Python
利用python修改json文件的value方法
Dec 31 Python
PyQt弹出式对话框的常用方法及标准按钮类型
Feb 27 Python
python3.6下Numpy库下载与安装图文教程
Apr 02 Python
python Elasticsearch索引建立和数据的上传详解
Aug 04 Python
对tensorflow中的strides参数使用详解
Jan 04 Python
构建高效的python requests长连接池详解
May 02 Python
Python3 + Appium + 安卓模拟器实现APP自动化测试并生成测试报告
Jan 27 Python
Python数据结构与算法之图的最短路径(Dijkstra算法)完整实例
Dec 12 #Python
你真的了解Python的random模块吗?
Dec 12 #Python
Python判断两个对象相等的原理
Dec 12 #Python
浅谈Django REST Framework限速
Dec 12 #Python
Django admin美化插件suit使用示例
Dec 12 #Python
Django admin实现图书管理系统菜鸟级教程完整实例
Dec 12 #Python
基于Django filter中用contains和icontains的区别(详解)
Dec 12 #Python
You might like
jquery1.5.1中根据元素ID获取元素对象的代码
2011/04/02 Javascript
JavaScript XML和string相互转化实现代码
2011/07/04 Javascript
JavaScript 原型继承
2011/12/26 Javascript
jQuery中:submit选择器用法实例
2015/01/03 Javascript
Jquery中的$.each获取各种返回类型数据的使用方法
2015/05/03 Javascript
jquery的幻灯片图片切换效果代码分享
2015/09/07 Javascript
JS+CSS实现大气的黑色首页导航菜单效果代码
2015/09/10 Javascript
基于jQuery实现表格的查看修改删除
2016/08/01 Javascript
微信js-sdk界面操作接口用法示例
2016/10/12 Javascript
详解基于javascript实现的苹果系统底部菜单
2016/12/02 Javascript
Vue实现双向数据绑定
2017/05/03 Javascript
把JavaScript代码改成ES6语法不完全指南(分享)
2017/09/10 Javascript
JS设计模式之惰性模式(二)
2017/09/29 Javascript
pace.js和NProgress.js两个加载进度插件的一点小总结
2018/01/31 Javascript
React 使用browserHistory项目访问404问题解决
2018/06/01 Javascript
typescript nodejs 依赖注入实现方法代码详解
2019/07/21 NodeJs
JavaScript面向对象中接口实现方法详解
2019/07/24 Javascript
layui下拉列表select实现可输入查找的方法
2019/09/28 Javascript
JavaScript事件循环及宏任务微任务原理解析
2020/09/02 Javascript
vue项目打包为APP,静态资源正常显示,但API请求不到数据的操作
2020/09/12 Javascript
JS highcharts实现动态曲线代码示例
2020/10/16 Javascript
[09:37]DOTA2卡尔工作室 英雄介绍圣堂刺客篇
2013/06/13 DOTA
Python实现的数据结构与算法之双端队列详解
2015/04/22 Python
python使用fileinput模块实现逐行读取文件的方法
2015/04/29 Python
Python实现控制台输入密码的方法
2015/05/29 Python
对Python 网络设备巡检脚本的实例讲解
2018/04/22 Python
利用Python实现在同一网络中的本地文件共享方法
2018/06/04 Python
python求加权平均值的实例(附纯python写法)
2019/08/22 Python
k-means 聚类算法与Python实现代码
2020/06/01 Python
浅谈python出错时traceback的解读
2020/07/15 Python
彻底搞懂python 迭代器和生成器
2020/09/07 Python
印尼最大的在线购物网站:MatahariMall.com
2016/08/26 全球购物
Juice Beauty官网:有机美容产品,护肤与化妆品
2020/06/13 全球购物
环境科学专业大学生自荐信格式
2013/09/21 职场文书
档案接收函范文
2014/01/10 职场文书
病假证明模板
2015/06/19 职场文书