js封装数据结构_04_单向链表

一、要想自己封装链表得先知道链表的特点:

链表的每个元素有一个存储元素本身的节点和一个指向下一个节点的引用(有些语言是指针);

链表一般有head、length等属性,一个指向头节点,一个表示链表节点的个数;

链表无法通过下标直接访问元素,需要从head指向的头节点开始一个一个的访问,直到找到对应的元素;

二、这里我实现了:

增:

  • append,向链尾添加节点
  • insert,向特定位置插入新节点

删:

  • remove_identical,链表去重
  • removeAt,指定位置删除节点
  • remove,从列表中移除指定节点

改:

  • update,修改某个位置的节点

查:

  • get,获取对应位置的元素
  • indexOf,返回队应元素的索引,没有则返回-1,有多个以数组形式返回

其他:

  • isEmpty,是否为空
  • size,包含元素个数
  • toString,重写tosTring()方法

三、难的点就说一下链表去重吧:

先把每个节点的数据放到数组里面

然后我们可以把链表去重转换为数组去重,这个简单吧,遍历啊,set啊都是可以实现的

dataArr = Array.from(new Set(dataArr));

然后更新head和length,再重新构造链表即可

四、源码

function LinKedList() {
  // 内部的类:节点类
  function Node(data, next = null) {
    this.data = data;
    this.next = next;
  }

  // 属性
  this.head = null;
  this.length = 0;

  // 方法1:append
  LinKedList.prototype.append = function (data) {
    //1.创建
    let newNode = new Node(data);
    // 2.判断是否是添加的第一个节点
    if (!this.length) {
      this.head = newNode;
    } else {
      // 查找都是从head开始
      let current = this.head;
      //3.末尾的node
      while (current.next) {
        current = current.next;
      }
      // 4.添加:最后节点的next指向最新的节点
      current.next = newNode;
    }
    //5.length++
    this.length++;
  };

  // 方法2:tostring
  LinKedList.prototype.toString = function () {
    let Values = [];
    let current = this.head;
    //将data放入values
    while (current) {
      Values.push(current.data);
      current = current.next;
    }
    //   返回数据,用string也行,这里用数组包裹
    return Values;
  };

  // 方法3:insert
  LinKedList.prototype.insert = function (position, element) {
    // 在插入之前做边界判断
    if (position < 0 && position > this.length) return false;

    // 根据data创建node
    let newNode = new Node(element);

    // 判断是否插入的是第一个
    if (!position) {
      newNode.next = this.head.next;
      this.head = newNode;
    } else {
      //包含了position==this.length这种情况
      let index = 0;
      let current = this.head;
      let previous = null;
      // 拿到当前的和以前的
      while (index++ < position) {
        previous = current;
        current = current.next;
      }
      // 连接节点
      newNode.next = current;
      previous.next = newNode;
    }
    // length++
    this.length++;
    return true;
  };

  // 方法4:get
  LinKedList.prototype.get = function (position) {
    // 是位置都来一个边界判断
    if (position < 0 && position >= this.length) return null;
    let index = 0;
    let current = this.head;
    while (index++ < position) {
      current = current.next;
    }
    return current.data;
  };

  // 方法5:indexOf
  LinKedList.prototype.indexOf = function (element) {
    let index = 0;
    let current = this.head;
    let indexArr = [];
    while (current) {
      let data = current.data;
      if (data == element) {
        indexArr.push(index);
      }
      current = current.next;
      index++;
    }
    if (!indexArr.length) return -1;
    return indexArr;
  };

  // 方法6:update
  LinKedList.prototype.update = function (position, element) {
    if (position < 0 && position >= this.length) return false;
    let index = 0;
    let current = this.head;
    while (index++ < position) {
      current = current.next;
    }
    current.data = element;
    return true;
  };

  // 方法7:removeAt
  LinKedList.prototype.removeAt = function (position) {
    // 边界
    if (position < 0 && position >= this.length) return false;
    let index = 0;
    let current = this.head;
    let previous = null;
    // 0?
    if (!position) {
      this.head = current.next;
      current.next = null;
      return true;
    }

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

    return true;
  };

  // 方法8:remove_identical
  LinKedList.prototype.remove_identical = function () {
    let current = this.head;
    let dataArr = [];
    while (current) {
      let data = current.data;
      dataArr.push(data);
      current = current.next;
    }
    current = this.head;
    // 将链表去重转换为数组去重
    dataArr = Array.from(new Set(dataArr));
    // 重新构造链表
    this.head = null;
    this.length = 0;
    for (let i = 0; i < dataArr.length; i++) {
      this.append(dataArr[i]);
    }
    return true;
  };

  // 方法9:remove
  LinKedList.prototype.remove = function (element) {
    let current = this.head;
    let previous = null;
    // 0?
    if (element == current.data) {
      this.head = current.next;
      current.next = null;
      this.index--;
      return true;
    }
    while (current) {
      if (element == current.data) {
        previous.next = current.next;
        current.next = null;
        this.index--;
        return true;
      }
      previous = current;
      current = current.next;
    }

    // 没有该元素,返回false
    return false;
  };

  // 方法10:isEmpty()
  LinKedList.prototype.isEmpty = function () {
    if (!this.length) return true;
    return false;
  };

  // 方法11:size
  LinKedList.prototype.size = function () {
    return this.length;
  };
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值