前言:既然前面我们已经学习了单链表的理论知识,不实践一下怎么能行呢。
千里之行,始于键盘下哦~
准备好接受头脑风暴了嘛
以下截图内容均来自力扣。
1.移除链表元素
思路一:在原链表的基础上直接更改,遍历链表,将不满足的节点删除
代码实现:
struct ListNode* removeElements(struct ListNode* head, int val) {
//先判断链表是否为空
if (head == NULL)
{
return NULL;
}
// 遍历原链表,将值为 val 的节点释放掉
// 先判断要删除的节点是否为头结点
struct ListNode* curr = head;
struct ListNode* prev = NULL;
while (curr!= NULL)
{
if (curr->val == val)
{
// 头删
if (prev == NULL)
{
head = curr->next;
free(curr);
curr = head;
}
else
{
// 中间或尾删
struct ListNode* del = curr;
prev->next = curr->next;
free(del);
curr = prev->next;
}
}
else
{
prev = curr;
curr = curr->next;
}
}
return head;
}
思路二:在开辟一个新的链表,将值不为val的节点放在新的链表中。最后返回新链表的头节点。
struct ListNode* removeElements(struct ListNode* head, int val) {
//创建一个新的空链表
struct ListNode* NewHead,*NewTail;
NewHead = NewTail=NULL;
//遍历原链表
struct ListNode* pcur = head;
while(pcur)
{
if(pcur->val!=val)
{
if(NewHead==NULL)
{
//链表为空
NewHead = NewTail = pcur;
}
else
{
//链表不为空
//尾插
NewTail->next=pcur;
NewTail=pcur;
}
}
pcur=pcur->next;
}
if(NewTail)
{
NewTail->next=NULL;
}
return NewHead;
}
2.反转链表
思路一:我们可以创建一个新的链表,将原链表的数据以头插(在开头位置即链表额开头)的方式插入进新的链表。
代码实现:
struct ListNode* reverseList(struct ListNode* head) {
struct ListNode* newhead = NULL;
struct ListNode* pcur = head;
while (pcur)
{
struct ListNode* tmp = pcur->next;
pcur->next = newhead;
newhead = pcur;
pcur = tmp;
}
return newhead;
}
也可以这样写,同一种思路的不同表现形式。
struct ListNode* reverseList(struct ListNode* head) {
if (!head) {
// 处理空链表的情况
return NULL;
}
// 创建一个新的链表,采用头插法插入数据
struct ListNode* newhead = NULL;
struct ListNode* pcur = head;
while (pcur) {
struct ListNode* tmp=pcur;
pcur=pcur->next;
if (newhead == NULL) {
// 链表为空
newhead = tmp;
newhead->next=NULL;
} else {
// 链表不为空
// 头插
tmp->next = newhead;
newhead = tmp;
}
// pcur = pcur->next;
}
return newhead;
}
思路二:创建三个指针变量n1,n2,n3.(这个思路非常不好想,但是它的实现可以说是非常的新颖,再一次打开我们的认知)
具体思路:
代码实现:
struct ListNode* reverseList(struct ListNode* head) {
if(head==NULL)
{
return NULL;
}
//创建三个指针变量
struct ListNode* n1,*n2,*n3;
n1=NULL;
n2=head;
n3=n2->next;
while(n2)
{
n2->next=n1;
n1=n2;
n2=n3;
if(n3)
n3=n2->next;
}
return n1;
}
3.链表的中间节点
思路一:我们可以遍历原链表,count进行计数,最后返回count/2的节点的next指针。
代码实现:
struct ListNode* middleNode(struct ListNode* head) {
if(head==NULL)
{
return NULL;
}
//遍历原链表,count计算,直接返回count/2的next节点
int count = 0;
struct ListNode* pcur = head;
while(pcur)
{
count++;
pcur=pcur->next;
}
int mid=count/2;
struct ListNode* tmp = head;
for(int i = 0;i<mid;i++)
{
tmp=tmp->next;
}
return tmp;
}
思路二:我们采用快慢指针的方式去做。慢指针每走一步,快指针就走两步。2slow=fast.
这个思路也是非常nice的哦。
代码实现:
struct ListNode* middleNode(struct ListNode* head) {
if(head==NULL)
{
return NULL;
}
//快慢指针
struct ListNode*slow,*fast;
slow=fast=head;
while(fast && fast->next)//两者不能交换位置
{
slow=slow->next;
fast=fast->next->next;
}
return slow;
}
上面的注释中提到不能交换位置,是为什么呢?
这个可以自己下去画图试一下哦。
4.合并两个有序链表
思路:开辟一个新的链表,比较原来两个链表的大小,将小的以头插的方式插入进新链表中,最后返回新链表的第一个有效节点。
代码实现:
struct ListNode* mergeTwoLists(struct ListNode* list1, struct ListNode* list2) {
if(list1==NULL)
{
return list2;
}
if(list2==NULL)
{
return list1;
}
//创建一个新的链表,比较两个原来的链表,谁小谁放在前面
//在创建新链表的时候,可以创建一个哨兵位,避免判断链表是否为空
struct ListNode* newhead,*newtail;
newhead=newtail=(struct ListNode*)malloc(sizeof(struct ListNode));
struct ListNode* l1=list1;
struct ListNode* l2=list2;
while(l1 && l2)//有一个为NULL就比较结束了
{
if(l1->val<l2->val)
{
//将list1拿下来
//尾插
newtail->next=l1;
newtail=l1;
l1=l1->next;
}
else
{
//将list2拿下来尾插
newtail->next=l2;
newtail=l2;
l2=l2->next;
}
}
//出了循环,说明l1为空,或者l2为空
if(l1)//说明l2为空
{
newtail->next=l1;
}
if(l2)//说明l1为空
{
newtail->next=l2;
}
//开辟的空间要手动释放
struct ListNode* ret=newhead->next;
free(newhead);
newhead=NULL;
return ret;
}
结束了
下次还记得来哦~