单链表的按值查找 单链表

已知一个带头的递增单链表,试编写一个算法,功能是从表中去除值大于min且值小于max的元素(假定表中存在这样的元素)
void DelList(LinkList L,int min,int max)
{
   LNode *ptr,*qtr,*s;
  _** ptr=L->next;
   ptr=L;**_
  while((ptr!=NULL)&&(ptr->Data<=min))
{    
    qtr=ptr;
    ptr=ptr->next;
}
  while((ptr!=NULL)&&(ptr->Data<max))
{
   s=ptr;
  ptr=ptr->next;
   free(s);
}
qtr->next=ptr;
}

代码块中的粗斜体部分:为什么要使指针ptr先指向链表的起始结点后,又使ptr指向头节点。为什么不能直接使ptr指向头节点呢?

ptr指针先指向链表的起始结点,然后再指向头节点,这是为了保证在循环中不会出现指针指向空地址的情况,避免程序崩溃。

在给定的代码块中,存在一些问题。以下是修正后的代码:

void DelList(LinkList L, int min, int max) {
    LNode *ptr, *qtr, *s;
    ptr = L;
    qtr = L;
    
    // 找到第一个大于等于min的节点
    while (ptr != NULL && ptr->Data <= min) {
        qtr = ptr;
        ptr = ptr->next;
    }
    
    // 删除值大于min且小于max的节点
    while (ptr != NULL && ptr->Data < max) {
        s = ptr;
        ptr = ptr->next;
        free(s);
    }
    
    qtr->next = ptr;
}

修正后的代码将从链表中删除值大于min且小于max的元素。请确保在调用此函数时,传入正确的链表和有效的min、max值。还要确保在函数调用后,适当释放已删除的节点内存。

注意:这是一个示例实现,具体的实现可能因链表结构和数据类型而有所不同。请根据实际情况进行适当的修改。

在给定的代码块中,对指针ptr进行了两次赋值,一次指向链表的起始结点,一次指向头节点。这是因为在删除操作时需要保留头节点的位置,以便在删除元素后能够正确连接链表的前后节点。

让我们来分析代码的执行流程:

  1. LNode *ptr, *qtr, *s;:定义了三个指针变量,其中ptr指向当前节点,qtr指向ptr的前一个节点,s用于保存待删除的节点。

  2. _**ptr = L->next;:这行代码将ptr指向链表的起始结点,即跳过头节点。

  3. ptr = L;:这行代码将ptr重新指向头节点。这是为了确保在删除操作时,qtr可以始终指向待删除节点的前一个节点,从而方便连接链表。

为什么不能直接使ptr指向头节点呢?如果直接将ptr指向头节点,那么在第一个while循环中,找到值大于等于min的节点时,无法记录该节点的前一个节点。这样在删除操作时,就无法正确连接链表。

通过在删除操作之前将ptr指向头节点,可以确保qtr指向待删除节点的前一个节点,从而正确连接链表。这样在执行qtr->next = ptr;时,即可将删除元素后的链表正确连接起来。

因此,在该代码中,对指针ptr先指向链表的起始结点,然后又指向头节点,是为了确保在删除操作中能够正确处理链表的连接关系。

可以直接指向L节点,第一句指向L的下一个节点没什么用,可以删掉。

  • 错误是:你把指针ptr先指向链表的起始节点(L->next),又把ptr指向头节点(L)。一个错误。

要实现这个,你要从头节点遍历链表,因为你要改头节点后面的第一个节点(如果位于min和max之间)。最简洁有效的方法:

void DelList(LinkList L, int min, int max) {
    LNode *cur = L;
    while (cur && cur->next) {
        if (cur->next->Data > min && cur->next->Data < max) {
            LNode *tmp = cur->next;
            cur->next = cur->next->next;
            free(tmp);
        } else {
            cur = cur->next;
        }
    }
}
  • 用一个指针cur来遍历链表。每一个节点,如果下一个节点的数据在min和max之间,就删除。否则就移到下一个节点。只要进行一次遍历就可以删除所有符合条件的节点。

首先,我们需要理解头节点的作用。链表中的头节点通常是一个辅助节点,它不存储任何有意义的数据,只用来辅助操作链表。头节点的存在可以简化链表的操作,并且在删除链表的第一个节点时特别有用。

在这段代码中,ptr指针用于遍历链表。开始时,ptr被赋值为链表的起始节点,即头节点的下一个节点(L->next)。然后,一个while循环用于将ptr指向第一个大于min的节点,以便从这个节点开始删除符合条件的元素。

接下来,我们需要保留头节点的引用(指针),以便在删除操作完成后更新链表的连接关系。因此,我们使用一个额外的指针qtr来保存ptr的前一个节点。这样,在删除操作结束后,我们可以通过qtr->next = ptr来确保链表的连接正确。

如果直接让ptr指向头节点,我们将无法在删除操作完成后更新头节点之前的节点的连接关系,因为我们无法获得头节点的前一个节点。这样会导致链表丢失了与头节点之前的节点的连接,从而使链表的一部分丢失。

所以,为了保留头节点的引用以及正确处理连接关系,我们需要先让ptr指向链表的起始节点,然后再用一个指针qtr来保存ptr的前一个节点。这样可以确保删除操作后链表的完整性和正确性。

这段代码应该这么写,供参考:

void deletes(LinkList L, int min, int max)
{
    LNode* ptr, * qtr, * s;
    qtr = L;
    ptr = L->next;
    while (ptr != NULL && ptr->data <= min)
    {
        qtr = ptr; ptr = ptr->next;
    }
    while (ptr != NULL && ptr->data < max)
    {
        s = ptr;
        qtr->next = ptr->next;
        ptr = ptr->next;
        free(s);
    }
}

试下

void DelList(LinkList L,int min,int max)
{
   LNode *ptr,*qtr,*s;
   ptr=L->next; // ptr指向链表的起始结点
   qtr=L; // qtr指向头结点
  while((ptr!=NULL)&&(ptr->Data<=min))
{    
    qtr=ptrptr=ptr->next;
}
  while((ptr!=NULL)&&(ptr->Data<max))
{
   s=ptr;
  ptr=ptr->next;
   free(s);
}
qtr->next=ptr;
}