Միաձուլման տեսակավորում. ալգորիթմ, առավելություններ և առանձնահատկություններ

Բովանդակություն:

Միաձուլման տեսակավորում. ալգորիթմ, առավելություններ և առանձնահատկություններ
Միաձուլման տեսակավորում. ալգորիթմ, առավելություններ և առանձնահատկություններ
Anonim

Merge sort-ը համակարգչային գիտության հիմնական ալգորիթմներից մեկն է, որը ձևակերպվել է դեռևս 1945 թվականին մեծ մաթեմատիկոս Ջոն ֆոն Նեյմանի կողմից: Մանհեթենի նախագծին մասնակցելիս Նեյմանը բախվեց հսկայական քանակությամբ տվյալների արդյունավետ մշակման անհրաժեշտության հետ: Նրա մշակած մեթոդը օգտագործում էր «բաժանիր և նվաճիր» սկզբունքը, որը զգալիորեն նվազեցրեց աշխատանքի համար պահանջվող ժամանակը։

Ալգորիթմի սկզբունքը և օգտագործումը

Միաձուլման տեսակավորման մեթոդն օգտագործվում է այնպիսի կառուցվածքների տեսակավորման խնդիրներում, որոնք պատվիրված են մուտք դեպի տարրեր, ինչպիսիք են զանգվածները, ցուցակները, հոսքերը:

Մշակման ընթացքում նախնական տվյալների բլոկը բաժանվում է փոքր բաղադրիչների, մինչև մեկ տարր, որն իրականում արդեն տեսակավորված ցուցակ է։ Այնուհետև այն նորից հավաքվում է ճիշտ հերթականությամբ։

Միաձուլման տեսակավորում
Միաձուլման տեսակավորում

Որոշակի երկարությամբ զանգվածի տեսակավորումը պահանջում է նույն չափի լրացուցիչ հիշողության տարածք, որում տեսակավորված զանգվածը հավաքվում է մասերով:

Մեթոդը կարող է օգտագործվել ցանկացած համադրելի տվյալների տեսակ պատվիրելու համար, ինչպիսիք են թվերը կամ տողերը:

Միաձուլումը տեսակավորված էհողամասեր

Ալգորիթմը հասկանալու համար դրա վերլուծությունը սկսենք վերջից՝ տեսակավորված բլոկների միաձուլման մեխանիզմից։

Եկեք պատկերացնենք, որ մենք ունենք թվերի երկու զանգված, որոնք տեսակավորված են ցանկացած ձևով, որոնք պետք է համակցվեն միմյանց հետ, որպեսզի տեսակավորումը չխախտվի: Պարզության համար մենք թվերը կդասավորենք աճման կարգով։

Տարրական օրինակ. երկու զանգվածները բաղկացած են մեկ տարրից:


int arr1={31}; int arr2={18};

Դրանք միավորելու համար անհրաժեշտ է վերցնել առաջին զանգվածի զրոյական տարրը (մի մոռացեք, որ համարակալումը սկսվում է զրոյից) և երկրորդ զանգվածի զրոյական տարրը։ Դրանք, համապատասխանաբար, 31-ն են և 18-ը։ Ըստ տեսակավորման պայմանի՝ առաջինը պետք է լինի 18 թիվը, քանի որ այն ավելի քիչ է։ Պարզապես տեղադրեք թվերը ճիշտ հերթականությամբ՝


int արդյունք={18, 31};

Դիտարկենք ավելի բարդ օրինակ, որտեղ յուրաքանչյուր զանգված բաղկացած է մի քանի տարրերից.


int arr1={2, 17, 19, 45}; int arr2={5, 6, 21, 30};

Միաձուլման ալգորիթմը բաղկացած է լինելու փոքր տարրերի հաջորդական համեմատությունից և դրանք ստացված զանգվածում ճիշտ հերթականությամբ տեղադրելուց: Ընթացիկ ցուցանիշներին հետևելու համար ներկայացնենք երկու փոփոխական՝ index1 և index2: Սկզբում մենք դրանք սահմանեցինք զրոյի, քանի որ զանգվածները դասավորված են, իսկ ամենափոքր տարրերը սկզբում են:


