介绍

要存储多个元素,一般都会选择数组,但是这种数据结构有一个缺点:一般数组的大小都是固定的,从数组的起点或中间插入或移除元素成本有点高。这时候就可以选择链表。
链表存储有序的元素集合,但不同于数组,链表的元素在内存中不是连续放置的,每个元素由一个存储元素本身的节点个指向下一个元素的引用组成。
image.png

相对于传统的数组,链表的一个好处在于,添加或移除元素的时候不需要移动其他元素。然 而,链表需要使用指针,因此实现链表时需要额外注意。数组的另一个细节是可以直接访问任何 位置的任何元素,而要想访问链表中间的一个元素,需要从起点(表头)开始迭代列表直到找到所需的元素。

创建链表

  1. function LinkedList() {
  2. let Node = function(element){ // Node辅助类,要加入列表的项。element要加入的值,next表示指向列表下一个节点
  3. this.element = element;
  4. this.next = null;
  5. };
  6. let length = 0; // 存储列表项数量
  7. let head = null; // 存储第一个节点的引用,存到变量head中。
  8. this.append = function(element){}; //向列表项尾部添加新的项
  9. this.insert = function(position, element){}; //向列表指定位置插入新的项
  10. this.removeAt = function(position){}; //从列表特定位置移除一项
  11. this.remove = function(element){}; //从列表中移除一项
  12. this.indexOf = function(element){}; //返回元素在列表的索引,没有则返回-1
  13. this.isEmpty = function() {}; //如果链表中不包含任何元素,返回true,如果链表长度大于0,则返回false
  14. this.size = function() {}; //返回链表的长度
  15. this.getHead = function(){};
  16. this.toString = function(){}; //输入链表元素值
  17. this.print = function(){};
  18. }

向链表尾部添加元素

两种场景:列表为空,添加的是第一个元素;列表不为空,向其追加元素

  1. this.append = function (element) {
  2. let node = new Node(element), //传入element值,作为Node项
  3. current; //{2}
  4. if (head === null) { //列表中第一个节点为空时,此时head指向node
  5. head = node;
  6. } else {
  7. current = head;
  8. //循环列表,直到找到最后一项
  9. while (current.next) {
  10. current = current.next;
  11. }
  12. //找到最后一项,将其next赋为node,建立链接
  13. current.next = node;
  14. }
  15. length++; //更新列表的长度
  16. };

从链表中移除元素

两种场景:移除第一个元素;移除第一个以外的元素。

  1. this.removeAt = function (position) {
  2. //检查越界值
  3. if (position > -1 && position < length) {
  4. let current = head,
  5. previous,
  6. index = 0;
  7. //移除第一项
  8. if (position === 0) {
  9. head = current.next;
  10. } else {
  11. while (index++ < position) {
  12. previous = current;
  13. current = current.next;
  14. }
  15. //将previous与current的下一项链接起来:跳过current,从而移除它
  16. previous.next = current.next;
  17. }
  18. length--;
  19. return current.element;
  20. } else {
  21. return null;
  22. }
  23. };

在任意位置插入元素

  1. this.insert = function (position, element) {
  2. //检查越界值
  3. if (position >= 0 && position <= length) {
  4. let node = new Node(element),
  5. current = head,
  6. previous,
  7. index = 0;
  8. if (position === 0) { //在第一个位置添加
  9. node.next = current;
  10. head = node;
  11. } else {
  12. while (index++ < position) {
  13. previous = current;
  14. current = current.next;
  15. }
  16. node.next = current;
  17. previous.next = node;
  18. }
  19. length++; //更新列表的长度
  20. return true;
  21. } else {
  22. return false;
  23. }
  24. };

toString方法

  1. this.toString = function () {
  2. let current = head,
  3. string = '';
  4. while (current) {
  5. string += current.element + (current.next ? 'n' : '');
  6. current = current.next;
  7. }
  8. return string;
  9. };

indexOf方法

  1. this.indexOf = function (element) {
  2. let current = head,
  3. index = -1;
  4. while (current) {
  5. if (element === current.element) {
  6. return index;
  7. }
  8. index++;
  9. current = current.next;
  10. }
  11. return -1;
  12. };

isEmpoty方法

  1. this.isEmpty = function() {
  2. return length === 0;
  3. };

size方法

  1. this.size = function() {
  2. return length;
  3. };

getHead方法

  1. this.getHead = function(){
  2. return head;
  3. };