欧拉图的遍历算法(递归)是否能改成迭代实现

kit_147 2009-09-29 11:30:44
我现在要遍历一个欧拉图,找出一条欧拉回路,采用的算法是:


选择一个起始顶点然后进行递归,对每一步来说:
1,搜索该点是否有新的相邻顶点,有则转到2,没有则将该点加入欧拉回路然后返回;
2,如果该顶点有新的相邻顶点,则依次对这些新相邻顶点进行处理,直到没有新的相邻顶点;
3,处理的方法为:将该顶点到该新相邻顶点间的弧标记为已访问;对该相邻顶点进行递归,然后把该顶点加入回路的末尾。

写的代码如下:

private void findEluer(int curr)
{
//搜索一个新的相邻顶点
int oneNeighbor = getOneNeighbor(curr);
if (oneNeighbor == -1) //没有新的相邻顶点
{
//该点加入回路
pathNode.Add(curr);
}
else
{
do
{
//访问该边
arc[curr].visit = ture;
//对该邻居进行递归
findEluer(oneNeighbor);
//搜索该结点的下一个邻居,以便返回后依次处理邻居
oneNeighbor = getOneNeighbor(curr);
} while (oneNeighbor != -1);

//该结点所有邻居已处理完毕,加入回路
pathNode.Add(curr);
}
}


问题:上述算法我在小数据量(900结点,4000弧左右)测试下能得到正确结果;
但现在所遍历的欧拉图数据量太大,大约有9000个结点,20000条左右的弧,用上述算法会导致堆栈溢出。
请问有什么方法可以进行改进?如何将递归改成迭代?
麻烦大家说详细一点,谢谢。
...全文
464 16 打赏 收藏 转发到动态 举报
写回复
用AI写文章
16 条回复
切换为时间正序
请发表友善的回复…
发表回复
hisence335 2010-06-24
  • 打赏
  • 举报
回复
/// <summary>
/// 寻找完整的欧拉路径,结果存入lstPathNode,(切换链,QQ:199404125)
/// </summary>
/// <param name="iCurrNodeID">当前处理路口ID</param>
/// <param name="lstPathNode">完整路径的节点列表</param>
protected override void FindEluer(ref int iPrevNodeID, int iCurrNodeID)
{
List<int> lstFindElur = new List<int>();

lstFindElur.Add(iCurrNodeID);

while (lstFindElur.Count != 0)
{
int iOneNeighbor = GetOneNeighbor(iPrevNodeID, iCurrNodeID);
iPrevNodeID = iCurrNodeID;

if (iOneNeighbor == -1)
{
lstBasePathNode.Add(iCurrNodeID);
lstFindElur.RemoveAt(lstFindElur.Count-1);

if (lstFindElur.Count != 0)
{
iCurrNodeID = lstFindElur[lstFindElur.Count - 1];
}
}
else
{

//访问该边
foreach (int i in this.Nodes[iCurrNodeID].StartArcIDs)
{
if (this.Arcs[i].EndNodeID == iOneNeighbor)
{
this.Arcs[i].Visited = true;
this.Nodes[iCurrNodeID].StartArcCount--; //出度减1
break;
}
}

lstFindElur.Add(iOneNeighbor);
iCurrNodeID = iOneNeighbor;
}
}

}
kit_147 2009-10-18
  • 打赏
  • 举报
回复
kit_147 2009-10-15
  • 打赏
  • 举报
回复
[Quote=引用 13 楼 mmmcd 的回复:]
我以前实现过“见路就走”
                        |----------|
                      |          |
          A -------- B -------- C
          |          |
          |          |
          -----------|
先在每个点记录一个度数,从A开始见路就走,路过的点,度数减2
如果得到路径:A-B-A
遍历这条路径上所有点,找出一个度数不为0的点,发现B的度数为2
从B开始,见路就走,得到 B-C-B
A-B-A删掉B,插入B-C-B
=>
A-B-C-B-A

可以达到目的
比递归实现起来痛苦就是了。
[/Quote]

能不能说详细点?我就是想要非递归的实现方法
mmmcd 2009-10-14
  • 打赏
  • 举报
回复
我以前实现过“见路就走”
|----------|
| |
A -------- B -------- C
| |
| |
-----------|
先在每个点记录一个度数,从A开始见路就走,路过的点,度数减2
如果得到路径:A-B-A
遍历这条路径上所有点,找出一个度数不为0的点,发现B的度数为2
从B开始,见路就走,得到 B-C-B
A-B-A删掉B,插入B-C-B
=>
A-B-C-B-A

可以达到目的
比递归实现起来痛苦就是了。
kit_147 2009-10-13
  • 打赏
  • 举报
回复
[Quote=引用 11 楼 glacier3d 的回复:]
                      |----------|
                      |          |
          A -------- B -------- C
          |          |
          |          |
          -----------|

