Go 語言二次封裝數組

來源:互聯網
上載者:User

類比動態數組的實現(自動擴容),完成數組的增刪查改操作:

自訂的數組結構

type Array struct {    data []interface{}  // 泛型數組    size int            // 元素數量}

數組的介面

type ArrayInterface interface {    // 添加    Add(int, interface{})    // 插入元素    AddLast(interface{})    AddFirst(interface{})    // 刪除    Remove(int) interface{}    RemoveFirst() interface{}    RemoveLast() interface{}    // 尋找    Find(interface{}) int // 尋找元素返回第一個索引    FindAll(interface{}) []int // 尋找元素返回所有索引    Contains(interface{}) bool // 尋找是否存在元素    Get(int) interface{}    // 修改    Set(int, interface{})    // 基本方法    GetCapacity() int // 獲得數組容量    GetSize() int  // 獲得元素個數    IsEmpty() bool // 查看數組是否為空白    // 自調用的方法    resize() // 用於數組的擴、縮容}

數組實現

resize 規則

數組 resize 規則:

  • 超過數組容量,按照當前容量的 2 倍擴容,
  • 數組元素個數為當前容量 1/4 時,鎖容為當前容量的一半。

如果在 1/2 時縮容,會導致擴容臨界點添加、刪除一個元素都是 O(n) 複雜度的情況。

數組實現

建構函式

Go 沒有提供建構函式,我們可以聲明一個函數代替

// 獲得自訂數組,參數為數組的初始長度func GetArray(capacity int) *Array {    arr := &Array{}    arr.data = make([]interface{}, capacity)    arr.size = 0    return arr}

基本方法

// 獲得數組容量func (a *Array) GetCapacity() int {    return len(a.data)}// 獲得數組元素個數func (a *Array) GetSize() int {    return a.size}// 判斷數組是否為空白func (a *Array) IsEmpty() bool {    return a.size == 0}

數組容量調整

// newCapacity 新數組容量// 邏輯:聲明新的數組,將原數組的值 copy 到新數組中func (a *Array) resize(newCapacity int) {    newArr := make([]interface{}, newCapacity)    for i := 0; i < a.size; i++ {        newArr[i] = a.data[i]    }    a.data = newArr}

尋找元素

尋找元素指輸入元素返回元素的索引

// 獲得元素的首個索引,不存在則返回 -1func (a *Array) Find(element interface{}) int {    for i:= 0; i < a.size; i++ {        if element == a.data[i] {            return i        }    }    return -1}// 獲得元素的所有索引,返回索引組成的切片func (a *Array) FindAll(element interface{}) (indexes []int) {    for i := 0; i < a.size; i++ {        if element == a.data[i] {            indexes = append(indexes, i)        }    }    return}// 查看數組是否存在元素,返回 boolfunc (a *Array) Contains(element interface{}) bool {    if a.Find(element) == -1 {        return false    }    return true}// 獲得索引對應元素,需要判斷索引有效範圍func (a *Array) Get(index int) interface{} {    if index < 0 || index > a.size - 1 {        panic("Get failed, index is illegal.")    }    return a.data[index]}

修改元素

修改索引對應元素值func (a *Array) Set(index int, element interface{}) {    if index < 0 || index > a.size - 1 {        panic("Set failed, index is illegal.")    }    a.data[index] = element}

添加元素

添加元素需要考慮擴容問題

func (a *Array) Add(index int, element interface{}) {    if index < 0 || index > a.GetCapacity() {        panic("Add failed, require index >= 0 and index <= capacity")    }    // 數組已滿則擴容    if a.size == len(a.data) {        a.resize(2 * a.size)    }    // 將插入的索引位置之後的元素後移,騰出插入位置    for i := a.size - 1; i > index; i-- {        a.data[i + 1] = a.data[i]    }    a.data[index] = element    // 維護數組元素的數量    a.size++}func (a *Array) AddLast(element interface{}) {    a.Add(a.size, element)}func (a *Array) AddFirst(element interface{}) {    a.Add(0, element)}

刪除元素

刪除元素需要考慮縮容問題

func (a *Array) Remove(index int) interface{} {    if index < 0 || index >= a.size {        panic("Remove failed, index is illegal.")    }    removeEle := a.data[index]    // 從 index 之後的元素,都向前移動一個位置    for i := index + 1; i < a.size; i++ {        a.data[i-1] = a.data[i]    }    a.size--    // 清理最後一個元素    a.data[a.size] = nil    // 考慮邊界情況,不能 resize 為0    if a.size == len(a.data)/4 && len(a.data)/2 != 0 {        a.resize(len(a.data) / 2)    }    return removeEle}func (a *Array) RemoveFirst() interface{} {    return a.Remove(0)}func (a *Array) RemoveLast() interface{} {    return a.Remove(a.size - 1)}

重寫 String 方法

重寫數組列印時的展示形式

func (a *Array) String() string {    var buffer bytes.Buffer    buffer.WriteString(fmt.Sprintf("Array: size = %d, capacity = %d\n", a.size, a.GetCapacity()))    buffer.WriteString("[")    for i := 0; i < a.size; i++ {        buffer.WriteString(fmt.Sprint(a.data[i]))        if i != a.size - 1 {            buffer.WriteString(",")        }    }    buffer.WriteString("]")    return buffer.String()}

最終測試

func main() {    arr := GetArray(10)    for i := 0; i < 10; i++ {        arr.AddLast(i)    }    fmt.Println(arr)    arr.Add(1, 100)    fmt.Println(arr)    arr.AddFirst(-1)    fmt.Println(arr)}

輸出結果:

Array: size = 10, capacity = 10[0,1,2,3,4,5,6,7,8,9]Array: size = 11, capacity = 20[0,100,2,2,3,4,5,6,7,8,9]Array: size = 12, capacity = 20[-1,100,100,2,2,3,4,5,6,7,8,9]

時間複雜度分析

添加操作

  • Add(int, interface{}) O(n)
  • AddLast(interface{}) O(1)
  • AddFirst(interface{}) O(n)

實際 AddLast 的均攤複雜度是 O(1),因為涉及到擴容的操作。長度為 n 的數組添加 n + 1 個元素,會操作 2n + 1。因為第 n + 1 次導致擴容的 n 次操作。

刪除操作

  • Remove(int) interface{} O(n)
  • RemoveFirst() interface{} O(n)
  • RemoveLast() interface{} O(1)

尋找操作

  • Find(interface{}) int O(n)
  • FindAll(interface{}) []int O(n)
  • Contains(interface{}) bool O(n)
  • Get(int) interface{} O(1)

修改操作

  • Set(int, interface{}) O(1)
相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.