数据结构中的数组元素查找插入删除总结

对于数组来说,查找就是检查它是否包含某个值,如果包含,还得给出其索引。
想要查找数组中是否存在某个值,计算机会先从索引0 开始,检查其值,如果不匹配,则继续下一个索引,以此类推,直至找到为止。
首先,计算机检查索引0。因为索引0 的值是"apples",并非我们所要的"dates",所以计算机跳到下一个索引上。索引1 也不是"dates",于是计算机再跳到索引2。

但索引2 的值仍不匹配,计算机只好再跳到下一格。

找到"dates"在索引3 那里。自此,计算机不用再往后跳了,因为结果已经得到。
因为我们检查了4 个格子才找到想要的值,所以这次操作总计是4 步。
这种逐个格子去检查的做法,就是最基本的查找方法——线性查找。

在数组上进行线性查找最多要多少步呢?如果我们要找的值刚好在数组的最后一个格子里(如本例的elderberries),那么计算机从头到尾检查每个格子,会在最后才找到。

同样,如果我们要找的值并不存在于数组中,那么计算机也还是得查遍每个格子,才能确定这个值不在数组中。
于是,一个5 格的数组,其线性查找的步数最大值是5,而对于一个500 格的数组,则是500。

以此类推,一个N 格的数组,其线性查找的最多步数是N(N 可以是任何自然数)。

可见,无论是多长的数组,查找都比读取要慢,因为读取永远都只需要一步,而查找却可能需要多步。


插入准确地说,是插入一个新值到数组之中。

往数组里插入一个新元素的速度,取决于你想把它插入到哪个位置上。
假设我们想要在购物清单的末尾插入"figs"。那么只需一步。因为之前说过了,计算机知道数组开头的内存地址,也知道数组包含多少个元素,所以可以算出要插入的内存地址,然后一步跳到那里插入就行了。

但在数组开头或中间插入,就另当别论了。这种情况下,我们需要移动其他元素以腾出空间,于是得花费额外的步数。例如往索引2 处插入"figs"。

为了达到目的,我们必须先把"cucumbers"、"dates"和"elderberries"往右移,以便空出索引2。而这也不是一步就能移好,因为我们首先要将"elderberries"右移一格,以空出位置给"dates",然后再将"dates"右移,以空出位置给"cucumbers"。
第1 步:"elderberries"右移。

第2 步:"date"右移。

第3 步:"cucembers"右移。

第4 步:至此,可以在索引2 处插入"figs"了。

如上所示,整个过程有4 步,开始3 步都是在移动数据,剩下1 步才是真正的插入数据。
最低效(花费最多步数)的插入是插入在数组开头。因为这时候需要把数组所有的元素都往右移。
于是,一个含有N 个元素的数组,其插入数据的最坏情况会花费N + 1 步。即插入在数组开头,导致N 次移动,加上一次插入。

 

数组的删除就是消掉其某个索引上的数据。

我们找回最开始的那个数组,删除索引2 上的值,即"cucumbers"。
第1 步:删除"cucumbers"。

虽然删除"cucumbers"好像一步就搞定了,但这带来了新的问题:数组中间空出了一个格子。因为数组中间是不应该有空格的,所以,我们得把"dates"和"elderberries"往左移。
第2 步:将"dates"左移。

第3 步:将"elderberries"左移。

结果,整个删除操作花了3 步。其中第1 步是真正的删除,剩下的2 步是移数据去填空格。
所以,删除本身只需要1 步,但接下来需要额外的步骤将数据左移以填补删除所带来的空隙。
跟插入一样,删除的最坏情况就是删掉数组的第一个元素。因为数组不允许空元素,当索引0 空出,那么剩下的所有元素都要往左移去填空。
对于含有5 个元素的数组,删除第一个元素需要1 步,左移剩余的元素需要4 步。

而对于500个元素的数组,删除第一个元素需要1 步,左移剩余的元素需要499 步。

可以推出,对于含有N个元素的数组,删除操作最多需要N 步。

如何分析数据结构的时间复杂度,那就可以开始探索各种数据结构的性能差异了。

了解这些非常重要,因为数据结构的性能差异会直接造成程序的性能差异。

 

posted @ 2020-03-29 21:42  jinlanu2  阅读(898)  评论(0编辑  收藏  举报