int index1=0; int index2=0;

Եկեք գրենք ամբողջ միաձուլման գործընթացը քայլ առ քայլ:

  1. Վերցրեք index1-ով տարրը arr1 զանգվածից, իսկ index2-ով տարրը arr2 զանգվածից:
  2. Համեմատե՛ք, ընտրե՛ք դրանցից ամենափոքրը և դրե՛քստացված զանգված։
  3. Ավելացրե՛ք փոքր տարրի ընթացիկ ինդեքսը 1-ով։
  4. Շարունակեք առաջին քայլից։
Պատվիրված զանգվածների միաձուլում
Պատվիրված զանգվածների միաձուլում

Առաջին ուղեծրում իրավիճակն այսպիսի տեսք կունենա՝


index1=0; ինդեքս 2=0; arr1[0]=2; arr2[0]=5; arr1[0] < arr2[0]; ինդեքս 1++; արդյունք[0]=arr1[0]; // արդյունք=[2]

Երկրորդ շրջադարձում՝


index1=1; ինդեքս 2=0; arr1 [1]=17; arr2[0]=5; arr1 [1] > arr2 [0]; ինդեքս 2++; արդյունք[1]=arr2[0]; // արդյունք=[2, 5]

Երրորդ:


index1=1; ինդեքս 2=1; arr1 [1]=17; arr2 [1]=6; arr1 [1] > arr2 [1]; ինդեքս 2++; արդյունք[2]=arr2 [1]; // արդյունք=[2, 5, 6]

Եվ այսպես շարունակ, մինչև արդյունքը լինի ամբողջովին դասավորված զանգված՝ {2, 5, 6, 17, 21, 19, 30, 45}։

Որոշակի դժվարություններ կարող են առաջանալ, եթե տարբեր երկարություններ ունեցող զանգվածները միաձուլվեն: Իսկ եթե ընթացիկ ինդեքսներից մեկը հասել է վերջին տարրին, և դեռ անդամներ են մնացել երկրորդ զանգվածում:


int arr1={1, 4}; int arr2={2, 5, 6, 7, 9}; // 1 քայլ ինդեքս1=0, ինդեքս2=0; 1 2 արդյունք={1, 2}; // 3 քայլ ինդեքս1=1, ինդեքս2=1; 4 < 5 արդյունք={1, 2, 4}; //4 քայլ ինդեքս 1=2, ինդեքս 2=1 ??

