• 数据结构与算法之美读书笔记6


    一、理解指针或引用的含义

    1.含义:将某个变量(对象)赋值给指针(引用),实际上就是就是将这个变量(对象)的地址赋值给指针(引用)。

    2.示例:

    p—>next = q; 表示p节点的后继指针存储了q节点的内存地址

    p—>next = p—>next—>next; 表示p节点的后继指针存储了p节点的下下个节点的内存地址。

    二、警惕指针丢失和内存泄漏(单链表)

    1.插入节点

            在节点a和节点b之间插入节点x,b是a的下一节点,,p指针指向节点a,则造成指针丢失和内存泄漏的代码:p—>next = x;x—>next = p—>next; 显然这会导致x节点的后继指针指向自身。
    正确的写法是2句代码交换顺序,即:x—>next = p—>next; p—>next = x;

    2.删除节点

            在节点a和节点b之间删除节点b,b是a的下一节点,p指针指向节点a:p—>next = p—>next—>next;

    三、利用“哨兵”简化实现难度

    1.什么是“哨兵”?

            链表中的“哨兵”节点是解决边界问题的,不参与业务逻辑。如果我们引入“哨兵”节点,则不管链表是否为空,head指针都会指向这个“哨兵”节点。我们把这种有“哨兵”节点的链表称为带头链表,或者头结点。相反,没有“哨兵”节点的链表就称为不带头链表或不带头结点的链表。

    2.未引入“哨兵”的情况

    1. //如果在p节点后插入一个节点,只需2行代码即可搞定:
    2. new_node—>next = p—>next;
    3. p—>next = new_node;
    4. //但,若向空链表中插入一个节点,则代码如下:
    5. if(head == null){
    6. head = new_node;
    7. }
    8. //如果要删除节点p的后继节点,只需1行代码即可搞定:
    9. p—>next = p—>next—>next;
    10. //但,若是删除链表的最有一个节点(链表中只剩下这个节点),则代码如下:
    11. if(head—>next == null){
    12. head = null;
    13. }


    从上面的情况可以看出,针对链表的插入、删除操作,需要对插入第一个节点和删除最后一个节点的情况进行特殊处理。这样代码就会显得很繁琐,所以引入“哨兵”节点来解决这个问题。

    3.引入“哨兵”的情况

    “哨兵”节点不存储数据,无论链表是否为空,head指针都会指向它,作为链表的头结点始终存在。这样,插入第一个节点和插入其他节点,删除最后一个节点和删除其他节点都可以统一为相同的代码实现逻辑了。很方便!

    四、重点留意边界条件处理

    经常用来检查链表是否正确的边界4个边界条件:

    1.如果链表为空时,代码是否能正常工作?

    2.如果链表只包含一个节点时,代码是否能正常工作?

    3.如果链表只包含两个节点时,代码是否能正常工作?

    4.代码逻辑在处理头尾节点时是否能正常工作?

    五、举例画图,辅助思考

    数形结合!

    六、多写多练,没有捷径

    拿出我大一上学期写的陈年代码举例😊

    常见的链表操作:

    链表遍历

    1. #include
    2. #include
    3. struct node
    4. {
    5. int num;
    6. struct node * next;
    7. };
    8. struct node * creat(int n)
    9. {
    10. struct node * head,*q,*p;
    11. head=(struct node *)malloc(sizeof(struct node));
    12. head->next=NULL;
    13. p=head;
    14. char s[1000];
    15. int i=0;
    16. scanf("%s",s);
    17. while(n--)
    18. {
    19. q=(struct node *)malloc(sizeof(struct node));
    20. q->num=s[i++]-'0';
    21. q->next=NULL;
    22. p->next=q;
    23. p=q;
    24. }
    25. return head;
    26. }
    27. int main()
    28. {
    29. int t,n;
    30. scanf("%d",&t);
    31. while(t--)
    32. {
    33. int sum=0;
    34. struct node *list1,*list2,*p,*q;
    35. scanf("%d",&n);
    36. list1=creat(n);
    37. list2=creat(n);
    38. p=list1->next;
    39. q=list2->next;
    40. while(n--)
    41. {
    42. //printf("%d %d\n",p->num,q->num);
    43. if(p->num == q->num)
    44. sum++;
    45. p=p->next;
    46. q=q->next;
    47. }
    48. printf("%d\n",sum);
    49. }
    50. return 0;
    51. }

    链表插入

    1. #include
    2. #include
    3. struct node
    4. {
    5. int num;
    6. struct node * next;
    7. };
    8. struct node * creat(int n)
    9. {
    10. int data;
    11. struct node * head,*p,*q;
    12. head = (struct node*)malloc(sizeof(struct node));
    13. head -> next=NULL;
    14. p=head;
    15. while(n--)
    16. {
    17. scanf("%d",&data);
    18. q = (struct node*)malloc(sizeof(struct node));
    19. q -> num = data;
    20. q -> next = NULL;
    21. p -> next = q;
    22. p=q;
    23. }
    24. return head;
    25. }
    26. void in(struct node * head,int data)
    27. {
    28. struct node * newNode =(struct node *)malloc(sizeof(struct node));
    29. newNode->num =data;
    30. newNode->next=NULL;
    31. struct node * Move=head->next;
    32. if(data <= Move->next->num)
    33. {
    34. newNode->next=Move->next;
    35. Move->next=newNode;
    36. }
    37. else
    38. {
    39. while(Move != NULL)
    40. {
    41. if(data>Move->num&&datanext->num)
    42. {
    43. newNode->next=Move->next;
    44. Move->next=newNode;
    45. break;
    46. }
    47. Move=Move->next;
    48. if(Move->next==NULL&&data>Move->num)
    49. {
    50. Move->next=newNode;
    51. break;
    52. }
    53. }
    54. }
    55. }
    56. void print(struct node * head)
    57. {
    58. struct node * pMove;
    59. pMove=(struct node *)malloc(sizeof(struct node));
    60. pMove=head->next->next;
    61. while(pMove!=NULL)
    62. {
    63. printf("%d ",pMove->num);
    64. pMove=pMove->next;
    65. }
    66. printf("\n");
    67. }
    68. int main()
    69. {
    70. int n,dataa;
    71. struct node * list;
    72. scanf("%d",&n);
    73. list=creat(n);
    74. dataa=list->next->num;
    75. //printf("%d",data);
    76. in(list,dataa);
    77. print(list);
    78. return 0;
    79. }

    链表查找

    1. #include
    2. #include
    3. struct node
    4. {
    5. int num;
    6. struct node * next;
    7. };
    8. struct node * creat(int n)
    9. {
    10. int data;
    11. struct node * head,*p,*q;
    12. head = (struct node*)malloc(sizeof(struct node));
    13. head -> next=NULL;
    14. p=head;
    15. while(n--)
    16. {
    17. scanf("%d",&data);
    18. q = (struct node*)malloc(sizeof(struct node));
    19. q -> num = data;
    20. q -> next = NULL;
    21. p -> next = q;
    22. p=q;
    23. }
    24. return head;
    25. }
    26. void fun(struct node * head)
    27. struct node * Move;
    28. Move=(struct node*)malloc(sizeof(struct node));
    29. Move=head->next;
    30. int min=Move->num;
    31. while(Move!=NULL)
    32. {
    33. if(min>Move->num)
    34. {
    35. min=Move->num;
    36. }
    37. Move=Move->next;
    38. }
    39. Move=head->next;
    40. if(min == Move->num)
    41. return 0;
    42. else
    43. {
    44. struct node * p;
    45. p=(struct node*)malloc(sizeof(struct node));
    46. while(Move!=NULL)
    47. {
    48. if(Move->next->num == min)
    49. {
    50. p=Move->next;
    51. Move->next=Move->next->next;
    52. p->next=head->next;
    53. head->next=p;
    54. break;
    55. }
    56. Move=Move->next;
    57. }
    58. }
    59. }
    60. void print(struct node * head)
    61. {
    62. struct node * pMove;
    63. pMove=(struct node *)malloc(sizeof(struct node));
    64. pMove=head->next;
    65. while(pMove!=NULL)
    66. {
    67. printf("%d ",pMove->num);
    68. pMove=pMove->next;
    69. }
    70. printf("\n");
    71. }
    72. int main()
    73. {
    74. int n,dataa;
    75. struct node * list;
    76. scanf("%d",&n);
    77. list=creat(n);
    78. fun(list);
    79. print(list);
    80. return 0;
    81. }

    链表排列

    1. #include
    2. #include
    3. struct node
    4. {
    5. int num;
    6. struct node * next;
    7. };
    8. struct node * creat(int n)
    9. {
    10. struct node * head,*p,*q;
    11. head=(struct node *)malloc(sizeof(struct node));
    12. head->next=NULL;
    13. p=head;
    14. while(n--)
    15. {
    16. q=(struct node *)malloc(sizeof(struct node));
    17. scanf("%d",&q->num);
    18. q->next=NULL;
    19. p->next=q;
    20. p=q;
    21. }
    22. return head;
    23. }
    24. void fun(struct node * head)
    25. {
    26. int temp;
    27. struct node *i,*j;
    28. for(i=head->next;i!=NULL;i=i->next)
    29. {
    30. for(j=i->next;j!=NULL;j=j->next)
    31. {
    32. if(j->num < i->num)
    33. {
    34. temp = j->num;
    35. j->num = i->num;
    36. i->num = temp;
    37. }
    38. }
    39. }
    40. }
    41. void print(struct node * head)
    42. {
    43. struct node * pMove;
    44. pMove=(struct node *)malloc(sizeof(struct node));
    45. pMove=head->next;
    46. while(pMove!=NULL)
    47. {
    48. printf("%d ",pMove->num);
    49. pMove=pMove->next;
    50. }
    51. printf("\n");
    52. }
    53. int main()
    54. {
    55. struct node * list;
    56. int n;
    57. scanf("%d",&n);
    58. getchar();
    59. list=creat(n);
    60. fun(list);
    61. print(list);
    62. return 0;
    63. }

    链表去重排序

    1. #include
    2. #include
    3. struct node
    4. {
    5. int num;
    6. struct node * next;
    7. };
    8. struct node *creat(int n)
    9. {
    10. struct node * head,*p,*q;
    11. head=(struct node *)malloc(sizeof(struct node));
    12. head->next=NULL;
    13. p=head;
    14. while(n--)
    15. {
    16. q=(struct node *)malloc(sizeof(struct node));
    17. scanf("%d",&q->num);
    18. q->next=NULL;
    19. p->next=q;
    20. p=q;
    21. }
    22. return head;
    23. }
    24. void print(struct node * head)
    25. {
    26. struct node * pMove;
    27. pMove=(struct node *)malloc(sizeof(struct node));
    28. pMove=head->next;
    29. while(pMove!=NULL)
    30. {
    31. printf("%d ",pMove->num);
    32. pMove=pMove->next;
    33. }
    34. printf("\n");
    35. }
    36. void delet(struct node * head,int data)
    37. {
    38. struct node * posNode=head->next;
    39. struct node * posNodeFront=head;
    40. while(posNode!=NULL)
    41. {
    42. if(posNode -> num == data)
    43. {
    44. posNodeFront->next =posNode->next;
    45. free(posNode);
    46. posNode=posNodeFront->next;
    47. }
    48. else
    49. {
    50. posNodeFront=posNode;
    51. posNode=posNode->next;
    52. }
    53. }
    54. }
    55. void fun(struct node * head1,struct node * head2)
    56. {
    57. int sign[1001]= {0},si[1001]= {0};
    58. struct node *Move1,*Move2;
    59. Move1=head1->next;
    60. Move2=head2->next;
    61. while(Move1!=NULL)
    62. {
    63. sign[Move1->num]++;
    64. Move1=Move1->next;
    65. }
    66. while(Move2!=NULL)
    67. {
    68. si[Move2->num]++;
    69. Move2=Move2->next;
    70. }
    71. /*
    72. Move1=head1;
    73. Move2=head2;
    74. */
    75. for(int i=0; i<1001; i++)
    76. {
    77. if(sign[i]>=1&&si[i]>=1)
    78. {
    79. for(int j=0; j
    80. {
    81. delet(head1,i);
    82. delet(head2,i);
    83. }
    84. }
    85. }
    86. //print(head1);print(head2);
    87. }
    88. void fun2(struct node * head)
    89. {
    90. int temp;
    91. struct node *i,*j;
    92. for(i=head->next; i!=NULL; i=i->next)
    93. {
    94. for(j=i->next; j!=NULL; j=j->next)
    95. {
    96. if(j->num < i->num)
    97. {
    98. temp = j->num;
    99. j->num = i->num;
    100. i->num = temp;
    101. }
    102. }
    103. }
    104. }
    105. void fun3(struct node * head)
    106. {
    107. int temp;
    108. struct node *i,*j;
    109. for(i=head->next; i!=NULL; i=i->next)
    110. {
    111. for(j=i->next; j!=NULL; j=j->next)
    112. {
    113. if(j->num > i->num)
    114. {
    115. temp = j->num;
    116. j->num = i->num;
    117. i->num = temp;
    118. }
    119. }
    120. }
    121. }
    122. int main()
    123. {
    124. int m,n;
    125. while(~scanf("%d%d",&m,&n))
    126. {
    127. struct node *list1,*list2;
    128. list1=creat(m);
    129. list2=creat(n);
    130. //print(list1);print(list2);
    131. fun2(list1);
    132. fun3(list2);
    133. //print(list1);print(list2);
    134. fun(list1,list2);
    135. print(list1);
    136. print(list2);
    137. }
    138. return 0;
    139. }

    单链表反转

    1. 思路就是两个两个的循环,设置当前位置,父亲位置,和儿子位置,并随着循环改变位置,两个两个的改变箭头方向,画个图就能很形象的理解解题步骤。
    2. /**
    3. * Definition for singly-linked list.
    4. * struct ListNode {
    5. * int val;
    6. * ListNode *next;
    7. * ListNode() : val(0), next(nullptr) {}
    8. * ListNode(int x) : val(x), next(nullptr) {}
    9. * ListNode(int x, ListNode *next) : val(x), next(next) {}
    10. * };
    11. */
    12. class Solution {
    13. public:
    14. ListNode* reverseList(ListNode* head) {
    15. struct ListNode *p,*q;
    16. p=head;
    17. q=nullptr;
    18. while(p){
    19. ListNode *t=p->next;
    20. p->next=q;
    21. q=p;
    22. p=t;
    23. }
    24. return q;
    25. }
    26. };

    链表中环的检测

    1. * Definition for singly-linked list.
    2. * struct ListNode {
    3. * int val;
    4. * ListNode *next;
    5. * ListNode(int x) : val(x), next(NULL) {}
    6. * };
    7. */
    8. class Solution {
    9. public:
    10. mapint> m;
    11. ListNode *detectCycle(ListNode *head) {
    12. while(head){
    13. if(m[head]!=NULL) return head;//如果该点被记录过,则该点为入口点
    14. m[head]=1;
    15. head=head->next;
    16. }
    17. return NULL;
    18. }
    19. };
    20. ```
    21. 利用map标记遍历过的结点即可。在遍历中先进行判断。

    两个有序链表合并

    1. * Definition for singly-linked list.
    2. * struct ListNode {
    3. * int val;
    4. * ListNode *next;
    5. * ListNode() : val(0), next(nullptr) {}
    6. * ListNode(int x) : val(x), next(nullptr) {}
    7. * ListNode(int x, ListNode *next) : val(x), next(next) {}
    8. * };
    9. */
    10. class Solution {
    11. public:
    12. ListNode* mergeTwoLists(ListNode* l1, ListNode* l2) {
    13. ListNode Head(0);//创建新空链表
    14. ListNode *p= &Head;//让p代表head
    15. while(l1 && l2){//当l1和l2都没到结尾时
    16. if(l1->val > l2->val) swap(l1,l2);
    17. p->next=l1;
    18. l1=l1->next;
    19. p=p->next;
    20. }
    21. p->next =l1?l1:l2;
    22. return Head.next;
    23. }
    24. };

    删除链表倒数第n个节点

    1. 删除链表的倒数第N个结点,即链表的第len-n个结点。
    2. 我们设置快慢指针。让快指针先走n步,再让快慢指针一起走。
    3. tip:为了防止空指针问题,我们应该设置一个头结点,它的next为head。
    4. 创建: ListNode anspre=new ListNode(-1);
    5. 然后令快慢指针等于该带有头结点的链表。
    6. fast=anspre;
    7. slow=anspre;
    8. 初始时:
    9. 🎈快指针所在结点处:n-1
    10. 🎈慢指针所在结点处:0-1
    11. 直到快指针为空
    12. ✨len-1
    13. ✨len-n-1(此时,慢指针位置是倒数第n个结点的前一个结点,可以通过slow-》next=slow-》next-》next达到删除结点的目的)
    14. ```
    15. class Solution {
    16. public:
    17. ListNode* removeNthFromEnd(ListNode* head, int n) {
    18. ListNode *fast,*slow;
    19. ListNode *anspre=new ListNode(-1);
    20. anspre->next=head;
    21. if(head==NULL)return {};
    22. fast=anspre;
    23. slow=anspre;
    24. for(int i=0;i<=n;i++){
    25. fast=fast->next;
    26. }
    27. while(fast!=NULL){
    28. fast=fast->next;
    29. slow=slow->next;
    30. }
    31. slow->next=slow->next->next;
    32. return anspre->next;
    33. }
    34. };

    求链表的中间节点

    快慢指针,一个一次走两步,一个一次走一步,快指针到达末尾时,慢指针在中间结点处。

    合并链表并排序

    1. #include
    2. #include
    3. struct node
    4. {
    5. int num;
    6. struct node * next;
    7. };
    8. struct node * creat(int n)
    9. {
    10. struct node * head,*p,*q;
    11. head=(struct node *)malloc(sizeof(struct node));
    12. head->next=NULL;
    13. p=head;
    14. while(n--)
    15. {
    16. q=(struct node *)malloc(sizeof(struct node));
    17. scanf("%d",&q->num);
    18. q->next=NULL;
    19. p->next=q;
    20. p=q;
    21. }
    22. return head;
    23. }
    24. void print(struct node * head)
    25. {
    26. struct node * pMove;
    27. pMove=(struct node *)malloc(sizeof(struct node));
    28. pMove=head->next;
    29. while(pMove!=NULL)
    30. {
    31. printf("%d ",pMove->num);
    32. pMove=pMove->next;
    33. }
    34. printf("\n");
    35. }
    36. struct node * fun(struct node * head1,struct node * head2)
    37. {
    38. struct node * Move;
    39. Move=head1->next;
    40. while(Move->next!=NULL)
    41. {
    42. Move=Move->next;
    43. }
    44. Move->next=head2->next;
    45. Move=head1;
    46. return Move;
    47. }
    48. void funnn(struct node * head)
    49. {
    50. int temp;
    51. struct node *i,*j;
    52. for(i=head->next;i!=NULL;i=i->next)
    53. {
    54. for(j=i->next;j!=NULL;j=j->next)
    55. {
    56. if(j->num > i->num)
    57. {
    58. temp = j->num;
    59. j->num = i->num;
    60. i->num = temp;
    61. }
    62. }
    63. }
    64. }
    65. int main()
    66. {
    67. int m,n;
    68. struct node *mlist,*nlist,*list;
    69. scanf("%d",&m);
    70. mlist=creat(m);
    71. scanf("%d",&n);
    72. nlist=creat(n);
    73. list=fun(mlist,nlist);
    74. funnn(list);
    75. print(list);
    76. return 0;
    77. }

  • 相关阅读:
    Windows系统下使用tar命令,压缩文件与解压缩文件并指定路径
    黑客帝国:随机字母生成器
    《儿童教育心理学》读书笔记
    Vue框架(三)------quasar组件使用及文件上传
    如何撰写综述性论文
    Arcgis如何制作专题地图中漂亮的饼图
    Docker安装可视化管理器Portainer
    MySQL学习笔记(1)——简单操作
    uniapp:录音权限检查,录音功能
    华为HCIP认证用处大吗?
  • 原文地址:https://blog.csdn.net/m0_62742402/article/details/126582557