看到这个题我先想到的是之前做过链表面试题中的:查找链表的倒数第K个节点(要求只遍历一次链表),而删除的话就是另外一个面试题:删除链表的pos节点;另外一种就是在OJ下实现的方法。
相关的链表面试题:
C语言实现单链表面试题—基础篇
https://blog.csdn.net/qq_37941471/article/details/78033970
C语言实现单链表面试题—进阶
https://blog.csdn.net/qq_37941471/article/details/80437143
代码实现:
#pragma once
#include <stdio.h>
#include <stdlib.h>
#include <malloc.h>
#include <windows.h>
#include <assert.h>
typedef int DataType;
typedef struct ListNode
{
DataType data;//节点存放的数据
struct ListNode* next;//下一个节点
}ListNode;
ListNode* BuyNode(DataType x)//创建节点
{
ListNode* Node = (ListNode*)malloc(sizeof(ListNode));//开辟空间
Node->data = x;
Node->next = NULL;
return Node;
}
void PrintList(ListNode *plist)//打印链表
{
ListNode* cur = plist;
while (cur)
{
printf("%d->",cur->data);
cur = cur->next ;
}
printf("NULL\n");
}
void PushFront(ListNode **pplist,DataType x)//头插
{
assert(pplist);
//1. 链表为空
//2. 非空
if( *pplist == NULL )
{
*pplist = BuyNode(x);
}
else //非空
{
ListNode* Node = BuyNode(x);
Node->next = *pplist;
*pplist = Node;
}
}
void PopFront(ListNode **pplist)//头删
{
assert(pplist);
//1. 链表为空
//2. 一个节点
//3. 多节点
if( *pplist == NULL )
return;
else if ( (*pplist)->next == NULL )
{
free(*pplist);
*pplist = NULL;
}
else//多节点
{
ListNode* tmp = *pplist;
ListNode* Next = (*pplist)->next ;
*pplist = Next;
free(tmp);
}
}
void PopBack(ListNode **pplist)//尾删
{
assert(pplist);
//1. 链表为空
//2. 一个节点
//3. 多个节点
if( *pplist == NULL )
return;
else if( (*pplist)->next == NULL )
{
free(*pplist);//malloc free()
*pplist = NULL;
}
else//多节点
{
ListNode* prev = *pplist;
ListNode* cur = *pplist;
while( cur->next )
{
prev = cur;
cur = cur->next ;
}
free(cur);
cur = NULL;
prev->next = NULL;
}
}
void Erase(ListNode **pplist,ListNode *pos)//删除pos节点
{
assert(pplist&&pos);
//1. 头删
//2. 尾删
//3. 中间删
if( *pplist == pos )//头删
{
PopFront(pplist);
}
else if( pos->next == NULL ) //尾删
{
PopBack(pplist);
}
else //中间删
{
ListNode* prev = *pplist;
while( prev->next != pos )
{
prev = prev->next ;
}
prev->next = pos->next ;
free(pos);
pos = NULL;
}
}
ListNode* FindKNode(ListNode* plist,int k)
{
ListNode* slow = plist;
ListNode* fast = plist;
int count = k;
assert(plist);
if( plist == NULL || k <=0 )
return NULL;
//快指针先走n步,然后快慢指针一起走,等快指针走完,慢指针就是要找的节点
while( --count > 0){//n--走n步,--n走n-1步,而这走n-1步才是第n个节点
fast = fast->next;
}
while( fast->next ){
fast = fast->next;
slow = slow->next;
}
return slow;
}
void test()//删除链表倒数第K个节点
{
ListNode* list = NULL;
PushFront(&list,4);
PushFront(&list,3);
PushFront(&list,2);
PushFront(&list,1);
PrintList(list);
Erase(&list,FindKNode(list,2));//删除倒数第2个节点
PrintList(list);
}
int main()
{
test();
return 0;
}
OJ下实现:
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
ListNode *removeNthFromEnd(ListNode *head, int n) {
//相当于查找链表的倒数第n个节点,然后删掉pos位
//1. 查找链表的倒数第n个节点 用快慢指针
if( head == NULL || n <= 0 )
return NULL;
ListNode* slow = head;
ListNode* fast = head;
//快指针先走n步,然后快慢指针一起走,等快指针走完,慢指针就是要找的节点
while( --n > 0){//n--走n步,--n走n-1步,而这走n-1步才是第n个节点
fast = fast->next;
}
ListNode* prev = NULL;
while( fast->next ){
prev = slow;
fast = fast->next;
slow = slow->next;
}
//2. 删掉pos位,slow就是要删除的节点
if( slow == head ){//头删
head = head->next;
}
else{
prev->next = slow->next;
}
return head;
}
};
在VS下测试代码:
#pragma once
#include <stdio.h>
#include <stdlib.h>
#include <malloc.h>
#include <windows.h>
#include <assert.h>
typedef int DataType;
typedef struct ListNode
{
DataType data;//节点存放的数据
struct ListNode* next;//下一个节点
}ListNode;
ListNode* BuyNode(DataType x)//创建节点
{
ListNode* Node = (ListNode*)malloc(sizeof(ListNode));//开辟空间
Node->data = x;
Node->next = NULL;
return Node;
}
void PrintList(ListNode *plist)//打印链表
{
ListNode* cur = plist;
while (cur)
{
printf("%d->",cur->data);
cur = cur->next ;
}
printf("NULL\n");
}
void PushFront(ListNode **pplist,DataType x)//头插
{
assert(pplist);
//1. 链表为空
//2. 非空
if( *pplist == NULL )
{
*pplist = BuyNode(x);
}
else //非空
{
ListNode* Node = BuyNode(x);
Node->next = *pplist;
*pplist = Node;
}
}
ListNode* removeNthFromEnd(ListNode *head, int n) {
//相当于查找链表的倒数第n个节点,然后删掉pos位
//1. 查找链表的倒数第n个节点 用快慢指针
ListNode* prev = NULL;
ListNode* slow = head;
ListNode* fast = head;
if( head == NULL || n <= 0 )
return NULL;
//快指针先走n步,然后快慢指针一起走,等快指针走完,慢指针就是要找的节点
while( --n > 0){//n--走n步,--n走n-1步,而这走n-1步才是第n个节点
fast = fast->next;
}
while( fast->next ){
prev = slow;
fast = fast->next;
slow = slow->next;
}
//2. 删掉pos位,slow就是要删除的节点
if( slow == head ){//头删
head = head->next;
}
else{
prev->next = slow->next;
}
return head;
}
void test()//删除链表倒数第K个节点
{
ListNode* list = NULL;
PushFront(&list,4);
PushFront(&list,3);
PushFront(&list,2);
PushFront(&list,1);
PrintList(list);
list = removeNthFromEnd(list,2);
PrintList(list);//删除倒数第2个节点
}
int main()
{
test();
return 0;
}
“`