简体   繁体   English

基本集路径算法中的错误/错误,我无法弄清楚

[英]bug/error in basis set path algorithm i can't figure out

The following looks through a 2d array to find basis set paths. 以下内容通过2D数组进行查找,以找到基本集路径。 It is supposed to print out the individual paths but not repeat any and end when all paths are found. 应该打印出单个路径,但不重复任何路径,并在找到所有路径时结束。 It however doesn't stop at the last path and has a bug in it somewhere in which the following happens: It goes halfway through the path and then goes to zero and ends the path for some reason. 但是,它不会在最后一条路径处停止,而在其中发生错误的地方发生以下错误:它经过路径的一半,然后归零,并出于某种原因结束了路径。

For example the table is filled with the following: all 0s, except for 例如,表中填充以下内容:全0,除了

[1][2], [1][3], [2][4], [2][5], [3][5], [4][6], [5][6], [6][0] [1] [2],[1] [3],[2] [4],[2] [5],[3] [5],[4] [6],[5] [6],[ 6] [0]

which all have a 1 in them. 里面都有1。 The desired paths are P1: 1 2 4 6 0 所需路径为P1:1 2 4 6 0

P2: 1 3 5 6 0 P2:1 3 5 6 0

P3: 1 2 5 6 0. P3:1 2 5 6 0。

The output I get when i run the program is 12460 运行程序时得到的输出是12460

13560 13560

1250 1250

124 124

Any and all help on this is much appreciated, this is just the function that scans through the array looking for paths, I can add the entire program if that would be helpful. 非常感谢您提供的所有帮助,这只是扫描数组以查找路径的功能,如果有帮助,我可以添加整个程序。 Thanks.. 谢谢..

void find_path(int map[][MAX], int x){
 int path =0;
 int m=1;
 int blah=0;
 bool path_found = false;

 do
 {
  for(int n=0;n<(x+1);n++){
   if(map[m][n]==-1){
    blah=(n+1);
    if(blah<(x+1)){
     for(blah;blah<(x+1);blah++){
      if(map[m][blah]==1){
       map[m][blah]=-1;
       path=m;
       path_found = true;
       cout<<path;
       m=blah;
       n=0;
      }
     }
    }
    else{  
    path=m;
    path_found=false;
    cout<<path;
    m=n;
    if(m==0){
     path=0;
     cout<<path<<endl;
     m=1;
     path_found=false;
     }
    } 
   }
   else if(map[m][n]==1){
    map[m][n]=-1;
    path=m;
    path_found = true;
    cout<<path;
    m=n;
    if(m==0){
     path=0;
     cout<<path<<endl;
     m=1;
     path_found=false;
    }
   }

  }
 } 
 while(m<(x+1) && path_found);
}

You have made an all too common mistake. 您犯了一个太常见的错误。 Far too many folks believe the primary goal in writing software is to tell the computer what to do. 太多的人认为编写软件的主要目的是告诉计算机该怎么做。 That is incorrect. 那是不对的。 The primary goal is to communicate CLEARLY what one is doing to other humans. 主要目标是与他人清楚地交流一下自己在做什么。 The secondary goal is telling the computer what to do. 第二个目标是告诉计算机该怎么做。

I suggest you don't use hardcoded numbers (-1 in map[][]=-1). 我建议您不要使用硬编码的数字(map [] [] =-1中为-1)。 Enums are made for this. 为此进行了枚举。 Variable names could be more descriptive. 变量名称可能更具描述性。 ("blah"?) You can leave for clauses empty, eg for(; blah<(x+1); blah++). (“ blah”?)您可以将for子句留空,例如for(; blah <(x + 1); blah ++)。 (Even for(;;) is valid.) Usually arrays go from 0..LIMIT-1 so you can say for(; blah<x; ++blah). (即使for(;;)也有效。)通常数组从0..LIMIT-1开始,因此您可以说for(; blah <x; ++ blah)。 Often ++foo is preferred to foo++, though it won't make much of a difference with ints. 通常,foo比foo ++更受foo的青睐,尽管它与ints并没有多大区别。 Watch out for underscores in names. 注意名称中的下划线。 It's easy to confuse path-found and path_found. 混淆path-found和path_found很容易。 ADD COMMENTS!!! 添加评论!!! Explain what you are doing. 解释你在做什么。 Add spaces while you are at it. 随时随地添加空格。 Compact code is nobody's friend. 紧凑的代码是没人的朋友。 At the very least, document that you are altering the values in MAP. 至少要记录您正在更改MAP中的值。

