C 如何在函数中编写函数(列表映射)

C 如何在函数中编写函数(列表映射),c,linked-list,C,Linked List,您好,我最近问了一些关于C中链表的问题。 首先,我要感谢所有帮助我的人。但我有一个问题我不能理解。我甚至问过教授,但他给我回了电子邮件,几乎没有什么信息。基本上我是在用C写一个链表(见上面的链接)。教授在头文件中告诉我们的一件事是: void list_map( INTLIST *list, void (*f)(void *) ); /*Applies a function to each element of the list */ 所以我给他发了邮件说: 另一个问题,在头文件中,您没有定

您好,我最近问了一些关于C中链表的问题。

首先,我要感谢所有帮助我的人。但我有一个问题我不能理解。我甚至问过教授,但他给我回了电子邮件,几乎没有什么信息。基本上我是在用C写一个链表(见上面的链接)。教授在头文件中告诉我们的一件事是:

void list_map( INTLIST *list, void (*f)(void *) );
/*Applies a function to each element of the list */
所以我给他发了邮件说:

另一个问题,在头文件中,您没有定义排序函数,我们是否需要用原型编写排序函数,最后是什么是列表映射

他回答说:

您需要实现一个排序函数f,它通过list_map(list,f)调用。希望它能消除你的疑虑

我唯一的疑问是这一点没有得到充分的教育。我能理解如何对链表进行排序事实上这里有一些伪代码:

tmp=head;

while(tmp!=NULL)
{
   tmp2=tmp->next; //pointer to next node
   while(tmp2!=NULL)
    {
     if (tmp2->data < tmp->data)
        {
         int x = tmp2->data;
         tmp2->data = tmp->data;
         tmp2->data = x;
        }
     tmp2=tmp2->next;
    }
   tmp=tmp->next;
}
我只想说:

list_map(myList, f()); //apply function f to the current linked list
或者我真的需要在某个地方定义列表映射吗?我不是一个典型的学生,只是想找个人来做我的工作。我真的尽力去理解这一点

谢谢大家

[编辑部分]

我想补充一点,卡莱布p.说的海报之一

“因此,您的工作是创建排序 将传递给的函数 请注意,正确的语法 通过它将是:

那么我的代码应该是这样的:

在.h文件中,我将函数原型化为:

void myCustomSort(void*);
然后在.cpp中变成:

void myCustomSort(void*f)
{
tmp=f->head; 

while(tmp!=NULL) 
{
   tmp2=tmp->next; //pointer to next node 
   while(tmp2!=NULL) 
   { 
     if (tmp2->data < tmp->data) 
        { 
         int x = tmp2->data; 
         tmp2->data = tmp->data; 
         tmp2->data = x; 
        } 
     tmp2=tmp2->next; 
    } 
   tmp=tmp->next; 
} 
}

但我不需要在任何地方定义列表地图吗?因为它在.h文件中,所以我不必定义它吗?

我认为list\u map函数调用函数pointer f(),它是指向函数的指针,该函数使用void指针并返回void。如果是这样的话,这是实现排序的疯狂方式,但却是可行的

定义一个函数,如

void Test(void *)
{...}
然后像这样将其传递到列表\u map()


我假设列表中的每个项都会调用您的测试函数。

列表映射的第二个参数是指向返回void并接收void指针的函数的指针。由于
list\u map
似乎是一个函数,我猜它将为列表的每个元素调用
f
(指向函数的指针)

因此,您的工作是创建一个排序函数,并将其传递到
list\u map
。请注意,传递它的正确语法为:

void yourCustomSort(void*);
list_map(myList, yourCustomSort);
我猜传递到排序函数中的
void*
可能会传递到链表中的一个节点


是对链接列表进行排序的好选择。

假设
list\u map
是这样实现的,按顺序为每个节点提供
f

void list_map(INTLIST *list, void (*f)(void *)) {
    INTLIST *node;
    for (node = list; node; node = node->next)
        f(node);
}
您可以实现

其中,
void-swap\u-head\u与最小的(void*)
将给定节点的数据与列表中其后任何节点的最小数据进行交换


由于这是家庭作业,我尽量不泄露整个解决方案

void swap_head_with_smallest(void *list) {
    INTLIST *head = list;
    INTLIST *smallest;

    /* set smallest the smallest node of
         head, head->tail, head->tail->tail, etc. */

    /* swap head->datum and smallest->datum */
}

你的教授试图教你一个在函数编程中很常见的概念,即高阶函数的概念。高阶函数可以将其他函数作为参数,类似于

list_of_cosines = map(cos, list_of_inputs)
其中,
输入列表
是一系列浮点值,
cos
是标准余弦函数。
map
函数将调用
cos
以获取
输入列表中的每个值,并返回相应结果的列表

