【问题标题】:Delete a prime number in a doubly linked list删除双向链表中的素数
【发布时间】:2021-11-22 21:26:33
【问题描述】:
#include <stdio.h>
#include <stdlib.h>

struct node 
{
    int data;
    struct node *next;
    struct node *prev;
}*head=NULL;

int length(struct node *p)
{
    int len;
    while(p!=NULL)
    {
        len++;
        p = p->next;
    }
    return len;
}

void display(struct node *p)
{
    if(p == NULL)
    {
        printf("Linked List is empty\n");
    }
    else
    {
        printf("Linked List: ");
        while(p!=NULL)
        {
            printf("%d ", p->data);
            p = p->next;
        }
    }
}

void insert(struct node *p, int index, int x)
{
    struct node *t;
    if(index == 0)
    {
        t = (struct node *)malloc(sizeof(struct node));
        t->data = x;
        t->next = head;
        t->prev = NULL;
        if(head != NULL)
        {
            head->prev = t;
        }
        head = t;
    }
    else
    {
        t = (struct node *)malloc(sizeof(struct node));
        t->data = x;

        for(int i=0; i<index-1; i++)
        {
            p = p->next;
        }
        t->prev = p;
        t->next = p->next;
        if(p->next != NULL)
        {
            p->next->prev = t;
        }
        p->next = t;
    }
}

int checkprime(int n)
{
    int prime = 1;
    for(int i=2; i<n; i++)
    {
        if(n % 2 == 0)
        {
            prime = 0;
            break;
        }
    }
    if(prime == 0)
    {
        return 0; //It is not a prime number.
    }
    else
    {
        return 1; //It is a prime number.
    }
}

void delete_prime_number(struct node *p)
{
    struct node *q;
    while(p != NULL)
    {
        q = p;
        p = p->next;
        if((checkprime(q->data)) == 1)
        {
            free(q);
        }
    }
}

int main()
{
    insert(head, 0, 2);
    insert(head, 1, 3);
    insert(head, 2, 4);
    insert(head, 3, 7);
    insert(head, 4, 8);
    insert(head, 5, 12);
    insert(head, 6, 15);
    insert(head, 7, 23);
    display(head);
    delete_prime_number(head);
    display(head);
    return 0;
}

这是我为此尝试过的代码。问题出在 delete_prime_function 中。当我运行它时,它会无限次打印随机值。 我创建了一个 checkprime 函数,如果数字是素数,它将返回 1,如果数字不是素数,则返回 0。 然后在 delete_prime 函数中,每次它都会检查条件 if((checkprime)==1),如果它为真,它将删除该节点,并且该过程将继续进行,直到指针“p”达到 NULL。 我没有找到我做错的地方。

编辑: 谢谢,我实现了@pmg 和@VladfromMoscow 指出的内容。这是工作代码。

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

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

int length(struct node *p)
{
    int len = 0;
    while (p != NULL)
    {
        len++;
        p = p->next;
    }
    return len;
}

void display(struct node *p)
{
    if (p == NULL)
    {
        printf("Linked List is empty\n");
    }
    else
    {
        printf("Linked List: ");
        while (p != NULL)
        {
            printf("%d ", p->data);
            p = p->next;
        }
    }
}

void insert(struct node **p, int index, int x)
{
    struct node *t;
    
    if (index == 0)
    {
        t = (struct node *)malloc(sizeof(struct node));
        t->data = x;
        t->next = *p;
        t->prev = NULL;
        if ((*p) != NULL)
        {
            (*p)->prev = t;
        }
        (*p) = t;
    }
    else
    {
        t = (struct node *)malloc(sizeof(struct node));
        t->data = x;
        for (int i = 0; i < index - 1; i++)
        {
            if((*p) == NULL)
            {
                printf("Linked List is empty!\n");
            }
            else
            {
                p = &(*p)->next;
            }    
        }
        t->prev = (*p);
        t->next = (*p)->next;
        if ((*p)->next != NULL)
        {
            (*p)->next->prev = t;
        }
        (*p)->next = t;
    }
}

int checkprime(int n)
{
    int prime = 1;
    if(n == 0 || n == 1)
    {
        return 0;
    }
    else
    {
        for (int i = 2; i < n; i++)
        {
            if (n % i == 0)
            {
                prime = 0;
                break;
            }
        }
        if (prime == 0)
        {
            return 0; //It is not a prime number.
        }
        else
        {
            return 1; //It is a prime number.
        }
    }  
}