Index1 փոփոխականը հասել է 2-ի արժեքին, սակայն arr1 զանգվածն այդ ինդեքսով տարր չունի: Այստեղ ամեն ինչ պարզ է. պարզապես երկրորդ զանգվածի մնացած տարրերը փոխանցեք ստացվածին` պահպանելով դրանց հերթականությունը:


արդյունք={1, 2, 4, 5, 6, 7, 9};

Այս իրավիճակը ցույց է տալիս մեզ անհրաժեշտությունըհամապատասխանեցնել ընթացիկ ստուգման ինդեքսը միավորվող զանգվածի երկարությամբ:

Միաձուլման սխեման տարբեր երկարությունների պատվիրված հաջորդականությունների (A և B) համար.

  • Եթե երկու հաջորդականությունների երկարությունը 0-ից մեծ է, համեմատեք A[0] և B[0] և տեղափոխեք փոքրը դեպի բուֆեր:
  • Եթե հաջորդականություններից մեկի երկարությունը 0 է, վերցրեք երկրորդ հաջորդականության մնացած տարրերը և առանց դրանց հերթականությունը փոխելու տեղափոխեք բուֆերի վերջ։

Երկրորդ փուլի իրականացում

Java-ում երկու տեսակավորված զանգվածների միացման օրինակ տրված է ստորև:


int a1=նոր int {21, 23, 24, 40, 75, 76, 78, 77, 900, 2100, 2200, 2300, 2400, 2500}; int a2=նոր int {10, 11, 41, 50, 65, 86, 98, 101, 190, 1100, 1200, 3000, 5000}; int a3=նոր int[a1.length + a2.length]; int i=0, j=0; for (int k=0; k a1.length-1) {int a=a2[j]; a3[k]=a; j++; } else if (j > a2.length-1) { int a=a1; a3[k]=a; i++; } else if (a1 < a2[j]) {int a=a1; a3[k]=a; i++; } else { int b=a2[j]; a3[k]=b; j++; } }

Այստեղ՝

  • a1 և a2 սկզբնական տեսակավորված զանգվածներն են, որոնք պետք է միավորվեն;
  • a3 – վերջնական զանգված;
  • i և j-ն ընթացիկ տարրերի ինդեքսներն են a1 և a2 զանգվածների համար:

Առաջին և երկրորդ, եթե պայմաններն ապահովում են, որ ինդեքսները զանգվածի չափից այն կողմ չեն անցնում: Երրորդ և չորրորդ պայմանի բլոկները, համապատասխանաբար, տեղափոխվում են ավելի փոքր տարրի ստացված զանգված:

Միավորել տեսակավորման տողերը
Միավորել տեսակավորման տողերը

Բաժանիր և տիրիր

Այսպիսով, մենք սովորել ենք միավորել տեսակավորվածըարժեքների հավաքածուներ. Կարելի է ասել, որ միաձուլման տեսակավորման ալգորիթմի երկրորդ մասը՝ ինքնին միաձուլումը, արդեն տեսակավորված է։

Այնուամենայնիվ, դուք դեռ պետք է հասկանաք, թե ինչպես կարելի է սկզբնական չտեսակավորված թվերի զանգվածից հասնել մի քանի տեսակավորվածների, որոնք կարող են միավորվել:

Եկեք դիտարկենք ալգորիթմի առաջին փուլը և սովորենք, թե ինչպես առանձնացնել զանգվածները:

Սա դժվար չէ. արժեքների սկզբնական ցանկը բաժանված է կիսով չափ, այնուհետև յուրաքանչյուր մասը նույնպես երկփեղկված է, և այսպես շարունակ, մինչև ստացվեն շատ փոքր բլոկներ:

Նման նվազագույն տարրերի երկարությունը կարող է հավասար լինել մեկի, այսինքն՝ իրենք կարող են լինել տեսակավորված զանգված, բայց դա անհրաժեշտ պայման չէ։ Բլոկի չափը որոշվում է նախօրոք, և ցանկացած հարմար տեսակավորման ալգորիթմ, որն արդյունավետորեն աշխատում է փոքր չափերի զանգվածների հետ (օրինակ՝ արագ տեսակավորում կամ ներդիր տեսակավորում), կարող է օգտագործվել այն պատվիրելու համար։

Այնպիսի տեսք ունի.


// բնօրինակ զանգված {34, 95, 10, 2, 102, 70}; // առաջին բաժանումը {34, 95, 10} և {2, 102, 70}; // երկրորդ բաժանում {34} և {95, 10} և {2} և {102, 70}

Ստացված բլոկները՝ բաղկացած 1-2 տարրից, շատ հեշտ է դասավորվում։

Դրանից հետո անհրաժեշտ է զույգերով միաձուլել արդեն տեսակավորված փոքր զանգվածները՝ պահպանելով անդամների հերթականությունը, ինչն արդեն սովորել ենք։

Զանգվածն ըստ միաձուլման տեսակավորման սխեմա
Զանգվածն ըստ միաձուլման տեսակավորման սխեմա

Առաջին փուլի իրականացում

Զանգվածի ռեկուրսիվ բաժանումը ներկայացված է ստորև:


void mergeSort(T a, երկար սկիզբ, երկար ավարտ) { long split; եթե(սկիզբ < ավարտ) { պառակտում=(սկիզբ + ավարտ)/2; mergeSort (a, start, split); mergeSort(a, split+1, finish); միաձուլում (ա, սկիզբ, պառակտում, ավարտ); } }

Ինչ է տեղի ունենում այս ծածկագրում.

  1. mergeSort ֆունկցիան ստանում է նախնական զանգվածը

    a

    և տեսակավորվող տարածաշրջանի ձախ և աջ սահմանները (ինդեքսները սկսվում են և

  2. ավարտել).
  3. Եթե այս հատվածի երկարությունը մեկից մեծ է (

    սկիզբ < ավարտ

    ), ապա այն բաժանվում է երկու մասի (

  4. բաժանում ինդեքսով), և յուրաքանչյուրը դասավորված է ռեկուրսիվորեն։
  5. Ձախ կողմի ռեկուրսիվ ֆունկցիայի կանչում տրված են սյուժեի մեկնարկային ինդեքսը և

    split

    ինդեքսը: Ճիշտի համար, համապատասխանաբար, սկիզբը կլինի

  6. (բաժանում + 1), իսկ վերջը կլինի սկզբնական բաժնի վերջին ցուցանիշը։
  7. միաձուլում

    ֆունկցիան ստանում է երկու դասավորված հաջորդականություն (

    a[start]…a[split]

    և

  8. a[բաժանում +1]…a[finish]) և միավորում է դրանք տեսակավորման կարգով:

Միաձուլման ֆունկցիայի մեխանիզմը քննարկված է վերևում:

Ալգորիթմի ընդհանուր սխեման

Միաձուլման տեսակավորման զանգվածի մեթոդը բաղկացած է երկու մեծ քայլերից.

  • Բաժանեք չտեսակավորված բնօրինակ զանգվածը փոքր կտորների:
  • Հավաքեք դրանք զույգերով՝ հետևելով տեսակավորման կանոնին։

Մեծ և բարդ առաջադրանքը բաժանվում է շատ պարզների, որոնք հաջորդաբար լուծվում են՝ տանելով ցանկալի արդյունքի։

Միաձուլման տեսակավորման ալգորիթմ
Միաձուլման տեսակավորման ալգորիթմ

Մեթոդի գնահատում

Միաձուլման տեսակավորման ժամանակային բարդությունը որոշվում է բաժանված ծառի բարձրությամբալգորիթմը և հավասար է զանգվածի տարրերի թվին (n) բազմապատկած նրա լոգարիթմի (log n): Նման գնահատականը կոչվում է լոգարիթմական։

Սա մեթոդի և՛ առավելությունն է, և՛ թերությունը: Դրա գործարկման ժամանակը չի փոխվում նույնիսկ ամենավատ դեպքում, երբ սկզբնական զանգվածը դասավորված է հակառակ հերթականությամբ: Այնուամենայնիվ, ամբողջությամբ տեսակավորված տվյալները մշակելիս ալգորիթմը ժամանակի շահույթ չի ապահովում։

Կարևոր է նաև նշել միաձուլման տեսակավորման մեթոդի հիշողության արժեքը: Դրանք հավասար են բնօրինակ հավաքածուի չափերին։ Այս լրացուցիչ հատկացված տարածքում, դասավորված զանգվածը հավաքվում է կտորներից:

Ալգորիթմի իրականացում

Պասկալի միաձուլման տեսակավորումը ներկայացված է ստորև:


Ընթացակարգ MergeSort (անունը` տող; var f: տեքստ); Var a1, a2, s, i, j, kol, tmp՝ ամբողջ թիվ; f1, f2՝ տեքստ; բ. բուլյան Սկիզբ:=0; Նշանակել (զ, անուն); զրոյացնել (զ); Մինչդեռ EOF(f)-ը չէ, սկսում է կարդալ (f, a1); inc(col); վերջ; փակել (զ); Assign(f1, '{1st օժանդակ ֆայլի անունը}'); Assign(f2, '{2-րդ օժանդակ ֆայլի անունը}'); s:=1; Մինչդեռ (s<kol) սկսում է Վերակայել(f); վերաշարադրել (f1); վերաշարադրել (f2); For i:=1-ից մինչև kol div 2 սկսեք Read(f, a1); Գրել (f1, a1, ' '); վերջ; Եթե (kol div 2) mod s0, ապա սկսեք tmp:=kol div 2; Մինչ tmp mod s0-ը սկսում է Read(f, a1); Գրել (f1, a1, ' '); inc (tmp); վերջ; վերջ; Մինչդեռ EOF(f)-ը չէ, սկսում է Read(f, a2); Գրել (f2, a2, ' '); վերջ; փակել (զ); փակել (f1); փակել (f2); վերաշարադրել (f); վերականգնել (f1); վերականգնել (f2); Կարդացեք (f1, a1); Read (f2, a2); Մինչդեռ (ոչ EOF(f1)) և (ոչ EOF(f2)) սկսում են i:=0; j:=0; բ:=ճշմարիտ; Մինչ (b) և (ոչ EOF(f1)) և (ոչ EOF(f2)) սկսվում են, եթե (a1<a2), ապա սկսեքԳրել (f, a1, ' '); Կարդացեք (f1, a1); inc(i); End else begin Write(f, a2, ' '); Read (f2, a2); inc(j); վերջ; Եթե (i=s) կամ (j=s) ապա b:=false; վերջ; Եթե ոչ b, ապա սկսեք while (i<s) և (ոչ EOF(f1)) սկսեք Write(f, a1, ' '); Կարդացեք (f1, a1); inc(i); վերջ; Մինչդեռ (j<s) և (ոչ EOF(f2)) սկսում են գրել (f, a2, ' '); Read (f2, a2); inc(j); վերջ; վերջ; վերջ; Մինչդեռ EOF(f1) չէ, սկսեք tmp:=a1; Կարդացեք (f1, a1); Եթե ոչ EOF(f1) ապա Write(f, tmp, ' ') else Write(f, tmp); վերջ; Մինչդեռ EOF(f2) չէ, սկսեք tmp:=a2; Read (f2, a2); Եթե ոչ EOF(f2) ապա Write(f, tmp, ' ') else Write(f, tmp); վերջ; փակել (զ); փակել (f1); փակել (f2); s:=s2; վերջ; Ջնջել (f1); Ջնջել (f2); Ավարտ;