C函数不能将其他函数类型作为参数,但它们可以将指向函数的指针作为参数(通常称为回调);标准示例是
qsort()
库函数,它将指向函数的指针作为其参数之一,该函数接受两个指向void的指针,并根据v1v2分别返回-1、0或1。例如:

int compareIntValues(const void *v1, const void *v2)
{
  int lv1 = *(int *) v1; // convert inputs from pointers to void
  int lv2 = *(int *) v2; // to the type we're actually interested in
  if (lv1 < lv2) return -1;
  if (lv1 > lv2) return 1;
  return 0;
}

int main(void)
{
  int values[] = {3, 1, 4, 5, 7, 9, 6, 2};
  ...
  qsort(values,                             // buffer containing items to sort
        sizeof values / sizeof values[0],   // number of items to sort
        sizeof values[0],                   // size of each item
        compareIntValues);                  // comparison function
  ... 
}
你的教授提供的界面有点混乱;要么列表指针和f()的参数都应该是
void*
(在这种情况下,您可以使用
list\u map
将函数映射到不同的列表类型),要么列表指针和f()的参数都应该是
INTLIST*
(因为您似乎在处理INTLIST类型)

如果我是对的,那么exercise在表面上有点毫无意义(为什么不直接调用排序函数呢?),但可能是你的教授正在构建更通用的东西。毕竟,没有理由认为
f
必须是一个排序函数;它可以是一个显示列表的函数,或者将列表保存到文件中,或者其他一些功能

我有一个关于如何使用回调对列表排序的不同示例;这可能有助于说明为什么这种方法是有用的

编辑


ephemient关于list_map需要做什么的例子可能比我写的更接近你教授的意图

如果节点中有指向列表头部的指针,则必须使用指向列表的指针作为边界。让我解释一下

map函数是函数式编程中的一个常见概念,现在,您只需知道这是一个函数,它获取一个列表,并应用另一个函数(应用函数)到列表的每个节点。我打赌你已经知道了

据我记忆所及,C语言没有映射函数,所以您必须自己定义一个映射函数。这并不难:只要从列表的最前面开始,一直走到最后。对于每个步骤,将当前listnode传递给执行需要执行的操作(在本例中为排序)的函数

现在是你的任务

  • 无法从应用的函数中获取任何数据(它返回void)
  • 您必须向下走,直到将每个节点传递给
    void list_sort(INTLIST *list) {
        list_map(list, swap_head_with_smallest);
    }
    
    void swap_head_with_smallest(void *list) {
        INTLIST *head = list;
        INTLIST *smallest;
    
        /* set smallest the smallest node of
             head, head->tail, head->tail->tail, etc. */
    
        /* swap head->datum and smallest->datum */
    }
    
    list_of_cosines = map(cos, list_of_inputs)
    
    int compareIntValues(const void *v1, const void *v2)
    {
      int lv1 = *(int *) v1; // convert inputs from pointers to void
      int lv2 = *(int *) v2; // to the type we're actually interested in
      if (lv1 < lv2) return -1;
      if (lv1 > lv2) return 1;
      return 0;
    }
    
    int main(void)
    {
      int values[] = {3, 1, 4, 5, 7, 9, 6, 2};
      ...
      qsort(values,                             // buffer containing items to sort
            sizeof values / sizeof values[0],   // number of items to sort
            sizeof values[0],                   // size of each item
            compareIntValues);                  // comparison function
      ... 
    }
    
    void list_map(INTLIST *list, void (*f)(void *))
    {
      // sort the list by passing it to f
      f(list); // or (*f)(list);
    }
    
    void sortListAscending(void *ptr)
    {
      INTLIST *ilptr = ptr;
      /**
       * sort the list in ascending order
       */
    }
    
    void sortListDescending(void *ptr)
    {
      INTLIST *ilptr = ptr;
      /**
       * sort the list in descending order
       */
    }
    
    int main(void)
    {
      INTLIST *theList;
      ...
      list_map(theList, sortListAscending); // sort the list in ascending order
      ...
      list_map(theList, sortListDescending); // sort the list in descending order
      ...
    }
    
    void ascendingSort(void*f)
    {
      cursor=f->head; 
      placed=false;
    
      while(!placed and cursor!=f) { 
        if (cursor->data < f->data) {
          cursor = cursor->next;
        } else {
          swap( cursor->data, f->data);
          placed=true;
        }
      }
    
      while(cursor!=f) { 
          cursor = cursor->next;
          swap(cursor->data, f->data);
      }
    
    void ascendingSort(void*f)
    {
      cursor=f->head; 
    
      while(cursor!=f) { 
        if (cursor->data > f->data) {
          swap( cursor->data, f->data);
        }
        cursor = cursor->next;
      }
    }