【问题标题】:Reversing sublist of even numbers反转偶数的子列表
【发布时间】:2021-08-29 15:43:45
【问题描述】:

我正在尝试反转偶数的子列表。代码中似乎存在逻辑错误,但我找不到。

    node *sublist_reverse(node *head)
    {
        node *temp=head,*wrking,*wrking_bfr,*node_tobe_ext;
        while(temp!=NULL)
        {
            if(temp->link->data%2==0)
            {
                while(temp->link->data%2==0)
                {
                    if(temp->data%2!=0)
                    {
                        wrking_bfr=temp;
                        wrking=wrking_bfr->link;
                    }
                    node_tobe_ext=wrking->link;
                    wrking->link=node_tobe_ext->link;
                    node_tobe_ext->link=wrking_bfr->link;
                    wrking_bfr->link=node_tobe_ext;
                    temp=wrking->link;
                }
            }
            else
            {
                temp=temp->link;
            }
        }
        return head;
    }

【问题讨论】:

  • 我不确定你真正想要实现什么,也许你想提供一个例子。然而,有一件事:if(temp->data%2!=0) 永远不会在你检查正好相反的循环中为真 (while(temp->link->data%2==0))。
  • 首先,决定一种语言,而不是两种。然后,阅读How to Ask,因为你说有问题,但没有描述那个失败!此外,还要从您的代码中提取minimal reproducible example。作为这里的新用户,也请带上tour并阅读How to Ask

标签: c algorithm linked-list reverse singly-linked-list


【解决方案1】:

对于你和我这样的初学者来说,这不是一个简单的任务。

您的函数是不正确的,至少因为在函数内指针head 没有被更改,尽管列表可以从包含偶数的节点开始,在这种情况下,指针head 的值将被更改。但这不会发生在您的函数中。函数中没有声明指针head的值会被改变。

我可以提出一个更通用的解决方案。对于初学者,该函数通过引用(通过指向它的指针)接受指向头节点的指针,并且还有一个指定谓词的参数。如果节点的子序列满足谓词,则将其反转。特别是谓词可以确定例如存储在节点中的数字是否为偶数。

你来了。

#include <stdio.h>
#include <stdlib.h>
#include <time.h>

typedef struct node
{
    int data;
    struct node *link;
} node;

int push_front( node **head, int data )
{
    node *new_node = malloc( sizeof( *new_node ) );
    int success = new_node != NULL;
    
    if ( success )
    {
        new_node->data = data;
        new_node->link = *head;
        *head = new_node;
    }
    
    return success;
}

FILE * display( const node *head, FILE *fp )
{
    for ( ; head != NULL; head = head->link )
    {
        fprintf( fp, "%d -> ", head->data );
    }
    
    fputs( "null", fp );
    
    return fp;
}

void reverse_ranges( node **head, int predicate( int ) )
{
    while ( *head )
    {
        if ( predicate( ( *head )->data ) )
        {
            node **current = head;
            head = &( *head )->link;
            
            while ( *head != NULL && predicate( ( *head )->data ) )
            {
                node *tmp = *current;
                *current = *head;
                *head = ( *head )->link;
                ( *current )->link = tmp;
            }                   
        }
        else
        {
            head = &( *head )->link;
        }
    }
}

int even( int data ) 
{ 
    return data % 2 == 0; 
}

int main(void) 
{
    node *head = NULL;
    
    srand( ( unsigned int )time( NULL ) );

    const int N = 15;

    for ( int i = 0; i < N; i++ )
    {
        push_front( &head, rand() % N );
    }

    fputc( '\n', display( head, stdout ) );
    
    reverse_ranges( &head, even );
    
    fputc( '\n', display( head, stdout ) );

    return 0;
}

程序输出可能看起来像

8 -> 10 -> 12 -> 7 -> 5 -> 10 -> 4 -> 8 -> 2 -> 6 -> 7 -> 1 -> 0 -> 4 -> 6 -> null
12 -> 10 -> 8 -> 7 -> 5 -> 6 -> 2 -> 8 -> 4 -> 10 -> 7 -> 1 -> 6 -> 4 -> 0 -> null

我认为释放列表所有已分配内存的函数将由您自己编写。

【讨论】:

    【解决方案2】:

    我正在尝试反转偶数的子列表。

    从提供的代码看来,您正在尝试做的是反转连续偶数的每个最大子列表,而不仅仅是一个。此外,这显然是在单链表的上下文中,与数组或双向链表相反。此外,我从您的代码中推断出node 被定义为结构类型,至少包含成员datalink,所以也许

    struct node {
        int data;
        struct node *link;
    };
    
    typedef struct node node;
    

    有了这些理解,您的想法似乎是扫描列表以找到偶数子列表的开头,反转该子列表,然后重复。这会产生代码中呈现的嵌套循环结构,这是解决问题的可行方法。

    请有人告诉我我的逻辑错误是什么。

    目前尚不清楚您在实施中发现了哪些具体问题或不当行为,但从代码中可以明显看出以下一些问题:

    • 当外部循环到达列表的末尾,当函数计算时,会发生不好的事情

          if(temp->link->data%2==0)
      

      这是因为当temp指向最后一个节点时,temp-&gt;link不是一个有效的节点指针。

    • 当内部循环到达列表末尾时也会发生坏事,当最后一个元素是偶数时会发生这种情况。这些是有问题的行:

                 node_tobe_ext=wrking->link;
                 wrking->link=node_tobe_ext->link;
      

      wrking 指向最后一个节点时,node_tobe_ext 不是有效的节点指针。

    • 当列表包含两个或更多偶数的初始子列表时,不能正确反转。可以看出一定是这种情况,因为第一个列表元素的奇偶校验甚至从未被检查过,而且该函数总是返回原始的head 指针。 (如果有两个或更多偶数的初始子链表,那么原来的头节点将不是最终链表的头。)

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-10-02
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-04-23
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多