了解列表中引用调用的函数

时间:2019-01-27 10:28:19

标签: c list recursion linked-list malloc

我想知道为什么下面给出的代码能很好地工作。

应该递归地给定一个列表,在偶数前加一个-1。

例如输入:4-> 7-> 1-> 10-> NULL输出:-1-> 10-> 1-> 7->-1-> 4-> NULL

我不知道该函数是递归的,由于该函数是通过引用调用自身的,因此每次跟踪都会改变最终的* head。

最后,我没有得到的是,鉴于那些(对我而言)对通过引用进行递归函数工作方式的误解,输出如何正确。

这是带有以下声明的代码:

typedef struct El {
    int info;
    struct El *next;}ElementoLista;
typedef ElementoLista *ListaDiElementi;

void inserisci(ListaDiElementi *head) { 
    if((*head) != NULL && ((*head)->info)%2 == 0) {
        inserisci(&(*head)->next);
        ListaDiElementi aux = malloc(sizeof(ElementoLista));
        aux->info = -1;
        aux->next = *head;
        *head = aux;
    } else {    
        if((*head) != NULL) {               
            inserisci(&(*head)->next); 
        }  
    }  
}

1 个答案:

答案 0 :(得分:1)

我认为您在代码上遇到的麻烦是由于代码“写得不好”,即不够清晰。我看到三个问题。

1)“指针的typedef”使您很难理解所涉及的类型。尤其是在不清楚特定类型是指针时。像ListaDiElementi这样的名称并不是(至少对我而言不是)清楚地表明这是一个指针。更好的名字可能是ElementoLista_ptr,但总的来说最好避免使用指针typedef。

2)函数参数名为head。这很令人困惑,因为我们通常认为head是指向列表第一个元素的指针。但这不是这里发生的事情。该参数实际上是一个双指针,并且它并不指向第一个元素。它指向next指针。

3)if构造隐藏了程序的逻辑。

因此,让我们重写代码以摆脱上面的情况,同时仍保持相同的功能:

typedef struct El {
    int info;
    struct El *next;
} ElementoLista;

void inserisci(ElementoLista **pNext) { 
    if ((*pNext) == NULL) return;

    inserisci(&(*pNext)->next);

    if(((*pNext)->info)%2 == 0) {
        ElementoLista* aux = malloc(sizeof(ElementoLista));
        aux->info = -1;
        aux->next = *pNext;
        *pNext = aux;
    }  
}

使用此代码,可以很容易地看到该代码不断递归调用它,直到到达结尾为止。在返回途中,即在函数调用返回时,代码检查是否需要插入“ -1”节点。

相同的代码加上一些注释来解释:

typedef struct El {
    int info;
    struct El *next;} ElementoLista;

// pNext is a pointer to the "next pointer" of the previous node
// Consequently (*pNext) is a pointer to the current node
void inserisci(ElementoLista **pNext) { 
    // Return if we have reached the end of the list
    if ((*pNext) == NULL) return;

    // Keep calling until the end is reached
    inserisci(&(*pNext)->next);

    // On the "way back" (i.e. as the recursive calls return) check
    // if we need to insert a "-1" node
    if(((*pNext)->info)%2 == 0) {
        // We need a new node
        ElementoLista* aux = malloc(sizeof(ElementoLista));
        aux->info = -1;

        // Make the new node point to current node
        aux->next = *pNext;

        // Update the next pointer to point to the new node
        *pNext = aux;
    }  
}

了解此代码的简化版本后,您还应该了解原始版本。