假设:
我国偏僻的山区中有个小村庄,叫A村,村里面有陈一、刘二、张三、李四、王五、赵六6个村民,村里还有一位非常聪明的村长
数组
现在这六个村民要修房子,于是村长就给6个村民划分了一块土地,让陈一、刘二、张三、李四、王五、赵六他们依次修改一块,就像下面一样:
0 | 1 | 2 | 3 | 4 | 5 |
---|---|---|---|---|---|
陈一 | 刘二 | 张三 | 李四 | 王五 | 赵六 |
村长分布为他们设定了门牌号,分布为0,1,2,3,4,5。这样,当村长要找“张三”的时候,就直接去敲门牌号为2的房子就可以了,村长觉得非常方面,这种排列的方式,村长叫他为“数组”
中间插入
这个时候,村里有来了一个新的村民,叫“郭七”,“郭七”是张三的好朋友,他告诉村长说,我要和张三的房子修改一块,于是,村长让“郭七”住“张三”的房子,“张三”住“李四”的房子,“李四”住“王五”的房子……,“赵六”自己修新房子,并取编号为6,但移动的村民有些不高兴了……
0 | 1 | 2 | 3 | 4 | 5 | 6 |
---|---|---|---|---|---|---|
陈一 | 刘二 | 郭七 | 张三 | 李四 | 王五 | 赵六 |
数据扩张
过了一段时间,村里又有来了一个新的村民,叫“罗八”,“罗八”也要修房子,但是村长发现这块土地只能修7个房子,已经没有地方修房子了,而在非常远的地方才有一块更大的土地,为了方便管理,村长没办法了,只能让大家搬家到新的土地,大家怨声载道……
总结
从上面可以看得出数组数组的优缺点如下:
优点
通过门牌号(索引)能够非常快的找到某个村民,比如门牌号为1,则找到了“刘二“,所以当我们不会经常修改数据,而对查询效率要求特别高的时候就需要使用数组结构
缺点
- 插入数据(或者删除数据)需要整体的移动,非常的影响性能
- 当数组空间不够的时候,需要整体的移动数据
解决方案
- 从上面村长选地可以看出,只有6个人时候,就选了一个7个人的土地,所以防止大家频繁的搬家,可以适当的多预留空间
链表
对于上面出现的问题,村长很头疼,于是他修改了一个方案,去解决平凡搬家的问题,他找了一块更大的地,让大家随意的修房子,但是有个要求,每个人必须记住他“下一家”的村民是谁?于是有了下面的结构:
村长 | 陈一 | 刘二 | 张三 | 李四 | 王五 | 赵六 | 郭七 | 罗八 |
---|---|---|---|---|---|---|---|---|
陈一 | 刘二 | 张三 | 李四 | 王五 | 赵六 | 郭七 | 罗八 | – |
当村长要让“张三”来村里开会时,他就告诉“陈一”,然后"陈一"告诉“刘二”,解着“刘二”告诉“张三”,此时,“张三”就知道要去村里开会了
然后,突然有一天,“赵六”要去出远门了,于是“村长”就让“王五”记住他的下一家是“郭七”了,之后直接通知“郭七”就可以了,数据结构就变为下面的样子了
村长 | 陈一 | 刘二 | 张三 | 李四 | 王五 | 郭七 | 罗八 |
---|---|---|---|---|---|---|---|
陈一 | 刘二 | 张三 | 李四 | 王五 | 郭七 | 罗八 | – |
过了几天,“赵六”回家了,村长又让“王五”记住他的下一家是“赵六”,并且让“赵六”记住,他的下一家是“郭七”。
通过上面,我们可以看得出,“赵六”的出去,回来(删除和插入),只影响了“王五”和“赵六”2个人,性能非常高效
当村里来新村里的时候,新村民可随意的修房子,然后,让“罗八”记住他即可
优点
- 插入和删除效率非常高
- 添加新数据,也不存在扩容问题
- 链表适合,数据不固定,需要经常插入或者删除数据的场景
缺点
- 当我们需要找到“张三”时候,不能通过门牌号,所有无法通过索引快速找到某个元素
- 当我们删除“赵六”的时候,想要找到“王五”,只能通过“村长”,“陈一”,“刘二”,“张三”,“李四”,才能找到“王五”,于是村长想了一个新的办法,让“每个村民”再记住他前面人是谁,于是我们叫这个模式为“双链表”
性能总结
数组
- 添加末尾:O(1)
- 添加中间:O(n)
- 删除末尾:O(1)
- 删除非末尾:O(n)
- 修改操作:O(1)
- 查询操作:O(n)
列表
- 添加数据:O(1)
- 删除数据:O(1)
- 修改操作:O(1)
- 查询操作:O(n)