All that said... Where to begin... 所有这些...从哪里开始...

Well, after changing nodes, I'd have started from the first path option, not at the current node plus 1. (Eg, Jump from 1-to-2, from 2-to-4, and then you start looking at map[4][5] instead of map[4][0] or map[4][1]. 好了,更改节点后,我将从第一个路径选项开始,而不是从当前节点加1开始。(例如,从1跳到2,从2跳到4,然后开始查看地图[4] [5]代替了map [4] [0]或map [4] [1]。

I would not have special cased 0 as an exit criteria. 我不会将特殊情况0作为退出条件。

Your line "for(blah;blah<(x+1);blah++){" does not exit (break) when a map[m][blah]==1 match is found, but marks it as -1 and continues looking for other matches. 找到map [m] [blah] == 1匹配项时,您的“ for(blah; blah <(x + 1); blah ++){”行不会退出(中断),但将其标记为-1并继续查找其他比赛。 That should create an interesting effect with the prior "for(int n=0;n<(x+1);n++){" line. 前面的“ for(int n = 0; n <(x + 1); n ++){”行应该会产生有趣的效果。

Once you hit M=6, N=1 you can never hit your special-cased-0 exit criteria and print. 一旦您达到M = 6,N = 1,您将永远无法达到特殊情况的0退出标准并打印。 ( You do realize you have n=0 followed by n++??? ) 您确实意识到自己有n = 0,然后是n ++ ???

Once you have a map full of -1's, you can never proceed further. 一旦您的地图充满了-1,就永远无法继续进行。 This is a real problem when some of your paths share the same links. 当您的某些路径共享相同的链接时,这是一个实际的问题。 Eg 1-2-4-6-0 and 1-3-5-6-0 share 6-0. 例如1-2-4-6-0和1-3-5-6-0共享6-0。

You do not detect a map full of -1's. 您不会检测到完整的-1的映射。 You have an endless loop. 你有无尽的循环。 (If you are going to set path_found to false, do it right after "do{", before "for(int n=0;n<(x+1);n++){". Not in some easily missed exit spot deep in nested if statements. (如果要将path_found设置为false,则应在“ do {”之后,“ for(int n = 0; n <(x + 1); n ++){”之前进行此操作。)在嵌套的if语句中。

I do not see the output 12460,13560,1250,124 when I run your program. 运行程序时看不到输出12460、13560、1250、124 I see 12460,135 and then it hangs. 我看到12460,135 ,然后挂起。 (And that only after I modified your software to flush output after every write.) (而且只有在我修改了软件以在每次写入后刷新输出之后,才可以这样做。)

You show no scaffolding code. 您没有显示脚手架代码。 Something like: 就像是:

void printMap(int theMap[][MAX] )
{
  for( int i=0; i<MAX; ++i )
  {
    cout << "[" << i << "] ";
    for ( int j=0;  j<MAX;  ++j )
      cout << "  " << theMap [i] [j];
    cout << endl;
  }  /* for( int i=0; i<MAX; ++i )  */
  cout << endl;
}

Coupled with a debugger (in gdb use "call printMap(map)") would be helpful to you. 加上调试器(在gdb中使用“ call printMap(map)”)将对您有所帮助。 (It certainly was to me.) (肯定是我。)

Your code replicates itself. 您的代码会自我复制。 That's usually a sign of a mistake. 这通常是错误的征兆。 Eg the "if(m==0){ path=0; cout<<path<<endl; m=1; path_found=false; }" bits. 例如,“ if(m == 0){path = 0; cout << path << endl; m = 1; path_found = false;}”位。 Or the "if(map[m][FOO]==1){ map[m][FOO]=-1; path=m; path_found = true; cout<<path; m=FOO;" 或“ if(map [m] [FOO] == 1){map [m] [FOO] =-1; path = m; path_found = true; cout << path; m = FOO;” part, where FOO is "blah" or "n". 部分,其中FOO是“ blah”或“ n”。


All this said, I've had to work with worse code (in professional situations no less). 综上所述,我不得不处理更糟糕的代码(在专业情况下同样如此)。 (Not often, but it does happen.) Keep at it, and you'll get better. (不经常发生,但确实会发生。)坚持下去,您会变得更好。 We all started in the same bad place. 我们都从同一个坏地方开始。 Practice, keep asking questions, and you will improve. 练习,不断提出问题,您会有所进步。



Responding to comment here... 在这里回应评论...

The only reason I had the special 0 case in there is because it was just hanging when it reached 0 because that row is empty and it stayed in an endless loop. 我有特殊的0情况的唯一原因是因为它到达0时才挂起,因为该行为空并且一直处于无休止的循环中。

You need a better test for your exit condition. 您需要针对退出条件进行更好的测试。

When I compile and run it i get the output I described, not what you get. 当我编译并运行它时,我得到的是我描述的输出,而不是你得到的。

I used g++ version 3.4.4 with: 我将g ++版本3.4.4用于:

#define MAX 7
                      /* 0  1  2  3  4  5  6 */
int  map[MAX][MAX] = { { 0, 0, 0, 0, 0, 0, 0 }, /*0*/
                       { 0, 0, 1, 1, 0, 0, 0 }, /*1*/
                       { 0, 0, 0, 0, 1, 1, 0 }, /*2*/
                       { 0, 0, 0, 0, 0, 1, 0 }, /*3*/
                       { 0, 0, 0, 0, 0, 0, 1 }, /*4*/
                       { 0, 0, 0, 0, 0, 0, 1 }, /*5*/
                       { 1, 0, 0, 0, 0, 0, 0 }  /*6*/
                     };

find_path( map, 6 );

Perhaps your input conditions are different? 也许您的输入条件不同?

I don't understand why it would reach m=6 n=1, other than [6][0], the rest of the row is 0s. 我不明白为什么它会达到m = 6 n = 1,除了[6] [0],其余的行都是0s。

The code below is yours (with minor cosmetic changes). 下面的代码是您的(外观有微小变化)。

N=0 occurs at Line=25. N = 0出现在Line = 25。 When the for loop at Line=16 completes, we resume the for loop at Line=9. 当Line = 16处的for循环完成时,我们在Line = 9处恢复for循环。 The first step there is the final iteration (n++) component. 第一步是最终迭代(n ++)组件。 Thus the next for loop iteration at Line=10 has m=blah=6 and n=1. 因此,在Line = 10处的下一个for循环迭代具有m = blah = 6和n = 1。 At this stage, none of your conditional tests (==-1, ==1) can ever be true. 在此阶段,没有任何条件测试(==-1,== 1)可以是真实的。

You really ought to try stepping through your code in a debugger. 您确实应该尝试在调试器中逐步执行代码。 See what the code is actually doing vs what you expected it to do. 查看代码的实际作用与预期的作用。

/* 0*/   void find_path( int map[][MAX], int x )
/* 1*/   {
/* 2*/     int  path = 0;
/* 3*/     int  m    = 1;
/* 4*/     int  blah = 0;
/* 5*/     bool path_found = false;
/* 6*/   
/* 7*/     do
/* 8*/     {
/* 9*/       for ( int n=0;  n < (x+1);  n++ )
/*10*/       {
/*11*/         if ( map [m] [n] == -1 )
/*12*/         {
/*13*/           blah = (n+1);
/*14*/           if ( blah < (x+1) )
/*15*/           {
/*16*/             for ( ;  blah < (x+1);  blah++ )
/*17*/             {
/*18*/               if ( map [m] [blah] == 1 )
/*19*/               {
/*20*/                 map [m] [blah] = -1;
/*21*/                 path = m;
/*22*/                 path_found = true;
/*23*/                 cout << path;
/*24*/                 m = blah;
/*25*/                 n = 0;
/*26*/               } /* if ( map [m] [blah] == 1 ) */
/*27*/             } /* for ( ;  blah < (x+1);  blah++ ) */
/*28*/           } /* if ( blah < (x+1) ) */
/*29*/           else
/*30*/           {
/*31*/             path = m;
/*32*/             path_found = false;
/*33*/             cout << path;
/*34*/             m = n;
/*35*/             if ( m == 0 )
/*36*/             {
/*37*/               path = 0;
/*38*/               cout << path << endl;
/*39*/               m = 1;
/*40*/               path_found = false;
/*41*/             } /* if ( m == 0 ) */
/*42*/           } /* if ( blah < (x+1) ) ... ELSE ... */
/*43*/         } /* if ( map [m] [n] == -1 ) */
/*44*/         else if ( map [m] [n] == 1 )
/*45*/         {
/*46*/           map [m] [n] = -1;
/*47*/           path = m;
/*48*/           path_found = true;
/*49*/           cout << path;
/*50*/           m = n;
/*51*/           if ( m == 0 )
/*52*/           {
/*53*/             path = 0;
/*54*/             cout << path << endl;
/*55*/             m = 1;
/*56*/             path_found = false;
/*57*/           } /* if ( m == 0 ) */
/*58*/         } /* if(map[m][n]==-1) ... ELSE IF (map[m][n]==1) ... */
/*59*/         
/*60*/       } /* for ( int n=0;  n < (x+1);  n++ ) */
/*61*/       
/*62*/     } /* do { ... } */ while(m<(x+1) && path_found);
/*63*/     
/*64*/   } /* void find_path( int map[][MAX], int x ) */

When I compile the function with the code you posted the I get 12460 as output and then it hangs in an endless loop, unless I take out the if ( blah < (x+1) and corresponding else, then I get the output I first described. 当我用您发布的代码编译该函数时,我得到12460作为输出,然后挂在一个无限循环中,除非我取出if(blah <(x + 1)和相应的else,然后我首先得到输出描述。

I have tried to work on it and came up with the following which gives me 124601356 as output and then ends. 我尝试进行处理,并提出了以下解决方案,该解决方案为我提供了124601356作为输出,然后结束。

void find_path(int map[][MAX], int x){
    int path =0;
    int m=1;
    int rest_of_row=0;
    bool path_found;
    do
    {
        path_found = false;
        for(int n=0;n<(x+1);n++){
            //check to see if the node is already used on a path
            if(map[m][n]==-1){
                rest_of_row=(n+1);
                path=m;

                //check to see there are any unused nodes for the path from found node +1 to end of row
                do{
                    if(map[m][rest_of_row]==1){
                        map[m][rest_of_row]=-1;
                        path_found = true;
                    }
                    else{
                        ++rest_of_row;
                    }
                }
                while(!path_found);

                m=n;


                if(path_found){
                    m=(rest_of_row);
                }

                cout<<path;
            }
            //else check to see if the node hasn't been used in the path
            else if(map[m][n]==1){
                map[m][n]=-1;
                path=m;
                path_found = true;
                cout<<path;
                m=n;
            }
            //if the node is at 0 path is complete, go back to 1 to check for new path
            if(m==0){
                path=m;
                m=1;
                path_found=false;
                cout<<path;
            }
        }
    }
    while(m<(x+1) && path_found);

}

Here's working code (using sufficiently advanced C++ that you can't get away with handing it in as your own work, also thanks to mrree, from whose answer I "lifted" the initializer for map). 这是工作代码(使用足够高级的C ++,您无法将其作为自己的工作来交付,这也要归功于mrree,我从他的回答中“提起”了地图的初始化程序)。 I suggest you think about the problem a little more deeply, starting with why my correct solution uses recursion and yours has neither recursion nor a stack. 我建议您从为什么我的正确解决方案使用递归而您的既没有递归又没有堆栈的角度更深入地思考问题。 I think it's actually possible to avoid the stack because the path array has all the state needed for backtracking, but you definitely do need some form of backtracking. 我认为实际上可以避免堆栈,因为path数组具有回溯所需的所有状态,但是您确实确实需要某种形式的回溯。

// enumpaths.cpp : Prints all longest paths given a digraph connectivity matrix
//

const size_t MAX = 7;

typedef void (*path_completed_cb)( const size_t (&path)[MAX], size_t const currentLength );

void follow_path( size_t (&path)[MAX], size_t const currentLength, const bool (&map)[MAX][MAX], path_completed_cb const callback )
{
 size_t currentEnd = path[currentLength-1];

 /* check for loops, if a loop exists then every finite path is
    a subpath of a longer (looped more often) path */
 for( size_t i = 0; i < currentLength; i++ ) {
  if (map[currentEnd][path[i]]) return; /* found a loop */
 }

 bool extended = false;
 /* look for continuances */
 for( size_t next = 0; next < MAX; next++ ) {
  if (map[currentEnd][next]) {
   extended = true;
   path[currentLength] = next;
   follow_path(path, currentLength+1, map, callback);
  }

 }
 if (!extended) {
  /* there were no outgoing arcs, this is a longest path */
  (*callback)(path, currentLength);
 }
}

void enum_paths( const bool (&map)[MAX][MAX], path_completed_cb const callback )
{
 for ( size_t start = 0; start < MAX; start++ ) {
  bool isSource = true;
  /* if any incoming arcs to node "start", then any paths
     starting at start are subpaths of longer paths */
  for (size_t pred = 0; pred < MAX; pred++ )
   if (map[pred][start]) isSource = false;

  if (isSource) {
   size_t path[MAX] = { start };
   follow_path(path, 1, map, callback);
  }
 }
}

#include <iostream>
#include <iomanip>

void print_path( const size_t (&path)[MAX], size_t const currentLength )
{
 using namespace std;
 cout << path[0];
 for( size_t i = 1; i < currentLength; i++ ) {
  cout << '-' << path[i];
 }
 cout << endl;
}

int main()
{                   
 const bool map[MAX][MAX] =
  /* 0  1  2  3  4  5  6 */
 { { 0, 0, 0, 0, 0, 0, 0 }, /*0*/
   { 0, 0, 1, 1, 0, 0, 0 }, /*1*/
   { 0, 0, 0, 0, 1, 1, 0 }, /*2*/
   { 0, 0, 0, 0, 0, 1, 0 }, /*3*/
   { 0, 0, 0, 0, 0, 0, 1 }, /*4*/
   { 0, 0, 0, 0, 0, 0, 1 }, /*5*/
   { 1, 0, 0, 0, 0, 0, 0 }  /*6*/
 };

 enum_paths(map, &print_path);

 return 0;
}

EDIT: Gave a try at doing it without recursion, and while simply removing the recursion would be just a mechanical transformation, doing it without introducing gotos is not easy. 编辑:尝试不进行递归,而简单地删除递归只是一种机械转换,而没有引入gotos并不容易。 Nor is merging the "start of path" case with the "middle of path" logic. 也没有将“路径的开始”情况与“路径的中间”逻辑合并。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM