算法图解学习笔记之数据结构
记录下算法图解中介绍的一些数据结构
一、数组
初始化数组的时候,分配的内存是连续的,所以数组中所有的元素都可以通过初始元素的地址加上索引获取对应的值。所以查询的时候很快,是O(1)
但是插入和删除的时候就比较慢。
因为插入的时候需要判断这段连续的内存空间够不够用,如果不够,那么需要重新申请新的内存空间,然后将旧数据移动到新内存中,插入数据。
如果够,那么需要将插入位置之后的元素都向后移动一格,腾出空间来插入新的元素。
删除的时候需要将删除位置之后的元素都向前移动一个,收缩空间。
所以插入和删除的时候是O(n)
二、链表
链表和内存不同,它不要求分配连续的地址。只需要足够的空间就行。
链表中除了末尾元素,其他元素会额外保存下个元素的地址(针对单链表而言,双链表的话还需要保存上个元素的地址)
那么在查询的过程中,链表就会比较慢,因为需要遍历每个元素,直到找到指定位置的元素。查询的时候是O(n)
但是插入和删除的时候很快
假设链表是这样的a->c->d
我们想在c之前插入b,那么我们需要,将b的下个元素地址指向(a指向的下个元素地址)c的地址,将a指向的下个元素地址改为b的地址即可。
删除的时候也是一样的 a->b->c
如果要删除b,需要只需要将a的下个元素地址指向c即可。
所以插入和删除的时候是O(1)
但是我感觉其实不是的,插入的时候,要找到插入位置的地址,这个其实也需要从头开始找(无论是单链表还是双链表,在插入的时候都要从头开始)。找到指定位置之后才改变指向元素地址。
删除的时候也是,如果也还是要找到指定位置次啊能改变指向元素地址。
理论上是O(1),但实际上很可能不是
三、栈(堆栈)
栈是一种后进先出的数据结构,后进先出是其最大的特点。只能将元素添加到栈顶,并且只能删除栈顶元素(只支持入栈和出栈)
插入元素时,将元素加入到栈顶,删除元素时,先删除栈顶元素。
其实跟洗盘子一样,将盘子一个个叠起来,后面的盘子要放在之前盘子的上面,洗盘子的时候,先洗上面的盘子。最后放的盘子会优先被洗掉。
很多语言中都使用到了栈,如函数的调用。函数a调用了函数b,函数b调用了函数c。
a在栈尾,调用b时,将b入栈,放到栈顶,b调用c时,将c入栈,放到栈顶。c函数执行结束,将c出栈。只剩a和b,b调用结束,将b出栈,只剩a。
实际生活中栈的使用很多。
四、散列表
哈希表其实就是散列表的一种,只是散列函数使用了哈希函数而已。
散列表通过关键字来执行查询,插入和删除操作。
散列表跟数组一样,申请一段连续的内存空间。通过散列函数(通常是哈希),将关键字转化为索引。
假设散列表申请了8块连续的内存空间,索引从1-7。散列函数会将关键字转为0-7之前的数值,然后将值存放在相应的地址。
其实和数组差不多,不过是数组直接通过索引来查询,而散列表多了一步,多了将关键字转化为索引这个步骤。
散列表中最重要的部分就是散列函数了。
散列函数需要满足以下条件
1、散列函数总是将相同的输入映射到相同的索引,如果映射到不同的索引,那么每次获取的值都不同,明显不对。
2、散列函数将不同的输入映射到不同的索引,如果不同输入映射到不同索引,后面的映射会覆盖前面的映射,明显也不对。
3、散列函数需要知道数组的大小,只返回有效的索引。以上述为例,散列函数只能返回0-7之间的数值。
散列表有很多重要作用,如查询,防止重复,以及缓存等等。
查询的时候,将关键字散列成索引,取值,利用数字的查询优势,快速取值。效率为O(1)
防止重复,将关键字散列成索引,取值,如果值存在,说明存在重复
缓存,其实就是利用查询快的优点,先将一些常用的信息放到散列表中。使用的时候先去散列表中去,如果散列表中存在,就直接返回,如果不存在再通过其他途径取。因为散列表查询速度快,所以可以这么做。
散列表很好用,但是也要注意以下几点
1、填装因子(即已使用的内存占未使用内存的比例)
假设总大小为10, 使用了3,那么就是十分之三。
如果装填因子太大,说明内存被大量使用,后续很可能不够用了。我们需要预先分配新的内存,降低装填因子。一般大于0.7就需要扩容。
2、良好的散列函数
上面说过,散列表重要的部分就是散列函数,除了要满足上述三种要求之外,散列表应该能让数组中的值均匀分布。如果每次都将关键字转为0或者1,那么经常会导致冲突。这就是不好的散列函数。
五、队列
队列是一种先进先出的数据结构,先进先出是其最大的特点。刚好跟栈相反。(只支持入队和出队)
添加元素时,将元素入队,放到队尾。删除元素时,将队头元素出队。
跟日常排队一样,加入队列时,需要排到队伍末尾,队头元素先出队。
六、图
图是一种多对多的数据结构,由节点和边组成。一个节点可能于众多节点直接相连,这些节点被称为邻居。
按边是否有方向,图分为有向图和无向图两种
有向图,顾名思义,就是有方向的图,a到b存在箭头,那么a可以到达b,但是b不一定能到达a
无向图,其实就是双向图。a到b存在路线,那么a可以到b,b也可以到a。
按边是否有权重,图分为加权图和非加权图
七、树
树是一种单对多的数据结构。最常用的是二叉树