使用C中的递归来反转链接列表

时间:2017-03-23 19:30:27

标签: c recursion linked-list

我是C的新手,我正在尝试创建一个函数来反转链表,只将List本身作为参数传递。这可以不将节点作为参数传递吗?

到目前为止,这是我的代码,我知道它无法正常工作,因为我无法弄清楚如何在列表的其余部分进行递归调用。

typedef struct {
    node_t *head;
    node_t *tail;
} LL_t;

typedef struct _node {
    int data;
    struct _node *next;
} node_t;

这里也是我的类型定义。

tail -200 FILENAME | grep CYP2C | awk '{ print "chr10\t",$2,"\t",$1}' | sed 's/10://g'

4 个答案:

答案 0 :(得分:2)

您可以使用简单的循环反转列表,不需要递归并且给出您的API,这是不合适的。

以下是您的功能的修改版本:

void reverse(LL_t *L) {
    node_t *prev = NULL;
    node_t *curr = L->head;
    L->tail = curr;
    while (curr != NULL) {
        node_t *next = curr->next;
        curr->next = prev;
        prev = curr;
        curr = next;
    }
    L->head = prev;
}

如果您需要使用递归,则可以测试列表是空的还是仅限于单例并且不执行任何操作,否则删除head元素,反转结果列表并将元素追加到末尾:

void reverse(LL_t *L) {
    if (L->head != L->tail) {
        /* at least 2 elements */
        node_t *node = L->head;
        L->head = node->next;
        node->next = NULL;
        reverse(L);
        L->tail = L->tail->next = node;
    }
}

请注意,如果列表太长,reverse将递归太多次并导致堆栈溢出,则此递归方法可能会有未定义的行为。

答案 1 :(得分:1)

struct node {
   int          value;
   struct node* next;
};

在常量堆栈空间中运行的非递归定义:

void reverse(struct node** ptr) {
   struct node* prev_ptr;
   struct node* node_ptr;

   if (prev_ptr = * ptr) {
      node_ptr = prev_ptr -> next;

      prev_ptr -> next = NULL;

      while (node_ptr) {
         struct node* temp = node_ptr -> next;

         node_ptr -> next = prev_ptr;

         prev_ptr = node_ptr;
         node_ptr = temp;
      }

      * ptr = prev_ptr;
   }
}

扩展等价的递归定义:

void reverse(struct node** ptr) {
   struct node* node_ptr;

   if (node_ptr = * ptr) {
      node_ptr -> next = NULL;

      * ptr = reverse_rec(node_ptr, node_ptr -> next);
   }
}

struct node* reverse_rec(struct node* prev_ptr, struct node* node_ptr) {
   if (! node_ptr) { return prev_ptr; }

   struct node* temp = reverse_rec(node_ptr, node_ptr -> next);
   node_ptr -> next = prev_ptr;
   return temp;
}

答案 2 :(得分:0)

这样可行,但使用递归来反转列表需要O(n)堆栈空间开销。这里的概念是推进L-> head的静态实例,同时为每个递归级别保留head的本地副本。递归一直持续到列表结束,然后使用head的本地实例反转列表,因为reverse()返回备份调用链。

void reverse(LL_t *L)
{
node_t *head;
    if(L->head == NULL || L->head->next == NULL)
        return;
    head = L->head;
    L->head = head->next;
    reverse(L);
    head->next->next = head;   // reverse the nodes
    head->next = NULL;
    L->tail = head;            // ends up setting tail to what was 1st node
}

答案 3 :(得分:0)

//反转链接列表的简单程序

void reverse(struct node * head_ref) {     struct node * first;

struct node* rest;
if (head_ref == NULL)
   return; 

first = head_ref;  
rest  = first->next; 
if (rest == NULL)
   return;   

reverse(rest); 
first->next->next  = first;      
first->next  = NULL;          
head_ref = rest;              

}