首先我们先创建一个链表,链表的创建在上一个链表的逆序打印中已经说过了,链接如下
http://blog.youkuaiyun.com/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;
}
这种移花接木大法我们一定要用的肥肠熟悉!!