簡體   English   中英

C:遞歸函數調用返回值(Tideman CS50)

[英]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 0locked[0][2]獲勝

d) id 2locked[2][4]中獲勝

e) 因此,如果你將locked[5][0]true ,你就創建了一個鏈,所以你不應該

如果您想查看實際工作的偽代碼,請參閱: https ://stackoverflow.com/a/74867105/14714821

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM