Data structures 为什么在排序链表中不能进行二进制搜索?

Data structures 为什么在排序链表中不能进行二进制搜索?,data-structures,Data Structures,是否可以在排序链表中使用二进制搜索来搜索元素? 如果不可能,那么问题是“为什么不可能”链接列表只允许顺序访问,因此即使列表已排序,也不可能进行二进制搜索 编辑: 正如其他人指出的那样,二进制搜索是可能的,但毫无意义 我们可以在链表中模拟随机访问,但这会很慢,并且平均时间复杂度为O(n),因此二进制搜索(通常为O(lgn))需要O(nlgn) 编辑2:正如@Ethag所指出的,如果它是一个双链接列表,二进制搜索只需要O(n)。在每一步中,我们都可以从上一个位置开始,而不是从头部/尾部开始,因此每次

是否可以在排序链表中使用二进制搜索来搜索元素?
如果不可能,那么问题是“为什么不可能”

链接列表只允许顺序访问,因此即使列表已排序,也不可能进行二进制搜索

编辑: 正如其他人指出的那样,二进制搜索是可能的,但毫无意义

我们可以在链表中模拟随机访问,但这会很慢,并且平均时间复杂度为O(n),因此二进制搜索(通常为O(lgn))需要O(nlgn)

编辑2:正如@Ethag所指出的,如果它是一个双链接列表,二进制搜索只需要O(n)。在每一步中,我们都可以从上一个位置开始,而不是从头部/尾部开始,因此每次移动的距离都是原来的一半

如果必须使用链表,最好使用线性搜索,它的复杂度只有O(n),并且比二进制搜索简单


如果要有效地搜索和插入/删除,可以使用其他数据结构,如二进制搜索树。

链表只允许顺序访问,因此即使对列表进行排序,也无法进行二进制搜索

编辑: 正如其他人指出的那样,二进制搜索是可能的,但毫无意义

我们可以在链表中模拟随机访问,但这会很慢,并且平均时间复杂度为O(n),因此二进制搜索(通常为O(lgn))需要O(nlgn)

编辑2:正如@Ethag所指出的,如果它是一个双链接列表,二进制搜索只需要O(n)。在每一步中,我们都可以从上一个位置开始,而不是从头部/尾部开始,因此每次移动的距离都是原来的一半

如果必须使用链表,最好使用线性搜索,它的复杂度只有O(n),并且比二进制搜索简单


如果您想有效地搜索和插入/删除,可以使用其他数据结构,如二元搜索树。

对排序数组进行二元搜索可以得到O(logn)比较和O(1)内存利用率的结果。排序数组上的线性搜索会给出O(N)比较和O(1)内存利用率的结果

除了正常的内存和比较度量之外,我们还有遍历步骤的概念。这对于没有随机访问的数据结构很重要。例如,在链表中,要从头部到达元素j,我们需要向前走j步。这些步骤可以在没有任何比较的情况下进行。正如评论中指出的,进行遍历步骤的成本可能与进行比较的成本不同。这里的遍历步骤转换为内存读取

问题是当我们的数据结构是一个排序的单链表时会发生什么?值得做二进制搜索吗

为了解决这个问题,我们需要研究排序单链表上二进制搜索的性能。代码如下所示:

struct Node {
        Node* next;
        int value;
};

Node* binarySearch(Node* n, int v) {
        if (v <= n->value) return n;

        Node *right, *left=n;
        int size = count(n);

        while (size > 1)
        {
                int newSize = (size / 2);

                right = left;
                for (int i = 0; (i < newSize) && (right->next!=nullptr); i++)
                        right = right->next;

                if (v == right->value) return right;
                else if (v > right->value) left = right;

                size -= newSize;
        }

        if (right && (v < right->value)) return right;
        else if (right->next) return right->next;
        else return nullptr;
}
尽管从技术上讲,排序数组所需的遍历步骤数为0。我们永远不必前进或后退。这个想法根本没有意义

按单个链接列表排序

 Binary: O(log N) comparisons, O(1) memory, O(N) traversal steps
 Linear: O(N) comparisons, O(1) memory, O(N) traversal steps

这是最糟糕的运行时。然而,杯子可能并不总是半空的:对排序数组进行二进制搜索会得到O(logn)比较和O(1)内存利用率的结果。排序数组上的线性搜索会给出O(N)比较和O(1)内存利用率的结果

除了正常的内存和比较度量之外,我们还有遍历步骤的概念。这对于没有随机访问的数据结构很重要。例如,在链表中,要从头部到达元素j,我们需要向前走j步。这些步骤可以在没有任何比较的情况下进行。正如评论中指出的,进行遍历步骤的成本可能与进行比较的成本不同。这里的遍历步骤转换为内存读取

问题是当我们的数据结构是一个排序的单链表时会发生什么?值得做二进制搜索吗

为了解决这个问题,我们需要研究排序单链表上二进制搜索的性能。代码如下所示:

struct Node {
        Node* next;
        int value;
};

Node* binarySearch(Node* n, int v) {
        if (v <= n->value) return n;

        Node *right, *left=n;
        int size = count(n);

        while (size > 1)
        {
                int newSize = (size / 2);

                right = left;
                for (int i = 0; (i < newSize) && (right->next!=nullptr); i++)
                        right = right->next;

                if (v == right->value) return right;
                else if (v > right->value) left = right;

                size -= newSize;
        }

        if (right && (v < right->value)) return right;
        else if (right->next) return right->next;
        else return nullptr;
}
尽管从技术上讲,排序数组所需的遍历步骤数为0。我们永远不必前进或后退。这个想法根本没有意义

按单个链接列表排序

 Binary: O(log N) comparisons, O(1) memory, O(N) traversal steps
 Linear: O(N) comparisons, O(1) memory, O(N) traversal steps
这是最糟糕的运行时。然而,杯子可能并不总是半空的:p

如何在一个只有O(1)额外空间、O(n)遍历时间和O(logn)比较的单链表中执行二进制搜索。我以前不相信这是可能的。为了好玩,我想我应该在Haskell中实现一个类似的算法:

bs::ordk=>Int->k->[(k,v)]->可能是v
bs 0=无
bs 1针(k,v):\
|k=针=仅v
|否则=没有
bs尺寸针左=箱滴尺寸“左
对(k,):
|针>=k->bs(尺寸-尺寸)针右
_->bs尺寸“左针
其中size'=size`quot`2
搜索::Ord k=>k->[(k,v)]->可能是v
搜索k kvs=bs(长度kvs)k kvs
这可以调整为使用O(log i)比较和O(i)遍历时间,其中i是从列表开始到查找的键所在或将所在位置的距离。这个实现可以改进,但要点很简单,用这个版本替换上面的
search

import Control.Applicative ((<|>))

search :: Ord k => k -> [(k,v)] -> Maybe v
-- The 10 can be replaced by any positive integer
search = go 10
  where
    -- The 2 can be replaced by any integer > 1
    go lim needle kvs@((k,_):_) | k <= needle =
      bs lim needle kvs <|> go (lim*2) needle (drop lim kvs)
    go _ _ _ = Nothing
import-Control.Applicative(())
搜索::Ord k=>k->[(k,v)]->可能是v
--10可以替换为任何正整数
搜索=go 10
哪里
--2可以替换为任何大于1的整数
go lim needle kvs@((k,):124; kethang如何在单链表中执行二进制搜索,只需O(1)个额外空间、O(n)个遍历时间和O(logn)个比较。我