Метод разделяй и властвуй при построении алгоритмов, пример алгоритма
Если алгоритм рекурсивно обращается к самому себе, время его работы часто
описывается с помощью рекуррентного уравнения, или рекуррентного соотношения, в котором полное время, требуемое для решения всей задачи с объемом ввода 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); // слить результаты в общий массив
}
}
