使用 一维稀疏数组 存储 N维数组 2021-06-11

使用 一维稀疏数组 存储 N维数组

不知道有没有什么实际用途,以及会不会增加时间空间复杂度。
主要目的是为了锻炼一下思维,还有就是懒。
因为要做五子棋,网上建议使用稀疏数组。
经过调查发现js的数组有稀疏数组模式Array(length),就直接没写稀疏数组的实现。
写完后发现缺陷很大,虽然已经满足了五子棋的需求。
有必要重新啃一下数据结构,最起码能对自己的代码做个评估。
※欢迎各位大神莅临指导。
※个人体会: 聪明的懒人总是很勤奋,因为所有事情都解决了,才能舒适的偷懒。

总结

目标: N维数组的稀疏存储

方案: 使用JS自带的一维稀疏数组实现

使用语言: TypeScript

结果:

  • 仅满足当前五子棋需求,以及一些填值就不会修改删除的场景
  • 无法对代码进行合理的评估

此需求后续计划:

  • 调查react + typeScript环境注意事项
  • 使用react + typeScript完成五子棋
  • 重新实现N维数组的稀疏存储
  • 深入学习react和typeScript
  • 重新学习数据结构
  • 养成写测试代码的好习惯(懒癌晚期,容我缓缓)

git地址

https://github.com/anywo/many-dimansional-sparse-array.git

npm地址

https://www.npmjs.com/package/many-dimansional-sparse-array

代码

/**
 * 多维稀疏数组
 * 一维数组存储方案,可能有维度扩展缺陷,可能有单元素复用缺陷
 * 维度从左向右上升,后面的高度全部为0可以做省略
 * 每层维度的下标从0开始,到length-1结束
 */
export default class ManyDimansionalSparseArray<T> {
  private lengthOfAxis: number[]; // 轴长
  private body: any[]; // 一维稀疏数组存储体
  private baseNumberOfEveryDimansional: number[] = new Array(); // 每个维度的基数
  constructor(...args: number[]) {
    this.lengthOfAxis = args; // 初始化轴长

    // 计算一维数组长度, 并且计算每个维度的基数
    let lengthOfBody: number = this.lengthOfAxis.reduceRight((total, curr) => {
      this.baseNumberOfEveryDimansional.unshift(total * curr);
      return this.baseNumberOfEveryDimansional[0];
    }, 1);

    // 完善基数数组
    this.baseNumberOfEveryDimansional.shift();
    this.baseNumberOfEveryDimansional.push(1);

    this.body = Array(lengthOfBody); // 初始化一维数组
  }

  /**
   * 多维数组值取得
   * @param args 多维数组的下标集合(可变参)
   * @returns 多维数组值
   */
  public get(...args: number[]): T {
    let indexOfBody: number = this.calculateindexOfBody(...args);
    return this.body[indexOfBody];
  }

  /**
   * 多维数组值设定
   * @param value 要设定的值
   * @param args 多维数组的下标集合(可变参)
   */
  public set(value: T, ...args: number[]): void {
    let indexOfBody: number = this.calculateindexOfBody(...args);
    this.body[indexOfBody] = value;
  }

  /**
   * 计算多维坐标在一维数组中的下标,与其他进制转10进制相似
   * @param args 多维数组的下标集合(可变参)
   * @returns 一维稀疏数组存储体
   */
  public calculateindexOfBody(...args: number[]): number {
    return args.reduce((total, x, i) => total + x * this.baseNumberOfEveryDimansional[i], 0);
  }

  /**
   * 元素循环
   * @param callback
   * @param isEachAll 是否循环全部,默认:false
   */
  public forEach(
    callback: (value: T, ...args: number[]) => void,
    isEachAll: boolean = false
  ): void {
    if (isEachAll) {
      // 循环所有元素
      this.forEachAll(callback);
    } else {
      // Array.forEach会跳过empty部分
      this.body.forEach((value, i) => {
        callback(value, ...this.calculateIndexsOfManyDimansionalArray(i));
      });
    }
  }

  /**
   * 循环所有元素
   * @param callback
   */
  private forEachAll(callback: (value: T, ...args: number[]) => void): void {
    for (let i: number = 0; i < this.body.length; i++) {
      // 遍历所有元素
      callback(this.body[i], ...this.calculateIndexsOfManyDimansionalArray(i)); // 执行回调
    }
  }

  /**
   * 计算多维数组的下标集合
   * 轴长:一维3,二维4,三维5
   * 基数:一维20(一维最小下标),二维5(二维最小下标),三维1(三维最小下标)
   * 存储体一维数组最大小标:59
   * 一维 坐标:2(59 / 20) 剩余:19(59 % 20)
   * 二维 坐标:3(19 / 5) 剩余:4(19 % 5)
   * 三维 坐标:4(4 / 1) 剩余:0(4 % 1)
   * @param indexOfBody 一维数组的下标
   * @returns 多维数组的下标集合
   */
  public calculateIndexsOfManyDimansionalArray(indexOfBody: number): number[] {
    let ret: number[] = new Array();
    this.baseNumberOfEveryDimansional.reduce((residue, baseNumber) => {
      ret.push(Math.floor(residue / baseNumber)); // 计算当前维度下标
      return residue % baseNumber; // 计算剩余
    }, indexOfBody);

    return ret;
  }
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值