Given this sample list:
[5, 3, 9, 10, 8, 2, 7]
How to find the minimum number using recursion? The answer is 2
.
I found this in a question paper while I was doing recursion exercises. I can’t figure out a way to solve this. To find it, do I have to sort the list first and then there’s nothing to do recursively. Can any one show me a path?
deceze♦
508k85 gold badges739 silver badges883 bronze badges
asked Jun 3, 2015 at 14:42
7
This is a recursive implementation of min
:
l=[5, 3, 9, 10, 8, 2, 7]
def find_min(l,current_minimum = None):
if not l:
return current_minimum
candidate=l.pop()
if current_minimum==None or candidate<current_minimum:
return find_min(l,candidate)
return find_min(l,current_minimum)
print find_min(l)
>>>
2
Take into account that this should not be used in real programs and should be treated as an exercise. The performance will be worse than the built-in min
by several orders of magnitude.
answered Jun 3, 2015 at 14:59
Sebastian WoznySebastian Wozny
15.4k6 gold badges50 silver badges64 bronze badges
3
>>> import random
>>> arr=[random.randint(0,8) for r in xrange(10)]
>>> arr
[8, 2, 5, 1, 2, 4, 0, 3, 1, 1]
>>> def func(arr):
if len(arr) == 1:
return arr[0]
else:
return min(arr[0],func(arr[1:]))
>>> f(arr)
0
NB the recursion isn’t really needed here.
answered Jun 3, 2015 at 14:55
0x900x90
39.1k36 gold badges164 silver badges245 bronze badges
4
This answer uses an accumulator to store the min value throughout the recursions.
list = [5, 3, 9, 10, 8, 2, 7]
def min_list(list, min=None):
if len(list) < 1:
return min
return min_list(list[1:], list[0] if min is None or list[0] < min else min)
print(min_list(list))
answered Jun 3, 2015 at 15:03
James BuckJames Buck
1,6408 silver badges13 bronze badges
1
Thats also working, but only for lists with a length that is a power of two. For other lengths you just have to tweak the split into smaller arrays. The approach is taken from merge sort.
def findCloseToZero(l):
if len(l) == 1:
return l[0]
else:
first = findCloseToZero(l[0:int(len(l)/2)])
sec = findCloseToZero(l[int(len(l)/2):])
return first if abs(first) < abs(sec) else sec
answered Oct 4, 2017 at 15:50
F.M.F.F.M.F.
1,8172 gold badges23 silver badges40 bronze badges
def find_smallest_elem(lst):
k=1
while k != len(lst):
if lst[0] > lst[k]:
return(find_smallest_elem(lst[k:]))
else:
k +=1
return(lst[0])
This seems to works fine
answered Nov 11, 2018 at 14:53
this is my answer using recursion and a line of code
def min_value(n_list):
return n_list[0] if len(n_list) == 1 else min(n_list[0], min_value(n_list[1:]))
answered Oct 2, 2020 at 8:02
Прошу пояснить что делает функция minimal
(построчно) и для чего мы выполняем то или иное действие в функции minimal
. В частности, я не понимаю что делает k=size>>1
, array+k
и size-k
.
#include <stdio.h>
#include <conio.h>
int minimal (int *array, int size)
{
int l, r, k;
if (size==1)
return *array;
l = minimal(array, k=size>>1);
r = minimal(array+k, size-k);
return l < r ? l : r;
}
void main(void)
{
int i;
int a[10];
for(i=0; i<10; i++)
{
printf("Vvedite znachenie elemnte %d massiva a: ", i);
scanf("%d", &a[i]);
}
printf ("Minimalnoe znachenie massiva = %d", minimal(a,10));
getch();
}
V-Mor
5,1171 золотой знак13 серебряных знаков31 бронзовый знак
задан 18 ноя 2020 в 20:45
1
Опираясь на комментарий @avp, распишу немного подробнее.
Во-первых, соглашусь с комментатором, что это то ещё извращение.
Во-вторых, по непонятному:
k=size>>1
: здесь используется оператор побитового сдвига>>
. Он сдвигает двоичное представление числа вправо на столько бит, сколько стоит после>>
. В данном случае на 1. То есть, если, например,size
в двоичном виде был1000100110001011
, то станет0100010011000101
(сдвинулось вправо на 1, самый правый элемент пропал, слева добавился 0). В данном случае это сделано для простого деления на 2 с округлением в меньшую сторону. То есть, эквивалентной записью было быk = floor(size / 2)
. Но сдвигом это работает быстрее (процессору так проще).array+k
наращивает указатель на массив наk
. Теперь, при рекурсивном вызове функции,array
будет начинаться не с нулевого элемента, а сk
-ого. Это аналогично передаче указателя наk
-ый элемент массива вот так:&array[k]
.size - k
– здесь всё просто. На предыдущей строкеk
присваивается половина размера массива с округлением в меньшую сторону, а значит оставшаяся часть массива, те самыеsize - k
элементов идут в следующий рекурсивный вызов.- Назначение функции – найти наименьший элемент массива с помощью дробления его на половинки, тех половинок на ещё половинки и так далее, пока половинки не станут размером в 1 элемент. Потом выбирается, какая из половинок больше, и возвращается в результат.
- Бонусом расскажу, что значит запись
l < r ? l : r
. Вдруг это тоже не понятно. Это аналогично простому условиюif
. Всё, что до знака?
– условие. Между вопросом и:
– действие, если условие выполнено. Всё, что после:
– если не выполнено. То есть в данном случае это можно переписать как:
if (l < r)
return l;
else
return r;
P.S. Я пояснил только непонятные моменты. Если Вам непонятно абсолютно всё, Вам не сюда, а в учебники по C.
ответ дан 19 ноя 2020 в 1:59
V-MorV-Mor
5,1171 золотой знак13 серебряных знаков31 бронзовый знак
Время на прочтение
3 мин
Количество просмотров 33K
Сегодня на Хабре появилась очень интересная статья, о поиске минимального (максимального) значения на отрезке в массиве. Так как статья оказалось интересной и популярной, я решил с вами поделиться ещё одним алгоритмом поиска в массиве некоторых «специальных» значений.
Наверняка каждому встречалась задача нахождения k-ого наименьшего элемента в массиве. k-ый элемент характеризуется тем, что он больше (или равен) k элементов массива и меньше или равен N-k оставшихся элементов (где N – число элементов в массиве).
Задача нахождения k-ого наименьшего элемента обычно связывается с задачей сортировки, так как очевидный метод нахождения этого элемента состоит в сортировке N элементов и выборе k-ого.
Но мы с вами пойдём немного другим путём. Я предполагаю, что читатели знают, как работает алгоритм быстрой сортировки, но на всякий случай напомню. В массиве выбирается случайный элемент x, и выполнется просмотр массива слева, пока не найдётся элемент a[i]>x, затем выполняется просмотр справа, пока не будет найден элемент a[j]<x. Как только два таких элемента найдены, выполняется их обмен и просмотр продолжается до тех пор, пока индексы i,j не станут равны где-то в середине массива. В результате получается массив левая часть которого содержит элементы <=x, а правая часть содержит элементы >=x. Описанная процедура применяется рекурсивно для левой и правой части и продолжается до тех пор, пока не будет получен полностью отсортированный массив. (Немного подробнее о эффективных алгоритмах сортировки).
Процедура разделения, используемая в быстрой сортировке, даёт потенциальную возможность находить искомый (k-ый) элемент гораздо быстрее.
Этот алгоритм работает следующим образом. На первом шаге вызывается процедура разделения с L=1 и R=N (т.е. разделение выполняется для всего массива), причём в качестве разделяющего значения x выбирается a[k]. После разделения получаются значения индексов i,j такие, что
a[h]<x для всех h<i
a[h]>x для всех h>j
i>j
Здесь возможны три случая:
•Разделяющее значение x оказалось слишком мало. В результате граница между двумя частями меньше нужного значения k. Тогда операцию разделения нужно повторить с элементами a[i]…a[R].
•Выбранное значение x оказалось слишком велико. Тогда операцию разделения нужно повторить с элементами a[L]…a[j].
•Элемент a[k] разбивает массив на две части в нужной пропорции и поэтому является искомым значением.
Операцию разделения нужно повторять, пока не реализуется случай 3. Этот цикл выражается следующим фрагментом (прошу прощения за Pascal, но мои ученики пока знают только его):
- procedure Find(k: integer);
- var
- L,R,i,j: integer;
- w,x: integer;
- begin
- L:=1; R:=N;
- while L<R—1 do
- begin
- x:=a[k];
- i:=L;
- j:=R;
- REPEAT
- while a[i]<x do
- i:=i+1;
- while x<a[j] do
- j:=j—1;
- if i<=j then
- begin
- w:=a[i];
- a[i]:=a[j];
- a[j]:=w;
- i:=i+1;
- j:=j—1;
- end;
- UNTIL i>j;
- if j<k then
- L:=i;
- if k<i then
- R:=j;
- end;
- end;
Если предположить, что в среднем каждое разбиение делит пополам размер части массива, в которой находится искомое значение, то необходимое число сравнений будет N+N/2+N/4+…+1=2N. Это объясняет эффективность приведённой процедуры для поиска медиан и прочих величин, а также объясняет её превосходство над простым методом, состоящем в предварительной сортировке всего массива с последующим выбором k-ого элемента (где наилучшее поведение имеет порядок N*log(N)).
Надеюсь, этот алгоритм поможет вам сделать ваши программы более эффективными и быстрыми. Спасибо за внимание.
#python-3.x #recursion
#python-3.x #рекурсия
Вопрос:
Я попробовал следующий код на python, но он выдает ошибку выхода индекса списка за пределы диапазона. Кто-нибудь может помочь
def mini2(x):
n=0
min1=x[n]
if min1>x[n 1]:
min1 = x[n 1]
mini1(x[(n 1):])
else:
min1<x[n 1]
mini1(x[(n 1):])
Комментарии:
1. Что такое
mini1
? В любом случае, вероятно, просто опечатка. Попробуйте свой код на PythonTutor , чтобы лучше понять вашу проблему. Что произойдет, если список в конечном итоге будет содержать только один элемент? И что возвращает функция?
Ответ №1:
Наблюдения за вашим кодом:
- Базовый вариант отсутствует — что, если список пуст? Как вы справляетесь с этим?
- Функция не возвращает никакого значения — во время рекурсии функция выполняется локально. Как зафиксировать возвращаемое значение?
- Опечатка для вызовов функций
Вот мое решение, аналогичное вашей реализации, с изменениями, как упоминалось выше:
def minimum(x):
n = 0
if len(x) == 1:
return x[0]
min1 = x[n]
min2 = minimum(x[(n 1):])
if min1 > min2:
min1 = min2
return min1
Ответ №2:
def mini2(x):
n = 0
min1 = x[n]
# termination case when only on element is left in the list
if len(x) == 1:
return x[0]
# cut down list and calls function again
if min1 > x[n 1]:
# deletes element n because it is greater then the next one
del x[n]
return(mini2(x))
else:
# deletes element n 1 because it is greater then the last one
del x[n 1]
return(mini2(x))
x = [9, 4, 12, 420, -30, 1337, 2, 18, 720]
print(mini2(x))
Это основано на вашем коде. Сокращать список при каждом вызове функции.
Без удаления (теперь нарезки)
def mini2(x):
n = 0
min1 = x[n]
# termination case when only on element is left in the list
if len(x) == 1:
return x[0]
# cut down list and calls function again
if min1 > x[n 1]:
# deletes element n because it is greater then the next one
# del x[n]
return(mini2(x[1:]))
else:
# deletes element n 1 because it is greater then the last one
# del x[n 1]
return(mini2(x[:1] x[2:]))
x = [9, 4, 12, 420, -30, 1337, 2, 18, 720]
print(mini2(x))
print(x)
Комментарии:
1. Почему вы удаляете элементы? В вопросе OP не упоминается ни одной ссылки на удаление элементов из
x
??2. @Stef вы правы, я не думал об изменении исходного списка. Я создал вторую версию, которая не изменяет исходную версию. Спасибо.
Найти минимальный элемент массива очень просто. Если это упорядоченный массив, то достаточно вернуть первое или последнее значение, в зависимости от того, как отсортированы данные, от наименьшего к наибольшему или от наибольших к наименьшим. Это очень простая задача.
В случае с неотсортированным массивом, задача поиска минимального значения элемента сводиться к полному обходу всех элементов и выбора из них — минимума.
Код программы для поиска минимального, по значению, элемента неупорядоченного массива
{$CODEPAGE UTF8}
program Minimal;
const
arrayLength = 10;
var
inputArray : array [1..arrayLength] of integer;
minimum, i: integer;
begin
randomize;
writeln ('Исходный массив: ');
{заполнение случайными числами}
for i := 1 to arrayLength do
begin
inputArray[i] := random(100);
write (inputArray[i]:4);
end;
writeln;
{поиск минимального значения}
{считаем что первый элемент и есть минимальный}
minimum := inputArray[1];
for i := 2 to arrayLength do
if minimum > inputArray[i] then {если минимум больше текущего}
minimum := inputArray[i]; {присваиваем ему текущее значение}
write('Минимальный элемент массива ', minimum);
readln;
end.
Найти минимальное значение, можно также, с использованием рекурсивного алгоритма.
Рекурсивный алгоритм поиска минимального элемента в одномерном массиве
{$CODEPAGE UTF8}
program MinimalElement;
const
arrayLen = 10;
var
inputArr : array [1..arrayLen] of integer;
min, i: integer;
function MinElement(minimal, index: integer):integer;
begin
if index > arrayLen then
MinElement := minimal
else
begin
if inputArr[index] < minimal then
minimal := inputArr[index];
MinElement := MinElement(minimal, index + 1); {рекурсивный вызов}
end;
end;
begin
randomize;
writeln ('Исходные данные: ');
for i := 1 to arrayLen do
begin
inputArr[i] := random(100);
write (inputArr[i]:4);
end;
writeln;
{рекуррентный поиск минимального значения}
min := inputArr[1];
min := MinElement(min, 2);
write('Минимальный элемент ', min);
readln;
end.