В настоящее время я беру курс онлайн-алгоритмов, в котором учитель не дает код для решения алгоритма, а скорее грубый псевдокод. Поэтому, прежде чем отвезти в Интернет для ответа, я решил взять удар в него сам.Эффективность алгоритма сортировки Merge
В этом случае алгоритм, который мы рассматривали, является алгоритмом сортировки слиянием. После получения псевдокода мы также проводим анализ алгоритма для времени выполнения против n числа элементов в массиве. После быстрого анализа учитель прибыл в 6nlog(base2)(n) + 6n
в качестве приблизительного времени выполнения алгоритма.
Псевдокод дано было для слияния части только алгоритма и задается следующим образом:
C = output [length = n]
A = 1st sorted array [n/2]
B = 2nd sorted array [n/2]
i = 1
j = 1
for k = 1 to n
if A(i) < B(j)
C(k) = A(i)
i++
else [B(j) < A(i)]
C(k) = B(j)
j++
end
end
Он в основном сделал пробой выше принимая 4n+2
(2
для деклараций i
и j
, и 4
для количества выполненных операций - for
, if
, назначение позиции массива и итерация). Он упростил это, я считаю, ради класса, до 6n
.
Все это имеет смысл для меня, мой вопрос возникает из реализации, которую я выполняю, и как она влияет на алгоритмы и некоторые компромиссы/неэффективность, которые она может добавить.
Ниже мой код в стрижа, используя площадку:
func mergeSort<T:Comparable>(_ array:[T]) -> [T] {
guard array.count > 1 else { return array }
let lowerHalfArray = array[0..<array.count/2]
let upperHalfArray = array[array.count/2..<array.count]
let lowerSortedArray = mergeSort(array: Array(lowerHalfArray))
let upperSortedArray = mergeSort(array: Array(upperHalfArray))
return merge(lhs:lowerSortedArray, rhs:upperSortedArray)
}
func merge<T:Comparable>(lhs:[T], rhs:[T]) -> [T] {
guard lhs.count > 0 else { return rhs }
guard rhs.count > 0 else { return lhs }
var i = 0
var j = 0
var mergedArray = [T]()
let loopCount = (lhs.count + rhs.count)
for _ in 0..<loopCount {
if j == rhs.count || (i < lhs.count && lhs[i] < rhs[j]) {
mergedArray.append(lhs[i])
i += 1
} else {
mergedArray.append(rhs[j])
j += 1
}
}
return mergedArray
}
let values = [5,4,8,7,6,3,1,2,9]
let sortedValues = mergeSort(values)
Мои вопросы для этого следующие:
Выполните
guard
заявления в начале функцииmerge<T:Comparable>
на самом деле это сделать более неэффективно? Учитывая, что мы всегда сокращаем половину массива, единственный раз, когда он будет считаться истинным, будет для базового случая и когда в массиве будет нечетное количество элементов.
Это похоже на то, что на самом деле это добавит больше обработки и даст минимальный доход с момента, когда это произойдет, когда мы вдвое уменьшим массив до точки, в которой нет элементов.Относительно моего
if
заявление в слиянии. Поскольку он проверяет несколько условий, влияет ли это на общую эффективность алгоритма, который я написал? Если это так, эффекты для меня кажутся такими, что они меняются в зависимости от того, когда он вырвется из инструкцииif
(например, в первом условии или во втором).
Это что-то, что считается тяжелым при анализе алгоритмов, и если да, то как вы объясняете дисперсию, когда она выходит из алгоритма?
Любой другой анализ/советы, которые вы можете дать мне в отношении того, что я написал, будут очень признательны.
Мне интересно, если 6n-часть в цикле for рассматривает A [i] или B [j] как чтение дважды во время слияния, один раз во время if и снова во время перемещения. – rcgldr