2d270e5a4677f33c4340e988c810aa1270727a512064ee07681c7d1622ab0a4a40e372b8809c5e01767b0ae30f007ff4336d982e65d489166c3b47f594eda3 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262
  1. /**
  2. * Refactored implementation of LinkedList (part of javascript-algorithms project) by Github users:
  3. * mgechev, AndriiHeonia, Microfed and Jakeh (part of javascript-algorithms project - all project contributors
  4. * at repository website)
  5. *
  6. * Link to repository: https://github.com/mgechev/javascript-algorithms
  7. */
  8. /**
  9. * Linked list node.
  10. *
  11. * @class NodeStructure
  12. * @util
  13. */
  14. class NodeStructure {
  15. constructor(data) {
  16. /**
  17. * Data of the node.
  18. * @member {Object}
  19. */
  20. this.data = data;
  21. /**
  22. * Next node.
  23. * @member {NodeStructure}
  24. */
  25. this.next = null;
  26. /**
  27. * Previous node.
  28. * @member {NodeStructure}
  29. */
  30. this.prev = null;
  31. }
  32. }
  33. /**
  34. * Linked list.
  35. *
  36. * @class LinkedList
  37. * @util
  38. */
  39. class LinkedList {
  40. constructor() {
  41. this.first = null;
  42. this.last = null;
  43. }
  44. /**
  45. * Add data to the end of linked list.
  46. *
  47. * @param {Object} data Data which should be added.
  48. */
  49. push(data) {
  50. const node = new NodeStructure(data);
  51. if (this.first === null) {
  52. this.first = node;
  53. this.last = node;
  54. } else {
  55. const temp = this.last;
  56. this.last = node;
  57. node.prev = temp;
  58. temp.next = node;
  59. }
  60. }
  61. /**
  62. * Add data to the beginning of linked list.
  63. *
  64. * @param {Object} data Data which should be added.
  65. */
  66. unshift(data) {
  67. const node = new NodeStructure(data);
  68. if (this.first === null) {
  69. this.first = node;
  70. this.last = node;
  71. } else {
  72. const temp = this.first;
  73. this.first = node;
  74. node.next = temp;
  75. temp.prev = node;
  76. }
  77. }
  78. /**
  79. * In order traversal of the linked list.
  80. *
  81. * @param {Function} callback Callback which should be executed on each node.
  82. */
  83. inorder(callback) {
  84. let temp = this.first;
  85. while (temp) {
  86. callback(temp);
  87. temp = temp.next;
  88. }
  89. }
  90. /**
  91. * Remove data from the linked list.
  92. *
  93. * @param {Object} data Data which should be removed.
  94. * @returns {Boolean} Returns true if data has been removed.
  95. */
  96. remove(data) {
  97. if (this.first === null) {
  98. return false;
  99. }
  100. let temp = this.first;
  101. let next;
  102. let prev;
  103. while (temp) {
  104. if (temp.data === data) {
  105. next = temp.next;
  106. prev = temp.prev;
  107. if (next) {
  108. next.prev = prev;
  109. }
  110. if (prev) {
  111. prev.next = next;
  112. }
  113. if (temp === this.first) {
  114. this.first = next;
  115. }
  116. if (temp === this.last) {
  117. this.last = prev;
  118. }
  119. return true;
  120. }
  121. temp = temp.next;
  122. }
  123. return false;
  124. }
  125. /**
  126. * Check if linked list contains cycle.
  127. *
  128. * @returns {Boolean} Returns true if linked list contains cycle.
  129. */
  130. hasCycle() {
  131. let fast = this.first;
  132. let slow = this.first;
  133. while (true) {
  134. if (fast === null) {
  135. return false;
  136. }
  137. fast = fast.next;
  138. if (fast === null) {
  139. return false;
  140. }
  141. fast = fast.next;
  142. slow = slow.next;
  143. if (fast === slow) {
  144. return true;
  145. }
  146. }
  147. };
  148. /**
  149. * Return last node from the linked list.
  150. *
  151. * @returns {NodeStructure} Last node.
  152. */
  153. pop() {
  154. if (this.last === null) {
  155. return null;
  156. }
  157. let temp = this.last;
  158. this.last = this.last.prev;
  159. return temp;
  160. };
  161. /**
  162. * Return first node from the linked list.
  163. *
  164. * @returns {NodeStructure} First node.
  165. */
  166. shift() {
  167. if (this.first === null) {
  168. return null;
  169. }
  170. const temp = this.first;
  171. this.first = this.first.next;
  172. return temp;
  173. };
  174. /**
  175. * Reverses the linked list recursively
  176. */
  177. recursiveReverse() {
  178. function inverse(current, next) {
  179. if (!next) {
  180. return;
  181. }
  182. inverse(next, next.next);
  183. next.next = current;
  184. }
  185. if (!this.first) {
  186. return;
  187. }
  188. inverse(this.first, this.first.next);
  189. this.first.next = null;
  190. const temp = this.first;
  191. this.first = this.last;
  192. this.last = temp;
  193. };
  194. /**
  195. * Reverses the linked list iteratively
  196. */
  197. reverse() {
  198. if (!this.first || !this.first.next) {
  199. return;
  200. }
  201. let current = this.first.next;
  202. let prev = this.first;
  203. let temp;
  204. while (current) {
  205. temp = current.next;
  206. current.next = prev;
  207. prev.prev = current;
  208. prev = current;
  209. current = temp;
  210. }
  211. this.first.next = null;
  212. this.last.prev = null;
  213. temp = this.first;
  214. this.first = prev;
  215. this.last = temp;
  216. };
  217. };
  218. export {NodeStructure};
  219. export default LinkedList;