再回首數據結構—數組(Golang實現)

數組爲線性數據結構,一般編程語言都有自帶了數組數據類型結構,數組存放的是有個相同數據類型的數據集;
  爲何稱數組爲線性數據結構:由於數組在內存中是連續存儲的數據結構,數組中每一個元素最多隻有左右兩個方向有相鄰的元素;數組中的每一個元素都有一個索引(或稱下標)標識,這個索引在編程語言中一般都是從0開始,經過索引可訪問到數組中對應的元素;數組的數據結構以下所示:編程

數組的優點

  從上文中咱們知道數組在內存中是連續存儲的也就是說數組中元素在內存塊爲連續,此時咱們利用此特性經過索引快速訪問數據元素;所以也稱數組支持隨機訪問
  下面咱們經過一個示例來講明數組的隨機訪問特性;數組

  在Go中定義一個長度爲7的數組:
  var array [7] int
  此時咱們能夠經過索引隨機訪問數組中元素如:array[5]便可訪問到數組中的第六個元素,這背後又是怎樣的呢,上面咱們說過數組在內存中的存儲結構是連續的上面咱們定義的數組結構以下所示:數據結構

  此處假設該數組內存空間首地址爲:000,因爲該數據類型爲int所以每一個數據元素佔4個字節,因此上面定義7個長度數組佔用的內存地址爲:000~024連續的地址空間;因此經過下面的計算公式便可實現數組的隨機訪問,好比訪問數組中第五個元素內存地址的計算公式以下:編程語言

  所訪問元素內存地址=數組首地址 + index * 數據類型大小
  array[5]內存地址 = 000 + 5 * 4
  因此數組的優點爲:一、簡單;二、支持隨機訪問,經過索引隨機訪問時間複雜度爲O(1)性能

數組插入與刪除

  數組的插入與刪除其實並不高效,因爲數組存儲是連續的內存空間,因此咱們在對數組進行操做時都須要去維護這個連續性,所以也就犧牲了一些效率,當插入或刪除數組中元素時數組中元素都須要大量移動以下圖所示:ui

  

  在索引爲3的位置插入g,需把索引3~n元素後移一位code

  

  刪除數組索引爲1的元素,需把索引2~n元素前移一位blog

  所以數組的插入、刪除平均時間複雜度爲:O(n),這裏說的是平均複雜度是由於還有例外狀況,好比在數組末尾插入元素、刪除數組末尾元素這些狀況時間複雜度爲O(1);
  每種編程語言中都存在數組,數組其實還分爲靜態數組動態數組;靜態數組是指數組建立後存儲空間固定不變的、而動態數組爲在使用數組過程當中當存儲空間不足時可動態擴容;下面爲使用Golang實現的動態數組封裝,動態數組的擴容、縮容須要注意擴容的大小與縮容的零界點,此處可能會影響到數組性能;索引

type Array struct {
    data []interface{}
    size int
  }

  func NewArray(capacity int) *Array {
    array := new(Array)
    array.data = make([]interface{}, capacity)
    array.size = 0
    return array
  }

  func NewDefaultArray() *Array {
    return NewArray(10)
  }

  /**
  獲取元素個數
   */
  func (a *Array) Size() int {
    return a.size
  }

  /**
  獲取容量大小
   */
  func (a *Array) Capacity() int {
    return len(a.data)
  }

  /**
  是否爲空
   */
  func (a *Array) IsEmpty() bool {
    return a.size == 0
  }

  /**
  往數組末尾添加元素
   */
  func (a *Array) AddLast(e interface{}) error {
    return a.Add(a.size, e)
  }

  /**
  清空數組
   */
  func (a *Array) Clear() {
    a.data = make([]interface{}, a.size)
    a.size = 0
  }

  /**
  往第一個位置添加元素
   */
  func (a *Array) AddFirst(e interface{}) error {
    return a.Add(0, e)
  }

  /**
  往指定索引添加元素
   */
  func (a *Array) Add(index int, e interface{}) error {
if index < 0 || index > a.size {
    return errors.New("Add failed, Require index >= 0 and index< size")
}

if a.size == len(a.data) {
    a.resize(2 * len(a.data))
}

for i := a.size - 1; i >= index; i-- {
    a.data[i+1] = a.data[i]
}
a.data[index] = e
a.size++
return nil
  }

  /**
  更新指定位置元素
   */
  func (a *Array) Update(index int, e interface{}) error {
    if index < 0 || index > a.size {
        return errors.New("update failed, Require index >= 0 and index< size")
    }
    a.data[index] = e
    return nil
  }

  /**
  獲取指定位置元素
   */
  func (a *Array) FindElement(index int) interface{} {
    if index < 0 || index > a.size {
        return errors.New("update failed, Require index >= 0 and index< size")
    }
    return a.data[index]
  }

  /**
  刪除數組指定索引位置的元素,返回刪除的元素
   */
  func (a *Array) Remove(index int) (e interface{}) {
    if index < 0 || index > a.size {
        return errors.New("remove failed, Require index >= 0 and index< size")
    }
    e = a.data[index]
    for i := index + 1; i < a.size; i++ {
        a.data[i-1] = a.data[i]
    }
    a.size--
    //刪除元素後數組縮小一位,將該位置元素置nil
    a.data[a.size] = nil
    return
  }

  /**
  刪除數組首個元素
   */
  func (a *Array) RemoveFirst() (e interface{}) {
    return a.Remove(0)
  }

  /**
  數組擴容
   */
  func (a *Array) resize(newCapacity int) {
    newData := make([]interface{}, newCapacity)
    for i := 0; i < a.size; i++ {
        newData[i] = a.data[i]
    }
    a.data = newData
  }

參考資料: https://zh.wikipedia.org/wiki/%E6%95%B0%E7%BB%84ip

文章首發地址:Solinx
http://www.solinx.co/archives/1265

相關文章
相關標籤/搜索