数据结构与算法之《列表结构》最用心的分享学习
简介
列表是在生活中特别常见都一种数据展示的方式,比如:购物车列表、班级排名、 公司人员清单。等等...列表展示数据比较清晰,对于列表的数据处理也比较方便 我们可以抽象出一个列表的数据类型定义。
列表是一组有序的数据,每一个列表中的数据项叫做元素,在很多强类型中列表中 的数据都是有数据类型统一的,在弱类型语言里比如 JavaScript 中就不存在数据类型的区别, 任意数据都可以放置进去。
由于列表是一个有序的元素集合,那么每个元素就会有个对应的位置信息,可以叫做下标,或者叫做索引。都是指当前元素在列表中的位置。
工作清单转换成一堆数据以及最后在列表中的展现方式
1、列表的抽象数据类型定义
| 属性/方法 | 描述 |
|---|---|
| listSize(属性) | 列表中多少个元素 |
| pos(属性) | 列表当前位置 |
| length(方法) | 获取列表元素数量 |
| clear(方法) | 清空列表所有元素 |
| toString(方法) | 返回列表中元素以字符串的方式返回 |
| getElement(方法) | 返回当前位置元素 |
| inset(方法) | 插入一个元素在指定元素后面 |
| append(方法) | 在列表的尾部增加一个元素 |
| remove(方法) | 删除指定元素 |
| front(方法) | 修改当前位置到列表第一位 |
| end(方法) | 修改当前位置到列表最后一位 |
| prev(方法) | 将当前位置前移一位 |
| next(方法) | 将当前位置后移一位 |
| hasNext(方法) | 是否还有下一个元素 |
| hasPrev(方法) | 是否还有前一个元素 |
| currPos(方法) | 返回当前位置 |
| moveTo(方法) | 将当前位置移动到指定位置 |
| findIndex(方法) | 返回指定元素在列表中到位置 |
| find(方法) | 查找是否存在指定元素 |
2、搭建开发环境
2.1、语言
使用 JavaScript 来编写列表类,虽然说已经内置了一个 Array,我们可以手动模拟实现一个。
2.2、创建文件
使用html文件通过浏览器解析来展示我们编写到 ListClass 类
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>学习数据结构与算法之列表类</title>
<script src="./JavaScript/ListClass.js"></script>
</head>
<body>
</body>
<script>
</script>
</html>
创建一个 JavaScript 到文件夹,存放编写到 xx.js 文件,并且创建 ListClass.js 文件
在 ListClass.js 中创建 ListClass 并做好初始化结构。
class ListClass {
constructor() {
// 当前存储容器
this.list = [];
// 列表元素的个数
this.listSize = 0;
// 列表的当前位置
this.pos = 0;
}
// length 方法返回当前元素的个数
length = () => {};
// clear 清空整个列表
clear = () => {};
// toString 返回列表的字符串形式
toString = () => {};
// getElement 返回当前位置的元素
getElement = () => {};
// inset 在现有的元素位置后插入新元素
inset = (element, after) => {};
// findIndex 查询指定元素到下标
findIndex = (element) => {};
// find 在列表中查找指定元素
find = (element) => {};
// append 在列表末尾添加新元素
append = (element) => {};
// remove 删除指定元素
remove = (element) => {};
// front 将列表当前位置移动到第一个元素
front = () => {};
// end 将列表当前位置移动到最后个元素
end = () => {};
// prev 将当前位置前移一位
prev = () => {};
// next 将当前位置后移一位
next = () => {};
// hasNext 判断是否还有后一位
hasNext = () => {};
// hasPrev 判断是否还有前一位
hasPrev = () => {};
// currPos 返回当前位置
currPos = () => {};
// moveTo 将当前位置移动到指定位置
moveTo = (index) => {};
}
3、对应实现所有方法
3.1、 length 方法的实现
length 方法主要返回当前列表中的元素个数,我们在初始化类中定义了一个属性 listSize 可以直接返回这个属性;
参数:无
返回值:当前列表元素个数
【实现】
length = () => this.listSize;
3.2、 clear 方法的实现
clear 方法是清空整个列表的方法,只要调用就会把列表置为初始状态,或者说是删除所有数据。
参数:无
返回值:无
【实现】
clear = () => {
// 清空列表
this.list.length = 0;
// 将列表数量重置
this.listSize = 0;
}
3.3、toString 方法的实现
toString 方法是将当前列表中所有元素都转成字符串用逗号拼接都方式返回。
参数:无
返回值:拼接好的字符串
【实现】
toString = () => {
// 定义返回值
let res = '';
// 循环获取容器内的数据
for (let i = 0; i < this.listSize; i++) {
// 拼接元素
res += this.list[i];
// 判断最后一个元素不拼接逗号,其他都拼接一个逗号用来隔开每个元素
res += i === this.listSize - 1 ? '' : ','
}
return res;
}
3.4、getElement 方法的实现
getElement 方法是获取当位置在列表中的元素,我们在类中定义了 pos 属性来记录当前位置
参数:无
返回值:列表当前位置
【实现】
getElement = () => this.list[this.pos];
3.5、inset 方法的实现
inset 方法是将一个元素插入到指定元素到后面,目前实现的规则是:
- 1、找到了指定元素就插入到指定元素到后面
- 2、没有找到指定元素,就在列表到尾部新增一个
- 3、任意以上到操作都需要更新一下当前 listSize 都数量
参数:
- 需要插入的元素 element
- 需要插入在那个元素后 after
返回值:
- 插入成功:true
- 插入失败:false
【实现】
inset = (element, after) => {
// 查找到需要插入到位置
let index = this.findIndex(after);
// 判断是否找到了
if (index === -1) {
return false;
}
// 将 index 位置往后到都单独存一份
const list = [];
for (let i = ++index; i < this.listSize; i++) {
list.push(this.list[i]);
}
// 插入元素
this.list[index++] = element;
// 增加列表数量
this.listSize++;
// 恢复之前都数据
for (; index < this.listSize; index++) {
this.list[index] = list.shift()
}
return true;
}
3.6、 findIndex 方法的实现
findIndex 方法是查找指定元素在列表中的位置,如果找不到就返回 -1
参数:需要查找到元素 element
返回值:
- 找到元素:对应下标
- 没有元素:-1
【实现】
findIndex = (element) => {
for (let i = 0; i < this.listSize; i++) {
if (this.list[i] === element) {
return i;
}
}
return -1;
}
3.7、 find 方法的实现
find 方式是用于查找指定元素是否在列表中
参数: 无
返回值:
- 存在:true
- 不存在:false
【实现】
find = (element) => {
for (let i = 0; i < this.listSize; i++) {
if (this.list[i] === element) {
return true;
}
}
return false;
}
3.8、 append 方法的实现
append 方法是在列表的尾部添加元素,然后更新 listSize 的长度
参数:需要添加的元素 element
返回值:无
【实现】
append = (element) => this.list[this.listSize++] = element;
3.9、 remove 方法的实现
remove 方法是在列表中删除指定元素,删除第一个出现的元素,如果出现重复元素的时候, 优先匹配第一个出现的元素,并且删除。
参数:需要删除的元素 element
返回值:
- 删除成功:true
- 删除失败:false
【实现】
remove = (element) => {
// 查找到需要删除到位置
let index = this.findIndex(element);
// 判断是否找到了
if (index === -1) {
return false;
}
// 减少列表数量
this.listSize--;
// 将 index 位置往后都前移一位
for (let i = index; i < this.listSize; i++) {
this.list[i] = this.list[i + 1]
}
return true;
}
3.10、 front 方法的实现
front 方法是将当前列表位置调整到第一位
参数:无
返回值:无
【实现】
front = () => this.pos = 0;
3.11、 end 方法的实现
end 方法是将当前列表位置调整到列表最后一位
参数:无
返回值:无
【实现】
end = () => this.pos = this.listSize - 1;
3.12、 prev 方法的实现
prev 方法是将当前列表位置向前调整一位,但是不能成负数
参数:无
返回值:无
【实现】
prev = () => {
if (this.pos > 0) {
this.pos--;
}
}
3.13、 next 方法的实现
next 方法是将当前列表位置向后调整一位,但是不能超过列表总长度
参数:无
返回值:无
【实现】
next = () => {
if (this.pos < this.listSize) {
this.pos++;
}
}
3.14、 hasNext 方法的实现
hasNext 方法判断当前位置往后一位是否还有元素
参数:无
返回值:
- 还有元素:true
- 没有元素:false
【实现】
hasNext = () => this.pos < this.listSize;
3.15、 hasPrev 方法的实现
hasPrev 方法判断当前位置往前一位是否还有元素
参数:无
返回值:
- 还有元素:true
- 没有元素:false
【实现】
hasPrev = () => this.pos > 0;
3.16、 currPos 方法的实现
currPos 方法返回当前列表位置
参数:无
返回值:当前列表位置
【实现】
currPos = () => this.pos;
3.17、 moveTo 方法的实现
moveTo 方法是将列表当前位置移动到指定位置
参数:无
返回值:当前列表位置
【实现】
moveTo = (index) => this.pos = index;
4、简单使用
4.1、添加工作清单内容
使用我们在 ListClass 类中定义的 append 方法添加每一个需要完成的工作项, 最后使用 toString 方法将所有工作项一一用逗号拼接起来
const list = new ListClass();
list.append('1、第一件事...');
list.append('2、第二件事...');
list.append('3、第三件事...');
list.append('4、第四件事...');
list.append('5、第五件事...');
console.log(list.toString());
// 1、第一件事...,2、第二件事...,3、第三件事...,4、第四件事...,5、第五件事...
4.2、插入工作清单内容
如果有着急的事情需要插队的时候,就可以使用我们的 inset 方法
list.inset('2.1、我是插队的任务...', '2、第二件事...');
console.log(list.toString());
// 1、第一件事...,2、第二件事...,2.1、我是插队的任务...,3、第三件事...,4、第四件事...,5、第五件事...
4.3、删除工作清单内容
当工作项完成当时候就可以把工作清单中当数据给删除啦。
list.remove('1、第一件事...');
list.remove('2、第二件事...');
list.remove('2.1、我是插队的任务...');
console.log(list.toString());
// 3、第三件事...,4、第四件事...,5、第五件事...
5、进阶使用
列表本质上是一个容器,一个有序存储元素项当一个容器,也叫做一种数据结构, 通常数据结构都会搭配一些算法来处理数据,或者完成一些特定场景的需求。
需求1:实现一个1-5的阶乘
关于实现这个1-5的阶乘有非常多办法,比如常见的递归:
const factorial = n1 => {
if( n1 === 1 ){
return n1;
}
return n1 * factorial(--n1)
}
console.log(factorial(5));// 120
我们还可以使用刚刚写列表来实现:
const factorial = n1 => {
const list = new ListClass();
let res = n1;
while (--n1 ){
list.append(n1);
}
while (list.hasNext()){
res *= list.getElement();
list.next();
}
return res;
}
console.log(factorial(5));// 120
上面这个方法有点类似将列表当成栈的结构在处理,栈的结构与列表类似,不过是两种不同的数据结构, 实现的方式和应用的场景很多的不同。
需求2:对列表中对元素进行排序
借助了原生JavaScript都能力来做都一个排序,如果用我们都列表本身都方法目前暂时做不到简单都调换循序, 可以后期增加一个调换位置都方法,倒是可以比较简洁都写完排序。
const list = new ListClass();
list.append('1、第一件事...');
list.append('3、第三件事...');
list.append('2、第二件事...');
list.append('5、第五件事...');
list.append('4、第四件事...');
console.log(list.toString()); // 1、第一件事...,3、第三件事...,2、第二件事...,5、第五件事...,4、第四件事...
const sort = (list, lifting) => {
// 定义临时存储
let item;
list = list.list
// 将列表都循环一次
for( let i = 0, len = list.length; i < len;i++ ){
// 每次将外层循环都元素与其他元素进行对比,确定下应该放置都位置
for( let j = i, len = list.length; j < len;j++ ){
// 判断是升序还是降序
if( lifting === 1 ){
if( list[i] > list[j] ){
item = list[j];
list[j] = list[i];
list[i] = item;
}
}else{
if( list[i] < list[j] ){
item = list[j];
list[j] = list[i];
list[i] = item;
}
}
}
}
}
sort(list, 1)
console.log(list.toString());// 1、第一件事...,2、第二件事...,3、第三件事...,4、第四件事...,5、第五件事...
sort(list, -1)
console.log(list.toString());// 5、第五件事...,4、第四件事...,3、第三件事...,2、第二件事...,1、第一件事...
以上就是关于列表数据结构的分享,欢迎各位朋友多多指导, 寻找志同道合喜欢学习对朋友,一起交流学习数据结构与算法。
各位朋友还有喜欢的数据结构可以留言后续更新哟