使用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

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM