Това ли е правилният начин за обяснение на псевдокода на MergeSort? Какво връщане има тук?

На различни уебсайтове псевдокодът е подобен на този по-долу:

merge_sort(num_list)
length <-- length of num_list

if length > 1

    shorter_list_A <-- first half of num_list
    shorter_list_B <-- second half of num_list

    result_A <-- merge_sort(shorter_list_A)
    result_B <-- merge_sort(shorter_list_B)

    sorted_list <-- merge(result_A, result_B)

    return sorted_list
else
    return num_list
end

И така, ако имаме 4 числа: 8,3,6,2

MergeSort(8,3,6,2)

първата половина от числата, поставени в Shorter_list_A(8,3), а втората половина от числата, поставени в Shorter_list_B(6,2)

    shorter_list_A <-- first half of num_list
    shorter_list_B <-- second half of num_list

Така че сега имаме два списъка: shorter_list_A(8,3) и Shorter_list_B (6,2)

    result_A <-- merge_sort(shorter_list_A)

Merge_sort извиква merge_sort отново, така че какво се случва там е следното:

merge_sort(Shorter_list_A)  // also 8,3
length <-- length of Shorter_list_A

if length > 1

    shorter_list_A <-- first half of Shorter_list_A 
//8 put to Shorter_list_A
    shorter_list_B <-- second half of Shorter_list_A
//3 put to Shorter_list_B

    result_A <-- merge_sort(shorter_list_A)
//merge_sort calls merge_sort again
    result_B <-- merge_sort(shorter_list_B)

    sorted_list <-- merge(result_A, result_B)

    return sorted_list
else
    return Shorter_list_A
end

Така че сега отново имаме два списъка: shorter_list_A(8) и Shorter_list_B (6)

От обяснението досега правилно ли съм разбрал това или напълно погрешно?

След това отново извиква merge_sort. Тъй като дължината на Shorter_list_A е само 1, той съдържа само едно число, което е 8. Какво се случва там е следното:

merge_sort(Shorter_list_A)
length <-- length of Shorter_list_A
    return Shorter_list_A
end

Връща Shorter_list_A, което е 8.

Какво връщане има точно тук? Заклещен съм там.


person Coder88    schedule 13.09.2015    source източник


Отговори (2)


Трябва да запомните, че той рекурсира надолу по short_list_A, докато не получи условието length <= 1, когато се върнете от рекурсивно повикване, той се връща към предишното повикване в стека на извикванията, което изглежда така:

result_A <-- merge_sort(shorter_list_A) 
// *** return here ***
result_B <-- merge_sort(shorter_list_B)
sorted_list <-- merge(result_A, result_B)
return sorted_list

Така че прави същото за result_B, след което обединява резултатите, преди да се върне нагоре в стека на повикванията.

Така че вземаме малък пример, където отстъпът показва дълбочината на рекурсия:

merge_sort([4,7,2,3,1,8,6,5])
    a = merge_sort([4,7,2,3])
        a = merge_sort([4,7])
            a = merge_sort([4])   // Doesn't recurse anymore length <= 1
            b = merge_sort([7])
            r = merge(a,b) = merge([4], [7])
            return r = [4,7]
        b = merge_sort([2,3])
            a = merge_sort([2])
            b = merge_sort([3])
            r = merge(a, b) = merge([2], [3])
            return r = [2,3]
        r = merge(a,b) = merge([4,7], [2,3])
        return r = [2,3,4,7]
    b = merge_sort([1,8,6,5])
        a = merge_sort([1,8])
            a = merge_sort([1])
            b = merge_sort([8])
            r = merge(a, b) = merge([1],[8])
            return r = [1,8]
        b = merge_sort([6,5])
            a = merge_sort([6])
            b = merge_sort([5])
            r = merge(a, b) = merge([6],[5])
            return r = [5,6]
        r = merge(a,b) = merge([1,8], [5,6])
        return r = [1,5,6,8]
    r = merge(a, b) = merge([2,3,4,7], [1,5,6,8])
    return r = [1,2,3,4,5,6,7,8]

Надяваме се, че това помага.

