首页 > 编程语言 > 详细

实现一个支持动态扩容的数组

时间:2020-04-01 19:24:11      阅读:263      评论:0      收藏:0      [点我收藏+]

主要考虑3个问题

  1. 主要的操作
  2. 扩容的策略
  3. 数据迁移策略

其中,主要操作如下:

PS. 注意没有插入操作,只有添加,删除,查找,修改操作。
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 // 查看数组是否为空
}

大概有3种设计方案

  1. 普通方案:两倍扩容+挨个元素拷贝。
  2. 仿造slice切片的方案:数组做底层存储+类似窗户的索引+ 更灵活的扩容+数组整体拷贝。
    删除元素时不需要真的删除,只是移动索引。
    增加元素时需要往底层数组添加元素,且移动索引。
  3. 加入COW机制的方案:针对多线程读多写少场景。// 附录2

方案1

// 附录1

方案2: slice的方案

  • 扩容策略:比较复杂
    技术分享图片
  • 数据迁移策略:整体拷贝
    技术分享图片

方案3: 针对并发读多写少的优化

  • CopyOnWriteArrayList使用场景
    1、读多写少(白名单,黑名单,系统配置的信息,商品类目的访问和更新场景),为什么?因为写的时候会复制新集合。
    2、集合不大,为什么?因为写的时候会复制新集合。
    实时性要求不高,为什么,因为有可能会读取到旧的集合数据。---- 也就是允许读到旧数据。

方案4

// 附录4
Q:golang的slice动态扩展实现为何不用动态链表?
A:对内存不优化,有gc压力。

扩展

slice并发不安全的问题

参考

  1. Go 语言实现动态数组
    https://github.com/hetong12345/goDataStructure/blob/master/array.go#L101
    https://github.com/JeffreyBool/array/blob/master/array.go
  2. 简单说一说Java中的CopyOnWriteArrayList
  3. 并发容器之CopyOnWriteArrayList
  4. golang的slice动态扩展实现为何不用动态链表?

实现一个支持动态扩容的数组

原文:https://www.cnblogs.com/yudidi/p/12614277.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!