深圳幻海软件技术有限公司 欢迎您!

【数据结构】单链表OJ题(一)

2023-09-05

🔥博客主页:小王又困了📚系列专栏:数据结构🌟人之为学,不日近则日退 ❤️感谢大家点赞👍收藏⭐评论✍️目录一、移除链表元素💡方法一:💡方法二:二、链表的中间节点💡方法一:三、链表中倒数第k个结点💡方法一:四、反转链表💡方法一:💡方法二:五、合并两个有序链表💡方法一:&n

🔥博客主页:小王又困了

📚系列专栏:数据结构

🌟人之为学,不日近则日退 

❤️感谢大家点赞👍收藏⭐评论✍️


目录

一、移除链表元素

💡方法一:

💡方法二:

二、链表的中间节点

💡方法一:

三、链表中倒数第k个结点

💡方法一:

四、反转链表

💡方法一:

💡方法二:

五、合并两个有序链表

💡方法一: 


🗒️前言:

在上一期中我们给大家介绍了单链表,也了解了单链表的实现。接下来就让我们进入实践,练习一些经典题目,让我们对单链表的理解更加深入。

一、移除链表元素

题目:

💡方法一:

我们使用两个指针遍历数组,遇到与 val 相同的数据域,就删除这个节点。我们在思考问题时要想全面,当要删除头节点时,常规方法就无法实现,对于删除头节点要做单独处理。

🍩常规删除: 

 🍩头节点删除

  1. struct ListNode* removeElements(struct ListNode* head, int val)
  2. {
  3. struct ListNode* prev=NULL;
  4. struct ListNode* cur=head;
  5. while(cur!=NULL)
  6. {
  7. //删除
  8. if(val==cur->val)
  9. {
  10. //头删
  11. if(cur==head)
  12. {
  13. head=cur->next;
  14. free(cur);
  15. cur=head;
  16. }
  17. //常规
  18. else
  19. {
  20. prev->next=cur->next;
  21. free(cur);
  22. cur=prev->next;
  23. }
  24. }
  25. //遍历
  26. else
  27. {
  28. prev=cur;
  29. cur=cur->next;
  30. }
  31. }
  32. return head;
  33. }

💡方法二:

我们通过遍历,把节点的数据域不等于val的节点尾接到新的链表中。我们要考虑第一个节点是不是要删除的。最后一个节点的指针域置空要放在循环结束后,判断tail是否为空指针。

  1. struct ListNode* removeElements(struct ListNode* head, int val)
  2. {
  3. struct ListNode* newhead=NULL;
  4. struct ListNode* tail=NULL;
  5. struct ListNode* cur=head;
  6. while(cur)
  7. {
  8. if(cur->next==val)
  9. {
  10. //删除
  11. struct ListNode* del=cur;
  12. cur=cur->next;
  13. free(del);
  14. }
  15. else
  16. {
  17. //尾插
  18. if(tail==NULL)
  19. {
  20. newhead=tail=cur;
  21. //tail=cur;
  22. }
  23. else
  24. {
  25. tail->next=cur;
  26. tail=tail->next;
  27. }
  28. cur=cur->next;
  29. }
  30. }
  31. if(tail)
  32. {
  33. tail->next=NULL;
  34. }
  35. return newhead;
  36. }

二、链表的中间节点

题目:

💡方法一:

我们可以定义两个指针,快指针一次走两步,慢指针一次走一步,当快指针走到结尾时,慢指针正好走了一半,这样我们就可以找到中间节点。

  1. struct ListNode* middleNode(struct ListNode* head)
  2. {
  3. struct ListNode* fast=head;
  4. struct ListNode* slow=head;
  5. while(fast&&fast->next)
  6. {
  7. fast=fast->next->next;
  8. slow=slow->next;
  9. }
  10. return slow;
  11. }

三、链表中倒数第k个结点

题目:

💡方法一:

我们可以参考上一题的方法,同样定义快慢指针,想让快指针走k步,然后在同时走,走到fast为空指针就找了倒数第k个节点。有可能链表没有k个节点,所以我们要加入判断。

  1. struct ListNode* FindKthToTail(struct ListNode* pListHead, int k )
  2. {
  3. struct ListNode* fast=pListHead;
  4. struct ListNode* slow=pListHead;
  5. while(k--)
  6. {
  7. //链表没有k步长
  8. if(fast==NULL)
  9. {
  10. return NULL;
  11. }
  12. fast=fast->next;
  13. }
  14. while(fast!=NULL)
  15. {
  16. fast=fast->next;
  17. slow=slow->next;
  18. }
  19. return slow;
  20. }

四、反转链表

题目:

💡方法一:

我们定义三个指针n1,n2,n3,来改变节点链接的顺序。将头节点变为尾节点,当n2为空指针时,n1就为链表的头节点,只需返回n1就可以。两个指针倒方向,一个指针保持下一个。

  1. struct ListNode* reverseList(struct ListNode* head)
  2. {
  3. struct ListNode* n1=NULL;
  4. struct ListNode* n2=head;
  5. struct ListNode* n3;
  6. if(n2)
  7. {
  8. n3=n2->next;
  9. }
  10. while(n2)
  11. {
  12. n2->next=n1;
  13. //往后走
  14. n1=n2;
  15. n2=n3;
  16. if(n3)
  17. {
  18. n3=n3->next;
  19. }
  20. }
  21. return n1;
  22. }

💡方法二:

将链表的节点一个一个拿下来,进行头插。这里要注意赋值的顺序。

  1. struct ListNode* reverseList(struct ListNode* head)
  2. {
  3. struct ListNode* cur=head;
  4. struct ListNode* newnode=NULL;
  5. while(cur)
  6. {
  7. //保存节点
  8. struct ListNode* next=cur->next;
  9. //头插
  10. cur->next=newnode;
  11. newnode=cur;
  12. cur=next;
  13. }
  14. return newnode;
  15. }

五、合并两个有序链表

题目:

💡方法一: 

我们创建一个带哨兵位的链表,这样在尾插时就不用判断是否是第一个节点,可以提高效率。要记住在最后要将哨兵位的空间释放。

  1. struct ListNode* mergeTwoLists(struct ListNode* list1, struct ListNode* list2)
  2. {
  3. if(list1==NULL)
  4. {
  5. return list2;
  6. }
  7. if(list2==NULL)
  8. {
  9. return list1;
  10. }
  11. struct ListNode* head=NULL;
  12. struct ListNode* tail=NULL;
  13. //创建一个哨兵位
  14. head=tail=(struct ListNode*)malloc(sizeof(struct ListNode));
  15. while(list1&&list2)
  16. {
  17. if(list1->val<list2->val)
  18. {
  19. tail->next=list1;
  20. tail=tail->next;
  21. list1=list1->next;
  22. }
  23. else
  24. {
  25. tail->next=list2;
  26. tail=tail->next;
  27. list2=list2->next;
  28. }
  29. }
  30. if(list1)
  31. {
  32. tail->next=list1;
  33. }
  34. if(list2)
  35. {
  36. tail->next=list2;
  37. }
  38. struct ListNode* del=head;
  39. head=head->next;
  40. free(del);
  41. return head;
  42. }

本次的内容到这里就结束啦。希望大家阅读完可以有所收获,同时也感谢各位读者三连支持。文章有问题可以在评论区留言,博主一定认真认真修改,以后写出更好的文章。你们的支持就是博主最大的动力。

文章知识点与官方知识档案匹配,可进一步学习相关知识
算法技能树首页概览51123 人正在系统学习中