数据结构与算法JS描述之列表
博主wx: -GuanEr-
,加博主进前端交流群
参考资料
数据结构与算法JS描述,[美] Michael McMillan 著,王群锋 杜欢 译
写在前面
写该系列的博客,初衷是帮助自己和初学者,奠定更高层次的编程基础和理念,能让大家对 JS 有更深层次的认知,并且借助 JS 了解高级的编程思想。
所有对于某个数据结构的算法的示范,并不是标准答案,只是我根据经验模仿了各种资料和其他成熟语言中的写法,如果有写的不精致的地方,或者更好的写法,联系我,我加以改正。
本来想用构造函数的形式实现这些数据结构,但是既然技术在更新,用新的语法可能更好一点。所以所有的代码实现方式都是 ES6+ 的代码。
一、什么是列表
- 列表是基础数据结构中最基础的一种数据结构
- 列表是由数据项构成的有限序列,这些数据项按照一定的线性顺序排列
- 我们把列表中的每个数据项称为元素
- 在 JS 中,列表中的元素可以为任意数据类型
- 列表虽然是有限数列,但是具体可以保存多少元素,没有事先限定,实际使用时,元素的数量受到程序内存的限制
二、列表类及其需要具备的基本算法
根据对列表概念的描述,我们能看出来,数组就是这样的,因为列表的主要呈现形式就是数组和链表。所以实现这个列表类,我其实是想仿写 JS
中的 Array
类。
基本算法
-
- length 属性(返回列表中元素的个数)
-
- add 方法(想列表的末尾添加指定的元素)
-
- insert 方法(向列表的指定位置添加指定的元素)
-
- remove 方法(从列表的指定位置删除元素)
-
- find 方法(返回列表中第一个符合指定条件的元素)
-
- findIndex 方法(返回列表中指定位置的元素)
-
- contains 方法(判断列表中是否包含指定数据)
-
- toString 方法(返回一个由指定字符连接了列表所有元素的字符串)
-
- each 方法(遍历列表)
-
- map 方法(返回一个根据指定条件生成的新的列表)
-
- filter 方法(返回一个根据指定条件过滤之后的新的列表)
-
- 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 中的任意函数验证这个列表类
列表这种数据结构是最简单,最基础的数据结构,如果数据存储模式更复杂,只有列表是不够的。