zoukankan      html  css  js  c++  java
  • 使用JavaScript浅谈列表

    什么是列表?

    列表是一组有序的数据。每个列表中的数据项称为元素。在JavaScript中,列表中的元素可以是任意类型的数据。列表中可以保存多少元素没有确定,实际使用时元素的数量受到程序内存的限制。

    现在我们来抽象一下列表的抽象数据类型定义

    listSize(属性):列表中的元素个数

    pos(属性):列表中的元素当前可访问的位置(位置指针)

    length(方法):返回列表中元素的个数

    clear(方法):清空列表中的所有元素

    toString(方法):返回列表的字符串形式

    getElement(方法):返回列表当前可访问位置对应的元素

    insert(方法):在现有元素后面插入新元素

    append(方法):在列表的末尾添加新元素

    remove(方法):从列表中移除元素

    front(方法):将列表的当前位置移动到第一个元素

    end(方法):将列表的当前位置移动到最后一个元素

    prev(方法):将列表的当前位置前移一位

    next(方法):将列表的当前位置后移一位

    hasNext(方法):判断列表在当前位置是否还有一下个元素

    hasPrev(方法):判断列表在当前位置是否还有上一个元素

    currPos(方法):返回列表的当前位置

    moveTo(方法):将列表的当前位置移动到指定位置

    上面抽象了列表的数据类型,包括要使用到的属性和方法,下面使用代码来实现一个列表类:

    // 定义列表类
    class List {
        constructor() {
            // 定义列表的元素个数
            this.listSize = 0;
            // 列表的位置指针
            this.pos = 0;
            // 列表的数据存储
            this.dataSource = [];
        }
    
        // append: 列表增加元素
        append(element) {
            this.dataSource[this.listSize++] = element;
        }
    
        // remove: 列表中删除元素
        remove(element) {
            var findAt = this.find(element);
            if (findAt > -1) {
                this.dataSource.splice(findAt, 1);
                --this.listSize;
                return true;
            }
            return false;
        }
    
        // find:辅助方法,用于查找要操作的元素
        find(element) {
            for (var i = 0; i < this.listSize; i++) {
                if (this.dataSource[i] === element) {
                    return i;
                }
            }
            return -1;
        }
    
        // length:返回列表中的元素个数
        length() {
            return this.listSize;
        }
    
        // toString: 返回列表的字符串形式
        toString() {
            return this.dataSource.toString();
        }
    
        // insert: 向列表中添加一个元素
        insert(element, after) {
            var insertPos = this.find(after);
            if (insertPos > -1) {
                this.dataSource.splice(insertPos + 1, 0, element);
                ++this.listSize;
                return true;
            }
            return false;
        }
    
        // clear: 清空列表中的元素
        clear() {
            this.dataSource.length = 0;
            this.listSize = this.pos = 0;
        }
    
        // front:指针归零(移动到列表的第一个元素的位置)
        front() {
            this.pos = 0;
        }
        // end: 指针移动到列表的最后一个元素的位置
        end() {
            this.pos = this.listSize - 1;
        }
        // hasPrev: 判断指针是否可以向前移动
        hasPrev() {
            return this.pos > 0
        }
        // hasNext: 判断指针是否可以向后移动
        hasNext() {
            return this.pos < this.listSize - 1
        }
        // moveTo: 修改指针的位置
        moveTo(position) {
            if (0 <= position && position <= this.listSize - 1) {
                this.pos = position;
            }
        }
        // prev: 指针向前移动一位
        prev() {
            if (this.hasPrev()) {
                --this.pos;
            }
        }
        // next: 指针向后移动一位
        next() {
            if (this.hasNext()) {
                ++this.pos;
            }
        }
        // getElement: 获取列表中指针所对应的元素
        getElement() {
            return this.dataSource[this.pos];
        }
        // currPos: 返回当前指针位置
        currPos() {
            return this.pos;
        }
    }

    其中next,prev,moveTo,front,end是我们设置的一些迭代器,使用迭代器有如下好处:

    1. 访问列表元素的时候,我们不必关心底层的数据存储结构。

    2.当对列表进行删除或增加操作的时候,存储列表元素的数组的索引值就更新了,此时只用更新列表,不需要更新迭代器。

    3.可以用不同类型的数据存储方式来实现List类,迭代器为访问列表中的元素提供了一种统一的方式。

    这样子我们就是实现了上面抽象的列表数据结构,接下来我们用它在做些什么。

    创建一个Person 类,该类用于保存人的姓名和性别信息。创建一个至少包含10个Person对象的列表。编写一个函数显示列表中所有拥有相同性别的人。

    分析如下,我们之前创建的列表类里面只适合操作基本数据类型,现在列表中的元素很明显是引用类型,所以我们想到的编写一个新的列表类,它拥有List类的所有方法,同时对有些方法实现覆盖,还要增加一些新的方法,以达到自己的需求。(之前定义的List类只是一个基本的模型而已,方便在实际应用中提供基础方法,自己实现相关的扩展)

    代码如下:

    // 定义列表类
    class List {
        constructor() {
            // 定义列表的元素个数
            this.listSize = 0;
            // 列表的位置指针
            this.pos = 0;
            // 列表的数据存储
            this.dataSource = [];
        }
    
        // append: 列表增加元素
        append(element) {
            this.dataSource[this.listSize++] = element;
        }
    
        // remove: 列表中删除元素
        remove(element) {
            var findAt = this.find(element);
            if (findAt > -1) {
                this.dataSource.splice(findAt, 1);
                --this.listSize;
                return true;
            }
            return false;
        }
    
        // find:辅助方法,用于查找要操作的元素
        find(element) {
            for (var i = 0; i < this.listSize; i++) {
                if (this.dataSource[i] === element) {
                    return i;
                }
            }
            return -1;
        }
    
        // length:返回列表中的元素个数
        length() {
            return this.listSize;
        }
    
        // toString: 返回列表的字符串形式
        toString() {
            return this.dataSource.toString();
        }
    
        // insert: 向列表中添加一个元素
        insert(element, after) {
            var insertPos = this.find(after);
            if (insertPos > -1) {
                this.dataSource.splice(insertPos + 1, 0, element);
                ++this.listSize;
                return true;
            }
            return false;
        }
    
        // clear: 清空列表中的元素
        clear() {
            this.dataSource.length = 0;
            this.listSize = this.pos = 0;
        }
    
        // front:指针归零(移动到列表的第一个元素的位置)
        front() {
            this.pos = 0;
        }
        // end: 指针移动到列表的最后一个元素的位置
        end() {
            this.pos = this.listSize - 1;
        }
        // hasPrev: 判断指针是否可以向前移动
        hasPrev() {
            return this.pos > 0
        }
        // hasNext: 判断指针是否可以向后移动
        hasNext() {
            return this.pos < this.listSize - 1
        }
        // moveTo: 修改指针的位置
        moveTo(position) {
            if (0 <= position && position <= this.listSize - 1) {
                this.pos = position;
            }
        }
        // prev: 指针向前移动一位
        prev() {
            if (this.hasPrev()) {
                --this.pos;
            }
        }
        // next: 指针向后移动一位
        next() {
            if (this.hasNext()) {
                ++this.pos;
            }
        }
        // getElement: 获取列表中指针所对应的元素
        getElement() {
            return this.dataSource[this.pos];
        }
        // currPos: 返回当前指针位置
        currPos() {
            return this.pos;
        }
    }
    
    // 创建Person类
    class Person {
        constructor(name, sex) {
            this.name = name;
            this.sex = sex;
        }
    }
    
    
    class PersonList extends List {
        // 重写getElement方法
        getElement() {
            return this.dataSource[this.pos].name;
        }
        // 返回指定性别人员集合
        displayNames(sex){
            return this.dataSource.filter(person=>person.sex === sex);
        }
    };
    
    // 列表装载
    const personList = new PersonList();
    for (let i = 0; i < 10; i++) {
        personList.append(new Person('a' + i, Math.random() > 0.5 ? '男' : '女'));
    }
    
    console.log(personList.getElement()); // a0
    personList.end();
    console.log(personList.getElement());// a9
    
    console.log(personList);
    console.log('personList列表中性别为男的人员组合为',personList.displayNames('男'));

    这样子我们就实现了需求,你可能会说需要这么麻烦,创建一个函数统计一下指定性别的人员就行了,为什么还要这些操作。其实在这里我们练习的是列表的使用,在这里只是举一个列子,其中滋味,自己体会。

    有了之前的List类,我们处理一些相关的问题,通过简单的继承,就会变得相当简单。

    我觉得学习新的知识之后,一定要用到实际开发中去,不然你学与不学有什么区别了,无非是浪费了一些时间来安慰自己罢了。

    源码和案例地址:https://gitee.com/mvc_ydb/data-structure/blob/master/list.js

  • 相关阅读:
    请求重定向,请求转发
    post、get方法乱码问题
    Servlet
    修改Servlet模板,让Servlet更清新
    Java-Python对垒之质数计算
    使用Packet Tracer对不同网段组网模拟
    哑编码的两种方法
    AdaBoost scikit-learn相关参数
    KNN scikit-learn相关参数
    递归思想的应用-根据二叉树的中序遍历和前序遍历重建二叉树
  • 原文地址:https://www.cnblogs.com/jsydb/p/12491840.html
Copyright © 2011-2022 走看看