person AChampion    schedule 13.09.2015
comment
Така че това, което разбрах е: 1) няма само един Shorter_A_list. Има няколко Shorter_A_lists; по един на всяко ниво на рекурсия. Вярно ли е? 2) тъй като никога не връща num_list, докато сортирането не завърши, може ли алгоритъмът да работи, премахвайки операторите IF, ELSE и RETURN NUM_LIST и просто използвайки само WHILE LENGTH ›= 1 оператор? 3) Все още не разбирам функцията на изразите RETURN NUM_LIST и RETURN SORTED_LIST. - person Coder88; 14.09.2015
comment
Да, има num_list на всяко ниво на рекурсия. Ако го поставите в цикъл while, губите цялата предишна информация, така че няма да работи. Върнатият num_list се изпълнява само и най-отдалечената дълбочина на рекурсивното дърво - когато не може да раздели num_list повече, навсякъде другаде връща сортирания списък. - person AChampion; 14.09.2015
comment
От вашите обяснения и обясненията на други уебсайтове разбрах какво прави RETURN. Но защо не се използва само RETURN, а RETURN NUM_LIST и RETURN SORTED_LIST? В статии за RETURN на уебсайтове като Wikipedia те пишат нещо като Някои езици за програмиране позволяват на функцията да посочи върната стойност, която да бъде предадена обратно към кода, който е извикал функцията. Предаване на стойност обратно към кода, какво означава това? - person Coder88; 14.09.2015
comment
Вижте стека по-горе, върнатата стойност се присвоява на стойността a или b в предишното извикване, така че след това можете да обедините (a,b). Ако не сте върнали стойност, никога няма да отразите промените в стека на повикванията. a на една дълбочина е различно от a на различна дълбочина. - person AChampion; 14.09.2015

Всяко връщане ще изпрати обратно на повикващия сортиран списък на елементите, които е получил като вход.

На най-долното ниво, когато има само един елемент, списъкът се сортира по подразбиране и се връща. Когато получите два сортирани списъка с по един елемент в result_A и result_B, вие ги предавате и двата на метода merge() и този метод вече върши тежката работа. Това взема двата списъка и ги обединява, за да даде нов списък, който съдържа елементите на двата списъка в сортиран ред.

Как изглежда Merge()?

Merge() ще създаде нов списък. Нека го наречем sorted_list и след това ще започне да чете от head на двата списъка, които е получил като вход и ще вземе минимума от двата елемента на head позиция и ще го постави в sorted_list, който току-що създаде. Методът ще продължи да консумира head от двата входни списъка, докато и двата не бъдат завършени. Сега сливането на двата списъка присъства в sorted_list в сортиран ред. Предположих, че искате списъкът да е сортиран от минимум към максимум.

Преглед на вашия пример

На последното ниво, с единични елементи, първият списък от head -> 8 -> null и вторият списък от head -> 3 -> null ще се слеят, за да образуват head -> 3 -> 8 -> null

На самото това ниво ще обедини двата списъка от head -> 6 -> null и head -> 2 -> null до head -> 2 -> 6 -> null

Нека долното ниво се нарича 0. На ниво 0 имахте само единични елементи. На ниво 1 ще имате списъци от два елемента. На ниво 2 ще имате два списъка от 2 елемента, обединени в един списък.

И така, от head -> 3 -> 8 -> null и head -> 2 -> 6 -> null ще получите head -> 2 -> 3 -> 6 -> 8 -> null.

И накрая този списък ще бъде върнат. Няма повече нива за изкачване. Това е нивото, на което сте получили оригиналния несортиран входен списък, така че при това връщане ефективно ще върнете сортирания списък на повикващия.

За да обобщим

Level num_list Shorter_List_A Shorter_List_B Result_A Result_B sorted_list

2     8,3,6,2  8,3            6,2            3,8      2,6      2,3,6,8

1(a)  8,3      8              3              8        3        3,8  
1(b)  6,2      6              2              6        2        2,6

0(a)  8        -              -              -        -        8
0(b)  3        -              -              -        -        3 
0(c)  6        -              -              -        -        6
0(d)  2        -              -              -        -        2 

И така, започнахме от ниво 2. Извикахме се рекурсивно на ниво 1(a), 1(b). След това от ниво 1 се извикахме рекурсивно отново на ниво 0(a), 0(b), 0(c), 0(d) и след това прехвърлихме обединените резултати до ниво 2 отново и след това върнахме сортиран списък.

