Skip to content

Latest commit

 

History

History
392 lines (325 loc) · 9.95 KB

链表.md

File metadata and controls

392 lines (325 loc) · 9.95 KB

链表

链表的定义

链表主要分为3类:单向链表、双向链表和循环链表

单向链表

链表是一种通过指针串联在一起的线性结构,每一个节点由两部分组成,一个是数据域一个是指针域(存放指向下一个节点的指针),最后一个节点的指针域指向null(空指针的意思)。单向链表只能从从一个方向由一个节点指向节点的下一个节点。

链表中的元素在内存中不必是连续的空间

相对于数组来说,链表的插入和删除操作速度更快,因为其只需要修改 操作节点 的前后节点的指针即可。不必像数组一样逐个去遍历。但在取下标值的数据时很慢,由于其要根据引用逐个进行查找。

单向链表

双向链表

双链表:每一个节点有两个指针域,一个指向下一个节点,一个指向上一个节点。

双链表 既可以向前查询也可以向后查询。也就是可以从头到尾遍历,也可以从尾到头遍历

双向链表

循环链表

循环链表,顾名思义,就是链表首尾相连。

循环链表可以用来解决约瑟夫环问题。

循环链表

封装链表

单向链表实现

function LinkedList() {
  function Node(data) {
    this.data = data;
    this.next = null;
  }
  // 链表属性
  this.head = null;
  this.length = 0;

  // 末尾添加元素
  LinkedList.prototype.append = function(data) {
    var newNode = new Node(data);

    if (this.length === 0) {
      this.head = newNode;
    } else {
      var current = this.head; // 从head开始,逐个查询其节点数据是否存在
      while (current.next) {
        current = current.next;
      }
      current.next = newNode;
    }
    this.length += 1;
  };

  // 转换为字符串
  LinkedList.prototype.toString = function() {
    var tempString = "";
    var current = this.head;
    while (current && current.data) {
      tempString += ` ${current.data} `;
      current = current.next || null;
    }
    return tempString;
  };

  // 插入元素
  LinkedList.prototype.insert = function(position, data) {
    var newNode = new Node(data);
    // 越界判断
    if (position < 0 || position > this.length) {
      throw new Error("Error: out of bounds");
      return;
    }

    if (position === 0) {
      newNode.next = this.head; // 将新数据项的指针,指向头部
      this.head = newNode; // 指定新数据项为头部
    } else {
      var previous = null;
      var current = this.head;
      var index = 0;

      while (index++ < position) {
        previous = current;
        current = current.next;
      }
      newNode.next = current;
      previous.next = newNode;
      this.length += 1;
    }
  };

  // 获取指定index的数据
  LinkedList.prototype.get = function(position) {
    // 越界判断
    if (position < 0 || position >= this.length) {
      throw new Error("Error: out of bounds");
      return;
    }
    let index = 0;
    let current = this.head;

    while (index++ < position) {
      current = current.next;
    }
    return current.data;
  };

  // 获取指定数据的下标
  LinkedList.prototype.indexOf = function(data) {
    var current = this.head;

    for (var i = 0; i < this.length; i++) {
      if (current.data === data) {
        return i;
      }
      current = current.next;
    }
    return -1;
  };

  // 修改指定位置元素
  LinkedList.prototype.update = function(position, data) {
    // 越界判断
    if (position < 0 || position >= this.length) {
      throw new Error("Error: out of bounds");
      return;
    }
    let index = 0;
    let current = this.head;

    while (index++ < position) {
      current = current.next;
    }
    current.data = data;
  };

  // 移除指定位置的元素
  LinkedList.prototype.removeAt = function(position) {
    // 越界判断
    if (position < 0 || position >= this.length) {
      throw new Error("Error: out of bounds");
      return;
    }

    var current = this.head;

    if (position === 0) {
      this.head = current.next;
    } else {
      var previous = null;
      var index = 0;

      while (index++ < position) {
        previous = current;
        current = current.next;
      }
      previous.next = current.next || null;
    }
    return current.data;
  };

  // 移除指定元素
  LinkedList.prototype.remove = function(data) {
    var position = this.indexOf(data);
    this.removeAt(position);
  };

  LinkedList.prototype.isEmpty = function() {
    return !!this.length;
  };

  LinkedList.prototype.size = function() {
    return this.length;
  };
}

var linkedList = new LinkedList();
linkedList.append("a");
linkedList.append("b");
linkedList.append("c");
linkedList.insert(1, "a++");
linkedList.update(0, "aaa");
// linkedList.removeAt(3)
linkedList.remove("b");
// linkedList.removeAt(linkedList.length -1)
// console.log(linkedList.indexOf('kerwin'))
// console.log(linkedList.get(1));
console.log(linkedList.toString());

