Merge sort-ը ամենարագ տեսակավորման ալգորիթմներից մեկն է։ Շատ ծրագրեր արտադրական միջավայրում օգտագործում են Merge sort-ի որևէ տարբերակը։ Մենք արդեն դիտարկել ենք ալգորիթմներ, որոնք աշխատում են քառակուսի ժամանակային բարդությամբ , օրինակ՝ Bubble sort (Պղպջակային տեսակավորում) կամ Selection sort (Ընտրությամբ տեսակավորում)։ Merge sort-ը շատ ավելի արագ է, քան բոլոր քառակուսի ժամանակային բարդությամբ տեսակավորումները և աշխատում է բարդությամբ։
Merge sort-ը «Բաժանիր և տիրիր (Divide & Conquer)» մոտեցման ալգորիթմ է, որը ռեկուրսիվ կերպով տեսակավորում է զանգվածի միջակայքերը և ապա միացնում (merge) դրանք։ Ալգորիթմի հիմնական մասն այն արդյունավետ մեխանիզմն է, որ երկու տեսակավորված զանգվածները միացնում է մեկ տեսակավորված զանգվածի մեջ։ Ալգորիթմը աշխատանքի ընթացքում զանգվածը բաժանում է երկու մասի։ Այնուհետև ռեկուրսիվ կերպով տեսակավորում է առաջին մասը, հետո ռեկուրսիվ տեսակավորում է երկրորդ մասը, և վերջում միացնում է (merge) երկու տեսակավորված մասերը մեկ ընդհանուր տեսակավորված զանգվածում։
def merge(a, b):
i, j, res = 0, 0, [] # i-ի և j-ի ինդեքսները a-ի և b-ի համար, իսկ res-ը արդյունքների զանգվածն է
while i < len(a) or j < len(b): # Քանի դեռ կան մնացած էլեմենտներ
ai = a[i] if i < len(a) else float('inf')
bj = b[j] if j < len(b) else float('inf')
if ai < bj: # Եթե a[i] < b[j], ապա վերցնենք a[i]
res.append(ai) # Ավելացնել a[i]-ը արդյունքների մեջ
i += 1 # Անցնել հաջորդ էլեմենտին
else: # Եթե a[i] >= b[j], ապա վերցնել b[j]
res.append(bj) # Ավելացնել b[j]-ը արդյունքների մեջ
j += 1 # Անցնել հաջորդ էլեմենտին
return res
def merge_sort(a):
if len(a) <= 1: # Եթե տեսակավորելու բան չկա
return a # Ուղղակի վերադարձնել նույն զանգվածը
l = merge_sort(a[: len(a) // 2]) # Տեսակավորել ձախ մասը
r = merge_sort(a[len(a) // 2:]) # Տեսակավորել աջ մասը
return merge(l, r)
Յուրաքանչյուր փուլում ալգորիթմը վերցնում է զանգվածը, բաժանում այն երկու մասի, առանձին տեսակավորում յուրաքանչյուր մասը և միացնում (merge) արդյունքը։ Նկատեք, որ մինչ այժմ դիտարկված բոլոր ալգորիթմները տեսակավորում էին տեղում (in-place), այսինքն՝ փոփոխում էին նույն զանգվածը։ Իսկ Merge sort-ն ամեն փուլում ստեղծում է նոր զանգված։ Տեղում Merge sort գրելը բավականին բարդ կլինի։ Կարո՞ղ եք բացատրել, թե ինչու։
Եկեք քայլ առ քայլ ուսումնասիրենք ալգորիթմի աշխատանքը մի քանի զանգվածների վրա:
[4, 1, -1, 0, 2, 8]
merge_sort([4, 1, -1, 0, 2, 8]):
merge_sort([4, 1, -1])
merge_sort([0, 2, 8])
merge_sort([4, 1, -1]):
merge_sort([4]) → return [4]
merge_sort([1, -1])
merge_sort([1, -1]):
merge_sort([1]) → return [1]
merge_sort([-1]) → return [-1]
Back to merge_sort([1, -1]) → return [-1, 1]
Back to merge_sort([4, 1, -1]) → return [-1, 1, 4]
merge_sort([0, 2, 8]):
merge_sort([0]) → return [0]
merge_sort([2, 8])
merge_sort([2, 8]):
merge_sort([2]) → return [2]
merge_sort([8]) → return [8]
Back to merge_sort([2, 8]) → return [2, 8]
Back to merge_sort([0, 2, 8]) → return [0, 2, 8]
Back to merge_sort([4, 1, -1, 0, 2, 8]) → return [-1, 0, 1, 2, 4, 8]
Առաջադրանք
Տրված է n ամբողջ թվերից բաղկացած զանգված։ Պահանջվում է տեսակավորել այն նվազման կարգով, օգտագործելով Merge Sort ալգորիթմը։
Մուտք
Մուտքի առաջին տողում տրված է մեկ ամբողջ թիվ n (1 ≤ n ≤ 100 000)։
Հաջորդ տողում տրված են n ամբողջ թվեր , որոնց ամբողջականությունը գտնվում է հատվածում :
Ելք
Ծրագիրը պետք է տպի n ամբողջ թվերը նվազման կարգով (բացատով բաժանված):