当前位置:   article > 正文

c语言:链表经典算法oj题

c语言:链表经典算法oj题

目录

问题1:移除链表元素

 方法1:递归删除

 方法2:连续尾插

问题2:链表的中间节点 

方法:快慢指针 

问题3:反转链表

方法: 三指针解法

问题4:合并两个有序链表

方法:比较大小,插入新链表,注意空指针等细节。 

问题5:环形链表的约瑟夫问题

​编辑

方法:环形链表


问题1:移除链表元素

题目链接:OJ链接

题目描述: 

 方法1:递归删除

情况1:不存在值的情况,返回一个空链表

情况2:头节点要删除,删除完继续返回新的头节点进行判断

情况3:不是情况1,2,不动原来的值,继续下一个节点的判断

最后返回头节点

  1. struct ListNode* removeElements(struct ListNode* head, int val)
  2. {
  3. // 不存在值的情况,链表为空
  4. if(head == NULL)
  5. {
  6. return NULL;
  7. }
  8. // 头节点的值是要删除的值的情况
  9. if(head->val == val)
  10. {
  11. // 新头节点指向下一个节点
  12. struct ListNode* newhead = head->next;
  13. // 释放原头节点的内存
  14. free(head);
  15. // 头节点赋值为新的头节点
  16. head = newhead;
  17. // 递归调用函数,去除剩余节点中的值为val的节点
  18. head = removeElements(head, val);
  19. }
  20. else
  21. {
  22. // 递归调用函数,去除剩余节点中的值为val的节点
  23. head->next = removeElements(head->next, val);
  24. }
  25. return head;
  26. }

 方法2:连续尾插

先头尾节点置为空,然后传入pcur值,没有pcur值说明停止循环

当不是删除值时

链表为空,头尾节点都指向当前的节点。

链表不为空时,尾插pcur。

是删除值时,pcur走向下一个节点

当尾节点是要删除的值时(且要存在),pcur就不要往下走了,newtail->next=NULL.

  1. typedef struct ListNode ListNode;
  2. struct ListNode* removeElements(struct ListNode* head, int val)
  3. {
  4. // 新链表的头节点和尾节点
  5. ListNode* newhead, * newtail;
  6. newhead = newtail = NULL;
  7. // 当前节点指针
  8. ListNode* pcur = head;
  9. // 遍历原链表
  10. while(pcur)
  11. {
  12. // 如果当前节点的值不等于要删除的值
  13. if(pcur->val != val)
  14. {
  15. // 如果新链表的尾节点为空,表示新链表为空
  16. if(newtail == NULL)
  17. {
  18. // 新链表的头尾节点都指向当前节点
  19. newhead = newtail = pcur;
  20. }
  21. else
  22. {
  23. // 将当前节点添加到新链表的尾部
  24. newtail->next = pcur;
  25. newtail = newtail->next;
  26. }
  27. }
  28. // 指针指向下一个节点
  29. pcur = pcur->next;
  30. }
  31. // 如果新链表的尾节点不为空,将尾节点的next指针置为NULL
  32. if(newtail)
  33. {
  34. newtail->next = NULL;
  35. }
  36. // 返回新链表的头节点
  37. return newhead;
  38. }


问题2:链表的中间节点 

 题目链接:OJ链接

方法:快慢指针 

慢指针每次走一步,快指针每次走两步

奇数时,快指针的下一个节点指向NULL时停止,返回慢指针此时位置

偶数时,快指针的节点指向NULL时停止,返回慢指针此时的位置

  1. typedef struct ListNode ListNode; // 定义结构体指针类型 ListNode
  2. struct ListNode* middleNode(struct ListNode* head)
  3. {
  4. ListNode* slow, * fast; // 定义慢指针 slow 和快指针 fast
  5. slow = fast = head; // 将慢指针和快指针都指向链表头部
  6. while (fast && fast->next) // 当快指针和快指针的下一个节点都不为空时
  7. {
  8. slow = slow->next; // 慢指针向后移动一步
  9. fast = fast->next->next; // 快指针向后移动两步
  10. }
  11. return slow; // 返回慢指针,即链表的中间节点
  12. }

注意:不要写成while(fast->next&&fast),因为如果fast为空指针,fast->next便不存在了。会报错


问题3:反转链表

题目链接:OJ链接

方法: 三指针解法

创建三个指针

n1指向为空(NULL),n2指向第一个节点,n3指向下一个节点

如果n2不为空,n2节点的指针由指向n3改为指向n1

n1=n2,n2=n3,n3=n3->next

以此类推,直到n2不为空。

  1. typedef struct ListNode ListNode; // 定义一个别名为ListNode的结构体
  2. struct ListNode* reverseList(struct ListNode* head)
  3. {
  4. if(head==NULL) // 如果头节点为空,则直接返回头节点
  5. return head;
  6. ListNode* n1, *n2, *n3; // 定义三个指针n1、n2、n3
  7. n1 = NULL; // n1指向NULL,表示反转链表的最后一个节点
  8. n2 = head; // n2指向头节点
  9. n3 = head->next; // n3指向头节点的下一个节点
  10. while(n2)
  11. {
  12. n2->next = n1; // 将n2的next指针指向n1,实现反转
  13. n1 = n2; // 将n2赋值给n1,更新n1的位置
  14. n2 = n3; // 将n3赋值给n2,更新n2的位置
  15. if(n3)
  16. n3 = n3->next; // 如果n3不为空,则将n3指向n3的下一个节点
  17. }
  18. return n1; // 返回反转后的链表的头节点
  19. }