person displayName    schedule 13.09.2015
comment
Всяко връщане ще изпрати обратно на повикващия сортиран списък на елементите, които е получил като вход. Можете ли да обясните какво имате предвид тук? Например, да кажем, че последната рекурсия (ниво 2) има само '8' в своя масив, така че използвайки RETURN NUM_LIST, тя връща '8'. Това означава ли, че поставя 8 на входа на своя повикващ? Също така поставяне на '8' на входа на merge_sort ниво 1? Така че след това да може да обедини 8 и 3 (което също се поставя с return num_list), когато се извика merge_sort на ниво 1? - person Coder88; 14.09.2015
comment
@Coder88: Това означава, че на всяко ниво, какъвто и списък да получим, връщаме друг списък със същите елементи в сортиран ред. Последната рекурсия е ниво 0, а не ниво 2 (започнах да наименувам от последното ниво нататък към най-високото ниво). Получаваме пълния несортиран списък на най-високо ниво. След това продължаваме да разделяме списъка наполовина и достигаме ниво 0. - person displayName; 14.09.2015
comment
@Coder88: Получаваме елементите на ниво 2 и се връщаме само от ниво 2. Но за да получим сортиран списък на ниво 2, отиваме на нива 1(a) и 1(b), а ниво 1(a,b) отиваме на ниво 0(a, b, c и d), за да получим сортираните списъци. - person displayName; 14.09.2015
comment
@Coder88: Вижте отново таблицата. Промених дизайна му. Разбираш ли го по-добре сега? - person displayName; 14.09.2015
comment
Както разбрах, RETURN X в подпрограма означава, че отнема X от подпрограмата към неговата оригинална рутина (или как да я нарека) и оригиналната рутина продължава работата си със стойността, получена от под- рутина. Така че, когато подпрограмата на MergeSort(shorter_list_A) приключи, тя връща стойността от това, така че MergeSort(shorter_list_A)=този списък и след това премества този списък към result_A, като използва символа ‹--. - person Coder88; 15.09.2015
comment
Ето една фиктивна презентация на Prezi: prezi.com/5hxesubf5ibu/merge-sort-pseudocode сините стрелки са извикване на подпрограма (или на рекурсия в този случай). И червените стрелки се завръщат. Мислите ли, че тази презентация на Prezi може да се използва за обяснение на Merge_sort? (Знам, че няма текст за обяснение, но може да се добави или да се добави гласово обяснение). - person Coder88; 15.09.2015
comment
@Coder88: Да. Обяснението, което си дал, и презентацията са здрави. - person displayName; 15.09.2015
comment
@Coder88: Ако искате да го обясните на някого, дръжте алгото до себе си и нарисувайте дърво (това ще стане, когато нарисувате рекурсивните извиквания), което показва какво е изпратено до възел (т.е. подпрограмата) и какво е върнато. - person displayName; 15.09.2015
comment
Всъщност просто исках да го обясня, за да съм сигурен, че самият аз го разбирам правилно. Но програмирането е малко като математика, понякога е лесно за разбиране, но трудно за обяснение. - person Coder88; 15.09.2015
comment
@Coder88: каквото плава в лодката ви. :) - person displayName; 15.09.2015
comment
Но се чудя къде последното RETURN SORTED_LIST връща списъка? Имам предвид, когато целият списък е сортиран, обединен и поставен в SORTED_LIST (като 2,3,6,8), тогава има RETURN SORTED_LIST. При изпълнение на последния RETURN SORTED_LIST, къде се връща SORTED_LIST? Или какво се случва? - person Coder88; 15.09.2015
comment
@Coder88: Към първоначалния обаждащ се. Този, който изпрати несортирания списък за сортиране. - person displayName; 15.09.2015
comment
Но какво ще стане, ако няма оригинален обаждащ се? Имам предвид, че ако merge_sort е настолен софтуер, където въвеждате някои числа и софтуерът ги сортира, където последното връщане връща sorted_list? - person Coder88; 15.09.2015
comment
@Coder88: За да започне това сортиране чрез сливане, ще има място, където ще има ред като merge_sort(inputList). Този списък ще съдържа числа, които трябва да бъдат сортирани. И окончателното връщане ще върне контрола обратно на самата тази линия. Обикновено резултатите се съхраняват в някаква променлива като var sortedList = merge_sort(inputList). - person displayName; 15.09.2015
comment
@Coder88: Контролът ще премине към merge_sort() само когато бъде извикан от някъде. И когато изпълнението приключи, контролът се връща обратно към повикващия (било то софтуер, или команден ред, или ред в друга функция). Например в Java управлението идва до main(), когато потребителят го извика. main() е просто функция като merge_sort() - person displayName; 15.09.2015
comment
. . . И окончателното връщане ще върне контрола обратно на самата тази линия. Какво имаш предвид тук? - person Coder88; 15.09.2015
comment
@Coder88: Например в Java, когато напишете List<int> sorted_list = merge_sort(inputUnsortedList), тогава, когато merge_sort() приключи, контролата ще се върне на същия този ред и sorted_list ще съхрани резултата от merge_sort(). След това контролата ще продължи да изпълнява следващия ред в този код. - person displayName; 15.09.2015