数据结构之List | 让我们一块来学习数据结构
列表[List]的定义
列表是一组有序的数据。每个列表中的数据项称为元素。在 JavaScript 中,列表中的元素 可以是任意数据类型。列表中可以保存多少元素并没有事先限定,实际使用时元素的数量 受到程序内存的限制。
不包含任何元素的列表称为空列表。列表中包含元素的个数称为列表的 length。在内部实 现上,用一个变量 listSize 保存列表中元素的个数。可以在列表末尾 append 一个元素, 也可以在一个给定元素后或列表的起始位置 insert 一个元素。使用 remove 方法从列表中 删除元素,使用 clear 方法清空列表中所有的元素。
还可以使用 toString() 方法显示列表中所有的元素,使用 getElement() 方法显示当前元素。列表拥有描述元素位置的属性。列表有前有后(分别对应 front 和 end)。使用 next() 方 法可以从当前元素移动到下一个元素,使用 prev() 方法可以移动到当前元素的前一个元 素。还可以使用 moveTo(n) 方法直接移动到指定位置,这里的 n 表示要移动到第 n 个位置。 currPos 属性表示列表中的当前位置。
列表的抽象数据类型定义
| 属性/方法 | 描述 |
|---|---|
| listSize | 列表的元素个数 |
| pos | 列表的当前位置 |
| length | 返回列表中元素的个数 |
| clear(方法) | 清空列表中的所有元素 |
| toString(方法) | 返回列表的字符串形式 |
| getElement(方法) | 返回当前位置的元素 |
| insert(方法) | 在现有元素后插入新元素 |
| append(方法) | 在列表的末尾添加新元素 |
| remove(方法) | 从列表中删除元素 |
| front(方法) | 将列表的当前位置设移动到第一个元素 |
| end(方法) | 将列表的当前位置移动到最后一个元素 |
| prev(方法) | 将当前位置后移一位 |
| next(方法) | 将当前位置前移一位 |
| currPos(方法) | 返回列表的当前位置 |
| moveTo(方法) | 将当前位置移动到指定位置 |
| contains(方法) | 判断给定值是否在列表中 |
| getElement(方法) | 显示当前值 |
实现列表类
根据上面定义的列表抽象数据类型,可以直接实现一个 List 类。让我们从定义构造函数开 始,虽然它本身并不是列表抽象数据类型定义的一部分:
class List {
constructor() {
this.dataSource = [];
this.listSize = 0;
this.pos = 0;
}
clear() {}
find() {}
toString() {}
insert() {}
append() {}
remove() {}
front() {}
end() {}
prev() {}
next() {}
length() {}
currPos() {}
moveTo() {}
getElement() {}
contains() {}
}
append:给列表添加元素
append(element) {
this.dataStore[this.listSize++] = element;
}
当新元素就位后,变量 listSize 加 1。
find:在列表中查找某一元素
find() 方法通过对数组对象 dataStore 进行迭代,查找给定的元素。如果找到,就返回该 元素在列表中的位置,否则返回 -1,这是在数组中找不到指定元素时返回的标准值。我们 可以在 remove() 方法中利用此值做错误校验。
find(element) {
for (let i = 0, len = this.dataStore.length; i < len; ++i) {
if (this.dataStore[i] == element) {
return i;
}
}
return -1;
}
remove:从列表中删除元素
remove() 方法是 List 类中较难实现的 一个方法。首先,需要在列表中找到该元素,然后删除它,并且调整底层的数组对象以填 补删除该元素后留下的空白。好消息是,可以使用数组的 splice() 方法简化这一过程。
remove(element) {
const index = this.find(element);
if (index === -1) {
return false
}
this.dataStore.splice(index, 1);
--this.listSize;
return true;
}
length:列表中有多少个元素
length() 方法返回列表中元素的个数:
length() {
return this.listSize;
}
toString:显示列表中的元素
现在是时候创建一个方法,用来显示列表中的元素了。
toString() {
return this.dataStore.toString();
}
insert:向列表中插入一个元素
接下来要讨论的方法是 insert()。如果在List中间位置删除了一个元素,但是现在又想将 它放回原来的位置,该怎么办? insert() 方法需要知道将元素插入到什么位置,因此现在 我们假设插入是指插入到列表中某个元素之后。
insert(element, index) {
const index = this.find(element);
if (index === -1) {
return false;
}
this.dataStore.splice(index + 1, 0, element);
++this.listSize;
return true;
}
clear:清空列表中所有的元素
clear() {
delete this.dataStore;
this.dataStore = [];
this.listSize = this.pos = 0;
}
contains:判断给定值是否在列表中
当需要判断一个给定值是否在列表中时,contains() 方法就变得很有用。
contains(element) {
for (let i = 0, len = this.dataStore.length; i < len; ++i) {
if (this.dataStore[i] == element) {
return true;
}
}
return false;
}
也可以使用之前实现的find方法
遍历列表
最后的一组方法允许用户在列表上自由移动
front() {
this.pos = 0;
}
end() {
this.pos = this.listSize - 1;
}
prev() {
if (this.pos > 0) {
--this.pos;
}
}
next() {
if (this.pos < this.listSize - 1) {
++this.pos;
}
}
currPos() {
return this.pos;
}
moveTo(position) {
this.pos = position;
}
getElement() {
return this.dataStore[this.pos];
}
使用迭代器访问列表
使用迭代器,可以不必关心数据的内部存储方式,以实现对列表的遍历。前面提到的方法 front()、end()、prev()、next() 和 currPos 就实现了 List 类的一个迭代器。以下是和使 用数组索引的方式相比,使用迭代器的一些优点。
访问列表元素时不必关心底层的数据存储结构。
当为列表添加一个元素时,索引的值就不对了,此时只用更新列表,而不用更新迭代器。
可以用不同类型的数据存储方式实现 List 类,迭代器为访问列表里的元素提供了一种 统一的方式。 了解了这些优点后,来看一个使用迭代器遍历列表的例子:
for(lists.front(); lists.currPos() < lists.length(); lists.next()) {
console.log(lists.getElement());
}
在 for 循环的一开始,将列表的当前位置设置为第一个元素。只要 currPos 的值小于列表 的长度,就一直循环,每一次循环都调用 next() 方法将当前位置向前移动一位。
同理,还可以从后向前遍历列表,代码如下:
for(lists.end(); lists.currPos() >= 0; lists.prev()) {
console.log(lists.getElement());
}
循环从列表的最后一个元素开始,当当前位置大于或等于 0 时,调用 prev() 方法后移 一位。
迭代器只是用来在列表上随意移动,而不应该和任何为列表增加或删除元素的方法一起 使用。
完整代码
class List {
constructor() {
this.dataStore = [];
this.listSize = 0;
this.pos = 0;
}
clear() {
delete this.dataStore;
this.dataStore = [];
this.listSize = this.pos = 0;
}
find(element) {
for (let i = 0, len = this.dataStore.length; i < len; ++i) {
if (this.dataStore[i] == element) {
return i;
}
}
return -1;
}
toString() {
return this.dataStore.toString();
}
insert(element, index) {
const index = this.find(element);
if (index === -1) {
return false;
}
this.dataStore.splice(index + 1, 0, element);
++this.listSize;
return true;
}
append(element) {
this.dataStore[this.listSize++] = element;
}
remove(element) {
const index = this.find(element);
if (index === -1) {
return false;
}
this.dataStore.splice(index, 1);
--this.listSize;
return true;
}
length() {
return this.listSize;
}
contains(element) {
for (let i = 0, len = this.dataStore.length; i < len; ++i) {
if (this.dataStore[i] == element) {
return true;
}
}
return false;
}
front() {
this.pos = 0;
}
end() {
this.pos = this.listSize - 1;
}
prev() {
if (this.pos > 0) {
--this.pos;
}
}
next() {
if (this.pos < this.listSize - 1) {
++this.pos;
}
}
currPos() {
return this.pos;
}
moveTo(position) {
this.pos = position;
}
getElement() {
return this.dataStore[this.pos];
}
}
参考资料
- 数据结构与算法JavaScript描述
数据结构之List | 让我们一块来学习数据结构的更多相关文章
- 数据结构之Queue | 让我们一块来学习数据结构
前面的两篇文章分别介绍了List和Stack,下面让我们一起来学习Queue 数据结构之List | 让我们一块来学习数据结构 数据结构之Stack | 让我们一块来学习数据结构 队列的概况 队列是一 ...
- 数据结构之LinkedList | 让我们一块来学习数据结构
highlight: monokai theme: vue-pro 上一篇文章中使用列表(List)对数据排序,当时底层储存数据的数据结构是数组.本文将讨论另外一种列表:链表.我们会解释为什么有时链表 ...
- 数据结构之Set | 让我们一块来学习数据结构
数组(列表).栈.队列和链表这些顺序数据结构对你来说应该不陌生了.现在我们要学习集合,这是一种不允许值重复的顺序数据结构.我们将要学到如何创建集合这种数据结构,如何添加和移除值,如何搜索值是否存在.你 ...
- 数据结构之Stack | 让我们一块来学习数据结构
栈的介绍 栈就是和列表类似的一种数据结构,它可用来解决计算机世界里的很多问题.栈是一种高 效的数据结构,因为数据只能在栈顶添加或删除,所以这样的操作很快,而且容易实现. 栈的使用遍布程序语言实现的方方 ...
- 《Java程序设计与数据结构教程(第二版)》学习指导
<Java程序设计与数据结构教程(第二版)>学习指导 欢迎关注"rocedu"微信公众号(手机上长按二维码) 做中教,做中学,实践中共同进步! 原文地址:http:// ...
- SqList *L 和 SqList * &L的区别/学习数据结构突然发现不太懂 小祥我查找总结了一下
小祥在学习李春葆的数据结构教程时发现一个小问题,建立顺序表和输出线性表,这两个函数的形参是不一样的. 代码在这里↓↓↓ //定义顺序表L的结构体 typedef struct { Elemtype d ...
- 在Object-C中学习数据结构与算法之排序算法
笔者在学习数据结构与算法时,尝试着将排序算法以动画的形式呈现出来更加方便理解记忆,本文配合Demo 在Object-C中学习数据结构与算法之排序算法阅读更佳. 目录 选择排序 冒泡排序 插入排序 快速 ...
- MySQL 学习 --- 数据结构和索引
本文参考了多篇文章集成的笔记,希望各位学习之前可以阅读以下参考资料先 概述 文章分几个部分 :第一部分介绍了B-Tree 和 B+Tree 这种数据结构作为索引:第二部分介绍索引的最左前缀原则和覆盖索 ...
- 省选算法学习-数据结构-splay
于是乎,在丧心病狂的noip2017结束之后,我们很快就要迎来更加丧心病狂的省选了-_-|| 所以从写完上一篇博客开始到现在我一直深陷数据结构和网络流的漩涡不能自拔 今天终于想起来写博客(只是懒吧.. ...
随机推荐
- Centos8.2安装Mongodb4.4.2(社区版)
1:下载 wget https://fastdl.mongodb.org/linux/mongodb-linux-x86_64-rhel80-4.4.2.tgz 官网地址: 2:解压 tar -zxv ...
- Pandas初体验
目录 Pandas 一.简介 1.安装 2.引用方法 二.series 1.创建方法 2.缺失数据处理 2.1 什么是缺失值 2.2 NaN特性 2.3 填充NaN 2.4 删除NaN 2.5 其他方 ...
- CSS 书写禅机
这是未来的趋势所向,如是我行. 注意:原文发表于 2017-9-6,随着框架不断演进,部分内容可能已不适用. CSS 日渐惹人憎恶. 究其原因颇多,归根结底,皆因 CSS 给人的感觉总是飘渺迷蒙.变幻 ...
- 基于docker部署skywalking实现全链路监控
一.概述 简介 skywalking是一个开放源码的,用于收集.分析,聚合,可视化来自于不同服务和本地基础服务的数据的可观察的平台,skywalking提供了一个简单的方法来让你对你的分布式系统甚至是 ...
- dubbo使用和配置讲解
1. 分布式系统中相关概念 1.1 互联网项目特点及目标 1.1.1 特点: 用户多 流量大.并发高 海量数据 易受攻击 功能繁琐 变更快 1.1.2 指标及相关目标 互联网项目三高目标:高并发.高可 ...
- 【Azure 微服务】Service Fabric, 使用ARM Template方式来更新SF集群的证书(Renew SF Certificate)
问题描述 因证书过期导致Service Fabric集群挂掉(升级无法完成,节点不可用)一文中,描述了因为证书过期而导致了SF集群不可用,并且通过命令dd-AzServiceFabricCluster ...
- Debian中的NVIDIA显卡驱动安装——超简单,一行命令
其实Debian的non-free固件中包含NVIDIA的显卡驱动,所以没必要在官网下run包一步一步来 sudo apt install nvidia-settings 安装时会提示与X冲突,没关系 ...
- ZooKeeper 基本概念并介绍RPC中Netty和Zookeeper的使用
前言 ZooKeeper 是一个分布式协调服务,可用于服务发现,分布式锁,分布式领导选举,配置管理等.Zookeeper提供一个类似Linux文件系统的属性结构,每个节点可存储少量的内存文件,并提供每 ...
- 给出镜像FreeBSD 基本要求
硬盘 ports 500G update 500G portsnap 500G pkg arm64 amd64 i386 11-12-13 4TB 网络流量一个月专线大概2w RMB CPU 内存 其 ...
- Kotlin/Java Base64编码和解码(图片、文件)
原文: Kotlin/Java Base64编码和解码(图片.文件) | Stars-One的杂货小窝 最近在项目中使用到了Base64编码和解码,便是稍微写篇文章记录一下 PS:本文代码都是使用Ko ...