📜  在Python中搜索对象列表(1)

📅  最后修改于: 2023-12-03 14:51:21.079000             🧑  作者: Mango

在Python中搜索对象列表

在编写Python代码时,经常需要在一个对象列表中搜索特定的数据。这个过程就叫做搜索。

Python提供了多种搜索方法,每一种都有自己的优缺点。在这篇文章中,我们将介绍常用的几种搜索方法。

线性搜索

线性搜索是最简单的搜索方法。线性搜索按顺序遍历列表中的每一个元素,直到找到匹配的数据或者遍历完整个列表。

以下是一个实现线性搜索的示例代码:

def linear_search(list, target):
    for i in range(len(list)):
        if list[i] == target:
            return i
    return -1

上面的代码中,我们定义了一个 linear_search 函数,它接受一个列表和一个目标值。函数遍历列表中的每个元素,如果找到目标值,就返回该元素在列表中的索引,否则返回 -1

线性搜索的时间复杂度为 $O(n)$,其中 $n$ 是列表的长度。因此,对于较大的列表,线性搜索的效率会非常低。

二分搜索

二分搜索又叫作折半查找,是一种高效的搜索方法。它前提是列表中的元素已经按照升序或者降序排列。

以下是一个实现二分搜索的示例代码:

def binary_search(list, target):
    low = 0
    high = len(list) - 1
    
    while low <= high:
        mid = (low + high) // 2
        if list[mid] == target:
            return mid
        elif list[mid] < target:
            low = mid + 1
        else:
            high = mid - 1
            
    return -1

上面的代码中,我们定义了一个 binary_search 函数,它接受一个已经排序的列表和一个目标值。函数首先将列表的低位和高位分别赋值为 0 和列表长度减 1。然后,它在循环中计算出中间值 mid,并将其与目标值进行比较。

如果 list[mid] 等于目标值,就返回 mid,表示找到了目标值。如果 list[mid] 小于目标值,说明目标值在 list[mid+1:] 中,因此将低位更新为 mid+1。如果 list[mid] 大于目标值,说明目标值在 list[:mid-1] 中,因此将高位更新为 mid-1

二分搜索的时间复杂度为 $O(\log n)$,其中 $n$ 是列表的长度。因此,对于大型排序列表,二分搜索的效率非常高。

插值搜索

插值搜索是一种基于二分搜索的高效搜索方法,用于在已经排序的列表中搜索目标值。

插值搜索与二分搜索的主要区别在于,它使用目标值和搜索范围的大小来估算目标值与搜索起点之间的距离。如果目标值在列表的前半部分,就使用二分搜索方法在前半部分继续查找。否则,如果目标值在列表的后半部分,就使用二分搜索方法在后半部分继续查找。

以下是一个实现插值搜索的示例代码:

def interpolation_search(list, target):
    low = 0
    high = len(list) - 1
    
    while low <= high and target >= list[low] and target <= list[high]:
        pos = low + int(((float(high - low) / ( list[high] - list[low] )) * ( target - list[low] )))
        if list[pos] == target:
            return pos
        elif list[pos] < target:
            low = pos + 1
        else:
            high = pos - 1
            
    return -1

上面的代码中,我们定义了一个 interpolation_search 函数,它接受一个已经排序的列表和一个目标值。我们首先将列表的低位和高位分别赋值为 0 和列表长度减 1。

然后,我们使用插值公式估算目标值在列表中的位置。插值公式为:

pos = low + int(((float(high - low) / ( list[high] - list[low] )) * ( target - list[low] )))

接下来,我们在循环中比较 list[pos] 与目标值的大小。如果 list[pos] 等于目标值,就返回 pos,表示找到了目标值。如果 list[pos] 小于目标值,说明目标值在 list[pos+1:] 中,因此将低位更新为 pos+1。如果 list[pos] 大于目标值,说明目标值在 list[:pos-1] 中,因此将高位更新为 pos-1

插值搜索的时间复杂度为 $O(\log\log n)$,其中 $n$ 是列表的长度。由于插值法能够更快地逼近目标值,因此对于数据分布比较均匀的列表,插值搜索的效率比二分搜索更高。

二叉搜索树

二叉搜索树是一种常用的数据结构,它能够高效地搜索和排序数据。二叉搜索树中的每个节点都包含一个键和一个值。所有节点的键都按照相应的顺序排列。

以下是一个实现二叉搜索树的示例代码:

class Node:
    def __init__(self, key=None, value=None):
        self.key = key
        self.value = value
        self.left = None
        self.right = None
        
class BinarySearchTree:
    def __init__(self):
        self.root = None
    
    def insert(self, key, value=None):
        if self.root is None:
            self.root = Node(key, value)
        else:
            self._insert(self.root, key, value)
    
    def _insert(self, node, key, value):
        if key < node.key:
            if node.left is None:
                node.left = Node(key, value)
            else:
                self._insert(node.left, key, value)
        elif key > node.key:
            if node.right is None:
                node.right = Node(key, value)
            else:
                self._insert(node.right, key, value)
        else:
            node.value = value
    
    def search(self, key):
        return self._search(self.root, key)
    
    def _search(self, node, key):
        if node is None:
            return None
        elif key < node.key:
            return self._search(node.left, key)
        elif key > node.key:
            return self._search(node.right, key)
        else:
            return node.value

上面的代码定义了一个 Node 类和一个 BinarySearchTree 类。其中,Node 类表示二叉搜索树的一个节点,BinarySearchTree 类表示整个二叉搜索树。

我们可以使用 insert 方法向二叉搜索树中添加一个新节点,使用 search 方法搜索一个节点。

二叉搜索树的时间复杂度取决于二叉树的高度,每次插入或搜索操作都将从根节点向下遍历树的高度。如果二叉搜索树不平衡,即高度很大,效率将非常低。因此,在实现二叉搜索树时,需要平衡左右子树来保持树的高度尽可能小。

总结

在Python中搜索对象列表是一个基本的任务。本文介绍了几种搜索方法,包括线性搜索、二分搜索、插值搜索和二叉搜索树。每种方法各有优缺点,需要根据具体的场景选择最合适的方法。