Метод разделяй и властвуй при построении алгоритмов, пример алгоритма
Если алгоритм рекурсивно обращается к самому себе, время его работы часто
описывается с помощью рекуррентного уравнения, или рекуррентного соотношения, в котором полное время, требуемое для решения всей задачи с объемом ввода n, выражается через время решения вспомогательных подзадач. Затем данное рекуррентное уравнение решается с помощью определенных математических методов, и устанавливаются границы производительности алгоритма.
Получение рекуррентного соотношения для времени работы алгоритма, основанного на принципе "разделяй и властвуй", базируется на трех этапах, соответствующих парадигме этого принципа. Обозначим через T (n) время решения задачи, размер которой равен п. Если размер задачи достаточно мал, скажем, n ≤ c, где с — некоторая заранее известная константа, то задача решается непосредственно в течение определенного фиксированного времени, которое мы обозначим через . Предположим, что наша задача делится на а подзадач, объем каждой из которых равен 1/Ь от объема исходной задачи.
Если разбиение задачи на вспомогательные подзадачи происходит в течение времени D (n), а объединение решений подзадач в решение исходной задачи — в течение времени С (n), то мы получим такое рекуррентное соотношение:
пример алгоритма сортировка слиянием
public void merge(int []arr, long left, long middle, long right) {
// Слияние упорядоченных частей массива в буфер temp
// с дальнейшим переносом содержимого temp в a[left]...a[right]
// текущая позиция чтения из первой последовательности a[left]...a[middle]
long pos1=left;
// текущая позиция чтения из второй последовательности a[middle+1]...a[right]
long pos2=middle+1;
// текущая позиция записи в temp
long pos3=0;
int[] temp = new int[right-left+1];
// идет слияние, пока есть хоть один элемент в каждой последовательности
while (pos1 <= middle && pos2 <= right)
{
if (arr[pos1] < arr[pos2])
temp[pos3++] = arr[pos1++];
else
temp[pos3++] = arr[pos2++];
}
// одна последовательность закончилась -
// копировать остаток другой в конец буфера
while (pos2 <= right) // пока вторая последовательность непуста
temp[pos3++] = arr[pos2++];
while (pos1 <= middle) // пока первая последовательность непуста
temp[pos3++] = arr[pos1++];
// скопировать буфер temp в a[lb]...a[ub]
for (pos3 = 0; pos3 < right - left + 1; pos3++)
arr[left + pos3] = temp[pos3];
}
//a - сортируемый массив, его левая граница left, правая граница right
void mergeSort(int[] arr, long left, long right)
{
long middle; // индекс, по которому делим массив
if (left < right) // если есть более 1 элемента
{
middle = (left + right) / 2;
mergeSort(arr, left, middle); // сортировать левую половину
mergeSort(arr, middle+1, right); // сортировать правую половину
merge(arr, left, middle, right); // слить результаты в общий массив
}
}