【问题标题】:Reversing a linked list without modifying the head pointer在不修改头指针的情况下反转链表
【发布时间】:2015-05-21 05:26:33
【问题描述】:

我正在编写一个程序来检查单链表是否为回文。 我的做法如下:

  1. 创建单链表
  2. 反转列表并将其存储在另一个变量中
  3. 比较两者。

反向操作修改头指针。为了不修改头指针,我创建了一个temp 变量来指向头并用相同的方式反转列表并返回temp 指针。操作如下:

struct node* reverse()
{
    struct node *temp=head;
    struct node *curr=temp, *prev=NULL, *next=NULL;
    while(curr!=NULL)
    {
          next = curr->next;
        curr->next = prev;
        prev = curr;
        curr = next;
    }
    temp = prev;
    return temp;
}

现在,我的回文函数实现如下:

int isPalindrome()
{
    struct node *temp=head, *rev=head;
    rev = reverse();
    while(temp!=NULL)
    {
        if(temp->data != rev->data)
            return 0;
        temp = temp->next;
        rev = rev->next;
    }
    return 1;
}

如果反向列表和原始列表节点不匹配,则返回0。否则返回1。

它适用于一些测试用例。但是当列表是 1->4->3->2->1 时。它返回 1 但它应该返回 0。

在锻炼时,我发现rev 函数修改了头指针。而现在,我的列表只有一个节点。

输出如下图所示:

  1. 第一个列表正在打印头指针未修改
  2. 第二个列表是反向列表
  3. 第三个列表是调用reverse函数后打印原始列表

【问题讨论】:

  • 嗯,反向列表和原始列表使用相同的节点,只能有一个方向。当您以相反的顺序重新排列它们时,原始顺序将丢失。如果您想拥有两个不同的列表,则必须进行“深拷贝”,即创建新节点作为现有节点的克隆。
  • 最好的设计是使用双链表,我们可以减少逆向的步骤。

标签: c pointers reverse palindrome


【解决方案1】:

在反转原始头部后,指向反转列表中的最后一个元素,这就是为什么您在第三个输出中只看到一个元素的原因。有几个选项供您选择:

  1. 使用双链表。从头到尾同时向相反方向遍历。

  2. 在反转之前复制原始列表并比较两个列表。

  3. 使用堆栈或其他一些数据结构来提供帮助(类似于上面的选项 2)。

  4. 修改您的算法以仅使用原始列表。

【讨论】:

  • 正如你所说,我已经在方法isPalindrome() 中将原始列表复制到变量temp 中。但事情并没有解决
  • 变量temp只是头指针的副本。您将不得不进行深度复制,这意味着复制所有节点并创建一个新列表,而不是仅仅操作原始列表。
【解决方案2】:

很明显,函数reverse 是错误的,因为它要构建一个新列表。这意味着它必须根据原始列表的节点为反向列表创建新节点。也就是说它必须使用标准函数malloc在内存中分配它的节点。

另外,定义一个比较两个列表的函数在逻辑上更一致。使用这个函数你可以判断一个列表是否是回文。

这是一个演示程序,您可以将其用作您自己程序的示例。

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

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

void push_front( struct node **head, int data )
{
    struct node *n = malloc( sizeof( struct node ) );

    n->data = data;
    n->next = *head;

    *head = n;
}

void display( struct node *head )
{
    for ( ; head != NULL; head = head->next )
    {
        printf( "%d ", head->data );
    }
    printf( "\n" );
}

struct node * reverse_copy( struct node *head )
{
    struct node *rev_head = NULL;

    for ( ; head != NULL; head = head->next )
    {
        push_front( &rev_head, head->data ); 
    }

    return rev_head;
}

int equal( struct node *head1, struct node *head2 )
{
    while ( head1 != NULL && head2 != NULL && head1->data == head2->data )
    {
        head1 = head1->next;
        head2 = head2->next;
    }

    return head1 == NULL && head2 == NULL;
}

void free_list( struct node **head )
{
    struct node *n = *head;

    while ( n != NULL )
    {
        struct node *tmp = n;
        n = n->next;
        free( tmp );
    }

    *head = NULL;
}

struct node *head;

int main(void) 
{
    push_front( &head, 1 );
    push_front( &head, 2 );
    push_front( &head, 3 );
    push_front( &head, 4 );
    push_front( &head, 1 );

    display( head );

    struct node *rev_head = reverse_copy( head );

    if ( equal( head, rev_head ) )
    {
        printf( "The list is a palindrome\n" );
    }
    else
    {
        printf( "The list is not a palindrome\n" );
    }

    free_list( &head );
    free_list( &rev_head );

    push_front( &head, 1 );
    push_front( &head, 2 );
    push_front( &head, 3 );
    push_front( &head, 2 );
    push_front( &head, 1 );

    display( head );

    rev_head = reverse_copy( head );

    if ( equal( head, rev_head ) )
    {
        printf( "The list is a palindrome\n" );
    }
    else
    {
        printf( "The list is not a palindrome\n" );
    }

    free_list( &head );
    free_list( &rev_head );

    return 0;
}

程序输出是

1 4 3 2 1 
The list is not a palindrome
1 2 3 2 1 
The list is a palindrome

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-10-12
    • 2020-04-09
    • 1970-01-01
    • 2018-07-25
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多