数据结构与算法JS描述之列表

数据结构与算法JS描述之列表

博主wx: -GuanEr-,加博主进前端交流群

参考资料

数据结构与算法JS描述,[美] Michael McMillan 著,王群锋 杜欢 译

写在前面

写该系列的博客,初衷是帮助自己和初学者,奠定更高层次的编程基础和理念,能让大家对 JS 有更深层次的认知,并且借助 JS 了解高级的编程思想。

所有对于某个数据结构的算法的示范,并不是标准答案,只是我根据经验模仿了各种资料和其他成熟语言中的写法,如果有写的不精致的地方,或者更好的写法,联系我,我加以改正。

本来想用构造函数的形式实现这些数据结构,但是既然技术在更新,用新的语法可能更好一点。所以所有的代码实现方式都是 ES6+ 的代码。

一、什么是列表

  • 列表是基础数据结构中最基础的一种数据结构
  • 列表是由数据项构成的有限序列,这些数据项按照一定的线性顺序排列
  • 我们把列表中的每个数据项称为元素
  • 在 JS 中,列表中的元素可以为任意数据类型
  • 列表虽然是有限数列,但是具体可以保存多少元素,没有事先限定,实际使用时,元素的数量受到程序内存的限制

二、列表类及其需要具备的基本算法

根据对列表概念的描述,我们能看出来,数组就是这样的,因为列表的主要呈现形式就是数组和链表。所以实现这个列表类,我其实是想仿写 JS 中的 Array 类。

基本算法

    1. length 属性(返回列表中元素的个数)
    1. add 方法(想列表的末尾添加指定的元素)
    1. insert 方法(向列表的指定位置添加指定的元素)
    1. remove 方法(从列表的指定位置删除元素)
    1. find 方法(返回列表中第一个符合指定条件的元素)
    1. findIndex 方法(返回列表中指定位置的元素)
    1. contains 方法(判断列表中是否包含指定数据)
    1. toString 方法(返回一个由指定字符连接了列表所有元素的字符串)
    1. each 方法(遍历列表)
    1. map 方法(返回一个根据指定条件生成的新的列表)
    1. filter 方法(返回一个根据指定条件过滤之后的新的列表)
    1. clear 方法(清空列表)

实现列表类

// 列表
class ArrayList {
  // 元素个数
  length = 0;
  // 数据源,保留当前列表的所有元素
  data = [];

  // 向列表的末尾添加指定的元素
  add(...newElList) {
    for(let i = 0; i < newElList.length; i++) {
      this.data[this.length] = newElList[i];
      this.length++;

      // 简写 this.data[this.length++] = newElList[i];
    }
  }

  /*
  *  insert 函数在列表的指定位置添加指定元素
  *
  *  index: 要插入元素的位置
  *  newElList: 要插入的元素列表,可以传任意数量
  *
  *  执行逻辑:
  *  将旧的列表从 index 的位置一分为二
  *  先将 index 之前的元素添加到临时列表中
  *  再将需要添加的元素列表追加进去
  *  最后将原来列表中 index 及之后的数据追加进去
  * */
  insert(index, ...newElList) {
    if(typeof index !== 'number') {
      console.error('ArrayList 的 insert 函数,第一个参数必须为 number 类型');
    } else {
      const tempArr = new ArrayList();
      // 步骤一
      for(let i = 0; i < index; i++) {
        tempArr.add(this.data[i]);
      }
      // 步骤二
      tempArr.add(...newElList);
      // 步骤三
      for(let i = index; i < this.length; i++) {
        tempArr.add(this.data[i]);
      }
      // 步骤四
      this.data = [...tempArr.data];
      this.length = tempArr.length;
    }
  }