void delete_prime_number(struct node **p)
{
    while (*p != NULL)
    {
        if (checkprime((*p)->data) == 1)
        {
            struct node *q = *p;
            if ((*p)->next != NULL)
            {
                (*p)->next->prev = (*p)->prev;
            }
            *p = (*p)->next;
            free(q);
        }
        else
        {
            p = &(*p)->next;
        }
    }
}

int main()
{
    struct node *head = NULL;
    insert(&head, 0, 2);
    insert(&head, 1, 3);
    insert(&head, 2, 4);
    insert(&head, 3, 7);
    insert(&head, 4, 8);
    insert(&head, 5, 12);
    insert(&head, 6, 15);
    insert(&head, 7, 23);
    display(head);
    delete_prime_number(&head);
    printf("\n");
    display(head);
    return 0;
}

再次感谢:)

【问题讨论】:

  • 您必须从列表中删除该节点。只需调用free(q) 即可释放内存,之后您将无法再次访问它。但该地址仍链接在您的列表中。
  • 不相关(但重要):if(n % 2 == 0) ==> if(n % i == 0)
  • @pmg 还有for(int i=2; i&lt;n; i++) ==> for(int i=2; i&lt;n/i+1; i++)

标签: c linked-list primes doubly-linked-list function-definition


【解决方案1】:

您的列表实现不正确,许多函数可能会调用未定义的行为。

对于初学者来说,函数不应依赖于全局变量head。在这种情况下,例如一个程序不能同时使用两个列表。

函数length 调用未定义的行为,因为局部变量len 未初始化。

int length(struct node *p)
{
    int len;
    while(p!=NULL)
    {
        len++;
        p = p->next;
    }
    return len;
}

你需要写

    int len = 0;

在函数中插入这段代码sn-p

    for(int i=0; i<index-1; i++)
    {
        p = p->next;
    }
    t->prev = p;
    t->next = p->next;
    if(p->next != NULL)
    {
        p->next->prev = t;
    }
    p->next = t;

您不检查p 是否等于NULL。例如,如果列表为空,则head 是一个空指针,并且用户指定的index 等于1,那么p 也将是一个空指针。因此,在诸如 p-&gt;next 之类的表达式中使用它会调用未定义的行为。

函数checkprime 也不正确。它表明由于 if 语句,数字 0、1 和所有奇数都是素数

    if(n % 2 == 0)
    {
        prime = 0;
        break;
    }

这将无法控制这些数字。

所以首先你必须在编写函数delete_prime_number之前正确编写列表(将head声明为局部变量)和所有提到的函数,这自然也是不正确的,因为至少它不会在指向时改变指针头节点包含一个素数。

至于函数delete_prime_number本身那么它可以定义如下wat

void delete_prime_number( struct node **head )
{
    while ( *head != NULL )
    {
        if ( checkprime( ( *head )->data ) )
        {
            struct node *tmp = *head;

            if ( ( *head )->next != NULL )
            {
                ( *head )->next->prev = ( *head )->prev;
            }
            
            *head = ( *head )->next;
             
            free( tmp );
        }
        else
        {
            head = &( *head )->next;
        }
    }
}

并且可以这样称呼

delete_prime_number( &head );

【讨论】:

  • 谢谢,我更正了所有错误,并在问题中进行了编辑
  • @ranger 您尚未更正所有错误。例如,像往常一样,您的函数说 0 和 1 是素数。在这个循环中 for (int i = 0; i next; } 你没有检查 p 是否等于 NULL。
  • 好的,所以我再次编辑了提到的错误,希望我做得对,再次感谢您的帮助
【解决方案2】:

想象一下这 3 个节点列表:

NULL==p   /<==p   /<==p
      NODE    NODE    NODE
         n==>/   n==>/   n==NULL

当您删除此列表中要获取的第二个节点时

NULL==p   /<==========p             // changed prev link in 3rd node
      NODE    ----    NODE          // deleted 2nd node
         n==========>/   n==NULL    // changed next link in 1st node

但是你的代码得到了这个

NULL==p    ----   /<==p             // prev links to deleted node
      NODE    ----    NODE
         n==>/   ----    n==NULL    // next links to deleted node

注意列表中第一个和最后一个节点的特殊情况。

【讨论】:

  • 谢谢,我知道我做错了什么,现在将再次执行此操作
猜你喜欢
  • 1970-01-01
  • 2014-03-04
  • 2021-04-01
  • 1970-01-01
  • 1970-01-01
  • 2016-06-11
  • 1970-01-01
  • 2018-09-16
  • 1970-01-01
相关资源
最近更新 更多