欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

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

程序员文章站 2024-03-02 14:58:16
...

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

参考资料

数据结构与算法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 中的任意函数验证这个列表类

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

扫码领取 Web 前端直播课免费学习名额,或进入前端技术交流群

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

其他文章链接:
JS 常见算法的解析和代码实现
Vue 利用 addRoutes 动态创建路由,并在页面刷新后保留动态路由的完整 Demo
React脚手架(5)Props和PropTypes检查类型
Vue 数据双向响应机制
Vue-cli 请求代理配置,封装 Axios 及请求拦截器和响应拦截器
Vue-cli + Element-UI 利用递归动态生成菜单栏
Vue-cli 中的打印功能(window.print)
React + Ant Design 利用递归动态生成菜单栏
Canvas 扫雷
Canvas 贪吃蛇大作战
webpack4.0 的配置及简单使用
Angular-cli 环境搭建,组件,组件的数据渲染,父子组件传值
React 脚手架(6)React-router 安装,配置,调用,嵌套,传参
Vue-6 Vuex(state, getters, mutations, actions, modules)
Vue-5 路由参数的传递和获取(query 和 params),导航守卫和路由元信息,History模式
Vue-4 路由的配置和调用,命名路由和命名视图,嵌套路由,重定向和别名
Vue-3 props,$emit,slot,render,JSX和createElement
Vue-1 Vue的基础语法
ECMAScript 6 字符串和数值的拓展
ECMAScript 6 类和类的继承
React脚手架(4)数据渲染方式
React脚手架(3)组件的样式和styled-components

React脚手架(2)组件的结构和JSX
React脚手架(1)安装项目
JS中的this
如何快速入门新的H5前端框架
vue前端学习交流群,广告卖课勿入!!!
web前端交流群小程序交流群vue交流群react交流群