当前位置:   article > 正文

leetCode 707---单链表的创建及相关方法实现(C语言版)_mylinkedlist* obj = mylinkedlistcreate();obj是什么意思

mylinkedlist* obj = mylinkedlistcreate();obj是什么意思

题目描述:

使用C语言实现单链表,单链表中的节点应该具有两个属性:val 和 next。val 是当前节点的值,next 是指向下一个节点的指针/引用。如果要使用双向链表,则还需要一个属性 prev 以指示链表中的上一个节点。假设链表中的所有节点都是 0-index 的。

在链表类中实现这些功能:

get(index):获取链表中第 index 个节点的值。如果索引无效,则返回-1。
addAtHead(val):在链表的第一个元素之前添加一个值为 val 的节点。插入后,新节点将成为链表的第一个节点。
addAtTail(val):将值为 val 的节点追加到链表的最后一个元素。
addAtIndex(index,val):在链表中的第 index 个节点之前添加值为 val  的节点。如果 index 等于链表的长度,则该节点将附加到链表的末尾。如果 index 大于链表长度,则不会插入节点。如果index小于0,则在头部插入节点。
deleteAtIndex(index):如果索引 index 有效,则删除链表中的第 index 个节点

思考设计:

首先要确定是否设置头节点,本题使用头节点。我一直对头节点和头指针这两个东西很迷,这几天我再单独写篇文章来和大家交流一下。

  • 节点设计

单链表的节点包括数据域和指针域,代码如下:

  1. /**
  2. * 构造节点
  3. */
  4. typedef struct
  5. {
  6. int val; //数据域,存储有我们需要使用的数据
  7. struct MylinkedList *next; //指针域,存储有指向下一个节点的指针
  8. } MyLinkedList;
  • 方法实现

1、myLinkedListCreate():构造函数,初始化链表

众所周知,我们使用头结点来代表整个列表。下面的obj就是头节点,可以代替整个链表。

  1. /**
  2. * 构造一个有头结点的空链表
  3. */
  4. MyLinkedList *myLinkedListCreate()
  5. {
  6. MyLinkedList *obj = (MyLinkedList *)malloc(sizeof(MyLinkedList)); //在内存空间中开辟一块和节点数据结构大小一样的内存空间,构造头节点
  7. obj->next = NULL; //头节点的指针域置空
  8. return obj;
  9. }

2、myLinkedListGet(MyLinkedList *obj, int index),获取链表中第 index 个节点的值。如果索引无效,则返回-1

链表中第0个节点指的是头节点后面那一个,其他的以此类推。注意index取负数、链表为空、index大于链表节点数的情况

  1. /**
  2. * 获取链表中第 index 个节点的值。如果索引无效,则返回-1
  3. */
  4. int myLinkedListGet(MyLinkedList *obj, int index)
  5. {
  6. int counter = 0; //计数器
  7. int value = 0;
  8. MyLinkedList *p = obj->next; //定义一个指针,并指向头节点的下一个节点,即第0个节点
  9. while (p && counter < index) //当P存在而且没有遍历到第index节点时继续移动指针,直到counter=index时跳出循环;若P为空也会跳出循环,此时counter不一定等于index
  10. {
  11. p = p->next;
  12. counter++;
  13. }
  14. if (!p || counter > index) //跳出while循环后counter<=index,若P为空说明查询节点的index大于链表节点数,返回-1;若用户输入的index是一个负数,虽然P不为空,但这种情况应该返回-1
  15. {
  16. return -1;
  17. }
  18. else
  19. {
  20. value = p->val;
  21. return value;
  22. }
  23. }

3、myLinkedListAddAtHead(MyLinkedList *obj, int val):头插法的实现,就是在头节点和第0个节点间插入一个新节点

  1. /**
  2. * 头插法的实现
  3. * 在头节点和第0个节点间插入一个新节点
  4. */
  5. void myLinkedListAddAtHead(MyLinkedList *obj, int val)
  6. {
  7. MyLinkedList *p = obj; //将头节点赋值给指针P
  8. MyLinkedList *head = (MyLinkedList *)malloc(sizeof(MyLinkedList)); //新建一个节点
  9. head->val = val; //给新节点数据域赋值
  10. head->next = p->next; //让新节点指向头节点的下一个节点
  11. p->next = head; //让头节点指向新节点完成插入
  12. }