Տեսողականորեն ալգորիթմի գործողությունն այսպիսի տեսք ունի (վերևում` չդասավորված հաջորդականություն, ներքևում` դասավորված):

Տեղադրման տեսակավորման պատկերացում
Տեղադրման տեսակավորման պատկերացում

Արտաքին տվյալների տեսակավորում

Շատ հաճախ անհրաժեշտություն է առաջանում տեսակավորել որոշ տվյալներ, որոնք տեղակայված են համակարգչի արտաքին հիշողության մեջ: Որոշ դեպքերում դրանք տպավորիչ չափի են և չեն կարող տեղադրվել RAM-ում՝ դրանց մուտքը հեշտացնելու համար: Նման դեպքերի համար օգտագործվում են արտաքին տեսակավորման մեթոդներ։

Արտաքին մեդիա մուտք գործելու անհրաժեշտությունը նվազեցնում է մշակման ժամանակի արդյունավետությունը:

Աշխատանքի բարդությունն այն է, որ ալգորիթմը կարող է միաժամանակ մուտք գործել տվյալների հոսքի միայն մեկ տարր: Եվ այս դեպքում լավագույն արդյունքներից մեկը ցուցադրվում է միաձուլման տեսակավորման մեթոդով, որը կարող է իրար հաջորդաբար համեմատել երկու ֆայլերի տարրերը։

