[英]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.