පහත දැක්වෙන්නේ යුක්කොනන් ඇල්ගොරිතම විස්තර කිරීමට උත්සාහ කිරීම, එය නූල් සරල වූ විට එය කරන්නේ කුමක්ද යන්න පෙන්වීමෙනි (එනම් නැවත නැවත අක්ෂර කිසිවක් අඩංගු නොවේ), පසුව එය සම්පූර්ණ ඇල්ගොරිතම දක්වා විහිදේ.
පළමුව, මූලික ප්රකාශ කිහිපයක්.
අප ගොඩනඟන්නේ මූලික වශයෙන් සෙවුම් ත්රිකෝණයකට සමානය. එබැවින් මූල නෝඩයක් ඇත, එයින් පිටතට යන දාර නව නෝඩ් වලට මඟ පාදයි, සහ තවත් දාර ඒවායින් පිටතට යයි, සහ යනාදිය
නමුත් : සෙවුම් ත්රිත්වයේ මෙන් නොව, දාරයේ ලේබල තනි අක්ෂර නොවේ. ඒ වෙනුවට, සෑම දාරයක්ම පූර්ණ සංඛ්යා යුගලයක් භාවිතයෙන් ලේබල් කර ඇත
[from,to]
. මේවා පෙළට යොමු කරන්නන් වේ. මෙම අර්ථයෙන් ගත් කල, සෑම දාරයක්ම අත්තනෝමතික දිගකින් යුත් ලේබලයක් දරයි, නමුත් ගත වන්නේ O (1) ඉඩක් පමණි (දර්ශක දෙකක්).
මූලික මූලධර්මය
පුනරාවර්තන අක්ෂර නොමැති නූලක්, විශේෂයෙන් සරල නූලක උපසර්ග ගසක් නිර්මාණය කරන්නේ කෙසේදැයි මම පළමුව නිරූපණය කිරීමට කැමැත්තෙමි:
abc
ඇල්ගොරිතම වමේ සිට දකුණට පියවරෙන් පියවර ක්රියා කරයි . නූලෙහි සෑම අක්ෂරයක් සඳහාම එක් පියවරක් ඇත. සෑම පියවරකටම එක් පුද්ගල මෙහෙයුමකට වඩා වැඩි ගණනක් ඇතුළත් විය හැකි නමුත්, සමස්ත මෙහෙයුම් ගණන O (n) බව අපි දකිමු (අවසානයේ අවසාන නිරීක්ෂණ බලන්න).
ඉතින්, අපි වමේ සිට ආරම්භ කර , මුලින්ම තනි අක්ෂරයක් පමණක් ඇතුල් කරන්න
a
, මූල නෝඩයේ සිට (වමේ) [0,#]
කොළයකට දාරයක් සාදා එය ලේබල් කරන්න , එයින් අදහස් වන්නේ දාරය 0 වන ස්ථානයේ සිට ආරම්භ වන උපස්ථරය නිරූපණය කරන බවයි. දී වත්මන් අවසන් . මම සංකේතය භාවිතා #
කරන්නේ වත්මන් අවසානය අර්ථ දැක්වීම සඳහා වන අතර එය 1 වන ස්ථානයේ (වහාම a
).
එබැවින් අපට ආරම්භක ගසක් ඇත, එය මේ ආකාරයෙන් පෙනේ:
එහි තේරුම මෙයයි:
දැන් අපි 2 වන ස්ථානයට ඉදිරියට යමු (වහාම b
). සෑම පියවරකදීම අපගේ ඉලක්කය
වන්නේ සියලු උපසර්ග වත්මන් ස්ථානයට ඇතුළු කිරීමයි. අපි මෙය කරන්නේ
- පවත්නා
a
-එජ් දක්වා පුළුල් කිරීමab
- සඳහා නව දාරයක් ඇතුල් කිරීම
b
අපගේ නිරූපණයේ දී මෙය පෙනේ
එහි තේරුම:
අපි කරුණු දෙකක් නිරීක්ෂණය කරමු :
- සඳහා අද්දර නියෝජනය
ab
වන එම එය මූලික ගසක් විය කිරීම සඳහා භාවිතා ලෙස: [0,#]
. අපි වර්තමාන පිහිටීම #
1 සිට 2 දක්වා යාවත්කාලීන කළ නිසා එහි අර්ථය ස්වයංක්රීයව වෙනස් වී ඇත .
- සෑම දාරයක්ම O (1) අවකාශය පරිභෝජනය කරයි, මන්ද එය පෙළ කොපමණ සංඛ්යාවක් නිරූපණය කළද එය පෙළට යොමු වන්නේ ලකුණු දෙකකින් පමණි.
ඊළඟට අපි නැවත පිහිටීම වැඩි කර ගස යාවත්කාලීන කරන්නේ c
පවතින සෑම දාරයකටම එකතු කර නව උපසර්ගය සඳහා එක් නව දාරයක් ඇතුල් කරමිනි c
.
අපගේ නිරූපණයේ දී මෙය පෙනේ
එහි තේරුම:
අපි නිරීක්ෂණය කරන්නේ:
-
එක් එක් පියවරෙන් පසු වත්මන් ස්ථානය දක්වා නිවැරදි උපසර්ගය ගස වේ
- පා in යේ අක්ෂර ඇති තරම් පියවර තිබේ
- එක් එක් පියවරේ වැඩ ප්රමාණය O (1) වේ, මන්ද දැනට පවතින සියලුම දාර වැඩි කිරීමෙන් ස්වයංක්රීයව යාවත්කාලීන වන
#
අතර අවසාන අක්ෂරය සඳහා එක් නව දාරයක් ඇතුළත් කිරීම O (1) කාලය තුළ කළ හැකිය. එබැවින් දිග n නූලක් සඳහා අවශ්ය වන්නේ O (n) කාලය පමණි.
පළමු දිගුව: සරල පුනරාවර්තන
ඇත්ත වශයෙන්ම මෙය ඉතා සියුම් ලෙස ක්රියාත්මක වන්නේ අපගේ සංගීතයට කිසිදු පුනරාවර්තනයක් නොමැති නිසාය. අපි දැන් වඩාත් යථාර්ථවාදී නූලක් දෙස බලමු:
abcabxabcd
එය ආරම්භ abc
පෙර උදාහරණය ලෙස, පසුව ab
නැවත නැවතත් ඇති අතර පසුව x
, පසුව abc
අනුගමනය නැවත නැවතත් d
.
පියවර 1 සිට 3 දක්වා: පළමු පියවර 3 න් පසු අපට පෙර උදාහරණයෙන් ගස ඇත:
පියවර 4: අපි 4 වන#
ස්ථානයට ගමන් කරමු . මෙය දැනට පවතින සියලුම දාරයන් ව්යංගයෙන් යාවත්කාලීන කරයි:
වත්මන් පියවරේ අවසාන උපසර්ගය මුලදී ඇතුළත් කළ යුතුය a
.
අප මෙය කිරීමට පෙර, අපි තවත් විචල්යයන් දෙකක් හඳුන්වා දෙන්නෙමු (ඊට අමතරව
#
), ඇත්ත වශයෙන්ම ඒවා සැමවිටම පැවතුන නමුත් අපි ඒවා මෙතෙක් භාවිතා කර නොමැත:
- මෙම ක්රියාකාරී අවස්ථාවක , ත්රිත්ව වන
(active_node,active_edge,active_length)
- මෙම
remainder
, අප ඇතුල් කිරීමට අවශ්ය කොපමණ නව suffixes පෙන්නුම් යනු පූර්ණ සංඛ්යාවකි වන
මේ දෙකෙහි නියම අරුත ඉතා ඉක්මනින් පැහැදිලි වනු ඇත, නමුත් දැන් අපි කියමු:
- සරල
abc
උදාහරණයේ දී, ක්රියාකාරී ලක්ෂ්යය සැමවිටම
(root,'\0x',0)
, එනම් active_node
මූල නෝඩය, active_edge
ශුන්ය අක්ෂරය ලෙස දක්වා ඇති '\0x'
අතර active_length
එය ශුන්ය විය. මෙහි ප්රති was ලය වූයේ සෑම පියවරකදීම අප ඇතුළු කළ එක් නව දාරයක් නැවුම් ලෙස සාදන ලද දාරයක් ලෙස මූල නෝඩයට ඇතුළත් කිරීමයි. මෙම තොරතුරු නියෝජනය කිරීම සඳහා ත්රිත්වයක් අවශ්ය වන්නේ මන්දැයි අපි ඉක්මනින් බලමු.
- මෙම
remainder
සෑම විටම එක් එක් පියවර ආරම්භයේදී 1 බවට නියම කර ඇත. මෙහි අර්ථය වූයේ එක් එක් පියවර අවසානයේ අපට සක්රියව ඇතුළත් කළ යුතු උපසර්ග ගණන 1 (සෑම විටම අවසාන අක්ෂරය පමණි).
දැන් මෙය වෙනස් වනු ඇත. අපි වත්මන් අවසාන අක්ෂරය මුලට ඇතුළු කරන a
විට, පිටතට යන දාරයක් දැනටමත් ආරම්භ වන බව අපට පෙනේ a
, විශේෂයෙන් : abca
. එවැනි අවස්ථාවක අප කරන දේ මෙන්න:
- අපි මූල නෝඩයේ නැවුම් දාරයක් ඇතුල් නොකරමු
[4,#]
. ඒ වෙනුවට උපසර්ගය a
දැනටමත් අපගේ ගසෙහි ඇති බව අපි දකිමු. එය අවසන් වන්නේ දිගු දාරයක් මැද ය, නමුත් අපට එයින් කරදරයක් නොවේ. අපි දේවල් එලෙසම තබමු.
- අප ක්රියාකාරී අවස්ථාවක සකස් කිරීමට
(root,'a',1)
. ඒ කියන්නේ සක්රිය ලක්ෂ්යය දැන් මූල නෝඩයේ පිටතට යන දාරයේ කොතැනක හෝ ඇති අතර, එය ආරම්භ වන්නේ a
, විශේෂයෙන්, එම දාරයේ 1 වන ස්ථානයට පසුව ය. දාරය එහි පළමු අක්ෂරයෙන් සරලව දක්වා ඇති බව අපි දකිමු a
. කිසියම් චරිතයකින් ආරම්භ වන එක් දාරයක් පමණක් තිබිය හැකි බැවින් එය ප්රමාණවත් වේ (සම්පූර්ණ විස්තරය කියවීමෙන් පසු මෙය සත්ය බව තහවුරු කරන්න).
- අපි වැඩි කරන්නෙමු
remainder
, එබැවින් ඊළඟ පියවර ආරම්භයේදී එය 2 ක් වනු ඇත.
නිරීක්ෂණය: අප ඇතුළු කළ යුතු අවසාන උපසර්ගය දැනටමත් ගසෙහි පවතින බව සොයා ගත් විට , ගස කිසිසේත් වෙනස් නොවේ (අපි සක්රීය ස්ථානය යාවත්කාලීන කරන්නේ සහ remainder
). ගස යනු වත්මන් ස්ථානය දක්වා වූ උපසර්ග ගසෙහි නිරවද්ය නිරූපණයක් නොවේ , නමුත් එහි සියලු උපසර්ග අඩංගු වේ (අවසාන උපසර්ගය ව්යංගයෙන්a
අඩංගු වන නිසා ). එබැවින්, විචල්යයන් යාවත්කාලීන කිරීම හැරුණු විට (ඒවා සියල්ලම ස්ථාවර දිග, එබැවින් මෙය O (1) වේ),
මෙම පියවරේදී කිසිදු කාර්යයක් සිදු නොවීය .
පියවර 5: අපි වත්මන් ස්ථානය 5 දක්වා යාවත්කාලීන කරමු #
. මෙය ගස ස්වයංක්රීයව යාවත්කාලීන කරයි:
හා නිසා remainder
2 වන , අපි, වර්තමාන තත්ත්වය අවසන් suffixes දෙකක් ඇතුල් කිරීමට අවශ්ය: ab
හා b
. මෙය මූලික වශයෙන් එයට හේතුව:
- මෙම
a
පෙර පියවරෙන් සිට ෙපර ෙයදුම නිසි ලෙස ඇතුළත් කර නැහැ. එබැවින් එය ඉතිරිව ඇති අතර , අප එක් පියවරක් ඉදිරියට ගොස් ඇති බැවින්, එය දැන් සිට වර්ධනය වී a
ඇත ab
.
- අපි නව අවසාන දාරය ඇතුළු කළ යුතුයි
b
.
ප්රායෝගිකව මෙයින් අදහස් කරන්නේ අපි ක්රියාකාරී ස්ථානයට ගොස් (එය a
දැන් abcab
අද්දර ඇති දෙයට පිටුපසට යොමු කරයි ), සහ වත්මන් අවසාන අක්ෂරය ඇතුළත් කරන්න b
. නමුත්: නැවතත්, එය b
දැනටමත් එම අද්දරම පවතින බව පෙනේ.
ඉතින්, නැවතත්, අපි ගස වෙනස් නොකරමු. අපි සරලවම:
- සක්රීය ලක්ෂ්යය යාවත්කාලීන කරන්න
(root,'a',2)
(පෙර මෙන් එකම නෝඩ් සහ දාරය, නමුත් දැන් අපි පිටුපසින් යොමු කරමු b
)
- වැටුප් වර්ධක මෙම
remainder
3 අප තවමත් නිසි පෙර පියවරෙන් සිට අවසන් අද්දර ඇතුළු කර නැහැ, අපි එක්කෝ වත්මන් අවසන් අද්දර ඇතුල් නැති නිසා.
පැහැදිලි කිරීමට: අපි ඇතුල් වුණා ab
හා b
වත්මන් පියවර නිසා නොව, ab
මේ වන විටත් සොයා ගෙන, අපි ක්රියාකාරී අවස්ථාවක යාවත්කාලීන සහ පවා ඇතුල් කිරීමට උත්සාහ කළේ නැත b
. මන්ද? මන්ද යත්, ab
ගස වේ,
සෑම ෙපර ෙයදුම (ඇතුළු එය b
) ද, ගස විය යුතුය. සමහර විට ව්යංගයෙන් පමණක් විය හැකි නමුත් එය එහි තිබිය යුතුය, මන්ද අප මෙතෙක් ගස ඉදිකර ඇති ආකාරය නිසාය.
අපි ඉදිරියට පියවර 6 incrementing විසින් #
. ගස ස්වයංක්රීයව යාවත්කාලීන වන්නේ:
නිසා remainder
3 වන , අපි ඇතුල් කිරීමට ඇති abx
, bx
හා
x
. සක්රීය ලක්ෂ්යය අපට පවසන්නේ කොතැනින් ab
කෙළවරද, එබැවින් අපට අවශ්ය වන්නේ එහි පැන පැන ඇතුල් කිරීමයි x
. ඇත්ත වශයෙන්ම, x
තවම එහි නොමැත, එබැවින් අපි abcabx
දාරය බෙදී අභ්යන්තර නෝඩයක් ඇතුළු කරමු:
දාර නිරූපණයන් තවමත් පෙළට යොමු කර ඇති බැවින් අභ්යන්තර නෝඩයක් බෙදීම හා ඇතුළත් කිරීම O (1) කාලය තුළ කළ හැකිය.
එබැවින් අපි ගනුදෙනු කර 2 දක්වා abx
අඩු remainder
කර ඇත්තෙමු. දැන් අපි ඊළඟ ඉතිරි උපසර්ගය ඇතුළත් කළ යුතුය bx
. නමුත් අප එය කිරීමට පෙර ක්රියාකාරී ලක්ෂ්යය යාවත්කාලීන කළ යුතුය. මේ සඳහා වන රීතිය, දාරයක් බෙදීමෙන් හා ඇතුළත් කිරීමෙන් පසුව, පහත රීතිය 1 ලෙස හඳුන්වනු ලබන අතර, active_node
එය මූල වන සෑම විටම අදාළ
වේ (තවත් අවස්ථා සඳහා අපි 3 වන රීතිය ඉගෙන ගනිමු). මෙන්න රීතිය 1:
මූලයෙන් ඇතුළු කිරීමෙන් පසුව,
active_node
මූලයේ පවතී
active_edge
අප ඇතුළු කළ යුතු නව උපසර්ගයේ පළමු අක්ෂරයට සකසා ඇත, එනම් b
active_length
1 කින් අඩු වේ
එබැවින්, නව ක්රියාකාරී ලක්ෂ්ය ත්රිත්වයෙන් (root,'b',1)
ඇඟවෙන්නේ ඊළඟ ඇතුල් කිරීම bcabx
කෙළවරේ, අක්ෂර 1 ට පිටුපසින්, එනම් පිටුපසින් කළ යුතු b
බවයි. අපට O (1) වේලාවේ ඇතුළත් කිරීමේ ස්ථානය හඳුනාගත හැකි අතර x
දැනටමත් තිබේද නැද්ද යන්න පරීක්ෂා කරන්න . එය තිබුනේ නම්, අපි වර්තමාන පියවර අවසන් කර සෑම දෙයක්ම ඒ ආකාරයෙන්ම තබමු. නමුත් x
නොපවතී, එබැවින් අපි දාරය බෙදීමෙන් එය ඇතුල් කරමු:
නැවතත්, මේ සඳහා O (1) කාලය ගත වූ අතර අපි remainder
1 ට යාවත්කාලීන කරන අතර ක්රියාකාරී ලක්ෂ්යය (root,'x',0)
1 වන රීතිය ලෙස දක්වා ඇත.
නමුත් අප විසින් කළ යුතු තවත් දෙයක් තිබේ. අපි මෙම රීතිය 2 ලෙස හඳුන්වමු :
අපි දාරයක් බෙදී නව නෝඩයක් ඇතුළු කළහොත්, එය වත්මන් පියවරේදී නිර්මාණය කරන ලද පළමු නෝඩය නොවේ නම් , අපි කලින් ඇතුළත් කළ නෝඩය සහ නව නෝඩය විශේෂ දර්ශකයක් හරහා උපසර්ග සම්බන්ධකයක් හරහා සම්බන්ධ කරමු . එය ප්රයෝජනවත් වන්නේ මන්දැයි අපි පසුව බලමු. මෙන්න අපට ලැබෙන දේ, උපසර්ග සබැඳිය තිත් දාරයක් ලෙස නිරූපණය කෙරේ:
වත්මන් පියවරේ අවසාන උපසර්ගය අප තවමත් ඇතුළත් කළ යුතුය
x
. සිට active_length
ක්රියාකාරී node එකක් මතම ඊට අදාල සංරචකයක් 0 දක්වා පහත වැටී ඇතත්, අවසන් ඇතුලත් කරන්න කෙලින්ම මූල සිදු කර ඇත. ආරම්භ වන මූල නෝඩයේ පිටතට යන දාරයක් නොමැති බැවින් x
, අපි නව දාරයක් ඇතුල් කරමු:
අපට පෙනෙන පරිදි, වර්තමාන පියවරේදී ඉතිරිව ඇති සියලුම ඇතුළත් කිරීම් සිදු කරන ලදී.
අපි සෑම විටම මෙන් ඊළඟ අක්ෂරයට ස්වයංක්රීයව එකතු කරන = 7
සැකසීමෙන් 7 වන පියවරට ඉදිරියට යමු . ඉන්පසු අපි නව අවසාන අක්ෂරය සක්රිය ස්ථානයට (මූලයට) ඇතුළු කිරීමට උත්සාහ කර එය දැනටමත් එහි ඇති බව සොයා ගනිමු. එබැවින් අපි කිසිවක් ඇතුළත් නොකර වත්මන් පියවර අවසන් කර සක්රිය ලක්ෂ්යය යාවත්කාලීන කරමු .#
a
(root,'a',1)
දී පියවර 8 , #
= 8, අපි ඇතුලත් b
පෙර දැක ලෙස, හා, අපි ක්රියාකාරී අවස්ථාවක යාවත්කාලීන මෙම එකම මාර්ගය (root,'a',2)
හා වැටුප් වර්ධක remainder
නිසා, වෙන කිසිවක් නොකර b
මේවන විටත්. කෙසේ වෙතත්, (O (1) වේලාවේදී) සක්රීය ලක්ෂ්යය දැන් කෙළවරක ඇති බව අපි දකිමු. අපි මෙය නැවත සැකසීමෙන් පිළිබිඹු කරමු
(node1,'\0x',0)
. මෙන්න, මා භාවිතා node1
කරන්නේ ab
දාරය අවසන් වන අභ්යන්තර නෝඩය වෙතය .
එවිට, පියවර #
= 9 දී , අපි 'c' ඇතුළු කළ යුතු අතර, අවසාන උපක්රමය තේරුම් ගැනීමට මෙය අපට උපකාරී වනු ඇත:
දෙවන දිගුව: උපසර්ග සබැඳි භාවිතා කිරීම
සෑම විටම මෙන්, #
යාවත්කාලීනය c
ස්වයංක්රීයව පත්ර දාරවලට එකතු වන අතර අපට 'සී' ඇතුළු කළ හැකිදැයි බැලීමට අපි ක්රියාකාරී ස්ථානයට යමු. 'සී' දැනටමත් එම අද්දර පවතින බව පෙනේ, එබැවින් අපි සක්රීය ලක්ෂ්යය
(node1,'c',1)
, වර්ධක remainder
සහ වෙන කිසිවක් නොකරමු.
දැන් පියවර #
= 10 , remainder
4 වේ, එබැවින් අපි මුලින්ම සක්රීය ස්ථානයට abcd
ඇතුළු කිරීමෙන් d
( පියවර 3 කට පෙර සිට ඉතිරිව තිබිය යුතුය
) .
d
සක්රීය ස්ථානයේ ඇතුළු කිරීමට උත්සාහ කිරීම O (1) වේලාවෙහි දාරය බෙදීමට හේතු වේ:
මෙම active_node
, භේදය ආරම්භ කරන ලද රතු, ඉහත ලෙස ලකුණු කර ඇත. මෙන්න අවසාන රීතිය, රීතිය 3:
active_node
මූල නෝඩ් නොවන දාරයකින් දාරයක් බෙදීමෙන් පසුව , අපි එම නෝඩයෙන් පිටතට යන උපසර්ග සබැඳිය අනුගමනය කර, කිසියම් දෙයක් තිබේ නම්, active_node
එය පෙන්වා ඇති නෝඩයට නැවත සකසන්න . උපසර්ග සම්බන්ධකයක් නොමැති නම්, අපි active_node
මූලයට සකසමු. active_edge
හා active_length
නොවෙනස්ව තිබෙනවා.
එබැවින් ක්රියාකාරී ලක්ෂ්යය දැන් ඇති (node2,'c',1)
අතර node2
එය රතු පැහැයෙන් සලකුණු කර ඇත:
ඇතුළත් කිරීම abcd
සම්පුර්ණ බැවින්, අපි remainder
3 දක්වා අඩු වන අතර වත්මන් පියවරේ ඊළඟ ඉතිරි උපසර්ගය සලකා බලමු
bcd
. 3 වන රීතිය මඟින් සක්රීය ලක්ෂ්යය නිවැරදි නෝඩයට හා දාරයට සකසා ඇති අතර එම නිසා bcd
එහි අවසාන අක්ෂරය d
සක්රීය ස්ථානයේ ඇතුළත් කිරීමෙන් ඇතුළත් කළ හැකිය
.
මෙය කිරීමෙන් තවත් දාරයක් බෙදීමට හේතු වන අතර, 2 වන රීතිය නිසා , අප කලින් ඇතුළත් කළ නෝඩයේ සිට නව එකට උපසර්ග සම්බන්ධකයක් සෑදිය යුතුය:
අපි නිරීක්ෂණය කරමු: ක්රියාකාරී ලක්ෂ්යය නැවත සැකසීමට උපසර්ග සබැඳි මඟින් අපට හැකි වන අතර එමඟින් O (1) ප්රයත්නයේදී ඉතිරිව ඇති ඇතුල් කිරීම සිදු කළ හැකිය . ලේබලයේ ඇත්ත වශයෙන්ම නෝඩය තහවුරු කිරීමට ඉහත ප්රස්ථාරය දෙස බලන්නab
දී node එකක් මතම ඊට අදාල සම්බන්ධ වේ b
(එහි ෙපර ෙයදුම), හා මංසල abc
සම්බන්ධ වේ
bc
.
වත්මන් පියවර තවම අවසන් නැත. remainder
දැන් 2 වන අතර, ක්රියාකාරී ලක්ෂ්යය නැවත සැකසීමට අපි 3 වන රීතිය අනුගමනය කළ යුතුය. වත්මන් active_node
(ඉහළ රතු) සඳහා උපසර්ග සම්බන්ධයක් නොමැති බැවින්, අපි root වෙත නැවත සකසමු. සක්රීය ස්ථානය දැන් (root,'c',1)
.
එබැවින් ඊළඟ ඇතුල් කිරීම සිදුවන්නේ මූල නෝඩයේ පිටතට යන එක් කෙළවරක වන අතර එහි ලේබලය ආරම්භ වන්නේ c
:cabxabcd
, පළමු අක්ෂරයට පිටුපසින්, එනම් පිටුපසිනි c
. මෙය තවත් භේදයකට හේතු වේ:
නව අභ්යන්තර නෝඩයක් නිර්මාණය කිරීම මෙයට සම්බන්ධ බැවින්, අපි 2 වන රීතිය අනුගමනය කර කලින් නිර්මාණය කළ අභ්යන්තර නෝඩයෙන් නව උපසර්ග සම්බන්ධකයක් සකසමු:
(මම භාවිතා කරමි Graphviz ඩොට් , මේ කුඩා ප්රස්තාර සඳහා නව ෙපර ෙයදුම ලින්ක් නැවත සංවිධානය පවතින දාර කිරීමට තිතක් විය. ඒ නිසා ඉහත, ඇතුළු කරන ලද එකම දෙය නම්, නව ෙපර ෙයදුම ලින්ක් බව තහවුරු හොඳින් පරීක්ෂා කර බලන්න.)
මේ සමඟ, remainder
1 ට සැකසිය හැකි අතර active_node
, root මූල බැවින්, සක්රීය ලක්ෂ්යය යාවත්කාලීන කිරීමට අපි රීතිය 1 භාවිතා කරමු (root,'d',0)
. මෙයින් අදහස් කරන්නේ වත්මන් පියවරේ අවසාන ඇතුළු කිරීම තනි එකක් ඇතුළත් කිරීමයිd
මූලයේ :
එය අවසාන පියවර වූ අතර අප අවසන් කර ඇත. ගණනක් ඇතඅවසාන නිරීක්ෂණ , නමුත්:
සෑම පියවරකදීම අපි ගමන් කරමු #
1 ස්ථානයකින් ඉදිරියට . මෙය O (1) කාලය තුළ සියලුම පත්ර නෝඩ් ස්වයංක්රීයව යාවත්කාලීන කරයි.
නමුත් එය අ) පෙර පියවර වලින් ඉතිරිව ඇති කිසිදු උපසර්ගයක් හා ආ) වත්මන් පියවරේ එක් අවසාන අක්ෂරයක් සමඟ කටයුතු නොකරයි .
remainder
අප විසින් අතිරේක ඇතුළත් කිරීම් කීයක් කළ යුතුදැයි අපට කියයි. මෙම ඇතුළත් කිරීම් වත්මන් ස්ථානයෙන් අවසන් වන නූලෙහි අවසාන උපසර්ගයට අනුරූප වේ #
. අපි එකින් එක සලකා බලමු. වැදගත්: සෑම ලක්ෂ්යයක්ම O (1) වේලාවේදී සිදු කරනුයේ සක්රීය ලක්ෂ්යය හරියටම යා යුත්තේ කොතැනටදැයි අපට පවසන හෙයින්, ක්රියාකාරී ස්ථානයේදී අපට එක් අක්ෂරයක් පමණක් එකතු කළ යුතුය. මන්ද? අනෙක් අක්ෂර ව්යංගයෙන් අඩංගු වන නිසා
(එසේ නොමැතිනම් ක්රියාකාරී ලක්ෂ්යය එය පවතින තැන නොවනු ඇත).
එවැනි එක් එක් ඇතුළත් කිරීමෙන් පසුව, අපි අඩු remainder
වී උපසර්ග සබැඳිය තිබේ නම් එය අනුගමනය කරමු . එසේ නොවේ නම් අපි මූලයට යමු (රීතිය 3). අප දැනටමත් මූලයේ සිටී නම්, අපි රීතිය 1 භාවිතා කරමින් ක්රියාකාරී ලක්ෂ්යය වෙනස් කරමු. ඕනෑම අවස්ථාවක, ගත වන්නේ O (1) කාලය පමණි.
මෙම එක් ඇතුළත් කිරීමක් අතරතුර, අපට ඇතුළු කිරීමට අවශ්ය චරිතය දැනටමත් එහි ඇති බව අපට පෙනී ගියහොත්, අපි කිසිවක් නොකර වර්තමාන පියවර අවසන් කරන්නෙමු, remainder
0 වුවද. හේතුව, ඉතිරිව ඇති ඕනෑම ඇතුල් කිරීමක් අප විසින් සෑදීමට උත්සාහ කළ උපසර්ගයන් වීමයි. එබැවින් ඒවා සියල්ලම වර්තමාන ගසෙහි ගම්ය වේ. කාරණයremainder
> 0 වර්ගයන් වග අප පසුව ඉතිරි suffixes සමග ගනුදෙනු.
ඇල්ගොරිතම remainder
> 0 අවසානයේ කුමක් කළ යුතුද? පා of යේ අවසානය මීට පෙර කොතැනක හෝ සිදු වූ උපස්ථරයක් වන විට මෙය සිදු වේ. එවැනි අවස්ථාවකදී, මීට පෙර සිදු නොවූ නූල් අවසානයේ එක් අමතර අක්ෂරයක් අප විසින් එකතු කළ යුතුය. සාහිත්යයෙහි සාමාන්යයෙන් ඩොලර් ලකුණ ඒ $
සඳහා සංකේතයක් ලෙස භාවිතා කරයි. එය වැදගත් වන්නේ ඇයි? -> පසුව අපි උපසර්ග සෙවීම සඳහා සම්පුර්ණ කරන ලද උපසර්ග ගස භාවිතා කරන්නේ නම්, අපි තරඟ භාර ගත යුත්තේ ඒවා පත්රයක අවසන් වුවහොත් පමණි . එසේ නොවුවහොත් අපට ව්යාජ තරග රාශියක් ලැබෙනු ඇත, මන්දයත් තිබිය යුතු බොහෝ ගසෙහි ව්යංගයෙන් නූල් අඩංගු වන අතර ඒවා ප්රධාන නූලෙහි සත්ය උපසර්ග නොවේ. බල කිරීමremainder
අවසානයේ 0 වීම යනු සියලු උපසර්ග පත්ර තුණ්ඩයකින් අවසන් වන බව සහතික කිරීමේ ක්රමයකි. කෙසේ වෙතත්, ප්රධාන උපස්ථරයේ සාමාන්ය උපස්ථර සෙවීම සඳහා අපට ගස භාවිතා කිරීමට අවශ්ය නම්, පහත දැක්වෙන OP හි අදහස අනුව මෙම අවසාන පියවර ඇත්ත වශයෙන්ම අවශ්ය නොවේ., උපසර්ග පමණක් නොවේ
ඉතින් සමස්ත ඇල්ගොරිතමයේ සංකීර්ණතාව කුමක්ද? පෙළ දිග අක්ෂර n නම්, පැහැදිලිවම පියවර n ක් ඇත (හෝ අපි ඩොලර් ලකුණ එකතු කළහොත් n + 1). සෑම පියවරකදීම අපි කිසිවක් නොකරමු (විචල්යයන් යාවත්කාලීන කිරීම හැර), නැතහොත් අපි remainder
ඇතුළත් කිරීම් සිදු කරන්නෙමු , සෑම එකක්ම O (1) කාලය ගතවේ. සිටremainder
පෙර පියවරයන්හි අප කිසිවක් කර නොමැති වාර ගණනක් පෙන්නුම් කරන සහ අප දැන් කරන සෑම ඇතුළු කිරීමක් සඳහාම අඩු වී ඇති හෙයින්, අප යමක් කරන මුළු වාර ගණන හරියටම n (හෝ n + 1) වේ. එබැවින් සම්පූර්ණ සංකීර්ණතාව O (n) වේ.
කෙසේ වෙතත්, මා නිසියාකාරව පැහැදිලි නොකළ එක් කුඩා දෙයක් තිබේ: එය සිදුවිය හැක්කේ අප උපසර්ග සබැඳියක් අනුගමනය කිරීම, ක්රියාකාරී ලක්ෂ්යය යාවත්කාලීන කිරීම සහ එහි active_length
සංරචකය නව සමඟ හොඳින් ක්රියා නොකරන බව සොයා ගැනීමෙනි active_node
. උදාහරණයක් ලෙස, මෙවැනි තත්වයක් සලකා බලන්න:
(ඉරුණු රේඛා ගසේ ඉතිරි කොටස දක්වයි. තිත් රේඛාව උපසර්ග සබැඳියකි.)
දැන් සක්රිය ලක්ෂ්යය වීමට ඉඩ දෙන්න (red,'d',3)
, එවිට එය දාරයේ පිටුපස ස්ථානයට f
යොමු කරයි defg
. දැන් අපි අවශ්ය යාවත්කාලීනයන් කළ බව උපකල්පනය කර දැන් රීතිය 3 ට අනුව ක්රියාකාරී ලක්ෂ්යය යාවත්කාලීන කිරීම සඳහා උපසර්ග සබැඳිය අනුගමනය කරන්න. නව ක්රියාකාරී ලක්ෂ්යය (green,'d',3)
. කෙසේ වෙතත්, d
හරිත නෝඩයෙන් පිටතට යන -edge එක de
, එබැවින් එහි ඇත්තේ අක්ෂර 2 ක් පමණි. නිවැරදි ක්රියාකාරී ලක්ෂ්යය සොයා ගැනීම සඳහා, අපි පැහැදිලිවම නිල් පැහැති නෝඩයට එම දාරය අනුගමනය කර නැවත සැකසිය යුතුය (blue,'f',1)
.
විශේෂයෙන්ම නරක නඩුවේ, active_length
වැනි විශාල ලෙස විය හැකි
remainder
n ලෙස විශාල ලෙස විය හැකි. නිවැරදි ක්රියාකාරී ලක්ෂ්යය සොයා ගැනීම සඳහා අපට අවශ්ය වන්නේ එක් අභ්යන්තර නෝඩයක් උඩින් පනින්න පමණක් නොව, බොහෝ විට නරකම අවස්ථාවක n දක්වාය. එයින් අදහස් කරන්නේ ඇල්ගොරිතමයට සැඟවුණු O (n 2 ) සංකීර්ණතාවයක් ඇති බවයි, මන්ද සෑම පියවරකදීමremainder
සාමාන්යයෙන් O (n) වන අතර, උපසර්ග සම්බන්ධතාවයක් අනුගමනය කිරීමෙන් පසු ක්රියාකාරී නෝඩයට පශ්චාත් ගැලපීම් O (n) විය හැකි ද?
හේතුව, ඇත්ත වශයෙන්ම අපට සක්රීය ලක්ෂ්යය (උදා: කොළ සිට නිල් දක්වා) වෙනස් කළ යුතු නම්, එය අපව එහි උපසර්ග සම්බන්ධකයක් ඇති නව නෝඩයකට ගෙන එනු ඇති අතර active_length
එය අඩු වනු ඇත. අපි උපසර්ග සම්බන්ධක දාමය අනුගමනය කරන විට, ඉතිරි කිරීම් ඇතුළත් කිරීම active_length
අඩු කළ හැකි අතර, අපට කළ හැකි ක්රියාකාරී ලක්ෂ්ය ගැලපුම් ගණන active_length
ඕනෑම වේලාවක වඩා විශාල විය නොහැක . සිට
active_length
හැකි වඩා විශාල විය කවදාවත් remainder
, සහ remainder
සෑම පියවරක් පමණක් නොව සාමාන්ය (n), නමුත් මෙතෙක් සිදු වැටුප් වර්ධක කර ඇති මුළු මුදල remainder
සමස්ත ක්රියාවලිය ක් පුරා ඉතා සාමාන්ය (n) වන අතර, ක්රියාකාරී අවස්ථාවක වෙනස්කම් සංඛ්යාව වේ O (n) වලින් ද සීමා වේ.