[英]C: Recursive Function Call Return Values (Tideman CS50)
我有一系列“节点”,需要创建一个函数来确定在节点之间添加一个新的“箭头”是否会创建一个循环(这是 CS50 中的 Tideman 问题)。 为了实现这一点,我写了一个单独的函数来使用递归; 然而,我的递归函数没有产生任何错误,但没有像我希望的那样工作。 下面是问题的视觉效果和我的理由。
我的计划是使用“if”条件来检查是否会创建循环,如果是,则使用“continue”来跳过 for 循环的迭代(理论上不添加比喻箭头)。 但是,我发现我的递归函数从未找到循环,这意味着它正在添加所有箭头。
以上图为例,我正在检查是否可以将紫色箭头从 B 添加到 C(索引 1 到 2)。 我使用递归来检查 C 指向的每个节点,如果当前节点的值等于所讨论的原始箭头的源(在本例中为 1),则以非零返回值结束。
从这个例子中,我预计当“当前”节点穿过蓝色链并再次到达节点 B 时,“循环”计数器将变为非零,并且整个递归函数将返回一个非零值。 然而,情况似乎并非如此。
我想我的功能不是很有效(预计会有一些建设性的批评),只是想了解递归应该如何工作。
这是我调用递归函数的函数:
// Lock pairs into the candidate graph in order, without creating cycles
void lock_pairs(void)
{
// Initialize variables
int cycle_start;
int current;
int cycle;
// Loop through pairs to determine acceptable locks
for (int i = 0; i < pair_count; i++)
{
// Set new cycle start and current node
cycle_start = pairs[i].winner;
current = pairs[i].loser;
// Reset Boolean
cycle = 0;
// If a cycle would be created, skip edge
if (cycle_created(current, cycle_start, cycle) > 0)
{
continue;
}
else
{
// Add edge by locking pairs
locked[pairs[i].winner][pairs[i].loser] = true;
}
}
return;
这是我的递归函数:
// Recursively check candidate node to see if cycle would be created
int cycle_created(int current, int cycle_start, int cycle)
{
// Reached start of cycle, exit function and don't add edge
if (current == cycle_start)
{
cycle++;
return cycle;
}
else
{
// Loop through all pairs
for (int j = 0; j < pair_count; j++)
{
// New candidate branch to investigate
if (current == pairs[j].winner)
{
// Set new branch to check
current = pairs[j].loser;
// Call function to check new branch
return cycle_created(current, cycle_start, cycle);
}
}
// No edge found where current node is the winner, can lock edge
return cycle;
}
}
这是我认为递归顺序发生的方式:
循环创建(2,1,0):
j = 0
当前==对[0].winner
当前 = pairs[0].loser = 5
返回 cycle_created(5,1,0)
循环创建(5,1,0):
j = 0
...
j = 5
当前 == 对 [5].winner
当前 = pairs[5].loser = 6
返回 cycle_created(6,1,0)
循环创建(6,1,0):
j = 0
...
j = 6
当前 == 对 [6].winner
当前 = pairs[6].loser = 4
返回 cycle_created(4,1,0)
循环创建(4,1,0):
j = 0
...
j = 4
当前==对[4].winner
当前 = 1
返回 cycle_created(1,1,0)
循环创建(1,1,0):
1 == 1
循环 = 1
返回 1
循环创建(4,1,1):
返回 (1)
循环创建(6,1,1):
返回 (1)
循环创建(5,1,1):
返回 (1)
循环创建(2,1,1):
返回 (1)
到目前为止,这是我的相关代码:
#include <cs50.h>
#include <stdio.h>
#include <string.h>
#include <stdbool.h>
// Max number of candidates
#define MAX 9
// preferences[i][j] is number of voters who prefer i over j
int preferences[MAX][MAX];
// locked[i][j] means i is locked in over j
bool locked[MAX][MAX];
// Each pair has a winner, loser
typedef struct
{
int winner;
int loser;
} pair;
// Array of candidates
string candidates[MAX];
pair pairs[MAX * (MAX - 1) / 2];
int pair_count;
int candidate_count;
// Function prototypes
bool vote(int rank, string name, int ranks[]);
void record_preferences(int ranks[]);
void add_pairs(void);
void sort_pairs(void);
void lock_pairs(void);
int cycle_created(int current, int cycle_start, int cycle);
int main(int argc, string argv[])
{
// Check for invalid usage
if (argc < 2)
{
printf("Usage: tideman [candidate ...]\n");
return 1;
}
// Populate array of candidates
candidate_count = argc - 1;
if (candidate_count > MAX)
{
printf("Maximum number of candidates is %i\n", MAX);
return 2;
}
for (int i = 0; i < candidate_count; i++)
{
candidates[i] = argv[i + 1];
}
// Clear graph of locked in pairs
for (int i = 0; i < candidate_count; i++)
{
for (int j = 0; j < candidate_count; j++)
{
locked[i][j] = false;
}
}
pair_count = 0;
int voter_count = get_int("Number of voters: ");
// Query for votes
for (int i = 0; i < voter_count; i++)
{
// ranks[i] is voter's ith preference
int ranks[candidate_count];
// Query for each rank
for (int j = 0; j < candidate_count; j++)
{
string name = get_string("Rank %i: ", j + 1);
if (!vote(j, name, ranks))
{
printf("Invalid vote.\n");
return 3;
}
}
record_preferences(ranks);
printf("\n");
}
add_pairs();
sort_pairs();
lock_pairs();
print_winner();
return 0;
}
// Update ranks given a new vote
bool vote(int rank, string name, int ranks[])
{
// Loop through each candidate
for (int i = 0; i < candidate_count; i++)
{
// Check if vote matches any existing candidates
if (strcmp(candidates[i], name) == 0)
{
// Update ranks array to indicate rank of input candidate
ranks[rank] = i;
return true;
}
}
// No candidate found
return false;
}
// Update preferences given one voter's ranks
void record_preferences(int ranks[])
{
// Loop through each candidate except final candidate (no preferences over others)
for (int i = 0; i < candidate_count - 1; i++)
{
// Loop through candidates following the row candidate
for (int j = i + 1; j < candidate_count; j++)
{
// Increment preferences array, since candidate i is preferred over candidate j
preferences[ranks[i]][ranks[j]]++;
}
}
return;
}
// Record pairs of candidates where one is preferred over the other
void add_pairs(void)
{
// Loop through row candidates (i)
for (int i = 0; i < candidate_count; i++)
{
// Loop through column candidates (j)
for (int j = 0; j < candidate_count; j++)
{
// Check if more voters prefer candidate i over candidate j
if (preferences[i][j] > preferences[j][i])
{
// Update winner and loser in pairs array with index as current pair count
pairs[pair_count].winner = i;
pairs[pair_count].loser = j;
// Increment pair count total
pair_count++;
}
}
}
return;
}
// Sort pairs in decreasing order by strength of victory
void sort_pairs(void)
{
// Initialize temporary variable pair
pair tmp;
// Loop through each pair, except last pair
for (int i = 0; i < pair_count - 1; i++)
{
// Loop through pair j following pair i
for (int j = i + 1; j < pair_count; j++)
{
// Check if second pair vote count is greater than first pair vote count
if (preferences[pairs[j].winner][pairs[j].loser] > preferences[pairs[i].winner][pairs[i].loser])
{
// Swap pairs
tmp = pairs[i];
pairs[i] = pairs[j];
pairs[j] = tmp;
}
}
}
return;
}
// Lock pairs into the candidate graph in order, without creating cycles
void lock_pairs(void)
{
// Initialize variables
int cycle_start;
int current;
int cycle;
// Loop through pairs to determine acceptable locks
for (int i = 0; i < pair_count; i++)
{
// Set new cycle start and current node
cycle_start = pairs[i].winner;
current = pairs[i].loser;
// Reset Boolean
cycle = 0;
// If a cycle would be created, skip edge
if (cycle_created(current, cycle_start, cycle) > 0)
{
continue;
}
else
{
// Add edge by locking pairs
locked[pairs[i].winner][pairs[i].loser] = true;
}
}
return;
}
// Recursively check candidate node to see if cycle would be created
int cycle_created(int current, int cycle_start, int cycle)
{
// Reached start of cycle, exit function and don't add edge
if (current == cycle_start)
{
cycle = 1;
return cycle;
}
else
{
// Loop through all pairs
for (int j = 0; j < pair_count; j++)
{
// New candidate branch to investigate
if (current == pairs[j].winner)
{
// Set new branch to check
current = pairs[j].loser;
// Call function to check new branch
return cycle_created(current, cycle_start, cycle);
}
}
// No edge found where current node is the winner, can lock edge
return cycle;
}
}
我认为您的方法是错误的,原因如下:
您不能寻找完整的循环,而要寻找链条。 如果一对失败者赢得锁定对与锁定对赢家,则存在链。 例如,这里存在一条链:
a) 你想锁定 pair 4 但是......
b) pairs[4].loser
返回0
,意味着失败者是 id 0
c) id 0
在locked[0][2]
获胜
d) id 2
在locked[2][4]
中获胜
e) 因此,如果你将locked[5][0]
为true
,你就创建了一个链,所以你不应该
如果您想查看实际工作的伪代码,请参阅: https ://stackoverflow.com/a/74867105/14714821
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.