Տվյալների ընթերցումարտաքին աղբյուրը, դրանց վերամշակումը և վերջնական ֆայլին գրելը կատարվում են պատվիրված բլոկներով (սերիաներով): Ըստ պատվիրված շարքերի չափերի հետ աշխատելու ձևի՝ կա տեսակավորման երկու տեսակ՝ պարզ և բնական միաձուլում։

Արտաքին միաձուլման տեսակավորում
Արտաքին միաձուլման տեսակավորում

Պարզ միաձուլում

Պարզ միաձուլմամբ շարքի երկարությունը ֆիքսված է։

Այսպիսով, բնօրինակ չտեսակավորված ֆայլում բոլոր շարքերը բաղկացած են մեկ տարրից: Առաջին քայլից հետո չափը մեծանում է երկուսի: Հաջորդը՝ 4, 8, 16 և այլն։

Այն աշխատում է այսպես.

  1. Աղբյուր ֆայլը (f) բաժանված է երկու օժանդակ ֆայլերի՝ f1, f2:
  2. Դրանք կրկին միաձուլվում են մեկ ֆայլի մեջ (f), բայց միևնույն ժամանակ բոլոր տարրերը համեմատվում են զույգերով և կազմում զույգեր։ Շարքի չափն այս քայլում դառնում է երկու։
  3. Քայլ 1 կրկնվում է։
  4. Քայլ 2-ը կրկնվում է, բայց արդեն պատվիրված 2-երը միաձուլվում են՝ ձևավորելով տեսակավորված 4-ներ:
  5. Օղակը շարունակվում է՝ ավելացնելով շարքը յուրաքանչյուր կրկնության վրա, մինչև որ ամբողջ ֆայլը տեսակավորվի:

