数组为线性数据结构,一般编程语言都有自带了数组数据类型结构,数组存放的是有个相同数据类型的数据集;
为何称数组为线性数据结构:由于数组在内存中是连续存储的数据结构,数组中每一个元素最多只有左右两个方向有相邻的元素;数组中的每一个元素都有一个索引(或称下标)标识,这个索引在编程语言中一般都是从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 }