使用 一维稀疏数组 存储 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;
}
}