TypeScript演算法與資料結構-陣列篇

郭勵之發表於2019-07-09

本文的原始碼在我的github,可以參考一下

陣列是資料結構中最簡單,也是使用最廣泛的一種。在原生的js中,陣列給我們提供了很多方便的操作方法,比如push(), pop(), shift(), unshift()。但是出於對資料結構的學習,我們將不使用這些已有的方法,而是自己實現這些方法。這樣也方便我們計算其時間複雜度。這裡我們選擇使用TypeScript實現,主要是因為TypeScript的強型別控制,以及泛型這些高階特性。

先來看我們自己實現陣列的例項屬性以及建構函式,我們用capacity來表示陣列的容量,雖然在TypeScript中並沒有像Java那樣嚴格限定陣列長度,但我們仍然希望儘量接近Java。我們用size來表示當前陣列中元素的個數

class MyArray<T> {
    private data: Array<T>;
    private size: number = 0;
    constructor(capacity = 10) {
        this.data = new Array(capacity);
    }
}

1.在陣列中插入元素

在陣列index位置插入元素是我們經常使用的一個操作,那我們就需要從之前陣列中index位置開始,每個元素向後移動一個位置。以便給新插入的元素挪出位置。在操作的末尾,我們需要維護一下陣列的size.

public add(index: number, e: T) {
    if (index < 0 || index > this.size) {
        throw new Error('Add failed. Required index >= 0 and index <= size.');
    }
    if (this.size === this.data.length) {
        this.resize(2 * this.data.length);
    }
    for (let i = this.size - 1; i >= index; i--) {
        this.data[i + 1] = this.data[i];
    }
    this.data[index] = e;
    this.size++;
}

陣列-插入

在陣列中新增元素,最好情況下,使用者只用操作一次,時間複雜度是O(1);最差的情況下,使用者需要操作size次,時間複雜度是O(n)

這裡有一點需要注意,當陣列當前元素的個數size和capacity相等時,我們需要給陣列進行擴容為2倍處理,這個我後面會專門提及

2.在陣列中查詢元素和修改元素

這個沒啥好說的,查詢和修改陣列中某個元素複雜度就是O(1)

public get(index: number): T {
    if (index < 0 || index >= this.size) {
        throw new Error('Get failed. Index is illegal.');
    }
    return this.data[index];
}

3.在陣列中刪除元素

在陣列index位置刪除元素,這裡我們需要把陣列從index+1位置開始,每個元素向前移動一個元素

public remove(index: number): T {
    if (index < 0 || index >= this.size) {
        throw new Error('Remove failed. Index is illegal.');
    }
    let ret = this.data[index];
    for (let i = index + 1; i < this.size; i++) {
        this.data[i - 1] = this.data[i];
    }
    this.size--;
    this.data[this.size] = undefined;
    // 如果陣列中的元素僅為陣列容量的1/4時,這時需要進行縮容操作
    if (this.size === this.data.length / 4 && this.data.length / 2 !== 0) {
        this.resize(this.data.length / 2);
    }
    return ret;
}

陣列-刪除

在陣列中刪除元素,最好情況下,使用者只用操作一次,時間複雜度是O(1);最差的情況下,使用者需要操作size次,時間複雜度是O(n)
當陣列中的元素個數僅為陣列容量的1/4時,我們需要對陣列進行縮容為1/2操作

4.陣列的擴容或者縮容

陣列的擴容和縮容操作很簡單,原理就是接受一個新的容量,把之前陣列中的內容複製到新陣列中,並返回新的陣列

private resize(newCapacity: number): void {
    let newData = new Array(newCapacity);
    for (let i = 0; i < this.size; i++) {
        newData[i] = this.data[i];
    }
    this.data = newData;
}

更多相關資料結構,可以前往我的github。持續更新中,喜歡的話給個star~

相關文章