目录
一、移除链表元素
1.思路
2.注意
3.解题
二、反转链表
思路1:三指针翻转法
(1)注意
(2)解题
思路2:头插法
(1)注意
(2)解题
三、链表的中间结点
思路1:快慢指针法
(1)注意
(2)解题
思路2:两次遍历法
(1)注意
(2)解题
四、返回倒数第k个结点
1.思路:快慢指针法
2.注意
3.解题
五、合并两个有序链表
1.思路
2.注意
3.解题
六、链表分割
1.思路
2.注意
3.解题
七、写在最后
一、移除链表元素
1.思路
创建一个新链表,用指针pcur遍历原链表,对每个结点的数据进行判断,如果等于val则不做处理,如果不相等则尾插到新链表中。
2.注意
(1)原链表可能为空,那么返回NULL;
(2)最后记得将newTail指向NULL,在此之前需要判断newTail不能为空,因为如果为空,不存在newTail->next。
3.解题
typedef struct ListNode ListNode;
struct ListNode*removeElements(ListNode* head , int val)
{
if(head == NULL)//传入的该链表可能为空
{
return NULL;
}
//创建一个新链表
ListNode* newHead = NULL;
ListNode* newTail = NULL;
//创建一个遍历该链表的指针
ListNode* pcur = head;
while(pcur)
{
if(pcur->val != val)
{
如果不等于val,尾插到新链表中
if(newHead == NULL)
{
newHead = newTail = pcur;
}
else
{
newTail->next = pcur;
newTail = newTail->next;
}
}
pcur = pcur->next;
}
//将尾结点指向NULL
if(newTail)
{
newTail->next = NULL;
}
return newHead;
}
二、反转链表
思路1:三指针翻转法
创建三个指针n1,n2,n3分别指向NULL、head和head->next,改变指向,将n2指向n1,进行循环遍历原链表。
(1)注意
①原链表可能为空,那么返回NULL;
②n1为反转链表的头结点。
(2)解题
typedef struct ListNode ListNode;
ListNode* reverseList(ListNode* head)
{
if(head == NULL)
{
return NULL;
}
ListNode *n1,*n2,*n3;
n1 = NULL;
n2 = head;
n3 = head->next;
while(n2)
{
n2->next = n1;
n1 = n2;
n2 = n3;
if(n3)
{
n3 = n3->next;
}
}
return n1;
}
思路2:头插法
创建新链表,通过pcur遍历原链表,将数据头插到原链表中,得到反转链表。
(1)注意
①创建新指针保存pcur的下一个结点,否则pcur无法找到原位置。
(2)解题
typedef struct ListNode ListNode;
struct ListNode* reverseList(struct ListNode* head)
{
//新链表
ListNode* newhead = NULL;
ListNode* pcur = head;
while(pcur)
{
//保存当前结点的下一个结点
ListNode* next = pcur->next;
//头插新结点
pcur->next = newhead;
//更新头结点
newhead = pcur;
//移动到下一个结点
pcur = next;
}
return newhead;
}
三、链表的中间结点
思路1:快慢指针法
初始时,快指针和慢指针都指向头结点。快指针一次经过两个结点,慢指针一次经过一个节点,当快指针走到链表结尾时,慢指针指向链表中间。
(1)注意
①分别分析一下链表长度为奇数和偶数时的情况(具体在代码中);
②最后返回指向链表中间的指针slow。
(2)解题
typedef struct ListNode ListNode;
ListNode* middleNode(ListNode* head)
{
ListNode* fast = head;
ListNode* slow = head;
while(fast && fast->next)
//由于fast->next要取next,因此不能为空
//且不能交换顺序:否则链表长度为偶数的情况不能实现
{
fast = fast->next->next;
slow = slow->next;
}
return slow;
}
思路2:两次遍历法
第一次遍历得到链表的长度len,由此得到半个长度mid,第二次遍历得到中间结点。
(1)注意
①mid为len/2+1(len为int类型);
②在第二个while循环中,pcur初始为head,每进行一次循环pcur就指向下一个结点。因此,当mid写为len/2,那么在第二次循环中就顺利可实现。
(2)解题
typedef struct ListNode ListNode;
struct ListNode* middleNode(struct ListNode* head)
{
ListNode* pcur = head;
int len = 0;
//遍历得到链表的长度len
while(pcur)
{
len++;
pcur = pcur->next;
}
int mid = len / 2 ;
//让pcur遍历链表,得到中间结点
pcur = head;
while(mid--)
{
pcur = pcur->next;
}
return pcur;
}
四、返回倒数第k个结点
1.思路:快慢指针法
初始时,快指针和慢指针都指向头结点。快指针先走k步,然后快、慢指针同时走,当快指针走到链表末尾时,慢指针走到倒数第k个结点。
2.注意
①返回的是倒数第k个结点保存的数据,而非指针;
②若k大于链表长度,fast会为空,此时返回NULL。
3.解题
typedef struct ListNode ListNode;
int kthToLast(struct ListNode* head, int k)
{
ListNode* fast = head;
ListNode* slow = head;
while(k--)
{
if(fast)
{
fast = fast->next;
}
else
{
return NULL;
}
}
while(fast)
{
fast = fast->next;
slow = slow->next;
}
return slow->val;
}
五、合并两个有序链表
1.思路
创建两个指针分别遍历两个链表,比较两个指针指向结点存储的数据,创建新链表,将小的数据存储在新链表中。
2.注意
①使用malloc创建非空链表,在尾插数据时不再需要判断newHead是否为NULL,避免代码冗余;
②当n1和n2其中一个为空会跳出循环,说明遍历完成。此时需要将另外一个尾插到新链表中。
③不必再令newTail指向空,因为此时尾结点不是newTail,而是后续尾插的n1或n2。
3.解题
typedef struct ListNode ListNode;
struct ListNode* mergeTwoLists(struct ListNode* list1, struct ListNode* list2)
{
if(list1 == NULL)
{
return list2;
}
if(list2 == NULL)
{
return list1;
}
//创建新链表
ListNode* newHead, *newTail;
newHead = newTail = (ListNode*)malloc(sizeof(ListNode));
ListNode* n1 = list1;
ListNode* n2 = list2;
while(n1 && n2)
{
if(n1->val < n2->val)
{
newTail->next = n1;
newTail = newTail->next;
n1 = n1->next;
}
else
{
newTail->next = n2;
newTail = newTail->next;
n2 = n2->next;
}
}
if(n1)
{
newTail->next = n1;
}
if(n2)
{
newTail->next = n2;
}
ListNode* ret = newHead->next;
free(newHead);
newHead = NULL;
return ret;
}
六、链表分割
1.思路
创建两个新链表(大于x和小于x的分别存储在两个链表中),用pcur遍历原链表,最后将大链表尾插在小链表后。
2.注意
①使用malloc创建两个非空链表,分别存储大于和小于x的数据。
3.解题
typedef struct ListNode ListNode;
ListNode* partition(ListNode* pHead, int x)
{
//大链表
ListNode* greaterHead, *greaterTail;
greaterHead = greaterTail = (ListNode*)malloc(sizeof(ListNode));
//小链表
ListNode* lessHead,*lessTail;
lessHead = lessTail = (ListNode*)malloc(sizeof(ListNode));
ListNode* pcur = pHead;
while(pcur)
{
if(pcur->val < x)
{
lessTail->next = pcur;
lessTail = lessTail->next;
}
else
{
greaterTail->next = pcur;
greaterTail = greaterTail->next;
}
pcur = pcur->next;
}
lessTail->next = greaterHead->next;
greaterTail->next = NULL;
ListNode* ret = lessHead->next;
free(lessHead);
free(greaterHead);
lessHead = greaterHead = NULL;
return ret;
}
七、写在最后
一起加油,敬请期待“单链表OJ题(下)”~