golang实现常用集合原理介绍

linmufeng 2020-04-20

golang本身对常用集合的封装还是比较少的,主要有数组(切片)、双向链表、堆等。在工作中可能用到其他常用的集合,于是我自己对常用的集合进行了封装,并对原理做了简单介绍,代码库地址:https://github.com/chentaihan/container,代码都是经过测试的,欢迎下载使用,反馈的问题我会第一时间修复

 

ArraySort排序数组

ArraySort使用数组保存数据,新增的时候通过类似二分查找找到插入位置,插入位置后面的数据往后移动一位,插入新元素,查找就是二分查找,删除就是通过二分查找找到对应的元素,之后的元素都向前移动一位。时间复杂度如下:

功能时间复杂度
新增O(n)
删除O(n)
查找O(logn)

LinkList单链表

通过链表头指针和链表尾两个指针将所有元素链接在一起,可以快速的在表头和表尾插入元素,删除和查找都是遍历链表,查找对应的元素,删除还需要改变指针指向。时间复杂度如下:

功能时间复杂度
新增O(1)
删除O(n)
查找O(n)

Queue循环队列

队列先进先出,循环队列采用数组保存元素,以循环的方式在数组中添加元素,当数组写满之后自动扩容,元素个数小于1M时二倍扩容,大于等于1M时每次加1M,删除元素的时候需要将对应的位置赋值为空指针,方便被删除的元素被回收。时间复杂度如下:

功能时间复杂度
进队列O(1)
出队列O(1)

QueueLink链表队列

队列先进先出,实现和单链表类似,进栈是在表尾添加元素,出栈就是表头出栈,即表头指向表头的下一个元素,相对数组实现的循环队列,链表队列不存在扩容的问题,但每个元素多了一个指针。时间复杂度如下:

功能时间复杂度
进队列O(1)
出队列O(1)

PriorityQueue优先级队列

优先级队列采用小堆实现,小堆采用数组保存数据,按照完全二叉树的方式操作数据,每个节点的值都小于等于左右子节点的值,保证了每次出队的都是最小值,即按照顺序出队。

时间复杂度如下:

功能时间复杂度
进队列O(logn)
出队列O(logn)

Stack栈

栈先进后出,采用数组保存元素,每次进栈的是栈顶元素,出栈的也是栈顶元素,当数组写满之后自动扩容,元素个数小于1M时二倍扩容,大于等于1M时每次加1M。时间复杂度如下:

功能时间复杂度
进栈O(1)
出栈O(1)

StackLink链表栈

队列先进先出,采用单链表保存数据,进栈是在表头添加元素,出栈就是表头出栈,即表头指向表头的下一个元素,相对数组实现的循环队列,链表队列不存在扩容的问题,但每个元素多了一个指针。时间复杂度如下:

功能时间复杂度
进栈O(1)
出栈O(1)

Map

对golang的map简单封装,增加了一些方法。对于golang中map的实现原理请看我的这篇文章:https://www.cnblogs.com/hlxs/p/10408961.html,时间复杂度如下:

功能时间复杂度
新增O(1)
修改O(1)
查询O(1)
删除O(1)

MapSync同步map

就是map+读写锁,时间复杂度和map一样

LinkMap

双向链表 + map,双向链表按照顺序保存新增的元素,可以按照添加的顺序遍历数据,增删改查时间复杂度都和map一样

TreeMap

通过二叉搜索树保存数据,后面会详细介绍二叉搜索树,使用二叉搜索树就不存在扩容的问题,hashmap则存在扩容的问题,时间复杂度如下:

功能时间复杂度
新增O(logn)
修改O(logn)
查询O(logn)
删除O(logn)

LRU

lru的实现原理其实和LinkMap几乎一样,只不过lru在修改或是查询的时候都会将被访问的元素移到链表的表头,表尾的数据是最先被淘汰的,时间复杂度如下:

功能时间复杂度
新增O(1)
修改O(1)
查询O(1)
删除O(1)

BinaryTree二叉搜索树

提供二叉搜索树的增删改查功能,删除相对复杂点,时间复杂度如下:

功能时间复杂度
新增O(logn)
修改O(logn)
查询O(logn)
删除O(logn)

heap大堆

堆是对golang本身container/heap的简单封装,大堆中某个节点的值总是不大于其父节点的值;堆总是一棵完全二叉树。,时间复杂度如下:

功能时间复杂度
新增O(logn)
查询O(n)
删除O(logn)

heap小堆

堆是对golang本身container/heap的简单封装,小堆中某个节点的值总是不小于其父节点的值;堆总是一棵完全二叉树。,时间复杂度如下:

功能时间复杂度
新增O(logn)
查询O(n)
删除O(logn)

 

 

相关推荐

末点 / 0评论 2020-06-27