图形结构DFS,BFS(数据结构)

1 概念

无向图,有向图的表示

1 邻接矩阵法

无向图的打印:

arr=[[0]*6 for row in range(6)]  #声明矩阵arr
#图各边的起点值和终点值
data=[[1,2],[2,1],[1,5],[5,1], \
      [2,3],[3,2],[2,4],[4,2], \
      [3,4],[4,3]]
for i in range(10):     #读取图的数据
    for j in range(2):  #填入arr矩阵
        for k in range(6):
            tmpi=data[i][0]    #tmpi为起始顶点
            tmpj=data[i][1]    #tmpj为终止顶点
            arr[tmpi][tmpj]=1  #有边的点填入1

print('无向图矩阵:')
for i in range(1,6):
    for j in range(1,6):
        print('[%d] ' %arr[i][j],end='')  #打印矩阵内容
    print() #打印完一行,打印一个空,转行

无向图矩阵:
[0] [1] [0] [0] [1]
[1] [0] [1] [1] [0]
[0] [1] [0] [1] [0]
[0] [1] [1] [0] [0]
[1] [0] [0] [0] [0]

有向图的打印:

arr=[[0]*6 for row in range(6)]  #声明矩阵arr
    
data=[[1,2],[2,1],[2,3],[2,4],[4,3],[4,1]]  #图各边的起点值和终点值
for i in range(6):      #读取图的数据
    for j in range(6):  #填入arr矩阵
        tmpi=data[i][0]     #tmpi为起始顶点
        tmpj=data[i][1]     #tmpj为终止顶点
        arr[tmpi][tmpj]=1   #有边的点填入1

print('有向图矩阵:')
for i in range(1,6):
    for j in range(1,6):
        print('[%d] ' %arr[i][j],end='')  #打印矩阵内容
    print()

有向图矩阵:
[0] [1] [0] [0] [0]
[1] [0] [1] [1] [0]
[0] [0] [0] [0] [0]
[1] [0] [1] [0] [0]
[0] [0] [0] [0] [0]

有向图和无向图打印是一样的,只不多有向图不再对称

2 邻接表法

ass list_node:
    def __init__(self):
        self.val=0
        self.next=None
        
head=[list_node()]*6 #声明一个节点类型的链表
##print(head) #里面是六个对象

newnode=list_node()


#图的数组声明
data=[[1,2],[2,1],[2,5],[5,2], \
      [2,3],[3,2],[2,4],[4,2], \
      [3,4],[4,3],[3,5],[5,3], \
      [4,5],[5,4]]

print('图的邻接表内容:')
print('----------------------------------')
for i in range(1,6):
    head[i].val=i  #链表头head
    head[i].next=None
    print('顶点 %d =>' %i,end='')  #把顶点值打印出来
    ptr=head[i]
    for j in range(14):    #遍历图的数组
        if data[j][0]==i:  #如果节点值=i,加入节点到链表头
            newnode.val=data[j][1]  #声明新节点,值为终点值
            newnode.next=None
            ptr=newnode       #加入新节点
            print('[%d] ' %newnode.val,end='')  #打印相邻顶点
    print()

首先i = 1的时候
head[i]的val是1(链表头),下一个是None,把这个节点型的变量赋值给ptr,然后开始找下一个,发现[1,2]种第一个是1

newnode的值就被赋值为2,为什么next要赋值为None呢,如果找不到起点是2的,那么说明2就是最后一个(链表尾),就直接是None,如果找到了下一个,也可以再更改newnode的val

3 邻接复合链表法

4 索引表格法

2 图形遍历

1 深度优先算法 dfs

class list_node:
    def __init__(self):
        self.val=0
        self.next=None

head=[list_node()]*9 #声明一个节点类型的链表数组
        
run=[0]*9

def dfs(current): #深度优先函数
    run[current]=1
    print('[%d] ' %current, end='')
    ptr=head[current].next
    while ptr!=None:
        if run[ptr.val]==0:        #如果顶点尚未遍历,
            dfs(ptr.val)           #就进行dfs的递归调用
        ptr=ptr.next
        
