Мы можем использовать оператор in в Python, чтобы проверить, присутствует ли строка в списке или нет. Также есть оператор not in, чтобы проверить, отсутствует ли строка в списке.
l1 = ['A', 'B', 'C', 'D', 'A', 'A', 'C'] # string in the list if 'A' in l1: print('A is present in the list') # string not in the list if 'X' not in l1: print('X is not present in the list')
Вывод:
A is present in the list X is not present in the list
Давайте посмотрим на другой пример, где мы попросим пользователя ввести строку для проверки в списке.
l1 = ['A', 'B', 'C', 'D', 'A', 'A', 'C'] s = input('Please enter a character A-Z:n') if s in l1: print(f'{s} is present in the list') else: print(f'{s} is not present in the list')
Вывод:
Please enter a character A-Z: A A is present in the list
Как найти строку в списке с помощью count()
Мы также можем использовать функцию count(), чтобы получить количество появлений строки в списке. Если его вывод равен 0, это означает, что строки нет в списке.
l1 = ['A', 'B', 'C', 'D', 'A', 'A', 'C'] s = 'A' count = l1.count(s) if count > 0: print(f'{s} is present in the list for {count} times.')
Поиск всех индексов строки в списке
Нет встроенной функции для получения списка всех индексов строки в списке. Вот простая программа для получения списка всех индексов, в которых строка присутствует в списке.
l1 = ['A', 'B', 'C', 'D', 'A', 'A', 'C'] s = 'A' matched_indexes = [] i = 0 length = len(l1) while i < length: if s == l1[i]: matched_indexes.append(i) i += 1 print(f'{s} is present in {l1} at indexes {matched_indexes}')
( 2 оценки, среднее 5 из 5 )
Помогаю в изучении Питона на примерах. Автор практических задач с детальным разбором их решений.
How do I search for items that contain the string 'abc'
in the following list?
xs = ['abc-123', 'def-456', 'ghi-789', 'abc-456']
The following checks if 'abc'
is in the list, but does not detect 'abc-123'
and 'abc-456'
:
if 'abc' in xs:
asked Jan 30, 2011 at 13:29
3
To check for the presence of 'abc'
in any string in the list:
xs = ['abc-123', 'def-456', 'ghi-789', 'abc-456']
if any("abc" in s for s in xs):
...
To get all the items containing 'abc'
:
matching = [s for s in xs if "abc" in s]
Mateen Ulhaq
23.8k18 gold badges95 silver badges132 bronze badges
answered Jan 30, 2011 at 13:32
Sven MarnachSven Marnach
567k117 gold badges934 silver badges834 bronze badges
19
Just throwing this out there: if you happen to need to match against more than one string, for example abc
and def
, you can combine two comprehensions as follows:
matchers = ['abc','def']
matching = [s for s in my_list if any(xs in s for xs in matchers)]
Output:
['abc-123', 'def-456', 'abc-456']
answered Aug 3, 2014 at 6:00
fantabolousfantabolous
21.1k7 gold badges54 silver badges49 bronze badges
4
Use filter
to get all the elements that have 'abc'
:
>>> xs = ['abc-123', 'def-456', 'ghi-789', 'abc-456']
>>> list(filter(lambda x: 'abc' in x, xs))
['abc-123', 'abc-456']
One can also use a list comprehension:
>>> [x for x in xs if 'abc' in x]
Mateen Ulhaq
23.8k18 gold badges95 silver badges132 bronze badges
answered Jan 30, 2011 at 13:34
MAKMAK
26k11 gold badges54 silver badges85 bronze badges
If you just need to know if ‘abc’ is in one of the items, this is the shortest way:
if 'abc' in str(my_list):
Note: this assumes ‘abc’ is an alphanumeric text. Do not use it if ‘abc’ could be just a special character (i.e. []’, ).
answered Apr 13, 2016 at 8:19
RogerSRogerS
1,3029 silver badges11 bronze badges
12
This is quite an old question, but I offer this answer because the previous answers do not cope with items in the list that are not strings (or some kind of iterable object). Such items would cause the entire list comprehension to fail with an exception.
To gracefully deal with such items in the list by skipping the non-iterable items, use the following:
[el for el in lst if isinstance(el, collections.Iterable) and (st in el)]
then, with such a list:
lst = [None, 'abc-123', 'def-456', 'ghi-789', 'abc-456', 123]
st = 'abc'
you will still get the matching items (['abc-123', 'abc-456']
)
The test for iterable may not be the best. Got it from here: In Python, how do I determine if an object is iterable?
answered Oct 20, 2011 at 13:24
Robert MuilRobert Muil
2,9381 gold badge24 silver badges30 bronze badges
4
x = 'aaa'
L = ['aaa-12', 'bbbaaa', 'cccaa']
res = [y for y in L if x in y]
jamylak
128k30 gold badges230 silver badges230 bronze badges
answered Jan 30, 2011 at 13:31
MariyMariy
5,6564 gold badges40 silver badges57 bronze badges
0
for item in my_list:
if item.find("abc") != -1:
print item
jamylak
128k30 gold badges230 silver badges230 bronze badges
answered Jan 30, 2011 at 13:38
RubyconRubycon
18.1k10 gold badges49 silver badges70 bronze badges
1
any('abc' in item for item in mylist)
answered Jan 30, 2011 at 13:34
ImranImran
86.2k23 gold badges97 silver badges131 bronze badges
I am new to Python. I got the code below working and made it easy to understand:
my_list = ['abc-123', 'def-456', 'ghi-789', 'abc-456']
for item in my_list:
if 'abc' in item:
print(item)
answered Apr 7, 2018 at 7:52
Amol ManthalkarAmol Manthalkar
1,8602 gold badges16 silver badges16 bronze badges
0
Use the __contains__()
method of Pythons string class.:
a = ['abc-123', 'def-456', 'ghi-789', 'abc-456']
for i in a:
if i.__contains__("abc") :
print(i, " is containing")
kalehmann
4,7316 gold badges24 silver badges36 bronze badges
answered Feb 8, 2019 at 16:37
Harsh LodhiHarsh Lodhi
1494 silver badges10 bronze badges
I needed the list indices that correspond to a match as follows:
lst=['abc-123', 'def-456', 'ghi-789', 'abc-456']
[n for n, x in enumerate(lst) if 'abc' in x]
output
[0, 3]
answered Jan 5, 2020 at 19:02
Grant ShannonGrant Shannon
4,6101 gold badge45 silver badges36 bronze badges
If you want to get list of data for multiple substrings
you can change it this way
some_list = ['abc-123', 'def-456', 'ghi-789', 'abc-456']
# select element where "abc" or "ghi" is included
find_1 = "abc"
find_2 = "ghi"
result = [element for element in some_list if find_1 in element or find_2 in element]
# Output ['abc-123', 'ghi-789', 'abc-456']
answered Jul 14, 2020 at 2:43
mylist=['abc','def','ghi','abc']
pattern=re.compile(r'abc')
pattern.findall(mylist)
Bugs
4,4919 gold badges32 silver badges41 bronze badges
answered Jul 4, 2018 at 13:32
3
Adding nan to list, and the below works for me:
some_list = ['abc-123', 'def-456', 'ghi-789', 'abc-456',np.nan]
any([i for i in [x for x in some_list if str(x) != 'nan'] if "abc" in i])
answered Feb 18, 2021 at 2:38
Sam S.Sam S.
6077 silver badges22 bronze badges
my_list = ['abc-123', 'def-456', 'ghi-789', 'abc-456']
for item in my_list:
if (item.find('abc')) != -1:
print ('Found at ', item)
answered Mar 16, 2018 at 9:14
I did a search, which requires you to input a certain value, then it will look for a value from the list which contains your input:
my_list = ['abc-123',
'def-456',
'ghi-789',
'abc-456'
]
imp = raw_input('Search item: ')
for items in my_list:
val = items
if any(imp in val for items in my_list):
print(items)
Try searching for ‘abc’.
answered Jan 26, 2019 at 2:44
def find_dog(new_ls):
splt = new_ls.split()
if 'dog' in splt:
print("True")
else:
print('False')
find_dog("Is there a dog here?")
4b0
21.7k30 gold badges94 silver badges141 bronze badges
answered Jul 18, 2019 at 8:22
Question : Give the informations of abc
a = ['abc-123', 'def-456', 'ghi-789', 'abc-456']
aa = [ string for string in a if "abc" in string]
print(aa)
Output => ['abc-123', 'abc-456']
cottontail
8,06618 gold badges40 silver badges47 bronze badges
answered Jun 16, 2018 at 10:52
Soudipta DuttaSoudipta Dutta
1,3151 gold badge12 silver badges7 bronze badges
Given a list, the task is to write a Python program to check whether a list contains a particular string or not.
Examples:
Input: l=[1, 1.0, 'have', 'a', 'geeky', 'day']; s='geeky' Output: geeky is present in the list
Input: l=['hello',' geek', 'have', 'a', 'geeky', 'day']; s='nice' Output: nice is not present in the list
Method #1: Using in operator
The in operator comes handy for checking if a particular string/element exists in the list or not.
Example:
Python3
l
=
[
1
,
2.0
,
'have'
,
'a'
,
'geeky'
,
'day'
]
s
=
'geeky'
if
s
in
l:
print
(f
'{s} is present in the list'
)
else
:
print
(f
'{s} is not present in the list'
)
Output:
geeky is present in the list
Time Complexity: O(n)
Auxiliary Space: O(1)
Method #2: Using count() function
The count() function is used to count the occurrence of a particular string in the list. If the count of a string is more than 0, it means that a particular string exists in the list, else that string doesn’t exist in the list.
Example:
Python3
l
=
[
'1'
,
1.0
,
32
,
'a'
,
'geeky'
,
'day'
]
s
=
'prime'
if
l.count(s) >
0
:
print
(f
'{s} is present in the list'
)
else
:
print
(f
'{s} is not present in the list'
)
Output:
prime is not present in the list
Time Complexity: O(n), where n is the number of elements in the list “test_list”.
Auxiliary Space: O(1), no extra space is required
Method #3: Using List Comprehension
List comprehensions are used for creating new lists from other iterables like tuples, strings, arrays, lists, etc. It is used to transform iterative statements into formulas.
Example:
Python3
l
=
[
'hello'
,
'geek'
,
'have'
,
'a'
,
'geeky'
,
'day'
]
s
=
'geek'
compare
=
[i
for
i
in
l
if
s
in
l]
if
len
(compare) >
0
:
print
(f
'{s} is present in the list'
)
else
:
print
(f
'{s} is not present in the list'
)
Output:
geeky is present in the list
Method #4: Using any() function
The any() function is used to check the existence of an element in the list. it’s like- if any element in the string matches the input element, print that the element is present in the list, else, print that the element is not present in the list.
Example:
Python3
l
=
[
'hello'
,
'geek'
,
'have'
,
'a'
,
'geeky'
,
'day'
]
s
=
'prime'
if
any
(s
in
i
for
i
in
l):
print
(f
'{s} is present in the list'
)
else
:
print
(f
'{s} is not present in the list'
)
Output:
prime is not present in the list
The time and space complexity for all the methods are the same:
Time Complexity: O(n) -> as the built-in operators and functions like ‘in’, ‘count’ take O(n)
Space Complexity: O(n)
Method #5 : Using list(),map(),join(),find() methods
Python3
l
=
[
1
,
2.0
,
'have'
,
'a'
,
'geeky'
,
'day'
]
s
=
'geeky'
nl
=
list
(
map
(
str
,l))
x
=
" "
.join(nl)
if
x.find(s)!
=
-
1
:
print
(f
'{s} is present in the list'
)
else
:
print
(f
'{s} is not present in the list'
)
Output
geeky is present in the list
Time Complexity: O(n) -> built-in functions like join takes O(n)
Space Complexity: O(n)
Method #6 : Using Counter() function
Python3
from
collections
import
Counter
l
=
[
1
,
2.0
,
'have'
,
'a'
,
'geeky'
,
'day'
]
s
=
'geeky'
freq
=
Counter(l)
if
s
in
freq.keys():
print
(f
'{s} is present in the list'
)
else
:
print
(f
'{s} is not present in the list'
)
Output
geeky is present in the list
Time Complexity: O(n)
Auxiliary Space: O(n)
Method 7: using operator.countOf() method
Python3
import
operator as op
l
=
[
'1'
,
1.0
,
32
,
'a'
,
'geeky'
,
'day'
]
s
=
'prime'
if
op.countOf(l, s):
print
(f
'{s} is present in the list'
)
else
:
print
(f
'{s} is not present in the list'
)
Output
prime is not present in the list
Time Complexity: O(N)
Auxiliary Space : O(1)
Method : using try/except and index()
You can use the index() method to find the first index of a string in a list. If the string is present in the list, the index() method returns the first index of the string, otherwise it raises a ValueError. To check if a string is present in a list, you can wrap the index() method in a try-except block, and print a message indicating whether the string is present in the list or not.
Python3
l
=
[
1
,
2.0
,
'have'
,
'a'
,
'geeky'
,
'day'
]
s
=
'geeky'
try
:
index
=
l.index(s)
print
(f
'{s} is present in the list at index {index}'
)
except
ValueError:
print
(f
'{s} is not present in the list'
)
Output
geeky is present in the list at index 4
Time Complexity: O(n) where n is the number of elements in the list, as the index() method iterates over the elements of the list until it finds the desired string or it exhausts the list.
Auxiliary Space: O(1), as the method uses only a few constant-sized variables, regardless of the size of the list.
Method : Using re
Algorithm
- Initialize a list l and a string s.
- Import the re module.
- Use the re.search() function to search for the string s in the list l.
- If a match is found, print that the string s is present in the list.
- If no match is found, print that the string s is not present in the list.
Python3
import
re
l
=
[
1
,
2.0
,
'have'
,
'a'
,
'geeky'
,
'day'
]
s
=
'geeky'
for
item
in
l:
if
isinstance
(item,
str
)
and
re.search(s, item):
print
(f
'{s} is present in the list'
)
break
else
:
print
(f
'{s} is not present in the list'
)
Output
geeky is present in the list
Time complexity: O(n*m), where n is the number of items in the list and m is the length of the longest string in the list.
Auxiliary Space: O(1), as we are not using any additional data structures in the program.
Method : Using operator.contains()
Approach
- Check whether given string is present in list using operator.contains()
- If yes display “string” is present in the list
- If not display “string” is not present in the list
Python3
import
operator
l
=
[
1
,
2.0
,
'have'
,
'a'
,
'geeky'
,
'day'
]
s
=
'geeky'
if
operator.contains(l, s):
print
(f
'{s} is present in the list'
)
else
:
print
(f
'{s} is not present in the list'
)
Output
geeky is present in the list
Time Complexity : O(N) N – length of list
Auxiliary Space : O(1)
Method : Using numpy:
- Import the numpy module.
- Initialize a list variable l with some string values.
- Initialize a string variable s with the value “prime”.
- Use a list comprehension to create a list of boolean values, where each value corresponds to whether the
- string s is present in the corresponding element of the list l.
- Use the np.any() method to check if any of the values in the resulting list is True.
- Print a message indicating whether the string s is present in the list or not, based on the value of res.
Python3
import
numpy as np
l
=
[
'hello'
,
'geek'
,
'have'
,
'a'
,
'geeky'
,
'day'
]
s
=
'prime'
res
=
np.
any
([s
in
i
for
i
in
l])
if
res:
print
(f
'{s} is present in the list'
)
else
:
print
(f
'{s} is not present in the list'
)
Output: prime is not present in the list
Time complexity: O(nm), where n is the length of the input list and m is the length of the input string. The list comprehension has a time complexity of O(nm), as it iterates over each element of the list and checks if the string s is present in it.
Auxiliary Space: O(nm), where n is the length of the input list and m is the length of the input string. The list comprehension creates a new list of boolean values, which has a length of n, and each value in the list is a string of length m. Hence, the space complexity is O(nm).
Last Updated :
11 Apr, 2023
Like Article
Save Article
- Используйте цикл
for
для проверки определенной строки в списке Python - Использование понимания списка для проверки определенной строки в списке Python
- Используйте функцию
filter()
для получения определенной строки в списке Python
Строки — это последовательность символов. Так же, как строки хранят символы в определенных позициях, мы можем использовать списки для хранения коллекции строк.
В этом руководстве мы получим строку с определенными значениями в списке Python.
Используйте цикл for
для проверки определенной строки в списке Python
for
используется для перебора последовательности в Python.
Его реализация для получения строки, содержащей определенные значения, показана в примере ниже.
py_list = ['a-1','b-2','c-3','a-4']
new_list =[]
for x in py_list:
if "a" in x:
new_list.append(x)
print(new_list)
Выход:
В приведенном выше коде оператор if
используется внутри цикла for
для поиска строк, содержащих a
в списке py_list
. Другой список с именем new_list
создается для хранения этих конкретных строк.
Использование понимания списка для проверки определенной строки в списке Python
Понимание списков — это способ создания новых списков на основе существующего списка. Он предлагает более короткий синтаксис, более компактный и быстрый, чем другие функции и циклы, используемые для создания списка.
Например,
py_list = ['a-1','b-2','c-3','a-4']
r = [s for s in py_list if "a" in s]
print(r)
Выход:
В приведенном выше коде понимание списка используется для поиска строк, имеющих a
в списке py_list
.
Обратите внимание, что написание того же кода с использованием других функций или циклов заняло бы больше времени, поскольку для их реализации требуется больше кода, но понимание списка решает эту проблему.
Мы также можем использовать понимание списка, чтобы найти строки, содержащие несколько определенных значений, т.е. мы можем найти строки, содержащие a
и b
в py_list
, объединив два понимания.
Например,
py_list = ['a-1','b-2','c-3','a-4','b-8']
q = ['a','b']
r = [s for s in py_list if any(xs in s for xs in q)]
print(r)
Выход:
['a-1', 'b-2', 'a-4','b-8']
Используйте функцию filter()
для получения определенной строки в списке Python
Функция filter()
фильтрует данную итерацию с помощью функции, которая проверяет, удовлетворяет ли каждый элемент какому-либо условию или нет.
Он возвращает итератор, который применяет проверку для каждого элемента в итерируемом объекте.
Например,
py_lst = ['a-1','b-2','c-3','a-4']
filter(lambda x: 'a' in x,py_lst)
print (filter(lambda x: 'a' in x,py_lst))
Выход:
<filter object at 0x7fd36c1905e0>
Обратите внимание, что вышеприведенный вывод представляет собой объект типа фильтр-итератор, поскольку функция filter()
возвращает итератор вместо списка.
Мы можем использовать функцию list()
, как показано в приведенном ниже коде, для получения списка.
list(filter(lambda x: 'a' in x,py_lst))
Выход:
В приведенном выше коде мы использовали filter()
, чтобы найти строку с определенными значениями в списке py_list
.
Введение
Поиск информации, хранящейся в различных структурах данных, является важной частью практически каждого приложения.
Существует множество различных алгоритмов, которые можно использовать для поиска. Каждый из них имеет разные реализации и напрямую зависит от структуры данных, для которой он реализован.
Умение выбрать нужный алгоритм для конкретной задачи является ключевым навыком для разработчиков. Именно правильно подобранный алгоритм отличает быстрое, надежное и стабильное приложение от приложения, которое падает от простого запроса.
В этой статье:
- Операторы членства (Membership Operators)
- Линейный поиск
- Бинарный поиск
- Улучшенный линейный поиск — Jump Search
- Поиск Фибоначчи
- Экспоненциальный поиск
- Интерполяционный поиск
Операторы членства (Membership Operators)
Алгоритмы развиваются и оптимизируются в результате постоянной эволюции и необходимости находить наиболее эффективные решения для основных проблем в различных областях.
Одной из наиболее распространенных проблем в области компьютерных наук является поиск в коллекции и определение того, присутствует ли данный объект в коллекции или нет.
Почти каждый язык программирования имеет свою собственную реализацию базового алгоритма поиска. Обычно — в виде функции, которая возвращает логическое значение True
или False
, когда элемент найден в данной коллекции элементов.
В Python самый простой способ поиска объекта — использовать операторы членства. Их название связано с тем, что они позволяют нам определить, является ли данный объект членом коллекции.
Эти операторы могут использоваться с любой итерируемой структурой данных в Python, включая строки, списки и кортежи.
in
— возвращаетTrue
, если данный элемент присутствует в структуре данных.not in
— возвращаетTrue
, если данный элемент не присутствует в структуре данных.
>>> 'apple' in ['orange', 'apple', 'grape'] True >>> 't' in 'pythonist' True >>> 'q' in 'pythonist' False >>> 'q' not in 'pythonist' True
Операторов членства достаточно, если нам нужно только определить, существует ли подстрока в данной строке, или пересекаются ли две строки, два списка или кортежа с точки зрения содержащихся в них объектов.
В большинстве случаев помимо определения, наличествует ли элемент в последовательности, нам нужна еще и позиция (индекс) элемента. Используя операторы членства, мы не можем получить ее.
Существует множество алгоритмов поиска, которые не зависят от встроенных операторов и могут использоваться для более быстрого и/или эффективного поиска значений. Кроме того, они могут дать больше информации (например, о позиции элемента в коллекции), а не просто определить, есть ли в коллекции этот элемент.
Линейный поиск
Линейный поиск — это один из самых простых и понятных алгоритмов поиска. Мы можем думать о нем как о расширенной версии нашей собственной реализации оператора in
в Python.
Суть алгоритма заключается в том, чтобы перебрать массив и вернуть индекс первого вхождения элемента, когда он найден:
def LinearSearch(lys, element): for i in range (len(lys)): if lys[i] == element: return i return -1
Итак, если мы используем функцию для вычисления:
>>> print(LinearSearch([1,2,3,4,5,2,1], 2))
То получим следующий результат:
1
Это индекс первого вхождения искомого элемента, учитывая, что нумерация элементов в Python начинается с нуля.
Временная сложность линейного поиска равна O(n). Это означает, что время, необходимое для выполнения, увеличивается с увеличением количества элементов в нашем входном списке lys
.
Линейный поиск не часто используется на практике, потому что такая же эффективность может быть достигнута с помощью встроенных методов или существующих операторов. К тому же, он не такой быстрый и эффективный, как другие алгоритмы поиска.
Линейный поиск хорошо подходит для тех случаев, когда нам нужно найти первое вхождение элемента в несортированной коллекции. Это связано с тем, что он не требует сортировки коллекции перед поиском (в отличие от большинства других алгоритмов поиска).
Бинарный поиск
Бинарный поиск работает по принципу «разделяй и властвуй». Он быстрее, чем линейный поиск, но требует, чтобы массив был отсортирован перед выполнением алгоритма.
Предполагая, что мы ищем значение val
в отсортированном массиве, алгоритм сравнивает val
со значением среднего элемента массива, который мы будем называть mid
.
- Если
mid
— это тот элемент, который мы ищем (в лучшем случае), мы возвращаем его индекс. - Если нет, мы определяем, в какой половине массива мы будем искать
val
дальше, основываясь на том, меньше или больше значениеval
значенияmid
, и отбрасываем вторую половину массива. - Затем мы рекурсивно или итеративно выполняем те же шаги, выбирая новое значение для
mid
, сравнивая его сval
и отбрасывая половину массива на каждой итерации алгоритма.
Алгоритм бинарного поиска можно написать как рекурсивно, так и итеративно. В Python рекурсия обычно медленнее, потому что она требует выделения новых кадров стека.
Поскольку хороший алгоритм поиска должен быть максимально быстрым и точным, давайте рассмотрим итеративную реализацию бинарного поиска:
def BinarySearch(lys, val): first = 0 last = len(lys)-1 index = -1 while (first <= last) and (index == -1): mid = (first+last)//2 if lys[mid] == val: index = mid else: if val<lys[mid]: last = mid -1 else: first = mid +1 return index
Если мы используем функцию для вычисления:
>>> BinarySearch([10,20,30,40,50], 20)
То получим следующий результат, являющийся индексом искомого значения:
1
На каждой итерации алгоритм выполняет одно из следующих действий:
- Возврат индекса текущего элемента.
- Поиск в левой половине массива.
- Поиск в правой половине массива.
Мы можем выбрать только одно действие на каждой итерации. Также на каждой итерации наш массив делится на две части. Из-за этого временная сложность двоичного поиска равна O(log n).
Одним из недостатков бинарного поиска является то, что если в массиве имеется несколько вхождений элемента, он возвращает индекс не первого элемента, а ближайшего к середине:
>>> print(BinarySearch([4,4,4,4,4], 4))
После выполнения этого фрагмента кода будет возвращен индекс среднего элемента:
2
Для сравнения: выполнение линейного поиска по тому же массиву вернет индекс первого элемента:
0
Однако мы не можем категорически утверждать, что двоичный поиск не работает, если массив содержит дубликаты. Он может работать так же, как линейный поиск, и в некоторых случаях возвращать первое вхождение элемента. Например:
>>> print(BinarySearch([1,2,3,4,4,4,5], 4)) 3
Бинарный поиск довольно часто используется на практике, потому что он эффективен и быстр по сравнению с линейным поиском. Однако у него есть некоторые недостатки, такие как зависимость от оператора //
. Существует много других алгоритмов поиска, работающих по принципу «разделяй и властвуй», которые являются производными от бинарного поиска. Некоторые из них мы рассмотрим далее.
Jump Search
Jump Search похож на бинарный поиск тем, что он также работает с отсортированным массивом и использует аналогичный подход «разделяй и властвуй» для поиска по нему.
Его можно классифицировать как усовершенствованный алгоритм линейного поиска, поскольку он зависит от линейного поиска для выполнения фактического сравнения при поиске значения.
В заданном отсортированном массиве мы ищем не постепенно по элементам массива, а скачкообразно. Если у нас есть размер прыжка, то наш алгоритм будет рассматривать элементы входного списка lys
в следующем порядке: lys[0]
, lys[0+jump]
, lys[0+2jump]
, lys[0+3jump]
и так далее.
С каждым прыжком мы сохраняем предыдущее значение и его индекс. Когда мы находим множество значений (блок), где lys[i]
< element < lys[i + jump]
, мы выполняем линейный поиск с lys[i]
в качестве самого левого элемента и lys[i + jump]
в качестве самого правого элемента в нашем множестве:
import math def JumpSearch (lys, val): length = len(lys) jump = int(math.sqrt(length)) left, right = 0, 0 while left < length and lys[left] <= val: right = min(length - 1, left + jump) if lys[left] <= val and lys[right] >= val: break left += jump; if left >= length or lys[left] > val: return -1 right = min(length - 1, right) i = left while i <= right and lys[i] <= val: if lys[i] == val: return i i += 1 return -1
Поскольку это сложный алгоритм, давайте рассмотрим пошаговое вычисление для следующего примера:
>>> print(JumpSearch([1,2,3,4,5,6,7,8,9], 5))
- Jump search сначала определит размер прыжка путем вычисления
math.sqrt(len(lys))
. Поскольку у нас 9 элементов, размер прыжка будет √9 = 3. - Далее мы вычисляем значение переменной
right
. Оно рассчитывается как минимум из двух значений: длины массива минус 1 и значенияleft + jump
, которое в нашем случае будет 0 + 3 = 3. Поскольку 3 меньше 8, мы используем 3 в качестве значения переменнойright
. - Теперь проверим, находится ли наш искомый элемент 5 между
lys[0]
иlys[3]
. Поскольку 5 не находится между 1 и 4, мы идем дальше. - Затем мы снова делаем расчеты и проверяем, находится ли наш искомый элемент между
lys[3]
иlys[6]
, где 6 — это 3 + jump. Поскольку 5 находится между 4 и 7, мы выполняем линейный поиск по элементам междуlys[3]
иlys[6]
и возвращаем индекс нашего элемента:
4
Временная сложность jump search равна O(√n), где √n — размер прыжка, а n — длина списка. Таким образом, с точки зрения эффективности jump search находится между алгоритмами линейного и бинарного поиска.
Единственное наиболее важное преимущество jump search по сравнению с бинарным поиском заключается в том, что он не опирается на оператор деления (/
).
В большинстве процессоров использование оператора деления является дорогостоящим по сравнению с другими основными арифметическими операциями (сложение, вычитание и умножение), поскольку реализация алгоритма деления является итеративной.
Стоимость сама по себе очень мала, но когда количество искомых элементов очень велико, а количество необходимых операций деления растет, стоимость может постепенно увеличиваться. Поэтому jump search лучше бинарного поиска, когда в системе имеется большое количество элементов: там даже небольшое увеличение скорости имеет значение.
Чтобы ускорить jump search, мы могли бы использовать бинарный поиск или какой-нибудь другой алгоритм для поиска в блоке вместо использования гораздо более медленного линейного поиска.
Поиск Фибоначчи
Поиск Фибоначчи — это еще один алгоритм «разделяй и властвуй», который имеет сходство как с бинарным поиском, так и с jump search. Он получил свое название потому, что использует числа Фибоначчи для вычисления размера блока или диапазона поиска на каждом шаге.
Числа Фибоначчи — это последовательность чисел 0, 1, 1, 2, 3, 5, 8, 13, 21 …, где каждый элемент является суммой двух предыдущих чисел.
Алгоритм работает с тремя числами Фибоначчи одновременно. Давайте назовем эти три числа fibM
, fibM_minus_1
и fibM_minus_2
. Где fibM_minus_1
и fibM_minus_2
— это два числа, предшествующих fibM
в последовательности:
fibM = fibM_minus_1 + fibM_minus_2
Мы инициализируем значения 0, 1, 1 или первые три числа в последовательности Фибоначчи. Это поможет нам избежать IndexError
в случае, когда наш массив lys
содержит очень маленькое количество элементов.
Затем мы выбираем наименьшее число последовательности Фибоначчи, которое больше или равно числу элементов в нашем массиве lys
, в качестве значения fibM
. А два числа Фибоначчи непосредственно перед ним — в качестве значений fibM_minus_1
и fibM_minus_2
. Пока в массиве есть элементы и значение fibM
больше единицы, мы:
- Сравниваем
val
со значением блока в диапазоне доfibM_minus_2
и возвращаем индекс элемента, если он совпадает. - Если значение больше, чем элемент, который мы в данный момент просматриваем, мы перемещаем значения
fibM
,fibM_minus_1
иfibM_minus_2
на два шага вниз в последовательности Фибоначчи и меняем индекс на индекс элемента. - Если значение меньше, чем элемент, который мы в данный момент просматриваем, мы перемещаем значения
fibM,
fibM_minus_1
иfibM_minus_2
на один шаг вниз в последовательности Фибоначчи.
Давайте посмотрим на реализацию этого алгоритма на Python:
def FibonacciSearch(lys, val): fibM_minus_2 = 0 fibM_minus_1 = 1 fibM = fibM_minus_1 + fibM_minus_2 while (fibM < len(lys)): fibM_minus_2 = fibM_minus_1 fibM_minus_1 = fibM fibM = fibM_minus_1 + fibM_minus_2 index = -1; while (fibM > 1): i = min(index + fibM_minus_2, (len(lys)-1)) if (lys[i] < val): fibM = fibM_minus_1 fibM_minus_1 = fibM_minus_2 fibM_minus_2 = fibM - fibM_minus_1 index = i elif (lys[i] > val): fibM = fibM_minus_2 fibM_minus_1 = fibM_minus_1 - fibM_minus_2 fibM_minus_2 = fibM - fibM_minus_1 else : return i if(fibM_minus_1 and index < (len(lys)-1) and lys[index+1] == val): return index+1; return -1
Используем функцию FibonacciSearch для вычисления:
>>> print(FibonacciSearch([1,2,3,4,5,6,7,8,9,10,11], 6))
Давайте посмотрим на пошаговый процесс поиска:
- Присваиваем переменной
fibM
наименьшее число Фибоначчи, которое больше или равно длине списка. В данном случае наименьшее число Фибоначчи, отвечающее нашим требованиям, равно 13. - Значения присваиваются следующим образом:
fibM = 13
fibM_minus_1 = 8
fibM_minus_2 = 5
index = -1
- Далее мы проверяем элемент
lys[4]
, где 4 — это минимум из двух значений —index + fibM_minus_2
(-1+5) и длина массива минус 1 (11-1). Поскольку значениеlys[4]
равно 5, что меньше искомого значения, мы перемещаем числа Фибоначчи на один шаг вниз в последовательности, получая следующие значения:
fibM = 8
fibM_minus_1 = 5
fibM_minus_2 = 3
index = 4
- Далее мы проверяем элемент
lys[7]
, где 7 — это минимум из двух значений:index + fibM_minus_2
(4 + 3) и длина массива минус 1 (11-1). Поскольку значениеlys[7]
равно 8, что больше искомого значения, мы перемещаем числа Фибоначчи на два шага вниз в последовательности, получая следующие значения:
fibM = 3
fibM_minus_1 = 2
fibM_minus_2 = 1
index = 4
- Затем мы проверяем элемент
lys[5]
, где 5 — это минимум из двух значений:index + fibM_minus_2
(4+1) и длина массива минус 1 (11-1) . Значениеlys[5]
равно 6, и это наше искомое значение!
Получаем ожидаемый результат:
5
Временная сложность поиска Фибоначчи равна O(log n). Она такая же, как и у бинарного поиска. Это означает, что алгоритм в большинстве случаев работает быстрее, чем линейный поиск и jump search.
Поиск Фибоначчи можно использовать, когда у нас очень большое количество искомых элементов и мы хотим уменьшить неэффективность, связанную с использованием алгоритма, основанного на операторе деления.
Дополнительным преимуществом использования поиска Фибоначчи является то, что он может вместить входные массивы, которые слишком велики для хранения в кэше процессора или ОЗУ, потому что он ищет элементы с увеличивающимся шагом, а не с фиксированным.
Экспоненциальный поиск
Экспоненциальный поиск — это еще один алгоритм поиска, который может быть достаточно легко реализован на Python, по сравнению с jump search и поиском Фибоначчи, которые немного сложны. Он также известен под названиями galloping search, doubling search и Struzik search.
Экспоненциальный поиск зависит от бинарного поиска для выполнения окончательного сравнения значений. Алгоритм работает следующим образом:
- Определяется диапазон, в котором, скорее всего, будет находиться искомый элемент.
- В этом диапазоне используется двоичный поиск для нахождения индекса элемента.
Реализация алгоритма экспоненциального поиска на Python:
def ExponentialSearch(lys, val): if lys[0] == val: return 0 index = 1 while index < len(lys) and lys[index] <= val: index = index * 2 return BinarySearch( lys[:min(index, len(lys))], val)
Используем функцию, чтобы найти значение:
>>> print(ExponentialSearch([1,2,3,4,5,6,7,8],3))
Рассмотрим работу алгоритма пошагово.
- Проверяем, соответствует ли первый элемент списка искомому значению: поскольку
lys[0]
равен 1, а мы ищем 3, мы устанавливаем индекс равным 1 и двигаемся дальше. - Перебираем все элементы в списке, и пока элемент с текущим индексом меньше или равен нашему значению, умножаем значение индекса на 2:
- index = 1,
lys[1]
равно 2, что меньше 3, поэтому значение index умножается на 2 и переменнойindex
присваивается значение 2. - index = 2,
lys[2]
равно 3, что равно 3, поэтому значениеindex
умножается на 2 и переменнойindex
присваивается значение 4. - index = 4,
lys[4]
равно 5, что больше 3. Условие выполнения цикла больше не соблюдается и цикл завершает свою работу.
- Затем выполняется двоичный поиск в полученном диапазоне (срезе)
lys[:4]
. В Python это означает, что подсписок будет содержать все элементы до 4-го элемента, поэтому мы фактически вызываем функцию следующим образом:
>>> BinarySearch([1,2,3,4], 3)
Функция вернет следующий результат:
2
Этот результат является индексом искомого элемента как в исходном списке, так и в срезе, который мы передаем алгоритму бинарного поиска.
Экспоненциальный поиск выполняется за время O(log i), где i — индекс искомого элемента. В худшем случае временная сложность равна O(log n), когда искомый элемент — это последний элемент в массиве (n — это длина массива).
Экспоненциальный поиск работает лучше, чем бинарный, когда искомый элемент находится ближе к началу массива. На практике мы используем экспоненциальный поиск, поскольку это один из наиболее эффективных алгоритмов поиска в неограниченных или бесконечных массивах.
Интерполяционный поиск
Интерполяционный поиск — это еще один алгоритм «разделяй и властвуй», аналогичный бинарному поиску. В отличие от бинарного поиска, он не всегда начинает поиск с середины. Интерполяционный поиск вычисляет вероятную позицию искомого элемента по формуле:
index = low + [(val-lys[low])*(high-low) / (lys[high]-lys[low])]
В этой формуле используются следующие переменные:
- lys — наш входной массив.
- val — искомый элемент.
- index — вероятный индекс искомого элемента. Он вычисляется как более высокое значение, когда значение val ближе по значению к элементу в конце массива (
lys[high]
), и более низкое, когда значение val ближе по значению к элементу в начале массива (lys[low]
). - low — начальный индекс массива.
- high — последний индекс массива.
Алгоритм осуществляет поиск путем вычисления значения индекса:
- Если значение найдено (когда
lys[index] == val
), возвращается индекс. - Если значение
val
меньшеlys[index]
, то значение индекса пересчитывается по формуле для левого подмассива. - Если значение
val
большеlys[index]
, то значение индекса пересчитывается по формуле для правого подмассива.
Давайте посмотрим на реализацию интерполяционного поиска на Python:
def InterpolationSearch(lys, val): low = 0 high = (len(lys) - 1) while low <= high and val >= lys[low] and val <= lys[high]: index = low + int(((float(high - low) / ( lys[high] - lys[low])) * ( val - lys[low]))) if lys[index] == val: return index if lys[index] < val: low = index + 1; else: high = index - 1; return -1
Если мы используем функцию для вычисления:
>>> print(InterpolationSearch([1,2,3,4,5,6,7,8], 6))
Наши начальные значения будут следующими:
val = 6,
low = 0,
high = 7,
lys[low] = 1,
lys[high] = 8,
index = 0 + [(6-1)*(7-0)/(8-1)] = 5
Поскольку lys[5]
равно 6, что является искомым значением, мы прекращаем выполнение и возвращаем результат:
5
Если у нас большое количество элементов и наш индекс не может быть вычислен за одну итерацию, то мы продолжаем пересчитывать значение индекса после корректировки значений high и low.
Временная сложность интерполяционного поиска равна O(log log n), когда значения распределены равномерно. Если значения распределены неравномерно, временная сложность для наихудшего случая равна O(n) — так же, как и для линейного поиска.
Интерполяционный поиск лучше всего работает на равномерно распределенных, отсортированных массивах. В то время как бинарный поиск начинает поиск с середины и всегда делит массив на две части, интерполяционный поиск вычисляет вероятную позицию элемента и проверяет индекс, что повышает вероятность нахождения элемента за меньшее количество итераций.
Python очень удобочитаемый и эффективный по сравнению с такими языками программирования, как Java, Fortran, C, C++ и т. д. Одним из ключевых преимуществ использования Python для реализации алгоритмов поиска является то, что вам не нужно беспокоиться о приведении или явной типизации.
В Python большинство алгоритмов поиска, которые мы обсуждали, будут работать так же хорошо, если мы ищем строку. Имейте в виду, что понадобится внести изменения в код для алгоритмов, которые используют искомый элемент для числовых вычислений, например алгоритм интерполяционного поиска.
Python также подходит, если вы хотите сравнить производительность различных алгоритмов поиска для вашего dataset’а. Создание прототипа на Python проще и быстрее, потому что вы можете сделать больше с меньшим количеством строк кода.
Чтобы сравнить производительность наших реализованных алгоритмов, в Python мы можем использовать библиотеку time:
import time start = time.time() # вызовите здесь функцию end = time.time() print(start-end)
Заключение
Существует множество возможных способов поиска элемента в коллекции. В этой статье мы обсудили несколько алгоритмов поиска и их реализации на Python.
Выбор используемого алгоритма зависит от данных, с которыми вы будете работать. Это ваш входной массив, который мы называли lys
во всех наших реализациях.
- Если вы хотите выполнить поиск в несортированном массиве или найти первое вхождение искомой переменной, то лучшим вариантом будет линейный поиск.
- Если вы хотите выполнить поиск в отсортированном массиве, есть много вариантов, из которых самый простой и быстрый — это бинарный поиск.
- Если у вас есть отсортированный массив, в котором вы хотите выполнить поиск без использования оператора деления, вы можете использовать либо jump search, либо поиск Фибоначчи.
- Если вы знаете, что искомый элемент, скорее всего, находится ближе к началу массива, вы можете использовать экспоненциальный поиск.
- Если ваш отсортированный массив равномерно распределен, то самым быстрым и эффективным будет интерполяционный поиск.
Если вы не уверены, какой алгоритм использовать для отсортированного массива, просто протестируйте каждый из них при помощи библиотеки time и выберите тот, который лучше всего работает с вашим dataset’ом.