Как рекурсивно найти минимальное значение

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's user avatar

deceze

508k85 gold badges739 silver badges883 bronze badges

asked Jun 3, 2015 at 14:42

Padmal's user avatar

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 minby several orders of magnitude.

answered Jun 3, 2015 at 14:59

Sebastian Wozny's user avatar

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

0x90's user avatar

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 Buck's user avatar

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.'s user avatar

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

Martin A Kraft's user avatar

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

Ryan Tan's user avatar

Прошу пояснить что делает функция 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's user avatar

V-Mor

5,1171 золотой знак13 серебряных знаков31 бронзовый знак

задан 18 ноя 2020 в 20:45

Vladislav's user avatar

1

Опираясь на комментарий @avp, распишу немного подробнее.

Во-первых, соглашусь с комментатором, что это то ещё извращение.

Во-вторых, по непонятному:

  1. k=size>>1: здесь используется оператор побитового сдвига >>. Он сдвигает двоичное представление числа вправо на столько бит, сколько стоит после >>. В данном случае на 1. То есть, если, например, size в двоичном виде был 1000100110001011, то станет 0100010011000101 (сдвинулось вправо на 1, самый правый элемент пропал, слева добавился 0). В данном случае это сделано для простого деления на 2 с округлением в меньшую сторону. То есть, эквивалентной записью было бы k = floor(size / 2). Но сдвигом это работает быстрее (процессору так проще).
  2. array+k наращивает указатель на массив на k. Теперь, при рекурсивном вызове функции, array будет начинаться не с нулевого элемента, а с k-ого. Это аналогично передаче указателя на k-ый элемент массива вот так: &array[k].
  3. size - k – здесь всё просто. На предыдущей строке k присваивается половина размера массива с округлением в меньшую сторону, а значит оставшаяся часть массива, те самые size - k элементов идут в следующий рекурсивный вызов.
  4. Назначение функции – найти наименьший элемент массива с помощью дробления его на половинки, тех половинок на ещё половинки и так далее, пока половинки не станут размером в 1 элемент. Потом выбирается, какая из половинок больше, и возвращается в результат.
  5. Бонусом расскажу, что значит запись l < r ? l : r. Вдруг это тоже не понятно. Это аналогично простому условию if. Всё, что до знака ? – условие. Между вопросом и : – действие, если условие выполнено. Всё, что после : – если не выполнено. То есть в данном случае это можно переписать как:
if (l < r)
    return l;
else
    return r;

P.S. Я пояснил только непонятные моменты. Если Вам непонятно абсолютно всё, Вам не сюда, а в учебники по C.

ответ дан 19 ноя 2020 в 1:59

V-Mor's user avatar

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, но мои ученики пока знают только его):

  1. procedure Find(k: integer);
  2. var
  3. L,R,i,j: integer;
  4. w,x: integer;
  5. begin
  6.   L:=1; R:=N;
  7.   while L<R1 do
  8.   begin
  9.     x:=a[k];
  10.     i:=L;
  11.     j:=R;
  12.     REPEAT
  13.       while a[i]<x do
  14.         i:=i+1;
  15.       while x<a[j] do
  16.         j:=j1;
  17.       if i<=then
  18.       begin
  19.         w:=a[i];
  20.         a[i]:=a[j];
  21.         a[j]:=w;
  22.         i:=i+1;
  23.         j:=j1;
  24.       end;
  25.     UNTIL i>j;
  26.     if j<k then
  27.       L:=i;
  28.     if k<i then
  29.       R:=j;
  30.   end;
  31. 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.

Смотрите также:

Понравилась статья? Поделить с друзьями:

Не пропустите также:

  • Как найти владельца ордена по номеру награды
  • Как найти следы отца джоэля в геншине
  • Как исправить ошибку 182 при установке драйверов амд
  • Как найти амулет аркея в скайриме
  • Как составить расписание игр для 7 команд

  • 0 0 голоса
    Рейтинг статьи
    Подписаться
    Уведомить о
    guest

    0 комментариев
    Старые
    Новые Популярные
    Межтекстовые Отзывы
    Посмотреть все комментарии