#声明图的边线数组       
data=[[1,2],[2,1],[1,3],[3,1], \
      [2,4],[4,2],[2,5],[5,2], \
      [3,6],[6,3],[3,7],[7,3], \
      [4,8],[8,4],[5,8],[8,5], \
      [6,8],[8,6],[8,7],[7,8]]
for i in range(1,9):  #共有八个顶点
    run[i]=0          #把所有顶点设置成尚未遍历过
    head[i]=list_node()
    head[i].val=i     #设置各个链表头的初值
    head[i].next=None
    ptr=head[i]        #设置指针指向链表头
    for j in range(20): #二十条边线
        if data[j][0]==i: #如果起点和链表头相等,则把顶点加入链表
            newnode=list_node()
            newnode.val=data[j][1]
            newnode.next=None
            while True:
                ptr.next=newnode    #加入新节点
                ptr=ptr.next
                if ptr.next==None:
                    break
        

print('图的邻接表内容:')      #打印图的邻接表内容
for i in range(1,9):
    ptr=head[i]
    print('顶点 %d=> ' %i,end='')
    ptr =ptr.next
    while ptr!=None:
        print('[%d] ' %ptr.val,end='')
        ptr=ptr.next
    print()
print('深度优先遍历的顶点:')      #打印深度优先遍历的顶点
dfs(1) #顶点是1
print()

在这里插入图片描述
深度优先遍历的顶点:
[1] [2]
[0, 1, 1, 0, 0, 0, 0, 0, 0]
[4]
[0, 1, 1, 0, 1, 0, 0, 0, 0]
[8]
[0, 1, 1, 0, 1, 0, 0, 0, 1]
[5]
[0, 1, 1, 0, 1, 1, 0, 0, 1]

[0, 1, 1, 0, 1, 1, 0, 0, 1]

[0, 1, 1, 0, 1, 1, 0, 0, 1]
[6] [3]
[0, 1, 1, 1, 1, 1, 1, 0, 1]

[0, 1, 1, 1, 1, 1, 1, 0, 1]
[7]
[0, 1, 1, 1, 1, 1, 1, 1, 1]

[0, 1, 1, 1, 1, 1, 1, 1, 1]

[0, 1, 1, 1, 1, 1, 1, 1, 1]

[0, 1, 1, 1, 1, 1, 1, 1, 1]

[0, 1, 1, 1, 1, 1, 1, 1, 1]

[0, 1, 1, 1, 1, 1, 1, 1, 1]

[0, 1, 1, 1, 1, 1, 1, 1, 1]

[0, 1, 1, 1, 1, 1, 1, 1, 1]

[0, 1, 1, 1, 1, 1, 1, 1, 1]

[0, 1, 1, 1, 1, 1, 1, 1, 1]

[0, 1, 1, 1, 1, 1, 1, 1, 1]

[0, 1, 1, 1, 1, 1, 1, 1, 1]

可以看出由1先找到了2,3,只弹出了2,由2找到了1,4,5,但是1已经出来了,只压入4,5,弹出4
[0, 1, 1, 0, 1, 0, 0, 0, 0]可以看出来,弹出的1,2,4已经打上了标记1,说明已经弹出来了,由4找到了8,压进去,弹出8,标记变为[0, 1, 1, 0, 1, 0, 0, 0, 1]

由8找到了5,6,7,弹出5
由5找到的2,8已经弹出不压入,顺着弹出6
由6找到了3,弹出3
由3找到的7压入弹出7,然后后面一次弹出直至清空队列

2 广度优先算法 bfs

MAXSIZE=10  #定义队列的最大容量	

front=-1 #指向队列的前端
rear=-1  #指向队列的末尾

class Node:
    def __init__(self,x):
        self.x=x        #顶点数据
        self.next=None  #指向下一个顶点的指针
        
class GraphLink:
    def __init__(self):
        self.first=None
        self.last=None
        
    def my_print(self):
        current=self.first
        while current!=None:
            print('[%d]' %current.x,end='')
            current=current.next
        print()

    def insert(self,x):
        newNode=Node(x)
        if self.first==None:
            self.first=newNode
            self.last=newNode
        else:
            self.last.next=newNode
            self.last=newNode
 
