Вопрос относительно рекурсивного стека при удалении среднего элемента из стека - PullRequest
0 голосов
/ 20 апреля 2020

У меня есть рабочий код для удаления среднего элемента из стека, это не проблема. Вот мой код:

def insert(stack,temp,curr,n):
#print(curr,stack)
    if curr!=n//2:
       print(curr)
       stack.append(temp)
    #return
    return

def delete_middle(stack,n,curr):
    while len(stack)>0:
       temp=stack.pop()
       delete_middle(stack,n,curr+1)
       insert(stack,temp,curr,n)
    #print(stack)
       return stack

delete_middle([2,4,1,18,34],5,0)

Мой код работает нормально. Но я пытаюсь понять, как работает рекурсивный стек. Например, мы делаем рекурсивный вызов delete_middle() около 5 раз (аналогично длине списка, stack). Каждый раз, когда переменная указателя, curr обновляется, чтобы указывать на текущий элемент. Как видите, последнее значение curr будет равно 5, но поскольку длина стека равна 0, рекурсивного вызова больше нет. И тогда вызывается функция insert().

Интересно, что если я посмотрю на значения curr внутри insert(), мы получим следующий вывод:

4
3
2
1
0

Почему мы не видим первое значение * 1017? * как 5 здесь? Я буду очень признателен за некоторые отзывы здесь. И могу ли я подумать о его сложности времени? Кажется, это O(N), где N - размер стека. Но я немного подзабыл об этом. Буду признателен за понимание здесь. спасибо

1 Ответ

2 голосов
/ 21 апреля 2020

Редактировать:

Функции вставки будут выполняться только после того, как рекурсивные функции будут использовать пустой стек.

START DELETE 0 [only one while loop executed]
START DELETE 1 [only one while loop executed]
START DELETE 2 [only one while loop executed]
START DELETE 3 [only one while loop executed]
START DELETE 4 [only one while loop executed]
START DELETE 5 [NO while loop executed because list is empty]
-------------------------
START INSERT iteration 4
END INSERT iteration 4
END DELETE 4
-------------------------
START INSERT iteration 3
END INSERT iteration 3
END DELETE 3
-------------------------
START INSERT iteration 2
END INSERT iteration 2
END DELETE 2
-------------------------
START INSERT iteration 1
END INSERT iteration 1
END DELETE 1
-------------------------
START INSERT iteration 0
END INSERT iteration 0
END DELETE 0

Итак, у нас сначала выполняется функция вставки (4), потому что, когда последний delete_middle (5) выполняется, список, стек пуст и не выполняет функцию вставки, как указано:

while len(stack)>0:
   ...........
   insert(stack,temp,curr,n)

Вышеуказанное в delete_middle с n=5 не будет выполнено, потому что len(stack)==0.

Как работает middle :

#first executed  delete_middle([2,4,1,18,34],5,0)
def delete_middle(stack,n,curr):                            iteration 1
    while len(stack)>0:                     initial stack   [2,4,1,18,34]   
       temp=stack.pop()               stack after removal   [2,4,1,18]
       .....
       delete_middle(stack,n,curr+1) -> becomes: delete_middle([2,4,1,18],5,1) iteration 2
                                          while len(stack)>0:                     initial stack   [2,4,1,18]   
                                          temp=stack.pop()                  stack after removal   [2,4,1]
                                          .....
                                          delete_middle(stack,n,curr+1) > becomes: delete_middle([2,4,1],5,2) and so on until stack = [] (empty)
                                          .....
      (!) During these iterations insert(stack,temp,curr,n) is not executed because:

Как вставить выполнить:

  delete_middle([2,4,1,18,34],5,0)
    # Iteration 1
    #delete_middle(stack,     n, curr+1)
    delete_middle([2,4,1,18], 5,   1   )
    insert not executed!
      # Iteration 2
      delete_middle([2,4,1],5,2)
      insert not executed!
        # Iteration 3
        delete_middle([2,4],5,3)
        insert not executed!
          # Iteration 4
          delete_middle([2],5,4)
          insert not executed!
            # Iteration 5
            delete_middle([],5,5) # returns nothing because it does not enter the while loop
            insert not executed!
    Only from now -> each insert will be executed from inside delete_middle!
            insert 4
              insert 3
                insert 2
                  insert 1

О сложности времени:

Time complexity = time taken to build the final list;
                = (1 pop + 1 insert) * n
                = O(n)

В худшем и худшем случае, вы могли бы скажем, что сложность O (n), потому что уменьшение размера списка на 1 элемент предполагает добавление 1 элемента в список, потому что у вас есть только одна рекурсия на уровень. (while .. return indentation)

Хотя pop равно O (1) и список уменьшается каждый раз (O (log n)), когда каждый middle_delete называется временем выполнения вашего алгоритма увеличивается с размером входных данных, выполняя (n-1) сложений в сумме; добавление всего оставшегося списка.

Некоторая отправная точка.


END edit

Что касается вашего кода, да, он работает, с некоторыми ограничениями, если можно:

  1. длина целевого списка должна быть нечетной
  2. принимает некоторые дополнительные ненужные * критерии (curr,n ) [необязательно, см. последнюю часть]
  3. функция не «вполне правильно» выполнена

Пояснения:

  1. Попробуйте сами

  2. Конец ответа (наберитесь терпения со мной :))

  3. Например:

В вашем коде:

while len(stack)>0:
   .....
   return stack

Похоже, вы возвращаете первое значение while l oop. Пример:

c = 0
def func(d):
  while d < 5:
    d+=1
    return d

print(func(c))

Рекурсивный эффект вызван умным использованием None результирующего веселья c (вставка) внутри while l oop. Это все равно что тянуть ручную остановку вместо педали. :)

Относительно ваших вопросов :

Как видно ниже, (среднее веселье c выполняется + вставить веселье c) для каждого элемента.

delete middle iterion 0
--------------------------
temp 34 0
delete middle iterion 1
--------------------------
temp 18 1
delete middle iterion 2
--------------------------
temp 1 2
delete middle iterion 3
--------------------------
temp 4 3
delete middle iterion 4
--------------------------
temp 2 4
delete middle iterion 5
--------------------------
======================
insert iteration 4
curr:4, stack:[], temp:2,n:5
======================
insert iteration 3
curr:3, stack:[2], temp:4,n:5
======================
insert iteration 2
curr:2, stack:[2, 4], temp:1,n:5
======================
insert iteration 1
curr:1, stack:[2, 4], temp:18,n:5
======================
insert iteration 0
curr:0, stack:[2, 4, 18], temp:34,n:5
[2, 4, 18, 34]

Почему мы не видим здесь первое значение curr как 5?

Если вы начнете (curr) с 0, вы увидите итерации от 4-> 0, в то время как при первоначальном curr равен 1, итерация будет 5-> 1; таким образом, 5 (N) удалить удовольствие c вызовы будут запущены.

Я немного переработал ваш код с помощью простой логики c:

Если у вас есть целевой список [1,2, .., n-1, n] и если вы хотите чтобы удалить среднюю часть с помощью рекурсивных функций, возможно, вам подойдет такой подход:

Давайте начнем со счетчика 0 count = 0, для каждого элемента списка счетчик будет увеличен на 1 count+=1

Теперь, чтобы убрать по одному элементу с каждой стороны (слева, справа), чтобы попасть в середину, мы можем сказать: если счетчик равен 0 или счетчик даже удаляет последний элемент из списка, если не удаляет первый элемент таким образом список теряет один элемент за итерацию.

if count == 0 and count % 2 == 0:
 target_list.pop(-1)
else:
 target_list.pop(0)

Тогда что, если список содержит четное количество элементов? Затем мы также включим этот сценарий: if len(target) == 2.

Также я предлагаю использовать один маленький трюк, тот факт, что значение по умолчанию для аргумента функции оценивается только один раз, во время определения функции.

что я имею в виду под этим? Проверьте пример для Распространенная ошибка # 1 .

Чтобы включить все вышеперечисленное в финальное веселье c (O (N)):

def eliminate_middle(target, count=0, beg_l=[],end_l=[]):
  print(count)                                    # O(N)
  if len(target) == 1:                            # if target has only one element
    return beg_l+sorted(end_l)

  else:

    if count == 0 or count % 2 == 0:

      if len(target) == 2:                        # case len(target) is Even 
        return beg_l+sorted(end_l)                #eliminates the two middle elements

      end_l.append(target.pop(-1))                #target loses last element
      return eliminate_middle(target,count+1)

    else:

      beg_l.append(target.pop(0))                 # target loses first element
      return eliminate_middle(target, count+1)

print(eliminate_middle([2,4,1,18,34]))
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...