无向图的欧拉回路线性时间算法

本文介绍了一种寻找无向图欧拉回路的线性时间算法,并提供了详细的C++实现代码。该算法利用邻接表存储图结构,通过不断移除边并追踪路径来构建欧拉回路。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >


// 无向图的欧拉回路线性时间算法
// by rappizit@yahoo.com.cn
// 2007-11-02

#include 
<vector>
#include 
<list>
#include 
<stack>
#include 
<algorithm>
#include 
<iostream>
using namespace std;

#define pause system("pause")
typedef vector 
<int> vi;
typedef list 
<int> li;
typedef vector 
<li> vli;

vi EulerCircle (vli G)
{
    
int n = G.size ();
    
int edge = 0;
    
for (int i = 0; i < n; i ++)
        {
        
int degree = G [i].size ();
        
if (degree % 2 || !degree)
            {
            
return vi (0);
            }
        edge 
+= degree;
        }
    vi path (edge 
/ 2 + 1);
    stack 
<int> s;
    
int p = 0, i = 0;
    
do    {
        
if (G [i].empty ())
            {
            
do    {
                s.pop ();
                path [p 
++= i;
                } 
while (!s.empty () && (i = s.top (), G [i].empty ()));
            }
        
else    {
            
int t = *(G [i].begin ());
            G [i].erase (G [i].begin ());
            G [t].erase (find (G [t].begin (), G [t].end (), i));
            
// 使用带有十字链接的双向邻接表可以常数时间地删除边 e(t, i)?!
            s.push (t);
            i 
= t;
            }
        } 
while (!s.empty ());
    
return path;
}


void main ()
{
    
int n, m;
    cin 
>> n >> m;
    vli G (n);
    
while (m --)
        {
        
int u, v;
        cin 
>> u >> v;
        G [u].push_back (v);    
// 这里为了迎合书上的例子,每条无向边分两次输入
        }
    vi path 
= EulerCircle (G);
    
if (path.size ())
        {
        
for (int i = 0; i < path.size (); i ++)
            {
            cout 
<< path [i] << " ";
            }
        cout 
<< endl;
        }
}

无向图的欧拉回路
采用邻接表存储,vector <list <int>> 类型。
1.如果某点的度数为奇数或零,则没有欧拉回路,返回空的 vector。
2.否则,从标号为 i = 0 的点开始。
3.如果 i 没有邻接点,那么堆栈中所有没有邻接点的点弹出到 vector path 中,如果堆栈非空则 i 赋值为栈顶元素。
  否则取 i 的第一个邻接点 t ,删除它们的边(要在 G 中的两处都删除)。将 t 压栈。i 赋值为 t 。
4.如果堆栈为空,返回 path,否则转 3。
算法时间复杂度为 O (E)。

测试数据:
7 20
0 1
0 2
0 5
0 6
1 0
1 2
2 0
2 3
2 4
2 1
3 4
3 2
4 6
4 5
4 3
4 2
5 4
5 0
6 4
6 0


测试结果:
0 6 4 2 3 4 5 0 2 1 0

过程图示:
First, the program adds the edge 0-1 to the tour and removes it from the adjacency lists (in two places) (top left, lists at left). Second, it adds 1-2 to the tour in the same way (left, second from top). Next, it winds up back at 0 but continues to do another cycle 0-5-4-6-0, winding up back at 0 with no more edges incident upon 0 (right, second from top). Then it pops the isolated vertices 0 and 6 from the stack until 4 is at the top and starts a tour from 4 (right, third from from top), which takes it to 3, 2, and back to 4, where upon it pops all the now-isolated vertices 4, 2, 3, and so forth. The sequence of vertices popped from the stack defines the Euler tour 0-6-4-2-3-4-5-0-2-1-0 of the whole graph.

First, the program adds the edge 0-1 to the tour and removes it from the adjacency lists (in two places) (top left, lists at left). Second, it adds 1-2 to the tour in the same way (left, second from top). Next, it winds up back at 0 but continues to do another cycle 0-5-4-6-0, winding up back at 0 with no more edges incident upon 0 (right, second from top). Then it pops the isolated vertices 0 and 6 from the stack until 4 is at the top and starts a tour from 4 (right, third from from top), which takes it to 3, 2, and back to 4, where upon it pops all the now-isolated vertices 4, 2, 3, and so forth. The sequence of vertices popped from the stack defines the Euler tour 0-6-4-2-3-4-5-0-2-1-0 of the whole graph.

参考来源:
Algorithms In Java, Part 5 Graph Algorithms , Chapter 17.7 / Java 算法(第 3 版,第 2 卷)——图算法,章节 17.7

PS:但是我是用 C++ 实现的^_^
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值