4、myLinkedListAddAtTail(MyLinkedList *obj, int val): 尾插法的实现,在链表最后的节点后再插入新的节点

  1. /**
  2. * 尾插法的实现
  3. * 在链表最后的节点后再插入新的节点
  4. */
  5. void myLinkedListAddAtTail(MyLinkedList *obj, int val)
  6. {
  7. MyLinkedList *tail = (MyLinkedList *)malloc(sizeof(MyLinkedList));
  8. tail->val = val;
  9. tail->next = NULL; //初始化新节点,指针域需要置空
  10. MyLinkedList *node = obj;
  11. while (node->next) //从头节点开始遍历链表,当节点的指针域为空时跳出循环,表明找到链表尾节点
  12. {
  13. node = node->next;
  14. }
  15. node->next = tail; //新节点成为尾节点
  16. }

5、myLinkedListAddAtIndex(MyLinkedList *obj, int index, int val):在第index节点前插入新节点,若index为负数则插入到链表头部,若index超出链表长度则不插入;这里也要注意链表为空,index越界、index为负数的情况。

  1. /**
  2. * 在第index节点前插入新节点,若index为负数则插入到链表头部,若index超出链表长度则不插入
  3. */
  4. void myLinkedListAddAtIndex(MyLinkedList *obj, int index, int val)
  5. {
  6. MyLinkedList *insertedNode = (MyLinkedList *)malloc(sizeof(MyLinkedList));
  7. insertedNode->val = val;
  8. MyLinkedList *node = obj;
  9. int counter = 0;
  10. if (index < counter) // index为负数时插入到链表头部
  11. {
  12. insertedNode->next = node->next;
  13. node->next = insertedNode;
  14. }
  15. while (node && counter < index) //counter等于index时,node的下标应该是index -1,这里和myLinkedListGet方法不同。差别在于当counter是0时,本方法node是头节点,但在myLinkedListGet方法中P是第0个节点
  16. {
  17. node = node->next;
  18. counter++;
  19. }
  20. if (!node || counter > index)
  21. {
  22. return -1;
  23. }
  24. insertedNode->next = node->next;
  25. node->next = insertedNode;
  26. }

6、myLinkedListDeleteAtIndex(MyLinkedList *obj, int index):若index有效的话则删除第index个节点,注意index为负数、链表为空的情况

  1. /**
  2. * 若index有效的话则删除第index个节点
  3. * 删除不同于插入。插入时,涉及第index、index-1两个节点,若第index-1个节点是尾节点,虽然第index个节点不存在,但是依然能插入;
  4. * 删除时,涉及第index-1、index、index+1三个节点,如果第index-1个节点为尾节点,则第index+1个节点即下面的temNode->next不存在,不能完成指针的赋值
  5. * 所以在判断循环时,判断条件是 node->next,这样才能保证第index+1个节点即下面的temNode->next存在(特殊条件就是为NULL)
  6. */
  7. void myLinkedListDeleteAtIndex(MyLinkedList *obj, int index)
  8. {
  9. MyLinkedList *node = obj;
  10. int counter = 0;
  11. while (node->next && counter < index) //找到第index-1 个节点,但需要保证第index+1个节点即下面的temNode->next存在(特殊条件就是为NULL)
  12. {
  13. node = node->next;
  14. counter++;
  15. }
  16. if (!(node->next) || counter > index)
  17. {
  18. return -1;
  19. }
  20. else
  21. {
  22. MyLinkedList *temNode = (MyLinkedList *)malloc(sizeof(MyLinkedList));
  23. temNode = node->next;
  24. node->next = temNode->next;
  25. free(temNode);
  26. }
  27. }

7、myLinkedListFree(MyLinkedList *obj):整表删除,从头节点开始删除

  1. /**
  2. * 整表删除
  3. */
  4. void myLinkedListFree(MyLinkedList *obj)
  5. {
  6. MyLinkedList *node = obj->next; //这里node指向的是头节点的下一个节点,与前面有所不同。整表删除时要将头节点以外的所有节点删除,保留头节点
  7. MyLinkedList *temNode = (MyLinkedList *)malloc(sizeof(MyLinkedList));
  8. while (node) //判断除当前结点是否为空,不为空时删除此节点
  9. {
  10. temNode = node->next; //删除时要保留被删除节点的下一个节点
  11. free(node);
  12. node = temNode;
  13. }
  14. obj->next = NULL;
  15. }

