从C中的链表中删除最后两个元素

时间:2016-11-25 11:10:55

标签: c list singly-linked-list

我有这段代码,它会从链表中删除最后一个元素。我必须做出哪些更改才能删除链表的最后两个元素?

void deletesEnd() {
    struct node *temp, *last;

    temp = head;
    last = temp;

    while (temp != NULL && temp->next != NULL) {
        last = temp;
        temp = temp->next;
    }

    if (last == temp) {
        free(temp);
        head = NULL;
    } else {
        free(last->next);
        last->next = NULL;
    }
}

4 个答案:

答案 0 :(得分:1)

删除列表最后2个元素的最简单方法是两次调用deletesEnd()。请注意,deletesEnd()应将head作为参数并返回新值。您可以通过发出嵌套调用删除最后2个:

struct node *deletesEnd(struct node *head) {
    struct node *temp, *last;

    last = temp = head;
    while (temp && temp->next != NULL) {
        last = temp;
        temp = temp->next;
    }
    if (last == head) {
        free(head);
        head = NULL;
    } else {
        free(last->next);
        last->next = NULL;
    }
    return head;
}

删除最后一个元素:head = deletesEnd(head);

删除最后两个元素:head = deletesEnd(deletesEnd(head));

设计的简单性不仅可以补偿枚举列表两次的开销。

如果您绝对需要特定功能,可以通过以下方式扩展您的方法:

struct node *deleteLast2Nodes(struct node *head) {
    struct node *temp, *last;

    last = temp = head;
    while (temp && temp->next != NULL && temp->next->next != NULL) {
        last = temp;
        temp = temp->next;
    }
    if (last == head) {
        if (head) {
            free(head->next);
        }
        free(head);
        head = NULL;
    } else {
        free(last->next->next);
        free(last->next);
        last->next = NULL;
    }
    return head;
}

答案 1 :(得分:0)

这是一个演示程序,显示如何同时删除最后两个节点。事实上,该函数与您的函数类似,不仅它检查next节点而且还检查next->next节点。

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

struct node
{
    int value;
    struct node *next;
} *head;

void push( int value )
{
    struct node *tmp = malloc( sizeof( struct node ) );
    tmp->value = value;
    tmp->next  = head;

    head = tmp;
}

void display()
{
    for ( struct node *current = head; current; current = current->next )
    {
        printf( "%d ", current->value );
    }
}

void deleteLastTwo()
{
    struct node *current = head;
    struct node *prev = head;

    if ( current && current->next )
    {
        while ( current->next->next )
        {
            prev = current;
            current = current->next;
        }
    }

    if ( current )
    {
        if ( current->next )
        {
            free( current->next );
        }

        if ( prev == current )
        {
            head = NULL;
        }
        else
        {
            prev->next = NULL;
        }

        free( current );
    }
}

int main(void) 
{
    const int N = 11;

    for ( int i = N; i != 0; i-- ) push( i - 1 );

    display();
    printf( "\n" );

    while ( head )
    {
        deleteLastTwo();
        display();
        printf( "\n" );
    }

    return 0;
}

程序输出

0 1 2 3 4 5 6 7 8 9 10 
0 1 2 3 4 5 6 7 8 
0 1 2 3 4 5 6 
0 1 2 3 4 
0 1 2 
0 

考虑到头节点被声明为全局变量时不是一个好主意。它可以被声明为局部变量更好。在这种情况下,您需要重写列表的方法,因为在大多数情况下,当前的方法将无法正常工作。

答案 2 :(得分:0)

此逻辑将删除单链表中的最后2个节点。

void deletesEnd()
{
    struct node *temp, *last;

    temp = head;
    last = temp;

    while (temp->next->next != NULL)
    {
        last = temp->next;
        if(last->next->next!=NULL)
                temp = temp->next;
        else
                break;
    }

        struct node *ptr=last->next;
        last->next=ptr->next;
        free(ptr);

        temp->next=last->next;
        free(last);
}

答案 3 :(得分:0)

为了好玩而且教育:简单的递归版。

  • 函数return:= us
  • 下的节点数
  • 递归返回后,我们可以决定是否太靠近尾部了。
  • 并自行删除
  • 因为我们传递一个指向指针的指针,这也适用于size = 2和更小
  • 的列表
unsigned del_tail_n(struct llist **pp, unsigned nn)
{
unsigned pos;
if (!*pp) return 0;

    // this recursive call returns 0 iff (*pp)->next is NULL
pos = del_tail_n( &(*pp)->next, nn);
if (pos < nn) {
        // free (*pp);
        *pp = NULL;
        }
return 1+pos;
}

对于那些不喜欢递归的人,这里是一个非递归版本。 [请注意,这两个版本适用于空列表(*pp == NULL),或适用于小于nn的列表

void del_tail_n2(struct llist **pp, unsigned nn)
{
struct llist *p;

        /* Advance p pointer n positions down, starting from *pp. */
for (p= *pp; p; p=p->next) {
        if (nn-- < 1) break;
        }

        /* Do a synchronous walk down for both p and *pp, until p is NULL. */
for ( ; p; p=p->next) {
        pp = &(*pp)->next;
        }

        /* Now, *pp is the first node to delete
        ** Delete it and everything below it.
        */
for ( ;(p = *pp); ){
        *pp = p->next;
        // free (p);
        }
return;
}