双向链表的代码实现

function DoublyLinkedList() {
  // 属性
  this.head = null;
  this.tail = null;
  this.length = 0;

  function Node(data) {
    this.data = data;
    this.next = null;
    this.prev = null;
  }

  DoublyLinkedList.prototype.append = function(data) {
    var newNode = new Node(data);

    if (!this.length) {
      this.head = newNode;
      this.tail = newNode;
      this.length += 1;
      return;
    }
    this.tail.next = newNode;
    newNode.prev = this.tail;
    this.tail = newNode;
    this.length += 1;
  };

  DoublyLinkedList.prototype.backwardString = function() {
    var current = this.head;
    var resultStr = "";

    while (current) {
      resultStr += current.data + " ";
      current = current.next;
    }
    return resultStr;
  };

  DoublyLinkedList.prototype.forwardString = function() {
    var current = this.tail;
    var resultStr = "";

    while (current) {
      resultStr += current.data + " ";
      current = current.prev;
    }
    return resultStr;
  };

  DoublyLinkedList.prototype.insert = function(position, data) {
    // 越界判断
    if (position < 0 || position > this.length) return;

    var newNode = new Node(data);

    if (!this.length) {
      this.head = newNode;
      this.tail = newNode;
      this.length += 1;
      return;
    }

    if (position === 0) {
      this.head.prev = newNode; // 将当前head移至第二个位置,并将prev指针指向新心结
      newNode.next = this.head; // 绑定新节点的next指针
      this.head = newNode; // 生成新的头节点
    } else if (position === this.length) {
      this.tail.next = newNode; // 末尾节点next指针指向新节点
      newNode.prev = this.tail; // 新节点的prev指针指向上一个节点
      this.tail = newNode; // 生成新的尾节点
    } else {
      var current = this.head;

      for (var i = 0; i < position; i++) {
        current = current.next;
      }

      newNode.next = current; // 新节点的next指针
      newNode.prev = current.prev; // 新节点的prev指针
      current.prev.next = newNode; // 修改当前节点的上一个节点next指针
      current.prev = newNode; // 修改当前节点的prev指针
    }
    this.length += 1;
  };

  DoublyLinkedList.prototype.get = function(position) {
    let current = this._getCurrent(position);

    return current.data;
  };

  DoublyLinkedList.prototype.indexOf = function(data) {
    var current = this.head;
    for (let i = 0; i < this.length; i++) {
      if (current.data === data) {
        return i;
      }
      current = current.next;
    }
    return -1;
  };

  DoublyLinkedList.prototype._getCurrent = function(position) {
    if (position < 0 || position >= this.length) return null;

    // 判断从头 or 从尾开始遍历
    if (position < this.length / 2) {
      current = this.head;
      for (let i = 0; i < position; i++) {
        current = current.next;
      }
    } else {
      current = this.tail;
      for (let i = this.length - 1; i > position; i--) {
        current = current.prev;
      }
    }
    return current;
  };

  DoublyLinkedList.prototype.update = function(position, data) {
    let current = this._getCurrent(position);

    current.data = data;
  };

  DoublyLinkedList.prototype.removeAt = function(position) {
    if (position < 0 || position >= this.length) return;
    var current = this.head;

    if (this.length === 1) {
      this.head = null;
      this.tail = null;
      return;
    }

    if (position === 0) {
      var temp = this.head.next;
      temp.prev = null;
      this.head = temp;
    } else if (position === this.length - 1) {
      current = this.tail;
      var temp = this.tail.prev;
      temp.next = null;
      this.tail = temp;
    } else {
      current = this._getCurrent(position);
      var prev = current.prev;
      var next = current.next;
      prev.next = next;
      next.prev = prev;
    }
    this.length -= 1;
    return current.data;
  };

  DoublyLinkedList.prototype.remove = function(data) {
    var index = this.indexOf(data);
    return this.removeAt(index);
  };

  DoublyLinkedList.prototype.isEmpty = function() {
    return !!this.length;
  };

  DoublyLinkedList.prototype.size = function() {
    return this.length;
  };

  DoublyLinkedList.prototype.getHead = function() {
    return this.head.data;
  };

  DoublyLinkedList.prototype.getTail = function() {
    return this.tail.data;
  };
}

var list = new DoublyLinkedList();
list.append("kerwin");
list.append("bob");
list.insert(0, 0);
list.insert(1, 1);
list.insert(3, 3);

// console.log(list.removeAt(4));
// console.log(list.remove("kerwin"));
console.log(list.backwardString());
console.log(list.get(2));
console.log(list.indexOf("kerwin"));
list.update(1, "ddd");
console.log(list.backwardString());