注意,n3为空就不用往下走了。 


问题4:合并两个有序链表

题目链接:OJ链接

 

方法:比较大小,插入新链表,注意空指针等细节。 

  1. typedef struct ListNode ListNode;
  2. struct ListNode* mergeTwoLists(struct ListNode* list1, struct ListNode* list2)
  3. {
  4. if(list1==NULL)
  5. return list2;
  6. if(list2==NULL)
  7. return list1;
  8. ListNode*n1,*n2;
  9. n1=list1,n2=list2;
  10. ListNode*newhead,*newtail;
  11. newhead=newtail=NULL;
  12. while(n1&&n2)
  13. {
  14. if(n1->val<n2->val)
  15. {
  16. if(newhead==NULL)
  17. {
  18. // 如果新链表头为空,则将当前节点设为新链表头和新链表尾
  19. newhead=newtail=n1;
  20. }
  21. else
  22. {
  23. // 如果新链表头不为空,则将当前节点接在新链表尾后,并更新新链表尾
  24. newtail->next=n1;
  25. newtail=newtail->next;
  26. }
  27. n1=n1->next;
  28. }
  29. else
  30. {
  31. if(newhead==NULL)
  32. {
  33. // 如果新链表头为空,则将当前节点设为新链表头和新链表尾
  34. newhead=newtail=n2;
  35. }
  36. else
  37. {
  38. // 如果新链表头不为空,则将当前节点接在新链表尾后,并更新新链表尾
  39. newtail->next=n2;
  40. newtail=newtail->next;
  41. }
  42. n2=n2->next;
  43. }
  44. }
  45. if(n1)
  46. {
  47. // 如果list1还有剩余节点,则将剩余节点接在新链表尾后,并更新新链表尾
  48. newtail->next=n1;
  49. newtail=newtail->next;
  50. }
  51. if(n2)
  52. {
  53. // 如果list2还有剩余节点,则将剩余节点接在新链表尾后,并更新新链表尾
  54. newtail->next=n2;
  55. newtail=newtail->next;
  56. }
  57. return newhead;
  58. }


 

 

问题5:环形链表的约瑟夫问题

题目链接:环形链表的约瑟夫问题_牛客题霸_牛客网

方法:环形链表

创建一个环形链表,每个人对应一个节点,将对应的离开人数的节点释放掉,并且改边释放节点前后指针的指向,直到剩一人为止

  1. typedef struct ListNode ListNode; // 定义一个 ListNode 结构体的别名为 ListNode
  2. ListNode* BuyNode(int x) // 定义一个函数 BuyNode,用于创建一个新的节点并返回指向该节点的指针
  3. {
  4. ListNode*newnode=(ListNode*)malloc(sizeof(ListNode)); // 分配内存空间
  5. newnode->val=x; // 设置节点的值为 x
  6. newnode->next=NULL; // 下一个节点指针为空
  7. return newnode; // 返回指向新节点的指针
  8. }
  9. // 创建不带头环形链表
  10. ListNode*ctreatelist(int n)
  11. {
  12. ListNode*phead=BuyNode(1); // 创建头节点
  13. ListNode*ptail=phead; // 尾节点指向头节点
  14. for(int i=2;i<=n;i++) // 循环创建 n 个节点
  15. {
  16. ptail->next=BuyNode(i); // 创建新节点并连接到尾节点的下一个
  17. ptail=ptail->next; // 尾节点指向新创建的节点
  18. }
  19. ptail->next=phead; // 尾节点指向头节点,形成环形链表
  20. return phead; // 返回头节点指针
  21. }
  22. // 约瑟夫环问题
  23. int ysf(int n, int m ) {
  24. ListNode*head=ctreatelist(n); // 创建包含 n 个节点的环形链表
  25. ListNode*pcur=head; // 当前节点指针指向头节点
  26. ListNode*prev=NULL; // 前一个节点指针初始化为空
  27. int count=1; // 计数器初始化为 1
  28. while(pcur->next!=pcur) // 当链表中还有多于一个节点时循环
  29. {
  30. if(count==m) // 当计数器等于 m 时
  31. {
  32. // 删除当前节点
  33. prev->next=pcur->next; // 前一个节点的指针指向当前节点的下一个节点
  34. free(pcur); // 释放当前节点的内存空间
  35. pcur=prev->next; // 当前节点指针指向下一个节点
  36. count=1; // 计数器重置为 1
  37. }
  38. else
  39. {
  40. prev=pcur; // 前一个节点指针指向当前节点
  41. pcur=pcur->next; // 当前节点指针指向下一个节点
  42. count++; // 计数器加 1
  43. }
  44. }
  45. return pcur->val; // 返回最后剩下的节点的值
  46. }

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/知新_RL/article/detail/640474
推荐阅读
相关标签
  

闽ICP备14008679号