数据结构与算法刷题笔记——第一周1:双重指针一趟扫描链表

Source

题目:
输入一个链表,删除链表的倒数第 n 个结点,并且返回链表的头结点。
进阶:仅用一趟扫描实现。
链表节点定义如下:
struct ListNode {
int val;
ListNode *next;
ListNode() : val(0), next(nullptr) {}
ListNode(int x) : val(x), next(nullptr) {}
ListNode(int x, ListNode *next) : val(x), next(next) {}
};

C语言版本:
struct ListNode{
int val;
ListNode *next;
}

请提交如下形式的函数:
ListNode* removeNthFromEnd(ListNode* head, int n) {

}

大一学C时链表了解得并不是很多,趁此机会好好复习(预习)一下。

第一次运行代码时出现了bug,发现只要删除第二个节点即倒数第N-1个节点以及第一个节点都会出问题。重新审阅了一遍代码后发现第一个指针向前移动N-1个节点时就已经指向Null了,因此需要对这两种情况单独讨论。

#include <stdio.h>
#include <stdlib.h>
//线性表 链式结构
typedef struct listNote{
    
      
    int val;
    struct listNote *next;
}ListNode;

struct listNote*AppendNode(struct listNote*head);//增加节点
void DeleteMemory(struct listNote *head);//释放内存
void Disply(struct listNote *head);//显示节点信息
ListNode* removeNthFromEnd(ListNode* head, int n);//删除倒数第N个节点

int main()
{
    
      
    int i = 0;
    int n = 0;
    struct listNote *head = NULL;
    char c;
    scanf("%c",&c);
    while(c == 'y')
    {
    
      
        head = AppendNode(head);
        Disply(head);
        scanf(" %c",&c);
        i++;
    }
    printf("是否删除节点?");
    scanf(" %c",&c);
    while(c == 'y')
    {
    
      
        printf("删除第几个节点");
        scanf(" %d",&n);
        head = removeNthFromEnd(head,n);
        Disply(head);
        printf("是否删除节点?");
        scanf(" %c",&c);
    }
    DeleteMemory(head);
    return 0;
}

struct listNote *AppendNode(struct listNote*head)
{
    
      
    struct listNote *p = NULL,*pr = head;
    int val;
    p = (struct listNote*)malloc(sizeof(struct listNote));
    if(p == NULL)
    {
    
      
        printf("No enough memory to allocate!\n");
        exit(0);
    }
    if(head == NULL)
    {
    
      
        head = p;
    }
    else
    {
    
      
        while (pr->next!= NULL )
        {
    
      
            pr = pr->next;
        }
        pr->next = p;
    }
    printf("Input node data:");
    scanf("%d",&val);
    p->val = val;
    p->next = NULL;
    return head;
};

void DeleteMemory(struct listNote *head)
{
    
      
    struct listNote *p = head,*pr = NULL;
    while(p != NULL)
    {
    
      
        pr = p;
        p = p->next;
        free(pr);
    }
}

void Disply(struct listNote *head)
{
    
      
    struct listNote *p = head;
    while(p != NULL)
    {
    
      
        printf("数据:%d\n",p->val);
        p = p->next;
    }
}

ListNode* removeNthFromEnd(ListNode* head, int n)
{
    
      
    ListNode *pre = head, *last = head;//双重指针
    ListNode *pr = NULL;
    int i;
    int j = 0;
    for(i = 0;i < n+1;i++)
    {
    
      
        if (pre!=NULL)
    {
    
      
        pre = pre->next;
        if(pre == NULL)
        {
    
      
            j++;
        }
    }
        else //计数器
    {
    
      
        j++;
    }
        if(j == 2)
    {
    
      
        pr = head;
        head = pr->next;
        free(pr);
    }
        else if(j == 1 && i == n)
    {
    
      
        pr = head->next;
        head->next = pr->next;
        free(pr);
    }
    }
    if(pre!=NULL)
    {
    
      
       while(pre!=NULL)
    {
    
      
        pre = pre->next;
        last = last->next;
    }
    pr = last->next;
    last->next = pr->next;
    free(pr);
    }
    return head;
}