#队列数据的存入
def enqueue(value):
    global MAXSIZE
    global rear
    global queue
    if rear>=MAXSIZE:
        return
    rear+=1
    queue[rear]=value
    

#队列数据的取出
def dequeue():
    global front
    global queue
    if front==rear:
        return -1
    front+=1
    return queue[front]

#广度优先查找法
def bfs(current):
    global front
    global rear
    global Head
    global run
    enqueue(current) #将第一个顶点存入队列
    run[current]=1   #将遍历过的顶点设置为1
    print('[%d]' %current, end='') #打印出该遍历过的顶点
    while front!=rear:             #判断当前的队伍是否为空
        current=dequeue()            #将顶点从队列中取出
        tempnode=Head[current].first #先记录当前顶点的位置
        while tempnode!=None:
            if run[tempnode.x]==0:
                enqueue(tempnode.x)
                run[tempnode.x]=1   #记录已遍历过
                print('[%d]' %tempnode.x,end='')
            tempnode=tempnode.next

#声明图的边线数组
Data=[[0]*2 for row in range(20)]

Data =[[1,2],[2,1],[1,3],[3,1],[2,4], \
       [4,2],[2,5],[5,2],[3,6],[6,3], \
       [3,7],[7,3],[4,5],[5,4],[6,7],[7,6],[5,8],[8,5],[6,8],[8,6]]

run=[0]*9 #用来记录各顶点是否遍历过
queue=[0]*MAXSIZE
Head=[GraphLink]*9
 			
print('图的邻接表内容:') #打印图的邻接表内容
for i in range(1,9):      #共有8个顶点
    run[i]=0              #把所有顶点设置成尚未遍历过
    print('顶点%d=>' %i,end='')
    Head[i]=GraphLink()
    for j in range(20):
        if Data[j][0]==i: #如果起点和链表头相等,则把顶点加入链表
            DataNum = Data[j][1]
            Head[i].insert(DataNum)
    Head[i].my_print()    #打印图的邻接标内容

print('广度优先遍历的顶点:') #打印广度优先遍历的顶点
bfs(1)
print()

在这里插入图片描述
[1]
[0, 1, 1, 0, 0, 0, 0, 0, 0]
[2]
[0, 1, 1, 1, 0, 0, 0, 0, 0]
[3]
[0, 1, 1, 1, 1, 0, 0, 0, 0]
[4]
[0, 1, 1, 1, 1, 1, 0, 0, 0]
[5]
[0, 1, 1, 1, 1, 1, 1, 0, 0]
[6]
[0, 1, 1, 1, 1, 1, 1, 1, 0]
[7]
[0, 1, 1, 1, 1, 1, 1, 1, 1]
[8]

这里从1开始,找到2,3,弹出2,标记变为[0, 1, 1, 0, 0, 0, 0, 0, 0]
从2开始找,找到4,5,接在后面加入队列,弹出3,标记变为 [0, 1, 1, 1, 0, 0, 0, 0, 0],此时队列由3,4,5
然后到了3,从3开始找找到了6,7,接在后面加入队列,队列变成4,5,6,7
弹出3后面的4,标记变为 [0, 1, 1, 1, 1, 0, 0, 0, 0]
从4找,找到了5,加在7后面,队列变成了5,6,7,5
然后弹出4后面的5,从5找找到了8,加入队列变成6,7,5,8
弹出6,找到7,8加到后面变成7,5,8,7,8
最后依次弹出7,8

DFS和BFS唯一的不同就是:DFS是依次在队列最前面加入未弹出过(即未到达过节点)的节点,然后从最前面依次弹出来,BFS是依次在队列最后面加入未弹出过(即未到达过节点)的节点,然后从前面一次弹出来

DFS是后进先出,后压进去的,反而先弹出
BFS是先进先出,后压进去的依次在后面排着,先进去的一个一个出,才轮的上后面的

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值