Ինչպե՞ս գիտեք, որ արտաքին տեսակավորումը պարզ միաձուլմամբ ավարտված է:

  • նոր շարքի երկարությունը (միաձուլումից հետո) տարրերի ընդհանուր քանակից ոչ պակաս;
  • մնացել է ընդամենը մեկ դրվագ;
  • Օժանդակ ֆայլ f2 մնացել է դատարկ:

Պարզ միաձուլման թերություններն են. քանի որ գործարկման երկարությունը ամրագրված է յուրաքանչյուր միաձուլման անցուղու վրա, մասնակի պատվիրված տվյալների մշակումը կպահանջվի այնքան ժամանակ, որքան բոլորովին պատահական տվյալները:

Բնական միաձուլում

Այս մեթոդը չի սահմանափակում երկարությունըշարքը, բայց ընտրում է հնարավոր առավելագույնը։

Տեսակավորման ալգորիթմ՝

  1. Ընթերցում է սկզբնական հաջորդականությունը f ֆայլից. Առաջին ստացված տարրը գրվում է f1 ֆայլում։
  2. Եթե հաջորդ գրառումը բավարարում է տեսակավորման պայմանը, ապա այն գրվում է այնտեղ, եթե ոչ, ապա երկրորդ օժանդակ ֆայլում f2:
  3. Այս կերպ բաշխվում են սկզբնաղբյուր ֆայլի բոլոր գրառումները, և f1-ում ձևավորվում է պատվիրված հաջորդականություն, որը որոշում է շարքի ընթացիկ չափը:
  4. F1 և f2 ֆայլերը միավորվել են:
  5. Ցիկլը կրկնվում է։

Շարքի ոչ ֆիքսված չափի պատճառով անհրաժեշտ է հաջորդականության վերջը նշել հատուկ գրանշանով։ Հետեւաբար, միաձուլման ժամանակ համեմատությունների թիվն ավելանում է։ Բացի այդ, օժանդակ ֆայլերից մեկի չափը կարող է մոտ լինել բնօրինակի չափին:

Միջինում բնական միաձուլումն ավելի արդյունավետ է, քան պարզ միաձուլումը արտաքին տեսակավորման հետ:

Ալգորիթմի առանձնահատկությունները

Երկու միանման արժեքներ համեմատելիս մեթոդը պահպանում է դրանց սկզբնական կարգը, այսինքն՝ այն կայուն է։

Տեսակավորման գործընթացը կարելի է շատ հաջողությամբ բաժանել բազմաթիվ թելերի:

Image
Image

Տեսանյութը հստակ ցույց է տալիս միաձուլման տեսակավորման ալգորիթմի աշխատանքը:

Խորհուրդ ենք տալիս: