【问题标题】:Reverse a linked list without using a pointer to pointer在不使用指针的情况下反转链表
【发布时间】:2017-07-23 23:36:30
【问题描述】:

我已经使用此代码成功实现了 2 指针解决方案:

void list_reverse(t_list **begin_list)
{
    t_list *new_root;
    t_list *root;
    t_list *next;

    new_root = 0;
    root = *(begin_list);
    while (root)
    {
        next = root->next;
        root->next = new_root;
        new_root = root;
        root = next;
    }
    *begin_list = new_root;
}

效果很好 - 至少根据我的测试。现在我想尝试仅使用单个指针来反转链表,而不使用return,所以我尝试将我的代码转换为void list_reverse(t_list *begin_list),但是*begin_list = new_root 当然不起作用,因为我不能更改begin_list。其余的似乎都可以工作。

如何在没有双指针的情况下修改begin_list

编辑:结构是:

typedef struct  s_list
{
    struct s_list   *next;
    void            *data;
}               t_list;

【问题讨论】:

  • 你尝试过使用递归吗?
  • 对函数参数的修改对函数调用者不可见。也不在您提供的代码中。 (你的函数改变了它的参数指向的对象,调用者碰巧也能看到它;这不是一回事。)但是你可以通过函数的返回将修改后的指针提供给调用者价值。
  • 这是不可能的,因为它不能改变第一个元素。 (将第一个元素设为虚拟时除外。)
  • @JohnBollinger 没有返回
  • @Luke,你错过了重点。 OP 已经知道如何使用指向指针的方法来做到这一点。问题是如何使用(单)指针直接指向列表节点:“我如何修改 begin_list 没有双指针?” (强调)。

标签: c pointers linked-list


【解决方案1】:

您可以通过交换第一个和最后一个节点(浅拷贝)来反转列表,然后反转列表。这样,最后一个节点的 content 将在头指针已经指向的初始节点中结束。

这是一个实现:

void swap(struct node *a, struct node *b) {
    struct node tmp = *a;
    *a = *b;
    *b = tmp;
}

void reverse(struct node *h) {
    // Null list and single-element list do not need reversal
    if (!h || !h->next) {
        return;
    }
    // Find the last node of the list
    struct node *tail = h->next;
    while (tail->next) {
        tail = tail->next;
    }
    // Swap the tail and the head **data** with shallow copy
    swap(h, tail);
    // This is similar to your code except for the stopping condition
    struct node *p = NULL;
    struct node *c = tail;
    do {
        struct node *n = c->next;
        c->next = p;
        p = c;
        c = n;
    } while (c->next != tail);
    // h has the content of tail, and c is the second node
    // from the end. Complete reversal by setting h->next.
    h->next = c;
}

Demo.

【讨论】:

    【解决方案2】:

    函数可以通过三种主要方式向其调用者提供计算值。

    1. 它可以return该值,或包含它的对象,或指向此类对象的指针(前提是在最后一种情况下,指向的对象比函数调用的寿命更长)。

    2. 它可以通过调用者提供的指针修改调用者可见的对象。

    3. 它可以将计算值记录在调用者可见的文件范围变量中。

    还有其他替代方案,主要涉及 I/O,但它们通常本着 (3) 的精神。

    您不得使用 (1)。您不能以您建议的方式使用 (2)。可能(3)是预期的答案,但这很丑陋,真的不应该推荐。那么该怎么办呢?

    也许您只是硬着头皮使用文件范围变量,但如果您被允许获得调用者的帮助和/或对列表的形式提出要求,那么您还有另一种可能性:拥有调用者传递一个在列表反转时不会改变的指针——即一个指向包含指向列表头的指针的结构的指针。然后该函数不需要修改该指针;它通过指向的对象返回新的列表头。

    通常使用代表整个列表的单独结构类型来执行此类操作。然而,如果你想一想,你会意识到你现有的列表节点类型已经有了合适的形式。如果您无法引入新结构,则可以使用现有结构——只需将列表中的第一个节点视为其余元素的非数据承载句柄。这有时被称为虚拟头节点,使用一个虚拟头节点的列表在许多方面提供了更简单的函数实现。

    【讨论】:

      【解决方案3】:

      看看这个:

      void reverse(struct node* head) {
          struct node *curr=head; 
          struct node *next=NULL;
          struct node *prev=NULL; 
          while(curr) { 
              next=curr->next; //we're basically stashing the next element
              curr->next=prev; //setting next pointer to the previous element
              prev=curr; //previous is now current
              curr=next; //and updating the current from the stashed value
          }
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2020-04-09
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多