  /*
  * remove 函数,从列表的指定位置删除指定个数的元素
  *
  * index: 要删除元素的位置,包含该位置
  * count: 要删除的元素个数
  *
  * 执行逻辑:
  * 先用中转量保留列表中原来的数据
  * 清空列表原来的数据源 data 并将 length 的值赋为 0
  * 循环中转量,将其中下标不在删除范围之内的元素添加进当前列表的数据源 data 里
  * */
  remove(index, count) {
    if(typeof index !== 'number' || typeof count !== 'number') {
      console.error('ArrayList 的 remove 函数,两个参数必须都是 number 类型');
    } else {
      // 根据 index 和 count 生成要删除的元素的下标区间
      const maxIndex = index + count - 1;
      const tempArr = [...this.data];
      this.data = [];
      this.length = 0;
      for(let i = 0; i < tempArr.length; i++) {
        if(i < index || i > maxIndex) {
          this.add(tempArr[i]);
        }
      }
    }
  }

  /*
  * find 函数,返回列表中第一个符合指定条件的元素
  *
  * cb: 需要执行的回调函数
  *
  * 执行逻辑:
  * 循环当前列表数据源中的每一个元素,将其所在的位置和这个数据本身传给回调函数作为实参
  * 然后拿到回调函数的返回值,第一个为 true 的元素就是 find 的执行结果
  *
  * 调用要求:
  * 回调函数必须有返回值
  * */
  find(cb) {
    if(typeof cb !== 'function') {
      console.error('ArrayList 的 find 函数接受一个回调函数作为参数');
    } else {
      for(let i = 0; i < this.length; i++) {
        const flag = cb(this.data[i], i);
        if(flag) {
          return this.data[i];
        }
      }
    }
  }

  /*
  * findIndex 函数,找到指定位置的元素
  * */
  findIndex(index) {
    if(index < 0 || index >= this.length) return null;
    for(let i = 0; i < this.length; i++) {
      if(i === index) return this.data[i];
    }
  }

  /*
  * contains 函数,判断列表中是否包含指定数据
  * */
  contains(el) {
    let flag = false;
    for(let i = 0; i < this.length; i++) {
      if(el === this.data[i]) {
        flag = true;
        break;
      }
    }
    return flag;
  }

  /*
  * toString 函数,返回一个由参数 str 连接的所有列表元素的字符串
  * */
  toString(str = ',') {
    let res = '';
    for(let i = 0; i < this.length; i++) {
      res += this.data[i];
      if(i !== this.length - 1) res += str;
    }
    return res;
  }

  /*
  * each 函数,遍历列表中所有的元素
  * */
  each(cb) {
    if(typeof cb !== 'function') {
      console.error('ArrayList 的 each 函数接受一个回调函数作为参数');
    } else {
      for(let i = 0; i < this.length; i++) {
        cb(this.data[i], i);
      }
    }
  }

  /*
  * map 函数,返回一个新列表,新列表中的每一项由源列表中的数据计算而成
  * */
  map(cb) {
    if(typeof cb !== 'function') {
      console.error('ArrayList 的 map 函数接受一个回调函数作为参数');
    } else {
      let tempArr = new ArrayList();
      for(let i = 0; i < this.length; i++) {
        tempArr.add(cb(this.data[i], i));
      }
      return tempArr;
    }
  }

  /*
  * filter 函数,返回一个新列表,该新列表中的元素,有原列表根据指定条件过滤得到
  * */
  filter(cb) {
    if(typeof cb !== 'function') {
      console.error('ArrayList 的 filter 函数接受一个回调函数作为参数');
    } else {
      let tempArr = new ArrayList();
      for(let i = 0; i < this.length; i++) {
        let res = cb(this.data[i], i);
        if(res !== undefined) {
          tempArr.add(this.data[i]);
        }
      }
      return tempArr;
    }
  }

  clear() {
    this.data = [];
    this.length = 0;
  }
}

// 调用
const arr = new ArrayList();
arr.add(45, 56, 43, 57, 29);
console.log(arr.data);

// 你可以调用 ArrayList 中的任意函数验证这个列表类

列表这种数据结构是最简单,最基础的数据结构,如果数据存储模式更复杂,只有列表是不够的。

扫码拉你进入前端技术交流群

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

锋利的二丫

如果对您有帮助,请博主喝杯奶茶

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值