নীচে উককোনেন অ্যালগরিদমকে বর্ণনা করার চেষ্টা করা হচ্ছে যখন প্রথমে স্ট্রিংটি সহজ হয় (যা কোনও পুনরাবৃত্তিযুক্ত অক্ষর ধারণ করে না) তখন এটি কী করে তা পূর্ণ আলগোরিদিম পর্যন্ত প্রসারিত করে what
প্রথমে কয়েকটি প্রাথমিক বক্তব্য।
আমরা যা বানাচ্ছি তা মূলত অনুসন্ধান ত্রয়ের মতো। সুতরাং একটি মূল নোড আছে, প্রান্তগুলি এর বাইরে বেরিয়ে যাচ্ছে নতুন নোডগুলিতে এবং আরও প্রান্তগুলি এর বাইরে চলে যাচ্ছে, এবং আরও
তবে : অনুসন্ধান অনুসন্ধানের মতো নয়, প্রান্তের লেবেলগুলি একক অক্ষর নয়। পরিবর্তে, প্রতিটি প্রান্তটি একটি জোড়া পূর্ণসংখ্যা ব্যবহার করে লেবেলযুক্ত
[from,to]
। এগুলি পাঠ্যের পয়েন্টার। এই অর্থে, প্রতিটি প্রান্তটি স্বেচ্ছাসেবী দৈর্ঘ্যের একটি স্ট্রিং লেবেল বহন করে তবে কেবল ও (1) স্থান (দুটি পয়েন্টার) নেয়।
মৌলিক নীতি
আমি প্রথমে প্রদর্শন করতে চাই যে কীভাবে একটি সাধারণ সরল স্ট্রিংয়ের প্রত্যয় গাছটি তৈরি করা যায়, কোনও স্ট্রিং যাতে পুনরাবৃত্তি না হয়:
abc
বাম থেকে ডানে অ্যালগরিদম পদক্ষেপে কাজ করে । নেই স্ট্রিং প্রতিটি অক্ষরের জন্য এক ধাপ । প্রতিটি পদক্ষেপে একাধিক স্বতন্ত্র অপারেশন জড়িত থাকতে পারে তবে আমরা দেখতে পাব (শেষে চূড়ান্ত পর্যবেক্ষণগুলি দেখুন) যে অপারেশনগুলির মোট সংখ্যা হ'ল (এন)।
সুতরাং, আমরা বাম থেকে শুরু করি , এবং প্রথমে a
মূল পাতায় মূল নোড (বাম দিকে) থেকে একটি প্রান্ত তৈরি করে এবং কেবলমাত্র একক অক্ষর সন্নিবেশ করান
[0,#]
, যার অর্থ প্রান্তটি 0 পজিশনে শুরু হওয়া এবং শেষের সমাপ্তিটিকে উপস্থাপিত করে এ বর্তমান শেষ । আমি প্রতীকটি বর্তমান প্রান্তটি #
বোঝাতে ব্যবহার করি , যা অবস্থান 1 এ (ডান পরে )।a
সুতরাং আমাদের কাছে একটি প্রাথমিক গাছ আছে যা দেখতে এটির মতো দেখাচ্ছে:
এবং এর অর্থ কী:
এখন আমরা অবস্থান 2 (ডান পরে b
) অগ্রগতি । প্রতিটি পদে পদে আমাদের লক্ষ্য
সন্নিবেশ করতে হয় বর্তমান অবস্থান সব প্রত্যয় আপ । আমরা এটি দ্বারা
- বিদ্যমান-
a
বৃদ্ধিকে প্রসারিত করা হচ্ছেab
- এর জন্য একটি নতুন প্রান্ত .োকানো হচ্ছে
b
আমাদের উপস্থাপনে এটির মতো দেখাচ্ছে
এবং এর অর্থ কী:
আমরা দুটি বিষয় পর্যবেক্ষণ করি :
- জন্য প্রান্ত প্রতিনিধিত্ব
ab
হয় একই যেমন প্রাথমিক গাছে ব্যবহার করা হয়: [0,#]
। এর অর্থ স্বয়ংক্রিয়ভাবে পরিবর্তিত হয়েছে কারণ আমরা বর্তমান অবস্থানটি #
1 থেকে 2 তে আপডেট করেছি ।
- প্রতিটি প্রান্ত O (1) স্পেস ব্যবহার করে, কারণ এটি কতগুলি অক্ষর উপস্থাপন করে তা পাঠ্যের মধ্যে কেবল দুটি পয়েন্টার নিয়ে গঠিত।
এরপরে আমরা আবার অবস্থানটি বৃদ্ধি করব এবং c
প্রতিটি বিদ্যমান প্রান্তে একটি যুক্ত করে এবং নতুন প্রত্যয়ের জন্য একটি নতুন প্রান্ত সন্নিবেশ করে গাছ আপডেট করব c
।
আমাদের উপস্থাপনে এটির মতো দেখাচ্ছে
এবং এর অর্থ কী:
আমরা পর্যবেক্ষণ:
- গাছটি
প্রতিটি পদক্ষেপের পরে বর্তমান অবস্থান পর্যন্ত সঠিক প্রত্যয় গাছ
- পাঠ্যটিতে অক্ষর রয়েছে যতগুলি পদক্ষেপ রয়েছে
- প্রতিটি পদক্ষেপে কাজের পরিমাণ হ'ল ও (1), কারণ সমস্ত বিদ্যমান প্রান্তগুলি ইনক্রিমেন্টিংয়ের মাধ্যমে স্বয়ংক্রিয়ভাবে আপডেট হয়
#
এবং চূড়ান্ত অক্ষরের জন্য একটি নতুন প্রান্ত সন্নিবেশ করা ও (1) সময়ে করা যেতে পারে। সুতরাং দৈর্ঘ্য n এর স্ট্রিংয়ের জন্য কেবল ও (এন) সময় প্রয়োজন।
প্রথম সম্প্রসারণ: সরল পুনরাবৃত্তি
অবশ্যই এটি এত সুন্দরভাবে কাজ করে কারণ আমাদের স্ট্রিংটিতে কোনও পুনরাবৃত্তি নেই। আমরা এখন আরও বাস্তবসম্মত স্ট্রিংয়ের দিকে নজর দিই:
abcabxabcd
এটি abc
পূর্ববর্তী উদাহরণের মতোই শুরু হয় , তারপরে ab
পুনরাবৃত্তি হয় এবং তার পরে অনুসরণ করা হয় x
এবং তারপরে abc
পুনরাবৃত্তি হয় d
।
পদক্ষেপ 1 থেকে 3 পর্যন্ত: প্রথম 3 টি পদক্ষেপের পরে আমাদের পূর্ববর্তী উদাহরণ থেকে গাছটি রয়েছে:
পদক্ষেপ 4: আমরা #
অবস্থান 4 এ চলেছি This এটি স্পষ্টভাবে এটিতে বিদ্যমান সমস্ত প্রান্তকে আপডেট করে:
এবং আমাদের বর্তমান ধাপের চূড়ান্ত প্রত্যয়টি a
মূলে sertোকানো দরকার।
এটি করার আগে আমরা আরও দুটি ভেরিয়েবল প্রবর্তন করি (পাশাপাশি
#
), যা অবশ্যই সেখানে সব সময় রয়েছে তবে আমরা এখনও এগুলি ব্যবহার করি নি:
- সক্রিয় বিন্দু , যা একটি ট্রিপল হয়
(active_node,active_edge,active_length)
- এটি
remainder
, যা একটি পূর্ণসংখ্যা নির্দেশ করে যে আমাদের কতগুলি নতুন প্রত্যয় inোকাতে হবে
এই দুটির সঠিক অর্থ শীঘ্রই স্পষ্ট হয়ে উঠবে, তবে আপাতত কেবল এইভাবে বলা যাক:
- সাধারণ
abc
উদাহরণে, সক্রিয় বিন্দু সর্বদা ছিল
(root,'\0x',0)
, অর্থাত্ active_node
মূলটি নোড active_edge
ছিল নাল অক্ষর হিসাবে নির্দিষ্ট '\0x'
, এবং active_length
শূন্য ছিল। এর প্রভাবটি ছিল যে আমরা প্রতিটি ধাপে newোকানো একটি নতুন প্রান্তটি একটি নতুন সৃজিত প্রান্ত হিসাবে মূল নোডে .োকানো হয়েছিল। এই তথ্য উপস্থাপনের জন্য ট্রিপল কেন প্রয়োজনীয় তা আমরা শীঘ্রই দেখব।
remainder
সবসময় প্রতিটি পদক্ষেপ শুরুতে 1 সেট করা হয়। এর অর্থ হ'ল প্রতিটি পদক্ষেপের শেষে আমাদের সক্রিয়ভাবে সন্নিবেশ করানোর প্রত্যয় সংখ্যা ছিল 1 (সর্বদা কেবল চূড়ান্ত চরিত্র)।
এখন এটি পরিবর্তন হতে চলেছে। আমরা যখন বর্তমান চূড়ান্ত অক্ষর সন্নিবেশ a
রুট সময়ে, আমরা লক্ষ্য ইতিমধ্যে একটি বহির্গামী প্রান্ত দিয়ে শুরু যে a
, বিশেষ করে: abca
। এই জাতীয় ক্ষেত্রে আমরা যা করি তা এখানে:
- আমরা রুট নোডে একটি নতুন প্রান্ত প্রবেশ করিনা
[4,#]
। পরিবর্তে আমরা কেবল লক্ষ্য করি যে প্রত্যয়টি a
ইতিমধ্যে আমাদের গাছে রয়েছে। এটি একটি দীর্ঘ প্রান্তের মাঝখানে শেষ হয়, তবে আমরা এটির দ্বারা বিরক্ত হই না। আমরা জিনিসগুলিকে কেবল সেভাবেই ছেড়ে দিই।
- আমরা সক্রিয় বিন্দু নির্ধারণ করতে
(root,'a',1)
। এর অর্থ সক্রিয় বিন্দু এখন মূল নোডের বহির্গামী প্রান্তের মাঝখানে কোথাও যেটি শুরু হয় a
, বিশেষত, সেই প্রান্তে 1 অবস্থানের পরে। আমরা লক্ষ্য করেছি যে প্রান্তটি কেবলমাত্র তার প্রথম অক্ষর দ্বারা নির্দিষ্ট করা হয়েছে a
। এটি পর্যাপ্ত কারণ যে কোনও নির্দিষ্ট অক্ষর দিয়ে কেবল একটি প্রান্ত শুরু হতে পারে (সম্পূর্ণ বিবরণটি পড়ার পরে এটি সত্য কিনা তা নিশ্চিত করুন)।
- আমরা এছাড়াও বৃদ্ধি
remainder
, সুতরাং পরবর্তী পদক্ষেপের শুরুতে এটি 2 হবে।
পর্যবেক্ষণ: যখন আমাদের অন্তর্ভুক্ত করতে হবে চূড়ান্ত প্রত্যয়টি ইতিমধ্যে গাছের মধ্যে উপস্থিত রয়েছে তখন গাছটি নিজেই মোটেও পরিবর্তিত হয় না (আমরা কেবল সক্রিয় বিন্দু আপডেট করি এবং remainder
)। গাছ তারপর প্রত্যয় গাছের একটি সঠিক উপস্থাপনা নয় বর্তমান অবস্থান পর্যন্ত কোন, কিন্তু এটা ধারণ করে (কারণ চূড়ান্ত প্রত্যয় সব প্রত্যয় a
অন্তর্ভুক্ত করা হয় পরোক্ষভাবে )। সুতরাং, ভেরিয়েবলগুলি আপডেট করা ছাড়াও (যা সমস্ত নির্দিষ্ট দৈর্ঘ্যের, সুতরাং এটি ও (1)),
এই পদক্ষেপে কোনও কাজ করা হয়নি।
পদক্ষেপ 5: আমরা বর্তমান অবস্থানটি #
5 এ আপডেট করি This এটি স্বয়ংক্রিয়ভাবে গাছটিকে এতে আপডেট করে:
এবং কারণ remainder
2 , আমাদের বর্তমান অবস্থার দুটি চূড়ান্ত প্রত্যয় সন্নিবেশ করা প্রয়োজন: ab
এবং b
। এটি মূলত কারণ:
a
পূর্ববর্তী ধাপে থেকে প্রত্যয় সঠিকভাবে কখনই ঢোকানো হয়েছে। সুতরাং এটি করেছে রয়ে , এবং যেহেতু আমরা এক ধাপ অগ্রগতির, এটি এখন থেকে উত্থিত হয়েছে a
থেকে ab
।
- এবং আমাদের নতুন চূড়ান্ত প্রান্তটি প্রবেশ করানো দরকার
b
।
অনুশীলনে এর অর্থ আমরা সক্রিয় পয়েন্টে চলে যাই (যা a
এখন কোন abcab
প্রান্তটি তার পিছনে নির্দেশ করে ) এবং বর্তমানের চূড়ান্ত অক্ষরটি সন্নিবেশ করি b
। তবে: আবারও দেখা যাচ্ছে b
যে একই ধারে ইতিমধ্যে উপস্থিত রয়েছে।
সুতরাং, আবার আমরা গাছ পরিবর্তন করি না। আমরা কেবল:
- সক্রিয় পয়েন্টটি আপডেট করুন
(root,'a',2)
(আগের মতো একই নোড এবং প্রান্ত, তবে এখন আমরা এর পিছনে দিকে নির্দেশ করি b
)
remainder
3 এ বৃদ্ধি করুন কারণ আমরা এখনও পূর্ববর্তী পদক্ষেপ থেকে চূড়ান্ত প্রান্তটি যথাযথভাবে প্রবেশ করিনি এবং আমরা বর্তমান চূড়ান্ত প্রান্তটি sertোকাও না।
স্পষ্ট হবে: আমরা সন্নিবেশ করতে ছিল ab
এবং b
বর্তমান পদক্ষেপে, কিন্তু কারণ ab
ইতিমধ্যে পাওয়া যায়নি, আমরা সক্রিয় বিন্দু আপডেট এবং এমনকি সন্নিবেশ করার প্রচেষ্টা করা হয়নি b
। কেন? কারণ যদি ab
গাছে থাকে তবে এর
প্রতিটি প্রত্যয় (সহ b
) অবশ্যই গাছে থাকতে হবে। সম্ভবত কেবল অন্তর্নিহিতভাবেই , তবে এটি অবশ্যই সেখানে রয়েছে, কারণ আমরা এখনও পর্যন্ত গাছটি তৈরি করেছি।
আমরা ইনক্রিমেন্ট করে step ধাপে এগিয়ে যাই #
। গাছটি স্বয়ংক্রিয়ভাবে আপডেট হয়:
remainder
3 কারণ , আমাদের সন্নিবেশ করতে হবে abx
, bx
এবং
x
। সক্রিয় বিন্দুটি আমাদের বলে দেয় কোথায় ab
শেষ হয়, সুতরাং আমাদের কেবল সেখানে লাফিয়ে theোকাতে হবে x
। সত্যই, x
এখনও সেখানে নেই, তাই আমরা abcabx
প্রান্তটি বিভক্ত করে একটি অভ্যন্তরীণ নোড সন্নিবেশ করলাম :
প্রান্তের উপস্থাপনাগুলি এখনও পাঠ্যের মধ্যে পয়েন্টার রয়েছে, সুতরাং বিভক্তকরণ এবং অভ্যন্তরীণ নোড সন্নিবেশ করাতে ও (1) সময়ে করা যেতে পারে।
সুতরাং আমরা এর সাথে ডিল করেছি abx
এবং হ্রাস remainder
পেয়েছি 2। এখন আমাদের পরবর্তী অবশিষ্ট প্রত্যয় inোকানো দরকার bx
,। তবে এটি করার আগে আমাদের সক্রিয় পয়েন্টটি আপডেট করতে হবে। এটির বিধি বিভাজন এবং একটি প্রান্ত সন্নিবেশ করার পরে, নীচের নিয়ম 1 বলা হবে , এবং এটি যখনই active_node
মূল হয় তখনই প্রয়োগ
হয় (আমরা আরও নীচে অন্যান্য মামলার জন্য নিয়ম 3 শিখব)। এখানে নিয়ম 1:
মূল থেকে একটি সন্নিবেশ পরে,
active_node
মূল থেকে যায়
active_edge
নতুন প্রত্যয়টির প্রথম চরিত্রে সেট করা আছে যা আমাদের sertোকাতে হবে, অর্থাত্ b
active_length
1 দ্বারা হ্রাস করা হয়
সুতরাং, নতুন সক্রিয়-পয়েন্ট ট্রিপলটি (root,'b',1)
নির্দেশ করে যে পরবর্তী সন্নিবেশটি bcabx
1 টি অক্ষরের পিছনে অর্থাৎ পিছনে প্রান্তে তৈরি করতে হবে b
। আমরা ও (1) সময়ে সন্নিবেশ পয়েন্টটি সনাক্ত করতে পারি এবং x
ইতিমধ্যে উপস্থিত কিনা তা যাচাই করতে পারি। যদি এটি উপস্থিত থাকে, আমরা বর্তমান পদক্ষেপটি শেষ করব এবং সমস্ত কিছু যেমন হয় তেমন রেখে দেব। তবে x
উপস্থিত নেই, তাই আমরা প্রান্তটি ভাগ করে এটি sertোকান:
আবার, এটি ও (1) সময় নিয়েছে এবং আমরা remainder
1 এ আপডেট করেছি এবং (root,'x',0)
নিয়ম 1 রাজ্য হিসাবে সক্রিয় পয়েন্ট ।
তবে আমাদের আরও একটি কাজ করা দরকার। আমরা এই বিধি 2 কল করব :
যদি আমরা একটি প্রান্তটি বিভক্ত করে একটি নতুন নোড সন্নিবেশ করি এবং যদি বর্তমান পদক্ষেপের সময় এটি তৈরি করা প্রথম নোড না হয় তবে আমরা পূর্বে প্রবেশ করা নোড এবং নতুন নোডটিকে একটি বিশেষ পয়েন্টার, একটি প্রত্যয় লিঙ্কের মাধ্যমে সংযুক্ত করি । কেন এটি কার্যকর তা আমরা পরে দেখব। আমরা যা পাই তা এখানে, প্রত্যয় লিঙ্কটি একটি বিন্দু প্রান্ত হিসাবে উপস্থাপিত:
আমাদের এখনও বর্তমান পদক্ষেপের চূড়ান্ত প্রত্যয় সন্নিবেশ করা প্রয়োজন
x
,। যেহেতু active_length
অ্যাক্টিভ নোডের উপাদানটি 0 তে নেমে গেছে, চূড়ান্ত সন্নিবেশটি সরাসরি রুটে তৈরি করা হয়। যেহেতু মূল নোডে কোনও বহির্গমন প্রান্ত শুরু হচ্ছে না তাই x
আমরা একটি নতুন প্রান্ত সন্নিবেশ করলাম:
আমরা দেখতে পাচ্ছি, বর্তমান পদক্ষেপে সমস্ত অবশিষ্ট সন্নিবেশ তৈরি করা হয়েছিল।
আমরা = 7 সেট করে 7 ধাপে এগিয়ে #
যাই, যা যথারীতি a
সমস্ত পাতার প্রান্তে স্বয়ংক্রিয়ভাবে পরবর্তী অক্ষরটি সংযোজন করে
। তারপরে আমরা সক্রিয় বিন্দুতে (মূল) নতুন চূড়ান্ত অক্ষরটি সন্নিবেশ করানোর চেষ্টা করি এবং এটি ইতিমধ্যে রয়েছে বলে মনে করি। সুতরাং আমরা কোনও পদক্ষেপ না সরিয়ে বর্তমান পদক্ষেপটি শেষ করি এবং সক্রিয় বিন্দুটিতে আপডেট করি (root,'a',1)
।
ইন পদক্ষেপ 8 , #
= 8, আমরা যোগ b
, এবং আগে দেখা, এই একমাত্র উপায় আমরা সক্রিয় বিন্দু আপডেট (root,'a',2)
এবং বৃদ্ধি remainder
অন্য কিছু না করে, কারণ b
ইতিমধ্যে উপস্থিত। তবে, আমরা লক্ষ্য করি (ও (1) সময়ে) সক্রিয় পয়েন্টটি এখন একটি প্রান্তের শেষে। আমরা এটিকে আবার সেট করে প্রতিফলিত করি
(node1,'\0x',0)
। এখানে, আমি প্রান্তটি শেষ হওয়া node1
অভ্যন্তরীণ নোডের উল্লেখ করতে ব্যবহার করি ab
।
তারপরে, পদক্ষেপ #
= 9 এ , আমাদের 'সি' toোকানো দরকার এবং এটি আমাদের চূড়ান্ত কৌশলটি বুঝতে সহায়তা করবে:
দ্বিতীয় এক্সটেনশন: প্রত্যয় লিঙ্ক ব্যবহার করে
সর্বদা হিসাবে, #
আপডেটটি c
পাতার কিনারাগুলিতে স্বয়ংক্রিয়ভাবে যুক্ত হয় এবং আমরা 'সি' sertোকাতে পারি কিনা তা দেখতে আমরা সক্রিয় বিন্দুতে যাই। দেখা যাচ্ছে যে 'সি' ইতিমধ্যে সেই প্রান্তে উপস্থিত রয়েছে, তাই আমরা সক্রিয় বিন্দুতে
(node1,'c',1)
, বৃদ্ধি বাড়িয়েছি remainder
এবং অন্য কিছুই করি না।
এখন ধাপে #
= 10 , remainder
4 হয়, এবং তাই আমাদের প্রথমে সক্রিয় পয়েন্টে সন্নিবেশ করিয়ে
abcd
(যা 3 টি পদক্ষেপ আগে থেকে যায়) সন্নিবেশ d
করা দরকার।
d
সক্রিয় বিন্দুতে সন্নিবেশ করানোর চেষ্টা ও (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 এর কারণে আমাদের অবশ্যই পূর্ববর্তী nোকানো নোড থেকে নতুনটিতে একটি প্রত্যয় লিঙ্ক তৈরি করতে হবে:
আমরা পালন: প্রত্যয় সংযোগগুলি তাই আমরা পরবর্তী করতে পারেন সক্রিয় বিন্দু পুনরায় সেট করতে সক্ষম অবশিষ্ট সন্নিবেশ হে (1) প্রচেষ্টা করেন। উপরের গ্রাফটি দেখতে নিশ্চিত করুন যে লেবেলে ab
নোডটি নোডের b
(তার প্রত্যয়) abc
সাথে যুক্ত হয়েছে এবং নোডটি সংযুক্ত রয়েছে
bc
।
বর্তমান পদক্ষেপটি এখনও শেষ হয়নি। remainder
এখন 2, এবং আবার সক্রিয় পয়েন্টটি পুনরায় সেট করতে আমাদের 3 রুল অনুসরণ করতে হবে। যেহেতু বর্তমানের active_node
(উপরে লাল) কোনও প্রত্যয় লিঙ্ক নেই, তাই আমরা রুটে পুনরায় সেট করি। সক্রিয় পয়েন্ট এখন (root,'c',1)
।
অত: পর পরবর্তী সন্নিবেশ রুট নোড যার ট্যাগ দিয়ে শুরু হয় এক বিদায়ী প্রান্ত ঘটে c
: cabxabcd
প্রথম অক্ষর, অর্থাত পিছনে পিছনে c
। এটি অন্য বিভক্তির কারণ:
এবং যেহেতু এটিতে একটি নতুন অভ্যন্তরীণ নোড তৈরি জড়িত, আমরা নিয়ম 2 অনুসরণ করি এবং পূর্বে নির্মিত অভ্যন্তরীণ নোড থেকে একটি নতুন প্রত্যয় লিঙ্ক সেট করি:
(আমি এই ছোট্ট গ্রাফগুলির জন্য গ্রাফভিজ ডট ব্যবহার করছি The নতুন প্রত্যয় লিঙ্কটি ডটকে বিদ্যমান প্রান্তগুলি পুনরায় সাজিয়েছে , তাই সাবধানে পরীক্ষা করে নিশ্চিত করুন যে উপরে inোকানো একমাত্র জিনিসই একটি নতুন প্রত্যয় লিঙ্ক))
এটির সাথে, remainder
1 এ সেট করা যেতে পারে এবং যেহেতু active_node
মূলটি মূল, আমরা সক্রিয় পয়েন্টটি আপডেট করতে নিয়ম 1 ব্যবহার করি (root,'d',0)
। এর অর্থ বর্তমানের পদক্ষেপের চূড়ান্ত সন্নিবেশ হ'ল মূলটিতে একটি একক প্রবেশ করানো d
:
এটি ছিল চূড়ান্ত পদক্ষেপ এবং আমরা সম্পন্ন করেছি। চূড়ান্ত পর্যবেক্ষণের সংখ্যা রয়েছে যদিও:
প্রতিটি পদক্ষেপে আমরা #
1 পজিশনে এগিয়ে যাই । এটি ও (1) সময়ে সমস্ত পাত নোডগুলি স্বয়ংক্রিয়ভাবে আপডেট করে।
তবে এটি ক) পূর্ববর্তী পদক্ষেপগুলি থেকে বাকি কোনও প্রত্যয় এবং খ) বর্তমান পদক্ষেপের একটি চূড়ান্ত চরিত্রের সাথে মোকাবিলা করে না ।
remainder
আমাদের আরও কত অতিরিক্ত সন্নিবেশ তৈরি করতে হবে তা আমাদের জানায়। এই সন্নিবেশগুলি স্ট্রিংয়ের চূড়ান্ত প্রত্যয়গুলির সাথে একের সাথে সামঞ্জস্য করে যা বর্তমান অবস্থানে শেষ হয় #
। আমরা একের পর এক বিবেচনা করি এবং সন্নিবেশ তৈরি করি। গুরুত্বপূর্ণ: প্রতিটি সন্নিবেশ O (1) সময়ে সম্পন্ন করা হয় যেহেতু সক্রিয় বিন্দুটি ঠিক কোথায় যেতে হবে তা আমাদের জানায় এবং সক্রিয় পয়েন্টে আমাদের কেবল একটি একক অক্ষর যুক্ত করতে হবে। কেন? কারণ অন্যান্য অক্ষরগুলি স্পষ্টভাবে অন্তর্ভুক্ত রয়েছে
(অন্যথায় সক্রিয় বিন্দুটি যেখানে থাকবে না সেখানে)।
এই জাতীয় প্রতিটি সন্নিবেশ করার পরে, আমরা remainder
যদি হ'ল প্রত্যাহার লিঙ্কটি হ্রাস করি এবং অনুসরণ করি। না হলে আমরা রুটে যাই (নিয়ম 3)। যদি আমরা ইতিমধ্যে রুট থেকে থাকে তবে আমরা নিয়ম 1 ব্যবহার করে সক্রিয় বিন্দুটি সংশোধন করি any যে কোনও ক্ষেত্রে এটি কেবল ও (1) সময় নেয়।
যদি, এই সন্নিবেশগুলির মধ্যে একটির মধ্যে, আমরা দেখতে পাই যে আমরা যে চরিত্রটি সন্নিবেশ করতে চাইছি তা ইতিমধ্যে সেখানে রয়েছে, আমরা কিছু করি না এবং বর্তমান পদক্ষেপটি শেষ করেও remainder
> 0 হয় না। কারণটি হ'ল যে কোনও সন্নিবেশ অবশিষ্ট রয়েছে তা কেবলমাত্র আমরা তৈরি করার চেষ্টা করেছি এমনটির প্রত্যয় হবে। সুতরাং এগুলি সমস্ত বর্তমান গাছে অন্তর্নিহিত । remainder
> 0 সত্যটি নিশ্চিত করে যে আমরা বাকী প্রত্যয়গুলি পরে করব with
অ্যালগরিদম remainder
> 0 এর শেষে হলে কী হবে ? যখনই পাঠ্যের সমাপ্তিটি এমন একটি স্ট্রস্ট্রিং যা এর আগে কোথাও ঘটেছিল তখন এটি ঘটবে। সেক্ষেত্রে স্ট্রিংয়ের শেষে আমাদের একটি অতিরিক্ত চরিত্র যুক্ত করতে হবে যা এর আগে ঘটে নি। সাহিত্যে, সাধারণত ডলার চিহ্নটি $
তার জন্য প্রতীক হিসাবে ব্যবহৃত হয়। কেন এটা ব্যাপার? -> পরে যদি আমরা প্রত্যয় অনুসন্ধানের জন্য সম্পূর্ণ প্রত্যয় গাছ ব্যবহার করি তবে আমাদের অবশ্যই ম্যাচগুলি কেবল কোনও পাতায় শেষ হলে তা গ্রহণ করতে হবে । তা না হলে আমরা কৃত্রিম মিলের একটি অনেক পাওয়া আছে কারণ হবে অনেক স্ট্রিং পরোক্ষভাবে যে প্রধান স্ট্রিং এর প্রকৃত প্রত্যয় হয় না গাছে রয়েছে। অত্যাচারremainder
শেষে 0 হতে হবে এটি নিশ্চিত করার একটি উপায় যা সমস্ত প্রত্যয় একটি পাতার নোডে শেষ হয়। যাইহোক, আমরা যদি সাধারণ সাবস্ট্রিংগুলি অনুসন্ধানের জন্য গাছটি ব্যবহার করতে চাই , তবে কেবল মূল স্ট্রিংয়ের প্রত্যয়ই নয় , এই চূড়ান্ত পদক্ষেপটি অবশ্যই প্রয়োজন হয় না, নীচে ওপি'র মন্তব্যের দ্বারা প্রস্তাবিত।
তাহলে পুরো অ্যালগরিদমের জটিলতা কী? যদি পাঠ্যটির দৈর্ঘ্য n অক্ষর হয় তবে স্পষ্টতই n পদক্ষেপ রয়েছে (বা আমরা ডলারের চিহ্নটি যুক্ত করলে এন + 1)। প্রতিটি পদক্ষেপে আমরা হয় (ভেরিয়েবলগুলি আপডেট করা ব্যতীত) কিছুই করি না, বা আমরা remainder
সন্নিবেশগুলি তৈরি করি, প্রত্যেকটি ও (1) সময় নেয়। যেহেতু remainder
পূর্ববর্তী পদক্ষেপগুলিতে আমরা কতবার কিছু না করে ইঙ্গিত করে এবং আমরা এখন যে প্রতিটি সন্নিবেশ করানো হয় তার জন্য হ্রাস করা হয়, আমরা কিছু বার করার মতো মোট সংখ্যা হ'ল এন (বা এন + 1)। অতএব, মোট জটিলতা হ'ল (এন)।
তবে, একটি ছোট জিনিস আছে যা আমি সঠিকভাবে ব্যাখ্যা করিনি: এটি ঘটতে পারে যে আমরা প্রত্যয় লিঙ্কটি অনুসরণ করি, সক্রিয় বিন্দুটি আপডেট করি এবং তারপরে দেখতে পাই যে এর active_length
উপাদানটি নতুনটির সাথে ভালভাবে কাজ করে না active_node
। উদাহরণস্বরূপ, এই জাতীয় পরিস্থিতি বিবেচনা করুন:
(ড্যাশযুক্ত রেখাগুলি গাছের বাকী অংশ নির্দেশ করে The বিন্দুযুক্ত রেখাটি একটি প্রত্যয় লিঙ্ক)
এখন সক্রিয় বিন্দু হতে দিন (red,'d',3)
, তাই এটি পিছনে জায়গা পয়েন্ট f
উপর defg
প্রান্ত। এখন ধরে নিন আমরা প্রয়োজনীয় আপডেটগুলি করেছি এবং এখন নিয়ম 3 অনুযায়ী সক্রিয় পয়েন্টটি আপডেট করতে প্রত্যয় লিঙ্কটি অনুসরণ করুন (green,'d',3)
। নতুন সক্রিয় বিন্দুটি হ'ল । তবে, d
সবুজ নোডের বাইরে চলে যাওয়া কাজটি হ'ল de
, সুতরাং এতে কেবল 2 টি অক্ষর রয়েছে। সঠিক সক্রিয় বিন্দুটি সন্ধান করার জন্য, অবশ্যই আমাদের অবশ্যই সেই প্রান্তটি নীল নোডে অনুসরণ করতে হবে এবং এতে পুনরায় সেট করতে হবে (blue,'f',1)
।
একটি বিশেষ খারাপ ক্ষেত্রে, active_length
মত বৃহৎ হতে পারে
remainder
, যা এন মত বৃহৎ হতে পারে। এবং এটি খুব ভালভাবে ঘটতে পারে যে সঠিক সক্রিয় পয়েন্টটি খুঁজতে, আমাদের কেবলমাত্র একটি অভ্যন্তরীণ নোডের উপরে ঝাঁপিয়ে পড়ার দরকার নেই, তবে সম্ভবত অনেকগুলি, সবচেয়ে খারাপ ক্ষেত্রে N পর্যন্ত। তার মানে কি অ্যালগরিদমের কোনও লুকানো ও (এন 2 ) জটিলতা রয়েছে, কারণ প্রতিটি পদক্ষেপে remainder
সাধারণত ও (এন) থাকে এবং প্রত্যয় লিঙ্ক অনুসরণ করার পরে সক্রিয় নোডের পোস্ট-অ্যাডজাস্টমেন্টগুলি ও (এন )ও হতে পারে?
না। কারণ হ'ল যদি সত্যই আমাদের সক্রিয় পয়েন্টটি সমন্বিত করতে হয় (যেমন উপরে সবুজ থেকে নীল থেকে), যা আমাদের একটি নতুন নোডে নিয়ে আসে যার নিজস্ব প্রত্যয় লিঙ্ক রয়েছে, এবং active_length
হ্রাস পাবে। আমরা যখন প্রত্যয় লিঙ্কগুলির শৃঙ্খলা অনুসরণ করি তখন আমরা বাকী সন্নিবেশগুলি তৈরি করি, active_length
কেবল হ্রাস করতে পারে এবং পথে চলতে পারি এমন সক্রিয় বিন্দুগুলির সংখ্যা active_length
নির্দিষ্ট সময়ের চেয়ে বড় হতে পারে না । যেহেতু
active_length
কখনই এর চেয়ে বড় হতে পারে না remainder
এবং remainder
ও (এন) কেবল প্রতিটি একক পদক্ষেপেই নয়, তবে remainder
পুরো প্রক্রিয়া চলাকালীন সর্বমোট বর্ধিত পরিমাণের পরিমাণও ও (এন) হ'ল, সক্রিয় বিন্দুর সামঞ্জস্য সংখ্যা এছাড়াও ও (এন) দ্বারা আবদ্ধ।