图是否有环的判定

dfs判断

首先明确三个概念,未访问的节点记为白节点,正在访问但没访问完(说白了,就是一条路没走到头还没退递归栈)的为灰节点,已经访问完的退出递归栈的为黑节点。

有了这个概念,思路就很简单了,如果访问过程中遇到了灰节点说明指向祖先了,则存在环,不明白的动手画一画,或者等过两天我的修改。

话不多说,见代码:

邻接表版本:

# 首先根据题意建,示例图(邻接表表示法)
graph = {
    'A': ['B'],
    'B': ['C'],
    'C': ['A'],  # 这里形成了一个环
    'D': ['E'],
    'E': []
}

dfs判断过程:

 def dfs(node):
        if state[node] == 1:
            return True
        if state[node] == 2:
            return False

        state[node] = 1 #即将进入递归栈染灰
        for neighbor in graph[node]:
            if dfs(neighbor):
                return True #部分有就都有

        state[node] = 2 #路走完了,退栈,染黑
        return False
    

全过程:
 

def has_cycle(graph):
    state = {node: 0 for node in graph} #white: 0, gray: 1, black: 2
    def dfs(node):
        if state[node] == 1:
            return True
        if state[node] == 2:
            return False

        state[node] = 1 #即将进入递归栈染灰
        for neighbor in graph[node]:
            if dfs(neighbor):
                return True #部分有就都有

        state[node] = 2 #路走完了,退栈,染黑
        return False

    for v in graph:
        if state[v] == 0:
            if dfs(v):
                return True

    return False

有向图按上述处理就好了,无向图,加个父节点不访问,以免误判即可:
 

def has_cycle(graph):
    state = {node: 0 for node in graph} #white: 0, gray: 1, black: 2
    def dfs(node, parent):
        if state[node] == 1:
            return True
        if state[node] == 2:
            return False

        state[node] = 1 #即将进入递归栈染灰
        for neighbor in graph[node]:
            if neighbor != parent: # 不访问父节点
                if dfs(neighbor, node):
                return True #部分有就都有

        state[node] = 2 #路走完了,退栈,染黑
        return False

    for v in graph:
        if state[v] == 0:
            if dfs(v, -1):
                return True

    return False

至于邻接矩阵的,可以选择转化为邻接表;当然不转也可以,详情见下面代码,由于大同小异给出了无向图的,有向图的就少个父节点而已:
 

graph = [
    [0, 1, 1, 0],  # A
    [1, 0, 0, 1],  # B
    [1, 0, 0, 1],  # C
    [0, 1, 1, 0]   # D
]
def has_cycle(graph):
    n = len(graph)
    state = [0]*n
    def dfs(node, parent):
        if state[node] == 1:
            return True
        if state[node] == 2:
            return False

        state[node] = 1 #即将进入递归栈染灰
        for neighbor in range(n):
            if neighbor != parent and graph[node][neighbor] == 1:
                if dfs(neighbor, node):
                    return True #部分有就都有

        state[node] = 2 #路走完了,退栈,染黑
        return False

    for v in graph:
        if state[v] == 0:
            if dfs(v, -1):
                return True

    return False

树的判断:

思路:连通分量为1(连通性),没有环的情况,就是树,所以在以上代码的情况上,添加一步连通分量的判断即可:

count = 0
for v in graph:
    if state[v] == 0:
        count += 1
        if dfs(v, -1):
            return False #有环,不是树

    return count == 1 # 无环,检查连通性

其他:

连通分量不为1,拓扑排序(有向图)都可以判断图里是否含环,日后闲暇再整理。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值