我们真的做了必须要做的事情吗

这段时间在自学有关计算机算法相关知识,之前学习的都是排序的相关内容,我们都在考虑如何把一堆杂乱无序的元素按照一定规则,排列成为有序的数组。事实上,排好序之后,确实能够解决很多问题,因为当一堆数据都是有序状态的时候,就已经能够自然而然反映出每个数据之间的相对关系。那是,有序是一种非常“强”的要求,很多时候,我们需要解决的问题并不需要把所有的数据从小到大进行排序,而只需要找出我们想关注元素。

假设我们已经完成了排序,整堆数据现在是有序的了,那么问题就比较相对容易处理。可以采用“二分查找法”,就是先比较数组中间元素我们要查找元素的相对大小,把数组分成两部分,通过逐次二分比较,层层缩小指定元素的位置范围。最后,总能够找到需要的元素位置。就好像我们小时候玩的“猜数字”的游戏一样,如果某次猜错了,我们都会问出题者是“大了还是小了”,然后在确定的范围中去查找。这种二分查找法的时间复杂度是O(logn)。

但是,排序本身是消耗时间和资源的,通过之前的学习,我们已经知道了目前性能最优的排序方法的时间复杂度就是O(nlogn)。进行二分查找的时间和排序的时间相比识很小的。所以做整件事情的时间复杂度还是O(nlogn)。那我们思考一下,这件事情有没有可以改进的空间呢?

其实优化的关键就在于其实我们并不需要把所有数据都按照从小到大的顺序排列好,而只是需要相对的大小关系。其实,可以用“二叉树”这种数据结构来解决这个问题。二叉树的基本原型就是根节点、“左孩子”、“右孩子”。其中,根节点大于“左孩子”,“右孩子”大于“根节点”。然后,各个“孩子”节点还可以继续往下延伸成一棵大的“二叉树”。

那么,如何将一堆数据整合成“二叉树”的结构呢,可以采用逐步插入的方式,第一个元素先当成是“根节点”,然后将它和接下来的元素进行比较,如果新元素比“根节点”要小,那么就递归插入到“根节点”的左子树。如果新元素大于“根节点”,那么就递归插入到“根节点”的右子树。这种操作可以证明时间复杂度为O(logn)。通过把整段数据数据整合成二叉树,虽然每一个数据的绝对位置我们不知道,但是我们可以通过一层一层遍历的方式通过“二分”来找到我们想找的元素。遍历的方法也很简单了,从整棵树的“根节点”开始,如果所要查找的元素比根节点要小,那么就去根节点的左子树中查找;如果所要查找的元素比根节点的要大,那就去根节点的右子树查找。这种方法,每查找一个元素的时间复杂度是O(logn)。

从学习这个算法的过程中,我明白了一个道理,那就是数据结构是为了解决问题而存在的,而不是为了创建一个数据结构而去创建数据结构。很多时候,做事情的效率不够高,其中的一个原因是我们除了做必须要做的事情之外,还做了别的额外的工作。所以有时候需要准确去分析需要解决的问题的本质,把一些费时间却不是为真正解决这个问题的“附加工作”去掉,提高做事情的效率。

你可能感兴趣的:(我们真的做了必须要做的事情吗)