循环链表可以像链表一样只有单向引用,也可以像双向链表一样有双向引用。循环链表和链表之间唯一的区别在于,最后一个元素指向下一个元素的指针(tail.next)不是引用null,而是指向第一个元素(head)
双向循环链表有指向head元素的tail.next,和指向tail元素的head.prev

实现一个循环链表

  1. function CircularLinkedList() {
  2. let Node = function(element){
  3. this.element = element;
  4. this.next = null;
  5. };
  6. let length = 0;
  7. let head = null;
  8. this.append = function(element){
  9. let node = new Node(element),
  10. current;
  11. if (head === null){ //first node on list
  12. head = node;
  13. } else {
  14. current = head;
  15. //loop the list until find last item
  16. while(current.next !== head){ //last element will be head instead of NULL
  17. current = current.next;
  18. }
  19. //get last item and assign next to added item to make the link
  20. current.next = node;
  21. }
  22. //set node.next to head - to have circular list
  23. node.next = head;
  24. length++; //update size of list
  25. };
  26. this.insert = function(position, element){
  27. //check for out-of-bounds values
  28. if (position >= 0 && position <= length){
  29. let node = new Node(element),
  30. current = head,
  31. previous,
  32. index = 0;
  33. if (position === 0){ //add on first position
  34. if(!head){ // if no node in list
  35. head = node;
  36. node.next = head;
  37. }else{
  38. node.next = current;
  39. //update last element
  40. while(current.next !== head){ //last element will be head instead of NULL
  41. current = current.next;
  42. }
  43. head = node;
  44. current.next = head;
  45. }
  46. } else {
  47. while (index++ < position){
  48. previous = current;
  49. current = current.next;
  50. }
  51. node.next = current;
  52. previous.next = node;
  53. }
  54. length++; //update size of list
  55. return true;
  56. } else {
  57. return false;
  58. }
  59. };
  60. this.removeAt = function(position){
  61. //check for out-of-bounds values
  62. if (position > -1 && position < length){
  63. let current = head,
  64. previous,
  65. index = 0;
  66. //removing first item
  67. if (position === 0){
  68. while(current.next !== head){ //needs to update last element first
  69. current = current.next;
  70. }
  71. head = head.next;
  72. current.next = head;
  73. } else { //no need to update last element for circular list
  74. while (index++ < position){
  75. previous = current;
  76. current = current.next;
  77. }
  78. //link previous with current's next - skip it to remove
  79. previous.next = current.next;
  80. }
  81. length--;
  82. return current.element;
  83. } else {
  84. return null;
  85. }
  86. };
  87. this.remove = function(element){
  88. let index = this.indexOf(element);
  89. return this.removeAt(index);
  90. };
  91. this.indexOf = function(element){
  92. let current = head,
  93. index = -1;
  94. //check first item
  95. if (element == current.element){
  96. return 0;
  97. }
  98. index++;
  99. //check in the middle of the list
  100. while(current.next !== head){
  101. if (element == current.element){
  102. return index;
  103. }
  104. current = current.next;
  105. index++;
  106. }
  107. //check last item
  108. if (element == current.element){
  109. return index;
  110. }
  111. return -1;
  112. };
  113. this.isEmpty = function() {
  114. return length === 0;
  115. };
  116. this.size = function() {
  117. return length;
  118. };
  119. this.getHead = function(){
  120. return head;
  121. };
  122. this.toString = function(){
  123. let current = head,
  124. s = current.element;
  125. while(current.next !== head){
  126. current = current.next;
  127. s += ', ' + current.element;
  128. }
  129. return s.toString();
  130. };
  131. this.print = function(){
  132. console.log(this.toString());
  133. };
  134. }