1.移除链表元素
看过题之后,我们可以想到两种方法。
思路一
我们可以依次遍历原链表,将原链表中结点值为val的结点依次释放掉。具体过程如下
我们使用pcur指针进行遍历原链表,用prev存储pcur的前一个结点,next存储pcur的后一个结点,若pcur->val == val ,则需要释放pcur,此时就需要next来存储pcur的下一个结点的地址。最后链表遍历完如图
思路二
创建一个新的链表,依次遍历原链表,找到结点值不为val的结点,依次尾插到新链表中。
具体过程如下:
从单链表的第一个结点开始遍历,如结点值不为val,则放入新的单链表中,pcur后移,newTail后移
当遇到结点值为val的时候,只有pcur后移,newTail不动,最后可以得到不含每一个结点值都不为val的新链表
按照这个思路,我们可以写出如下代码
运行过后,会出现最后一个原链表中值为val的结点为删除
解决:链表每个结点都有数据域和指针域组成,当5加入新链表中时,此时这个结点的指针域还是指向下一个结点,若下一个结点值为val就会造成最后一个结点值为val的结点为释放。
改成后如下:
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* struct ListNode *next;
* };
*/
typedef struct ListNode ListNode;
struct ListNode* removeElements(struct ListNode* head, int val) {
//创建空链表
ListNode* newHead,*newTail;
newHead = newTail = NULL;
//遍历原链表
ListNode* pcur = head;
while(pcur)
{
//找不为val的结点,尾插到新链表中
if(pcur->val != val)
{
//链表为空
if(newHead == NULL)
{
newHead = newTail = pcur;
}
//链表不为空
else
{
newTail->next = pcur;
newTail = newTail->next;
}
}
pcur = pcur->next;
}
if(newTail)
newTail->next = NULL;
return newHead;
}
2.反转链表
思路一
我们可以直接反转原链表的指向,使之直接反转成功
具体过程如下图
代码实现如下
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* struct ListNode *next;
* };
*/
struct ListNode* reverseList(struct ListNode* head) {
struct ListNode* tail = NULL;
struct ListNode* pcur = head;
while(pcur)
{
struct ListNode* tmp = pcur->next;
pcur->next = tail;
tail = pcur;
pcur = tmp;
}
return tail;
}
思路二
使用三个指针完成反转
首先将n2指向n1,随后n1移到n2,n2移到n3,n3移到他的下一个结点,不断循环
最后,如图
代码实现如下
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* struct ListNode *next;
* };
*/
struct ListNode* reverseList(struct ListNode* head) {
//链表为空
if(head == NULL)
return head;
//创建三个指针
struct ListNode* n1,*n2,*n3;
n1 = NULL, n2 = head, n3 = n2->next;
//开始循环
while(n2)
{
n2->next = n1;
n1 = n2;
n2 = n3;
if(n3)
n3 = n3->next;
}
return n1;
}
3.链表的中间结点
思路一
最容易想到的就是先遍历一遍原链表得到链表的长度,之后再遍历到链表的中间结点即可
代码实现如下
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* struct ListNode *next;
* };
*/
struct ListNode* middleNode(struct ListNode* head){
struct ListNode* p = head;
int len = 0;
int k = 0;
while(p)
{
p = p -> next;
len++;
}
p = head;
while(k < len / 2)
{
k++;
p = p -> next;
}
return p;
}
思路二 快慢指针
这里使用快慢双指针可以更妙的解决此题
定义两个指针,一个为slow,一个为fast
slow每次走一步,fast每次走两步,结点数为单数时,当fast->next == NULL时,slow指向的刚好为中间结点
结点数为偶数时 如图
代码实现如下
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* struct ListNode *next;
* };
*/
struct ListNode* middleNode(struct ListNode* head) {
//定义快慢指针
struct ListNode* slow = head;
struct ListNode* fast = head;
//循环开始
while(fast && fast->next)
{
slow = slow->next;
fast = fast->next->next;
}
//退出循环时,slow刚好指向中间结点
return slow;
}
4.合并两个有序链表
思路:创建一个新链表,遍历两个原链表,依次将结点值小的结点尾插到新链表中
代码实现如下:
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* struct ListNode *next;
* };
*/
typedef struct ListNode ListNode;
struct ListNode* mergeTwoLists(struct ListNode* list1, struct ListNode* list2) {
//判断是否为空链表
if(list1 == NULL)
return list2;
if(list2 == NULL)
return list1;
ListNode* l1 = list1;
ListNode* l2 = list2;
//创建新链表
ListNode* newHead,*newTail;
newHead = newTail = NULL;
while(l1 && l2)
{
if(l1->val < l2->val)
{
//尾插l1
if(newHead == NULL)
{
newHead = newTail = l1;
} else {
newTail->next = l1;
newTail = newTail->next;
}
l1 = l1->next;
}else {
//尾插l2
if(newHead == NULL)
{
newHead = newTail = l2;
}else {
newTail->next = l2;
newTail = newTail->next;
}
l2 = l2->next;
}
}
if(l1)
{
newTail->next = l1;
}
if(l2)
{
newTail->next = l2;
}
return newHead;
}
观察代码发现,有很多重复且类似的代码,这是由于新链表存在空链表和非空链表两种情况,为了解决这个问题我们可以直接使新链表为非空链表,用malloc函数为其分配空间。
代码实现如下:
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* struct ListNode *next;
* };
*/
typedef struct ListNode ListNode;
struct ListNode* mergeTwoLists(struct ListNode* list1, struct ListNode* list2) {
//判断是否为空链表
if(list1 == NULL)
return list2;
if(list2 == NULL)
return list1;
ListNode* l1 = list1;
ListNode* l2 = list2;
//创建新链表
ListNode* newHead,*newTail;
newHead = newTail = (ListNode*)malloc(sizeof(ListNode));
while(l1 && l2)
{
if(l1->val < l2->val)
{
//尾插l1
newTail->next = l1;
newTail = newTail->next;
l1 = l1->next;
}else {
//尾插l2
newTail->next = l2;
newTail = newTail->next;
l2 = l2->next;
}
}
if(l1)
{
newTail->next = l1;
}
if(l2)
{
newTail->next = l2;
}
//释放内存
ListNode* ret = newHead->next;
free(newHead);
newHead = NULL;
return ret;
}