8、主函数: 大家可以自己试一试,看看结果对不对。

  1. int main()
  2. {
  3. MyLinkedList *obj = myLinkedListCreate();
  4. int param_1 = myLinkedListGet(obj, 0);
  5. printf("%d\n", param_1);
  6. myLinkedListAddAtHead(obj, 0);
  7. int param_2 = myLinkedListGet(obj, 0);
  8. printf("%d\n", param_2);
  9. myLinkedListAddAtTail(obj, 1);
  10. int param_3 = myLinkedListGet(obj, 0);
  11. printf("%d\n", param_3);
  12. myLinkedListAddAtIndex(obj, 1, 2);
  13. int param_4 = myLinkedListGet(obj, 1);
  14. printf("%d\n", param_4);
  15. myLinkedListDeleteAtIndex(obj, 2); //02
  16. myLinkedListFree(obj);
  17. int param_5 = myLinkedListGet(obj, 0);
  18. printf("%d\n", param_5);
  19. }
  • 所有代码:

  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. /**
  4. * 构造节点
  5. */
  6. typedef struct
  7. {
  8. int val; //数据域,存储有我们需要使用的数据
  9. struct MylinkedList *next; //指针域,存储有指向下一个节点的指针
  10. } MyLinkedList;
  11. /**
  12. * 构造一个有头结点的空链表
  13. */
  14. MyLinkedList *myLinkedListCreate()
  15. {
  16. MyLinkedList *obj = (MyLinkedList *)malloc(sizeof(MyLinkedList)); //在内存空间中开辟一块和节点数据结构大小一样的内存空间,构造头节点
  17. obj->next = NULL; //头节点的指针域置空
  18. return obj;
  19. }
  20. /**
  21. * 获取链表中第 index 个节点的值。如果索引无效,则返回-1
  22. */
  23. int myLinkedListGet(MyLinkedList *obj, int index)
  24. {
  25. int counter = 0; //计数器
  26. int value = 0;
  27. MyLinkedList *p = obj->next; //定义一个指针,并指向头节点的下一个节点,即第0个节点
  28. while (p && counter < index) //当P存在而且没有遍历到第index节点时继续移动指针,直到counter=index时跳出循环;若P为空也会跳出循环,此时counter不一定等于index
  29. {
  30. p = p->next;
  31. counter++;
  32. }
  33. if (!p || counter > index) //跳出while循环后counter<=index,若P为空说明查询节点的index大于链表节点数,返回-1;若用户输入的index是一个负数,虽然P不为空,但这种情况应该返回-1
  34. {
  35. return -1;
  36. }
  37. else
  38. {
  39. value = p->val;
  40. return value;
  41. }
  42. }
  43. /**
  44. * 头插法的实现
  45. * 在头节点和第0个节点间插入一个新节点
  46. */
  47. void myLinkedListAddAtHead(MyLinkedList *obj, int val)
  48. {
  49. MyLinkedList *p = obj; //将头节点赋值给指针P
  50. MyLinkedList *head = (MyLinkedList *)malloc(sizeof(MyLinkedList)); //新建一个节点
  51. head->val = val; //给新节点数据域赋值
  52. head->next = p->next; //让新节点指向头节点的下一个节点
  53. p->next = head; //让头节点指向新节点完成插入
  54. }
  55. /**
  56. * 尾插法的实现
  57. * 在链表最后的节点后再插入新的节点
  58. */
  59. void myLinkedListAddAtTail(MyLinkedList *obj, int val)
  60. {
  61. MyLinkedList *tail = (MyLinkedList *)malloc(sizeof(MyLinkedList));
  62. tail->val = val;
  63. tail->next = NULL; //初始化新节点,指针域需要置空
  64. MyLinkedList *node = obj;
  65. while (node->next) //从头节点开始遍历链表,当节点的指针域为空时跳出循环,表明找到链表尾节点
  66. {
  67. node = node->next;
  68. }
  69. node->next = tail; //新节点成为尾节点
  70. }
  71. /**
  72. * 在第index节点前插入新节点,若index为负数则插入到链表头部,若index超出链表长度则不插入
  73. */
  74. void myLinkedListAddAtIndex(MyLinkedList *obj, int index, int val)
  75. {
  76. MyLinkedList *insertedNode = (MyLinkedList *)malloc(sizeof(MyLinkedList));
  77. insertedNode->val = val;
  78. MyLinkedList *node = obj;
  79. int counter = 0;
  80. if (index < counter) // index为负数时插入到链表头部
  81. {
  82. insertedNode->next = node->next;
  83. node->next = insertedNode;
  84. }
  85. while (node && counter < index) //counter等于index时,node的下标应该是index -1,这里和myLinkedListGet方法不同。差别在于当counter是0时,本方法node是头节点,但在myLinkedListGet方法中P是第0个节点
  86. {
  87. node = node->next;
  88. counter++;
  89. }
  90. if (!node || counter > index)
  91. {
  92. return -1;
  93. }
  94. insertedNode->next = node->next;
  95. node->next = insertedNode;
  96. }
  97. /**
  98. * 若index有效的话则删除第index个节点
  99. * 删除不同于插入。插入时,涉及第index、index-1两个节点,若第index-1个节点是尾节点,虽然第index个节点不存在,但是依然能插入;
  100. * 删除时,涉及第index-1、index、index+1三个节点,如果第index-1个节点为尾节点,则第index+1个节点即下面的temNode->next不存在,不能完成指针的赋值
  101. * 所以在判断循环时,判断条件是 node->next,这样才能保证第index+1个节点即下面的temNode->next存在(特殊条件就是为NULL)
  102. */
  103. void myLinkedListDeleteAtIndex(MyLinkedList *obj, int index)
  104. {
  105. MyLinkedList *node = obj;
  106. int counter = 0;
  107. while (node->next && counter < index) //找到第index-1 个节点,但需要保证第index+1个节点即下面的temNode->next存在(特殊条件就是为NULL)
  108. {
  109. node = node->next;
  110. counter++;
  111. }
  112. if (!(node->next) || counter > index)
  113. {
  114. return -1;
  115. }
  116. else
  117. {
  118. MyLinkedList *temNode = (MyLinkedList *)malloc(sizeof(MyLinkedList));
  119. temNode = node->next;
  120. node->next = temNode->next;
  121. free(temNode);
  122. }
  123. }
  124. /**
  125. * 整表删除
  126. */
  127. void myLinkedListFree(MyLinkedList *obj)
  128. {
  129. MyLinkedList *node = obj->next; //这里node指向的是头节点的下一个节点,与前面有所不同。整表删除时要将头节点以外的所有节点删除,保留头节点
  130. MyLinkedList *temNode = (MyLinkedList *)malloc(sizeof(MyLinkedList));
  131. while (node) //判断除当前结点是否为空,不为空时删除此节点
  132. {
  133. temNode = node->next; //删除时要保留被删除节点的下一个节点
  134. free(node);
  135. node = temNode;
  136. }
  137. obj->next = NULL;
  138. }
  139. /**
  140. * Your MyLinkedList struct will be instantiated and called as such:
  141. * MyLinkedList* obj = myLinkedListCreate();
  142. * int param_1 = myLinkedListGet(obj, index);
  143. * myLinkedListAddAtHead(obj, val);
  144. * myLinkedListAddAtTail(obj, val);
  145. * myLinkedListAddAtIndex(obj, index, val);
  146. * myLinkedListDeleteAtIndex(obj, index);
  147. * myLinkedListFree(obj);
  148. */
  149. int main()
  150. {
  151. MyLinkedList *obj = myLinkedListCreate();
  152. int param_1 = myLinkedListGet(obj, 0);
  153. printf("%d\n", param_1); //-1
  154. myLinkedListAddAtHead(obj, 0);
  155. int param_2 = myLinkedListGet(obj, 0);
  156. printf("%d\n", param_2); //0
  157. myLinkedListAddAtTail(obj, 1); // 0 1
  158. int param_3 = myLinkedListGet(obj, 0);
  159. printf("%d\n", param_3); //0
  160. myLinkedListAddAtIndex(obj, 1, 2); //021
  161. int param_4 = myLinkedListGet(obj, 1);
  162. printf("%d\n", param_4); //2
  163. myLinkedListDeleteAtIndex(obj, 2); //02
  164. myLinkedListFree(obj);
  165. int param_5 = myLinkedListGet(obj, 0);
  166. printf("%d\n", param_5); //-1
  167. }

 

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

闽ICP备14008679号