Вот рекурсивная функция, которая использует стек, в котором мы храним номера разделов в порядке возрастания. Это достаточно быстро и очень интуитивно понятно.
# get the partitions of an integer
Stack = []
def Partitions(remainder, start_number = 1):
if remainder == 0:
print(" + ".join(Stack))
else:
for nb_to_add in range(start_number, remainder+1):
Stack.append(str(nb_to_add))
Partitions(remainder - nb_to_add, nb_to_add)
Stack.pop()
Когда стек заполнен (сумма элементов стека соответствует числу, которое мы хотим разделить), мы печатаем его, удаляем его последнее значение и проверяем следующее возможное значение, которое будет сохранено в стек. Когда все следующие значения были проверены, мы снова выталкиваем последнее значение стека и возвращаемся к последней вызывающей функции. Вот пример выходных данных (с 8):
Partitions(8)
1 + 1 + 1 + 1 + 1 + 1 + 1 + 1
1 + 1 + 1 + 1 + 1 + 1 + 2
1 + 1 + 1 + 1 + 1 + 3
1 + 1 + 1 + 1 + 2 + 2
1 + 1 + 1 + 1 + 4
1 + 1 + 1 + 2 + 3
1 + 1 + 1 + 5
1 + 1 + 2 + 2 + 2
1 + 1 + 2 + 4
1 + 1 + 3 + 3
1 + 1 + 6
1 + 2 + 2 + 3
1 + 2 + 5
1 + 3 + 4
1 + 7
2 + 2 + 2 + 2
2 + 2 + 4
2 + 3 + 3
2 + 6
3 + 5
4 + 4
8
Структура рекурсивной функции проста для понимания и проиллюстрирована ниже (для целого числа 31):
remainder
соответствует значению оставшегося числа, которое мы хотим разделить (31 и 21 в приведенном выше примере). start_number
соответствует первому номеру раздела, его значение по умолчанию равно единице (1 и 5 в примере выше).
Если бы мы хотели вернуть результат в список и получить количество разделов, мы могли бы сделать это:
def Partitions2_main(nb):
global counter, PartitionList, Stack
counter, PartitionList, Stack = 0, [], []
Partitions2(nb)
return PartitionList, counter
def Partitions2(remainder, start_number = 1):
global counter, PartitionList, Stack
if remainder == 0:
PartitionList.append(list(Stack))
counter += 1
else:
for nb_to_add in range(start_number, remainder+1):
Stack.append(nb_to_add)
Partitions2(remainder - nb_to_add, nb_to_add)
Stack.pop()
Наконец, большое преимущество функции Partitions
, показанной выше, состоит в том, что она очень легко адаптируется, чтобы найти все композиции натурального числа (две композиции могут иметь одинаковый набор чисел, но порядок в этом случае различен): нам просто нужно сбросить переменную start_number
и установить ее в 1 в for
петля.
# get the compositions of an integer
Stack = []
def Compositions(remainder):
if remainder == 0:
print(" + ".join(Stack))
else:
for nb_to_add in range(1, remainder+1):
Stack.append(str(nb_to_add))
Compositions(remainder - nb_to_add)
Stack.pop()
Пример вывода:
Compositions(4)
1 + 1 + 1 + 1
1 + 1 + 2
1 + 2 + 1
1 + 3
2 + 1 + 1
2 + 2
3 + 1
4
Вместо файлов pid, если у вашего сценария есть однозначно идентифицируемое имя, вы можете сделать что-то вроде этого:
#!/bin/bash
COMMAND=$0
# exit if I am already running
RUNNING=`ps --no-headers -C${COMMAND} | wc -l`
if [ ${RUNNING} -gt 1 ]; then
echo "Previous ${COMMAND} is still running."
exit 1
fi
... rest of script ...
Вы можете использовать pidof -x
, если вы знаете имя процесса, или kill -0
, если вы знаете PID.
Пример:
if pidof -x vim > /dev/null
then
echo "Vim already running"
exit 1
fi
Почему бы не установить файл блокировки?
Что-то вроде
yourapp.lock
Просто удалите его, когда процесс будет завершен, и проверьте его перед запуском .
Это можно сделать с помощью
if [ -f yourapp.lock ]; then
echo "The process is already launched, please wait..."
fi
Используйте этот сценарий:
FILE="/tmp/my_file"
if [ -f "$FILE" ]; then
echo "Still running"
exit
fi
trap EXIT "rm -f $FILE"
touch $FILE
...script here...
Этот сценарий создаст файл и удалит его при выходе.
Чтобы расширить то, что говорит @bgy, безопасный атомарный способ создать файл блокировки, если он еще не существует, и потерпеть неудачу, если его нет, - это чтобы создать временный файл, а затем жестко связать его со стандартным файлом блокировки. Это защищает от другого процесса, создающего файл между вашим тестированием и созданием.
Вот код файла блокировки из моего почасового сценария резервного копирования:
echo $$ > /tmp/lock.$$
if ! ln /tmp/lock.$$ /tmp/lock ; then
echo "previous backup in process"
rm /tmp/lock.$$
exit
fi
Не забудьте удалить как файл блокировки, так и временный файл. файл, когда вы закончите, даже если вы выйдете раньше из-за ошибки.
For a method that does not suffer from parsing bugs and race conditions, check out: