python_图_2021-6-15

图的基本概念


graph:重在由一些基本元素构造而来的图,如点,线段等
图(graph)是比树更为一般的结构,也是由节点和边组成的,树可以说是一种特殊性质的图.
图可以用来表示现实中的很多事物如:道路交通系统,航班路线,互联网连接,大学中课程的先修次序
在这里插入图片描述
在这里插入图片描述
还有一个跟六度空间一样的玩意,什么任意两个人之间可以通过最多六个人联系起来,这违背了我的尝试,我是不信的,不过说不定哪天我就信了

在这里插入图片描述

一些听起来很专业的术语表


顶点是图的基本组成部分
而边分为有向边和无向边,相应的图被称为有向图和无向图
在这里插入图片描述

这个东西就是为了表达一个顶点到另一个顶点的代价,可以给权重也可以不给
在这里插入图片描述

图的定义


一个图的基本组成部分就是顶点vertex,顶点到顶点就构成了边,如果是赋权图就再加一个权重weight就可以了
在这里插入图片描述

举个例子
在这里插入图片描述

对于无权图路径是指从该顶点到末尾顶点的边的数量之和,有权图是指从该顶点到末尾顶点权重之和
在这里插入图片描述
圈是指一个闭环,如果有向图不存在任何圈,就是有向无权图

Graph的抽象数据类型定义


就是定义一个Graph的类,里面有各种各样的方法.
可以添加顶点:addVertex,有向边:addEdge,带权有向边:addEdge让他默认为一个数,查找顶点getVertex,getvertices返回图中所有顶点列表
在这里插入图片描述

具体的两种实现方法

在这里插入图片描述

邻接矩阵

这个东西比较好理解,就是列为fromvert,行为tovert,里面保存的是权重
在这里插入图片描述
主要的问题就是一般不会有那么紧的排列,所以利用的效率不高

邻接列表

可以看到邻接列表是一种稀疏图的更高效实现的方式,就是当前节点保存了对应的顶点和他们之间的边
在这里插入图片描述

具体的代码实现


1.首先创建一个顶点类

#首先是Vertex类
class Vertex:
    def __init__(self,key):
        self.id=key
        self.connectedTo={}   #用来保存相连顶点,里面有相连顶点,以及对应的权重
    def addNeighbor(self,nbr,weight=0):  #nbr是顶点对象的key
        self.connectedTo[nbr]=weight   #这个函数是用来 将与此顶点相连的顶点保存起来
    def __str__(self):
        return str(self.id)+' connectedTo:'\
            +str([x.id for x in self.connectedTo])  #返回的是该顶点的名称和与其相连的顶点
    def getConnections(self):
        return self.connectedTo.keys()  #获得与其相连的所有顶点
    def getId(self):
        return self.id    #获得本顶点的名字
    def getweight(self,nbr):
        return self.connectedTo[nbr]    #获得与nbr之间的权重

有必要提一下的是python的类方法中的__str__()方法,这个方法是python的内置方法使用如下

最开始的输出
class  obj:
    def __init__(self):
        pass
p=obj()
print(p)   <class '__main__.obj'>


class  obj:
    def __str__(self):
        pass
p=obj()
print(p)    报错  我需要字符串而你什么都不干



class  obj:
    def __str__(self):
        print(1)
p=obj()
print(p)   会输出1 同时也会报错因为没有返回字符串

但是当有了返回值之后就不一样了
class  obj:
    def __str__(self):
        return 1
p=obj()
print(p)   报错 因为不是字符串



class  obj:
    def __str__(self):
        return '1'
p=obj()
print(p)  1 因为有返回值,且为字符串

所以说只要是有正确的__str__()方法的时候打印对象就成了打印字符串

创建一个图类

class Graph:
    def __init__(self):
        self.verList={}    #包含所有顶点
        self.numVertices=0  #记录顶点个数
    def addVertex(self,key):
        self.numVertices=self.numVertices+1  #顶点个数加一
        newVertex=Vertex(key)   #创建一个新的顶点
        self.verList[key]=newVertex   #根据顶点的key保存顶点
    def getvertex(self,key):
        if key in self.verList:
            #能进来说明有对应的key
            return self.verList[key]
        else:
            return None
    def __contains__(self, item):       #这个方法是使 in 可以直接被使用,进行判断用的
        return item in self.verList
    def addEdge(self,f,t,weight=0):
        #f为一个顶点的key
        if f not in self.verList:
            #能进来说明没有这个顶点需要创建一个
            self.addVertex(f)
        if t not in self.verList:
            self.addVertex(t)
        #添加这个顶点,以及与其相连的顶点
        self.verList[f].addNeighbor(self.verList[t],weight)
        #因为是有向图,每条边均为有向边,所以不考虑t的邻居添加f
    def getVertices(self):
        return self.verList.keys()  #这个得到的是所有顶点所对应的键
    def __iter__(self):
        return iter(self.verList.values())

重点还是提一下__contains__()方法,他是需要去传入一个参数item的,主要就是判断该item是否在某个属性中


class obj:
    def __init__(self):
        self.list=[1,2,3]
    def __contains__(self,item):
        return item in self.list
p=obj()
print(1 in p)  True
print(4 in p) 	False
如果删除了呢
class obj:
    def __init__(self):
        self.list=[1,2,3]
p=obj()
print(1 in p)
print(4 in p)
这是会报错的TypeError: argument of type 'obj' is not iterable
说对象是不可迭代的

并且contains中return后所跟不一定是 in
class obj:
    def __init__(self):
        self.list=[1,2,3]
    def __contains__(self,item):
        return 1
p=obj()
print(1 in p)  True
print(4 in p) 	True 但返回值一定是bool类型

还有__iter__()方法:使对象本身可以被迭代

class obj:
    def __init__(self):
        self.list=[1,2,3]
p=obj()
for i in p:
    print(i)  TypeError: 'obj' object is not iterable
那么如果加上__iter__()方法呢?
class obj:
    def __init__(self):
        self.list=[1,2,3]
    def __iter__(self):
        return 1 		TypeError: iter() returned non-iterator of type 'int'
p=obj()
for i in p:
    print(i)
class obj:
    def __init__(self):
        self.list=[1,2,3]
    def __iter__(self):
        return [1,2,3]
p=obj()
for i in p:
    print(i)   TypeError: iter() returned non-iterator of type 'list'

上面两个报错大同小异,都是说返回的类型是什么什么而非迭代器,这时候怎么办呢?
请出我们的iter关键字可以将返回对象转化为迭代器

class obj:
    def __init__(self):
        self.list=[1,2,3]
    def __iter__(self):
        return iter([1])
p=obj()
for i in p:
    print(i)  1

图的实际应用


词梯问题是一个关于最短路径的问题

在这里插入图片描述
如果每个单词在创建边时都进行一次比对的话需要n**2的次数,这是一个很大的计算复杂度
在这里插入图片描述

这里是一个优化,他建立了一个桶.一个桶中的所有单词之间都是可以建边的

在这里插入图片描述

这是老师写的代码文件
在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值