剑指offer(面试题):找出链表中的倒数第K个节点

首先我们先创建一个链表,链表的创建在上一个链表的逆序打印中已经说过了,链接如下
http://blog.csdn.net/qq_36767247/article/details/78828609
其实就是简单的初始化,创建节点,然后在尾插节点就行
好了我们进入正题

此题中我们可以利用快慢指针
定义两个指针,一个指针先走K步,然后两个指针一起走,此时两个指针就距离为K,所以当快指针走到NULL的时候,慢指针刚好走到倒数第K个节点

我们可以画个图解释一下
这里写图片描述

然后我们直接写代码就好

//将链表的头结点和K传入函数
//找到单链表的倒数第K个节点,只能遍历一次链表
LinkNode *FindK(LinkNode *head,size_t k)
{
    //定义两个快慢指针,让快的先走k步
    //然后快慢指针两个一起走
    //当快指针走完链表时,慢指针刚好走到单数第K个节点
    if (head == NULL)
    {
        //空链表
        return NULL;
    }
    LinkNode *fast = head;
    LinkNode *slow = head;
    size_t n = k;
    while (n--)
    {
        if (fast == NULL)
        {
            //此时表示K>=n
            return NULL;
        }
        fast = fast->next;
    }
    while (fast != NULL)
    {
        fast = fast->next;
        slow = slow->next;
    }
    return slow;
}

顺带的我们已经找到链表的第K个节点那么我们怎么直接将这个节点删除并且不再次遍历链表呢

我们可以应用移花接木大法,画个图
这里写图片描述
就将这倒数第K个节点的value等于它的下一个节点的value,它的next等于它的写一个节点的next,然后将它的下一个节点一释放
用代码实现

//删除链表的倒数第K个节点
void DelectK(LinkNode **head,size_t k)
{
    //先找出倒数第k个节点
    //然后再用移花接木法不用遍历进行删除
    if (head == NULL)
    {
        //非法输入
        return;
    }
    if (*head == NULL)
    {
        //空链表
        return;
    }
    LinkNode *cur = *head;
    LinkNode *to_delect = FindK(*head,k);
    LinkNode *node = to_delect->next;
    to_delect->value = node->value;
    to_delect->next = node->next;
    free(node);
    return;
}
//测试:
void DelectKTest(LinkNode *head)
{
    TITLE;
    printf("\n");
    LinkNodeInit(&head);
    LinkNodePushBack(&head, 'a');
    LinkNodePushBack(&head, 'b');
    LinkNodePushBack(&head, 'c');
    LinkNodePushBack(&head, 'd');
    Printf(head);
    printf("删除之后:\n");
    DelectK(&head, 4);
    Printf(head);

}

运行结果
这里写图片描述
其实我们是可以看到删除之后d节点的地址是和我们没删除之前的即将被删除节点的地址是相同的,这也侧面的映证了我们的移花接木大法!!

此移花接木大法对其他的删除呀,增加呀,不让我们遍历链表的有奇效
比如说让我们在指定元素之前插入一个元素不让我们遍历链表!!
我们可以这样
这里写图片描述
我想这个图应该就能看的比较清楚了吧
然后就是代码

//在无头单链表的一个节点之前插入一个节点(不能遍历链表)
void LinkNodePushFront(LinkNode **head, LinkNode *pos,LinkType value)
{
    //还是跟刚才一样的移花接木法!!

    if (head == NULL)
    {
        return;
    }
    if (*head == NULL)
    {
        //空链表的情况
        //即直接尾插
        LinkNode *new_node = LinkNodeCreat(value);
        return;
    }
    LinkNode *new_node = LinkNodeCreat(value);
    LinkNode *cur = pos;
    new_node->next = cur->next;
    new_node->value = cur->value;
    cur->value = value;
    cur->next = new_node;
}

这种移花接木大法我们一定要用的肥肠熟悉!!

猜你喜欢

转载自blog.csdn.net/qq_36767247/article/details/78917397