只是“见路就走”是不行的,如图:假设从A开始走,A---> B ---->A----->无路走了,而c还没走
[/Quote]

不是很明白你的图,请问你是指的是,结点A有一条双行线(横线)通向B,从其他结点有一条单行线通向A(竖线)吗?
这里有2个问题:
1,我这个图是个欧拉图,就是说每个结点的出度和入度是相等的,不存在上述情况;
2,我的目标是找欧拉回路,就是通过每条边一次。不是遍历结点。
glacier3d 2009-10-07
  • 打赏
  • 举报
回复
|----------|
| |
A -------- B -------- C
| |
| |
-----------|

只是“见路就走”是不行的,如图:假设从A开始走,A---> B ---->A----->无路走了,而c还没走
kit_147 2009-10-07
  • 打赏
  • 举报
回复
kit_147 2009-10-05
  • 打赏
  • 举报
回复
[Quote=引用 4 楼 iwantnon 的回复:]
引用 1 楼 iwantnon 的回复:
偶拉图通常得是多重图,那么,首先的问题是,你用什么样的数据结构来表示多重图呢?

重申我的观点:找欧拉回路的问题本身根本谈不上什么算法,因为只要“见未走过的路就走”就能完成任务。
所以问题只有一个:用什么数据结构来表示这个欧拉图(多重图),这个一解决,所有问题都不存在了。
[/Quote]

我采用的数据结构就是类似邻接表的结构。我写了2个类,Node类表示结点,Arc类表示边。Node类中有2个属性,一个是“出度”,一个是“关联边表”。每遍历完一条关联边,则出度递减。
我的确是采用你说的“见未走过的路就走”的方法进行遍历的。现在的问题是:
我写这个“见未走过的路就走”的算法采用的是递归方式实现的,我想把它改成用非递归的方式实现,解决递归太深堆栈会溢出的问题。
我自己比较菜,把递归改未非递归没有成功,所以发帖请大家赐教一下。呵呵。谢谢。
glacier3d 2009-10-01
  • 打赏
  • 举报
回复
对了,顶点的度递减后,邻接矩阵里的值也递减
glacier3d 2009-10-01
  • 打赏
  • 举报
回复
另外,4楼说的貌似有点问题,不是“见未走过的路就走”就可以,那样可能有的路走不到。

可以不用递归,采用那种连接各个圈的思想来求解,伪码如下:

bigCircle = null
for i in (1,n)
{
smallCircle = null
if(degree(vertex(i)) >0) add vertex(i) to smallCircle;
var currentVertex = vertex(i);
var nextVertex;
while ( degree(vertex(i)) > 0 )
{
nextVertex = the vertex connected with currentVertex;
add nextVertex to smallCircle;
--degree(currentVertex);
--degree(nextVertex);
currentVertex = nextVertex;
}

add smallCircle to bigCircle;
}
glacier3d 2009-10-01
  • 打赏
  • 举报
回复
[Quote=引用 4 楼 iwantnon 的回复:]
引用 1 楼 iwantnon 的回复:
偶拉图通常得是多重图,那么,首先的问题是,你用什么样的数据结构来表示多重图呢?

重申我的观点:找欧拉回路的问题本身根本谈不上什么算法,因为只要“见未走过的路就走”就能完成任务。
所以问题只有一个:用什么数据结构来表示这个欧拉图(多重图),这个一解决,所有问题都不存在了。
[/Quote]

多重图也可以用邻接表或邻接矩阵表示啊,比如:邻接矩阵里的权是是就表示几重边,走过一次给递减1就行了
iwantnon 2009-09-30
  • 打赏
  • 举报
回复
偶拉图通常得是多重图,那么,首先的问题是,你用什么样的数据结构来表示多重图呢?
无天 2009-09-30
  • 打赏
  • 举报
回复
学习了
iwantnon 2009-09-30
  • 打赏
  • 举报
回复
[Quote=引用 1 楼 iwantnon 的回复:]
偶拉图通常得是多重图,那么,首先的问题是,你用什么样的数据结构来表示多重图呢?
[/Quote]
重申我的观点:找欧拉回路的问题本身根本谈不上什么算法,因为只要“见未走过的路就走”就能完成任务。
所以问题只有一个:用什么数据结构来表示这个欧拉图(多重图),这个一解决,所有问题都不存在了。
poson 2009-09-30
  • 打赏
  • 举报
回复
把已经访问过的路径放到文件中,再计算。
dotmonkey 2009-09-30
  • 打赏
  • 举报
回复
用goto实现“递归”。。。
可以参考vs中qsort的实现。

33,010

社区成员

发帖
与我相关
我的任务
社区描述
数据结构与算法相关内容讨论专区
社区管理员
  • 数据结构与算法社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