diff --git a/src/backend/optimizer/geqo/geqo_recombination.c b/src/backend/optimizer/geqo/geqo_recombination.c index 652fadc745..ef433e54e5 100644 --- a/src/backend/optimizer/geqo/geqo_recombination.c +++ b/src/backend/optimizer/geqo/geqo_recombination.c @@ -29,39 +29,33 @@ * * Randomly generates a legal "traveling salesman" tour * (i.e. where each point is visited only once.) - * Essentially, this routine fills an array with all possible - * points on the tour and randomly chooses the 'next' city from - * this array. When a city is chosen, the array is shortened - * and the procedure repeated. */ void init_tour(PlannerInfo *root, Gene *tour, int num_gene) { - Gene *tmp; - int remainder; - int next, - i; + int i, + j; - /* Fill a temp array with the IDs of all not-yet-visited cities */ - tmp = (Gene *) palloc(num_gene * sizeof(Gene)); + /* + * We must fill the tour[] array with a random permutation of the numbers + * 1 .. num_gene. We can do that in one pass using the "inside-out" + * variant of the Fisher-Yates shuffle algorithm. Notionally, we append + * each new value to the array and then swap it with a randomly-chosen + * array element (possibly including itself, else we fail to generate + * permutations with the last city last). The swap step can be optimized + * by combining it with the insertion. + */ + if (num_gene > 0) + tour[0] = (Gene) 1; - for (i = 0; i < num_gene; i++) - tmp[i] = (Gene) (i + 1); - - remainder = num_gene - 1; - - for (i = 0; i < num_gene; i++) + for (i = 1; i < num_gene; i++) { - /* choose value between 0 and remainder inclusive */ - next = geqo_randint(root, remainder, 0); - /* output that element of the tmp array */ - tour[i] = tmp[next]; - /* and delete it */ - tmp[next] = tmp[remainder]; - remainder--; + j = geqo_randint(root, i, 0); + /* i != j check avoids fetching uninitialized array element */ + if (i != j) + tour[i] = tour[j]; + tour[j] = (Gene) (i + 1); } - - pfree(tmp); } /* alloc_city_table