最小のデヌタ構造

ゞェヌムズ・カむルはか぀おデヌタ構造に関する投皿を取り、それを曞いお、JavaScriptでの実装を远加したした。 そしお、私は取り、翻蚳したした。

免責事項投皿には倚くのasciiグラフィックがありたす。 モバむルデバむスからそれを読たないでください-テキストフォヌマットはあなたを倱望させたす。




今日、私たちはすべおのデヌタ構造に぀いお孊びたす。

「おお、なんお面癜い 」ず

はい、今日で最もゞュヌシヌなトピックではありたせんが、非垞に重芁です。 CS101のようなコヌスを受講するためではなく、プログラミングをよりよく理解するためです。

デヌタ構造を知るこずは次のこずに圹立ちたす。

最初の方が重芁だず思いたす。 適切なデヌタ構造は、混乱を招くロゞックを排陀するこずでコヌドを劇的に簡玠化できたす。

2番目のポむントも重芁です。 プログラムのパフォヌマンスたたはメモリを考慮するず、デヌタ構造の正しい遞択は䜜業に倧きく圱響したす。

デヌタ構造に慣れるために、それらのいく぀かを実装したす。 心配しないでください、コヌドは簡朔になりたす。 実際、さらにコメントがあり、それらの間のコヌドは1぀、2぀、蚈算ミスです。

 ============================================================================ ,.-'`'-.,.-'`'-.,.-'`'-.,.-'`'-.,.-'`'-.,.-'`'-.,.-'`'-.,.-'`'-.,.-'`'-.,.-' ============================================================================ 
============================================================================ ,.-'`'-.,.-'`'-.,.-'`'-.,.-'`'-.,.-'`'-.,.-'`'-.,.-'`'-.,.-'`'-.,.-'`'-.,.-' ============================================================================

デヌタ構造ずは䜕ですか


実際、これらはさたざたな問題をより効果的に解決するためにデヌタを保存および敎理する方法です。 デヌタはさたざたな方法で衚瀺できたす。 どのようなデヌタで、どのようなデヌタを䜿甚するかに応じお、1぀のプレれンテヌションが他のプレれンテヌションよりも効果的です。

これが起こる理由を理解するために、たずアルゎリズムに぀いお話したしょう。

 /*** ===================================================================== ***\ * * * ,--,--. ,--,--. * * ,----------. | | | | | | _____ * * |`----------'| | | | | | | | | ,------. * * | | | | | | | | ,--. | oo | |`------'| * * | | ,| +-|-+ | | +-|-+ |` | | |_____| | | * * | | ,:==| | |###|======|###| | |====#==#====#=,, | | * * | | || `| +---+ | | +---+ |' ,,=#==#====O=`` ,| | * * | | || | | | | | | ``=#==#====#=====|| | * * `----------' || | | | | | | |__| `| | * * | | ``=| |===`` `--,',--` `--,',--` /||\ `------' * ** \_/ \_/ / / \ \ / / \ \ //||\\ |_| |_| ** \*** ===================================================================== ***/ 
/*** ===================================================================== ***\ * * * ,--,--. ,--,--. * * ,----------. | | | | | | _____ * * |`----------'| | | | | | | | | ,------. * * | | | | | | | | ,--. | oo | |`------'| * * | | ,| +-|-+ | | +-|-+ |` | | |_____| | | * * | | ,:==| | |###|======|###| | |====#==#====#=,, | | * * | | || `| +---+ | | +---+ |' ,,=#==#====O=`` ,| | * * | | || | | | | | | ``=#==#====#=====|| | * * `----------' || | | | | | | |__| `| | * * | | ``=| |===`` `--,',--` `--,',--` /||\ `------' * ** \_/ \_/ / / \ \ / / \ \ //||\\ |_| |_| ** \*** ===================================================================== ***/

アルゎリズム


アルゎリズムずは、実行される䞀連のアクションのsuchな名前です。

デヌタ構造はアルゎリズムを䜿甚しお実装され、アルゎリズムはデヌタ構造を䜿甚しお実装されたす。 すべおがデヌタ構造ずアルゎリズムで構成されおおり、顕埮鏡の小さな男性がパンチカヌドを䜿っお走り、コンピュヌタヌを機胜させるレベルたでです。 たあ、はい、Intelはサヌビスに顕埮鏡の人々を持っおいたす。起きおください

特定のタスクは、無数の方法で実珟されたす。 その結果、䞀般的な問題を解決するために倚くの異なるアルゎリズムが発明されたした。

たずえば、芁玠の順序付けられおいないセットを゜ヌトするには、途方もなく倚くのアルゎリズムがありたす。

挿入゜ヌト、遞択゜ヌト、マヌゞ゜ヌト、バブル゜ヌト、ヒヌプ゜ヌト、クむック゜ヌト、シェル゜ヌト、ティム゜ヌト、ブロック゜ヌト、ビット単䜍゜ヌト...

それらのいく぀かは他のものよりもはるかに高速です。 他のものはより少ないメモリを消費したす。 さらに、他の実装も簡単です。 4぀は、デヌタセットに関する仮定に基づいおいたす。

各゜ヌトは、特定のタスクに最適です。 したがっお、アルゎリズムを盞互に比范する方法を理解するために、たずニヌズず基準を決定する必芁がありたす。

アルゎリズムのパフォヌマンスを比范するために、平均生産性ず最悪の堎合のパフォヌマンスの倧たかな枬定倀を䜿甚しお、「O」ずいう甚語が倧きく䜿甚されおいるこずを瀺したす。

 /*** ===================================================================== ***\ * abd * * ab O(N^2) d * * O(N!) ab O(N log N) dc * * abdc * * abdc O(N) * * abdc * * abdc * * abdc * * ab c O(1) * * eeee ec deeeeeeee * * ba cd * * ba cdfffffff * ** cadf fdfffff O(log N) ** \*** ===================================================================== ***/ 
/*** ===================================================================== ***\ * abd * * ab O(N^2) d * * O(N!) ab O(N log N) dc * * abdc * * abdc O(N) * * abdc * * abdc * * abdc * * ab c O(1) * * eeee ec deeeeeeee * * ba cd * * ba cdfffffff * ** cadf fdfffff O(log N) ** \*** ===================================================================== ***/

ああ倧きい


「O」倧-盞察比范のためのアルゎリズム性胜の抂算掚定方法の指定。

Oh big-コンピュヌタサむ゚ンスが借甚した数孊的衚蚘法。転送されるN個のデヌタの量ずアルゎリズムの関係を決定したす。

Oラヌゞは、2぀の䞻芁な量を特城付けたす。

掚定実行時間 -特定のデヌタセットに察しおアルゎリズムが実行する操䜜の総数。

ボリュヌム掚定は、アルゎリズムが特定のデヌタセットを凊理するために必芁なメモリの総量です。

芋積もりは互いに独立しお行われたす。䞀郚のアルゎリズムは、より倚くのメモリを䜿甚しながら、他のアルゎリズムよりも少ない操䜜を実行できたす。 芁件を定矩したら、適切なアルゎリズムを遞択できたす。

About Bigの䞀般的な意味は次のずおりです。

     ,       ----------------------------------------------------------------------------  O(1) !!  O(log N) !  O(N) . -  O(N log N) ...  O(N ^ 2)   O(2 ^ N)   O(N!)  

私たちが話しおいる数字の順序を知るために、これらの倀がNに䟝存するものを芋おみたしょう。

  N = 5 10 20 30 ----------------------------------------------------------------------- O(1) 1 1 1 1 O(log N) 2.3219... 3.3219... 4.3219... 4.9068... O(N) 5 10 20 30 O(N log N) 11.609... 33.219... 84.638... 147.204... O(N ^ 2) 25 100 400 900 O(2 ^ N) 32 1024 1,048,576 1,073,741,824 O(N!) 120 3,628,800 2,432,902,0... 265,252,859,812,191,058,636,308,480,000,000 

ご芧のずおり、比范的小さな数字でも* dofiga *䜙分な䜜業を行うこずができたす。

デヌタ構造を䜿甚するず、アクセス、怜玢、挿入、削陀ずいう4぀の䞻芁なアクションを実行できたす。

デヌタ構造は、䞀方のアクションでは良いが、もう䞀方のアクションでは悪いこずに泚意しおください。

      ------------------------------------------------------------------------  O(1) O(N) O(N) O(N)   O(N) O(N) O(1) O(1)    O(log N) O(log N) O(log N) O(log N) 

たたは...

      ------------------------------------------------------------------------                   

さらに、䞀郚のアクションでは、「平均」パフォヌマンスず「最悪の堎合」のパフォヌマンスが異なりたす。

理想的なデヌタ構造は存圚したせん。 デヌタずその凊理方法に基づいお、最適なものを遞択したす。 適切な遞択を行うには、さたざたな䞀般的なデヌタ構造を知るこずが重芁です。

 /*** ===================================================================== ***\ * _.-.. * * ,'9 )\)`-.,.--. * * `-.| `. * * \, , \) * * `. )._\ (\ * * |// `-,// * * ]|| //" * ** hjw "" "" ** \*** ===================================================================== ***/ 
/*** ===================================================================== ***\ * _.-.. * * ,'9 )\)`-.,.--. * * `-.| `. * * \, , \) * * `. )._\ (\ * * |// `-,// * * ]|| //" * ** hjw "" "" ** \*** ===================================================================== ***/

蚘憶


コンピュヌタヌのメモリは退屈なものです。 これは、情報が保存される順序付けられたスロットのグルヌプです。 アクセスするには、メモリ内のアドレスを知る必芁がありたす。

メモリフラグメントは次のように衚すこずができたす。

 : |1001|0110|1000|0100|0101|1010|0010|0001|1101|1011... : 0 1 2 3 4 5 6 7 8 9 ... 
: |1001|0110|1000|0100|0101|1010|0010|0001|1101|1011... : 0 1 2 3 4 5 6 7 8 9 ...

プログラミング蚀語でなぜそうなのか疑問に思ったら、カりントは0から始たりたす-メモリはそのように機胜するからです。 メモリの最初のフラグメントを読み取るには、0〜1を読み取り、2番目-1〜2を読み取りたす。これらのフラグメントのアドレスは、それぞれ0ず1です。

もちろん、コンピュヌタヌは䟋に瀺されおいるよりも倚くのメモリを持っおいたすが、そのデバむスは考慮されたテンプレヌトの原理を継続しおいたす。

蚘憶の広倧さは、野生の西のようなものです。 コンピュヌタヌで実行される各プログラムは、同じ*物理*デヌタ構造内に保存されたす。 メモリの䜿甚は困難な䜜業であり、メモリを䜿甚しお䜜業するための抜象化のレベルが远加されおいたす。

抜象化には2぀の远加の目的がありたす。

-デヌタをメモリに保存しお、効率的か぀/たたは迅速に䜜業できるようにしたす。

-デヌタをメモリに保存しお、䜿いやすくしたす。

 /*** ===================================================================== ***\ * * _______________________ * * ()=(_______________________)=() * * * * | | * * | ~ ~~~~~~~~~~~~~ | * * * * * | | * * * | ~ ~~~~~~~~~~~~~ | * * * | | * * | ~ ~~~~~~~~~~~~~ | * * * * | | * * * |_____________________| * * * * ()=(_______________________)=() * ** ** \*** ===================================================================== ***/ 
/*** ===================================================================== ***\ * * _______________________ * * ()=(_______________________)=() * * * * | | * * | ~ ~~~~~~~~~~~~~ | * * * * * | | * * * | ~ ~~~~~~~~~~~~~ | * * * | | * * | ~ ~~~~~~~~~~~~~ | * * * * | | * * * |_____________________| * * * * ()=(_______________________)=() * ** ** \*** ===================================================================== ***/

リスト


最初に、メモリずデヌタ構造間の盞互䜜甚の耇雑さを瀺すリストを実装したす。

リストは、同じ倀が䜕回でも存圚できる倀の番号付きシヌケンスの衚珟です。

通垞のJavaScript配列で衚されるメモリの空のブロックから始めたしょう。 リストの長さも保存する必芁がありたす。

実際には、「メモリ」には取埗および読み取りが可胜な長さの倀がないため、長さを個別に保存するこずに泚意しおください。

 class List { constructor() { this.memory = []; this.length = 0; } //... } 

最初のステップは、リストからデヌタを取埗するこずです。 通垞のリストを䜿甚するず、必芁なアドレスがすでにわかっおいるため、メモリに非垞にすばやくアクセスできたす。

リストアクセス操䜜の耇雑さはO1-「FUCKLY !!」です。

 get(address) { return this.memory[address]; } 

リストにはシリアル番号があるため、先頭、䞭間、末尟に倀を挿入できたす。

リストの先頭たたは末尟に倀を远加および削陀するこずに焊点を圓おたす。 これを行うには、4぀のメ゜ッドが必芁です。

「プッシュ」操䜜から始めたしょう-リストの最埌に芁玠を远加したす。

これは、リストに続くアドレスに倀を远加するのず同じくらい簡単です。 長さを保存するため、アドレスの蚈算は簡単です。 倀を远加し、長さを増やしたす。

リストの最埌にアむテムを远加-定数O1-「FUCKLY !!」

 push(value) { this.memory[this.length] = value; this.length++; } 

Haberのコメント poxuは著者に同意せず、リストにアむテムを远加するのが難しくなるメモリ拡匵操䜜があるず説明しおいたす。

次に、「pop」メ゜ッドを実装し、リストの最埌から芁玠を削陀したす。 プッシュず同様に、最埌のアドレスから倀を削陀するだけです。 さお、長さを短くしたす。

リストの末尟からアむテムを削陀する-定数O1-「FUCKLY !!」

 pop() { //   —   . if (this.length === 0) return; //   ,   ,  . var lastAddress = this.length - 1; var value = this.memory[lastAddress]; delete this.memory[lastAddress]; this.length--; //  ,     . return value; } 


「プッシュ」および「ポップ」はリストの最埌で機胜し、䞀般的には単玔な操䜜です。これらはリストの残りの郚分には圱響しないからです。

リストの先頭を操䜜し、「unshift」ず「shift」の操䜜を行ったずきに䜕が起こるか芋おみたしょう。

リストの先頭に新しい芁玠を远加するには、埌続のすべおの倀を1぀ず぀シフトするこずにより、この倀のスペヌスを解攟する必芁がありたす。

 [a, b, c, d, e] 0 1 2 3 4 ⬊ ⬊ ⬊ ⬊ ⬊ 1 2 3 4 5 [x, a, b, c, d, e] 
[a, b, c, d, e] 0 1 2 3 4 ⬊ ⬊ ⬊ ⬊ ⬊ 1 2 3 4 5 [x, a, b, c, d, e]

このようなシフトを行うには、各芁玠を調べお、前の芁玠をその堎所に配眮する必芁がありたす。

リストの各芁玠を通過する必芁があるため、次のようにしたす。

リストの䞀番䞊にアむテムを远加するず、ON-「NORMAS」ず盎線的になりたす。

 unshift(value) { // C ,     . var previous = value; //    ... for (var address = 0; address < this.length; address++) { //    «current»    «previous», //    «current»   . var current = this.memory[address]; this.memory[address] = previous; previous = current; } //         . this.memory[this.length] = previous; this.length++; } 

リストを反察方向にシフトする関数-シフトを蚘述するこずは残っおいたす。

最初の倀を削陀しおから、リストの各芁玠を前のアドレスに移動したす。

 [x, a, b, c, d, e] 1 2 3 4 5 ⬋ ⬋ ⬋ ⬋ ⬋ 0 1 2 3 4 [a, b, c, d, e] 
[x, a, b, c, d, e] 1 2 3 4 5 ⬋ ⬋ ⬋ ⬋ ⬋ 0 1 2 3 4 [a, b, c, d, e]

リストの䞀番䞊からアむテムを削陀する-線圢ON-「NORMAS」。

 shift() { //   —   . if (this.length === 0) return; var value = this.memory[0]; //    ,   for (var address = 0; address < this.length - 1; address++) { //       . this.memory[address] = this.memory[address + 1]; } //   ,      . delete this.memory[this.length - 1]; this.length--; return value; } 

リストは、最埌にあるアむテムにすばやくアクセスしお䜜業するずいう玠晎らしい仕事をしたす。 ただし、芋たように、メモリアドレスを手動で凊理する必芁があるため、最初たたは途䞭の芁玠に぀いおはあたり良くありたせん。

芁玠のアドレスを知らなくおも倀を远加、アクセス、削陀するための異なるデヌタ構造ずそのメ゜ッドを芋おみたしょう。

 /*** ===================================================================== ***\ * ((\ * * ( _ ,-_ \ \ * * ) / \/ \ \ \ \ * * ( /)| \/\ \ \| | .'---------------------'. * * `~()_______)___)\ \ \ \ \ | .' '. * * |)\ ) `' | | | .'-----------------------------'. * * / /, | '...............................' * * ejm | | / \ _____________________ / * * \ / | |_) (_| | * * \ / | | | | * * ) / | | | | * ** / / (___) (___) ** \*** ===================================================================== ***/ 
/*** ===================================================================== ***\ * ((\ * * ( _ ,-_ \ \ * * ) / \/ \ \ \ \ * * ( /)| \/\ \ \| | .'---------------------'. * * `~()_______)___)\ \ \ \ \ | .' '. * * |)\ ) `' | | | .'-----------------------------'. * * / /, | '...............................' * * ejm | | / \ _____________________ / * * \ / | |_) (_| | * * \ / | | | | * * ) / | | | | * ** / / (___) (___) ** \*** ===================================================================== ***/

ハッシュテヌブル


ハッシュテヌブルは、順序付けられおいないデヌタ構造です。 むンデックスの代わりに、「キヌ」ず「倀」を䜿甚しお、キヌごずにメモリアドレスを蚈算したす。

意味は、キヌが「ハッシュ」されおおり、メモリを効果的に操䜜できるようにするこずです-倀の远加、受信、倉曎、削陀。

 var hashTable = new HashTable(); hashTable.set('myKey', 'myValue'); hashTable.get('myKey'); // >> 'myValue' 

繰り返したすが、メモリを衚す通垞のJavaScript配列を䜿甚したす。

 class HashTable { constructor() { this.memory = []; } // ... } 

キヌず倀のペアをハッシュテヌブルからメモリに保存するには、キヌをアドレスに倉換する必芁がありたす。 このハッシュ操䜜。

キヌを入力ずしお受け入れ、このキヌに察応する䞀意の番号に倉換したす。

 hashKey("abc") => 96354 hashKey("xyz") => 119193 

このような操䜜には泚意が必芁です。 キヌが倧きすぎる堎合、メモリ内の存圚しないアドレスにマップされたす。

したがっお、ハッシュ関数はキヌのサむズを制限する必芁がありたす。 䜿甚可胜なメモリアドレスの数を無制限の倀に制限したす。

ハッシュテヌブルの実装はすべおこの問題に盎面しおいたす。

ただし、䜜業の構造のみを怜蚎するため、衝突は発生しないものずしたす。

hashKey関数を定矩したしょう。

内郚ロゞックには入らないでください。入力ずしお文字列を受け取り、ほずんどの堎合䞀意のアドレスを返すず信じおください。これは他の関数で䜿甚したす。

 hashKey(key) { var hash = 0; for (var index = 0; index < key.length; index++) { // ---. var code = key.charCodeAt(index); hash = ((hash << 5) - hash) + code | 0; } return hash; } 

ここで、キヌごずに倀を受け取るget関数を定矩したす。

ハッシュテヌブルから倀を読み取るこずの難しさは、定数O1-「FUCKLY !!」です。

 get(key) { //     . var address = this.hashKey(key); //    ,    . return this.memory[address]; } 

デヌタを受信する前に、たずデヌタを远加しおおくずいいでしょう。 set関数はこれに圹立ちたす。

ハッシュテヌブルに倀を蚭定する難しさは、定数O1-「FUCKLY !!」です。

 set(key, value) { //        . var address = this.hashKey(key); //       . this.memory[address] = value; } 

最埌に、ハッシュテヌブルから倀を削陀する方法が必芁です。 ハッシュテヌブルから倀を削陀する難しさは、定数O1-「FUCKLY !!」です。

 remove(key) { //  ,  ,  . var address = this.hashKey(key); //  ,   . if (this.memory[address]) { delete this.memory[address]; } } 

 ============================================================================ ,.-'`'-.,.-'`'-.,.-'`'-.,.-'`'-.,.-'`'-.,.-'`'-.,.-'`'-.,.-'`'-.,.-'`'-.,.-' ============================================================================ 
============================================================================ ,.-'`'-.,.-'`'-.,.-'`'-.,.-'`'-.,.-'`'-.,.-'`'-.,.-'`'-.,.-'`'-.,.-'`'-.,.-' ============================================================================

ここで、メモリの盎接的な操䜜を停止したす。埌続のすべおのデヌタ構造は、他のデヌタ構造を介しお実装されたす。

新しい構造は、次の2぀のこずに焊点を圓おおいたす。

このようなデヌタ構造の目的は、さたざたなタむプのプログラムで䜿甚する情報を敎理するこずです。 より耇雑なロゞックを衚珟するための蚀語を提䟛したす。 同時に、実装の詳现が抜象化されたす。 実装を倉曎しお、より高速にするこずができたす。

 /*** ===================================================================== ***\ * _ . - - -- .. _ * * |||| .-' /```\ `'-_ /| * * |||| ( /`` \___/ ```\ ) | | * * \__/ |`"-//..__ __..\\-"`| | | * * || |`"||...__`````__...||"`| | | * * || |`"||...__`````__...||"`| \ | * * || _,.--|`"||...__`````__...||"`|--.,_ || * * || .'` |`"||...__`````__...||"`| `'. || * * || '. `/ |...__`````__...| \ .' || * * || `'-..__ `` ````` `` __..-'` || * * `""---,,,_______,,,---""` * ** ** \*** ===================================================================== ***/ 
/*** ===================================================================== ***\ * _ . - - -- .. _ * * |||| .-' /```\ `'-_ /| * * |||| ( /`` \___/ ```\ ) | | * * \__/ |`"-//..__ __..\\-"`| | | * * || |`"||...__`````__...||"`| | | * * || |`"||...__`````__...||"`| \ | * * || _,.--|`"||...__`````__...||"`|--.,_ || * * || .'` |`"||...__`````__...||"`| `'. || * * || '. `/ |...__`````__...| \ .' || * * || `'-..__ `` ````` `` __..-'` || * * `""---,,,_______,,,---""` * ** ** \*** ===================================================================== ***/

スタック


スタックはリストのようなものです。 これらも順序付けられおいたすが、アクションに制限がありたす。リストの末尟からのみ倀を远加および削陀できたす。 前に芋たように、メモリに盎接アクセスするず、これは非垞に迅速に発生したす。

ただし、他のデヌタ構造を介しおスタックを実装しお、远加の機胜を取埗できたす。

スタックを䜿甚する最も䞀般的な䟋は、スタックにアむテムを远加するプロセスず、アむテムを最埌から削陀するプロセスがあり、最近远加したアむテムに優先順䜍を付けるこずです。

再びJavaScript配列が必芁になりたすが、今回はメモリを象城するのではなく、䞊蚘で実装したようなリストを象城したす。

 class Stack { constructor() { this.list = []; this.length = 0; } // ... } 

リストメ゜ッドず機胜的に同じ2぀のメ゜ッド、「プッシュ」ず「ポップ」を実装する必芁がありたす。

プッシュは、アむテムをスタックの䞀番䞊に远加したす。

 push(value) { this.length++; this.list.push(value); } 


ポップは䞊郚からアむテムを削陀したす。

 pop() { //   —   . if (this.length === 0) return; //       . this.length--; return this.list.pop(); } 

さらに、peek関数を远加しお、スタックの䞀番䞊にある芁玠を削陀せずに衚瀺したす。 ご泚意 Translatorpeek-芋おみたしょう。

 peek() { //   ,   . return this.list[this.length - 1]; } 


 /*** ===================================================================== ***\ * /:""| ,@@@@@@. * * |: oo|_ ,@@@@@`oo * * C _) @@@@C _) * * ) / "@@@@ '= * * /`\\ ```)/ * * || | | /`\\ * * || | | || | \ * * ||_| | || | / * * \( ) | ||_| | * * |~~~`-`~~~| |))) | * * (_) | | (_) |~~~/ (_) * * | |`""....__ __....""`| |`""...._|| / __....""`| | * * | |`""....__`````__....""`| |`""....__`````__....""`| | * * | | | ||``` | | ||`|`` | | * * | | |_||__ | | ||_|__ | | * * ,| |, jgs (____)) ,| |, ((;:;:) ,| |, * ** `---` `---` `---` ** \*** ===================================================================== ***/ 
/*** ===================================================================== ***\ * /:""| ,@@@@@@. * * |: oo|_ ,@@@@@`oo * * C _) @@@@C _) * * ) / "@@@@ '= * * /`\\ ```)/ * * || | | /`\\ * * || | | || | \ * * ||_| | || | / * * \( ) | ||_| | * * |~~~`-`~~~| |))) | * * (_) | | (_) |~~~/ (_) * * | |`""....__ __....""`| |`""...._|| / __....""`| | * * | |`""....__`````__....""`| |`""....__`````__....""`| | * * | | | ||``` | | ||`|`` | | * * | | |_||__ | | ||_|__ | | * * ,| |, jgs (____)) ,| |, ((;:;:) ,| |, * ** `---` `---` `---` ** \*** ===================================================================== ***/

キュヌ


次に、キュヌを䜜成したす-スタックを補完する構造です。 違いは、キュヌの芁玠が最埌からではなく、最初から削陀されるこずです。 最初に叀い芁玠、次に新しい芁玠。

すでに述べたように、機胜は制限されおいるため、キュヌの実装はさたざたです。 良い方法は、リンクリストを䜿甚するこずです。これに぀いおは埌で説明したす。

そしお再び、私たちはJavaScript配列からの助けを求めおいたす キュヌの堎合、再びメモリではなくリストず芋なしたす。

 class Queue { constructor() { this.list = []; this.length = 0; } // ... } 

スタックず同様に、キュヌにアむテムを远加および削陀するための2぀の関数を定矩したす。

最初は「゚ンキュヌ」です-リストの最埌にアむテムを远加したす。

 enqueue(value) { this.length++; this.list.push(value); } 


さらに-「デキュヌ」。 アむテムはリストの最埌からではなく、最初から削陀されたす。

 dequeue() { //   —   . if (this.length === 0) return; //     shift   . this.length--; return this.list.shift(); } 

スタックのように、「ピヌク」関数を宣蚀したす。これにより、キュヌの先頭で倀を削陀せずに取埗できたす。

 peek() { return this.list[0]; } 

リストはキュヌの実装に䜿甚されおいるため、シフト方匏の線圢パフォヌマンスを継承するこずに泚意するこずが重芁です぀たり、ON-“ NORMAS。”。

埌で説明するように、リンクリストを䜿甚するず、より高速なキュヌを実装できたす。

 ============================================================================ ,.-'`'-.,.-'`'-.,.-'`'-.,.-'`'-.,.-'`'-.,.-'`'-.,.-'`'-.,.-'`'-.,.-'`'-.,.-' ============================================================================ 
============================================================================ ,.-'`'-.,.-'`'-.,.-'`'-.,.-'`'-.,.-'`'-.,.-'`'-.,.-'`'-.,.-'`'-.,.-'`'-.,.-' ============================================================================

これからは、倀が盞互に参照するデヌタ構造を䜿甚したす。

 +-   -------------------------------------+ | +-  A ------------+ +-  B ------------+ | | | : 1 | | : 2 | | | |  : ( B) | |  : ( A) | | | +------------------------+ +------------------------+ | +--------------------------------------------------------+ 

デヌタ構造の芁玠は、それ自䜓が意味ず远加情報を含むミニ構造になりたす-芪構造の他の芁玠ぞのリンク。

今、あなたは私が意味するこずを理解するでしょう。

 /*** ===================================================================== ***\ * * * | RICK ASTLEY'S NEVER GONNA... * * | +-+ * * | +-+ |-| [^] - GIVE YOU UP * * | |^| |-| +-+ [-] - LET YOU DOWN * * | |^| |-| +-+ |*| [/] - RUN AROUND AND DESERT YOU * * | |^| |-| +-+ |\| |*| [\] - MAKE YOU CRY * * | |^| |-| |/| |\| +-+ |*| [.] - SAY GOODBYE * * | |^| |-| |/| |\| |.| |*| [*] - TELL A LIE AND HURT YOU * * | |^| |-| |/| |\| |.| |*| * * +-------------------------------- * ** ** \*** ===================================================================== ***/ 
/*** ===================================================================== ***\ * * * | RICK ASTLEY'S NEVER GONNA... * * | +-+ * * | +-+ |-| [^] - GIVE YOU UP * * | |^| |-| +-+ [-] - LET YOU DOWN * * | |^| |-| +-+ |*| [/] - RUN AROUND AND DESERT YOU * * | |^| |-| +-+ |\| |*| [\] - MAKE YOU CRY * * | |^| |-| |/| |\| +-+ |*| [.] - SAY GOODBYE * * | |^| |-| |/| |\| |.| |*| [*] - TELL A LIE AND HURT YOU * * | |^| |-| |/| |\| |.| |*| * * +-------------------------------- * ** ** \*** ===================================================================== ***/

カりント


実際、グラフはアスキヌグラフを芋たずきに思っおいたものずはたったく異なりたす。

グラフは次のような構造



です。線で接続された倚くの「頂点」A、B、C、D、...がありたす。

これらのピヌクは次のように衚すこずができたす。

 Node { value: ..., lines: [(Node), (Node), ...] } 

そしお、グラフ党䜓は次のようになりたす。

 Graph { nodes: [ Node {...}, Node {...}, ... ] } 

JavaScript配列を持぀頂点のリストを想像しおください。配列は、意図的に頂点を順序付けるためではなく、頂点を栌玍する堎所ずしお䜿甚されたす。

 class Graph { constructor() { this.nodes = []; } // ... } 


グラフに倀を远加しお、線のない頂点を䜜成したしょう。

 addNode(value) { this.nodes.push({ value: value, lines: [] }); } 

次に、グラフ内の頂点を探す方法が必芁です。通垞、グラフの䞊郚に別のデヌタ構造を䜜成しお、怜玢を高速化したす。

しかし、この堎合、すべおの頂点を調べお、察応する倀を芋぀けたす。この方法は遅いですが動䜜したす。

 find(value) { return this.nodes.find(function(node) { return node.value === value; }); } 

これで、䞀方から他方に「線」を描くこずで2぀の頂点を接続できたす翻蚳者のメモグラフアヌク。

 addLine(startValue, endValue) { //      . var startNode = this.find(startValue); var endNode = this.find(endValue); // ,      . if (!startNode || !endNode) { throw new Error('   '); } //    startNode      endNode. startNode.lines.push(endNode); } 

結果のグラフは次のように䜿甚できたす。

 var graph = new Graph(); graph.addNode(1); graph.addNode(2); graph.addLine(1, 2); var two = graph.find(1).lines[0]; 


このような小さなタスクにはあたりにも倚くの䜜業が行われおいるようですが、これは匷力なパタヌンです。

耇雑なプログラムの透明性を維持するためによく䜿甚されたす。これは、デヌタ自䜓に察する操䜜ではなく、デヌタ間の関係を最適化するこずで実珟されたす。グラフ内の1぀の頂点を遞択するず、それに関連付けられおいる芁玠を非垞に簡単に芋぀けるこずができたす。

グラフは倚くのこずを衚すこずができたす。ナヌザヌずその友人、node_modulesフォルダヌの800個の䟝存関係、さらにはむンタヌネット自䜓も、盞互にリンクされたWebペヌゞリンクのグラフです。

 /*** ===================================================================== ***\ * _______________________ * * ()=(_______________________)=() ,-----------------,_ * * | | ," ", * * | ~ ~~~~~~~~~~~~~ | ,' ,---------------, `, * * | ,----------------------------, ,----------- * * | ~ ~~~~~~~~ | | | * * | `----------------------------' `----------- * * | ~ ~~~~~~~~~~~~~ | `, `----------------' ,' * * | | `, ,' * * |_____________________| `------------------' * * ()=(_______________________)=() * ** ** \*** ===================================================================== ***/ 
/*** ===================================================================== ***\ * _______________________ * * ()=(_______________________)=() ,-----------------,_ * * | | ," ", * * | ~ ~~~~~~~~~~~~~ | ,' ,---------------, `, * * | ,----------------------------, ,----------- * * | ~ ~~~~~~~~ | | | * * | `----------------------------' `----------- * * | ~ ~~~~~~~~~~~~~ | `, `----------------' ,' * * | | `, ,' * * |_____________________| `------------------' * * ()=(_______________________)=() * ** ** \*** ===================================================================== ***/

リンクリスト


グラフのような構造がデヌタの順序付きリストを最適化する方法を芋おみたしょう。

リンクリストは、他の構造の実装によく䜿甚される䞀般的なデヌタ構造です。リンクリストの利点は、アむテムを先頭、䞭間、末尟に远加する効率です。

リンクリストは基本的にグラフに䌌おいたす。他の頂点を指す頂点を操䜜したす。これらは次のように配眮されおいたす。

 1 -> 2 -> 3 -> 4 -> 5 
1 -> 2 -> 3 -> 4 -> 5

この構造をJSONずしお衚すず、次のような結果が埗られたす。

 { value: 1, next: { value: 2, next: { value: 3, next: {...} } } } 


グラフずは異なり、リンクリストには単䞀の頂点があり、そこから内郚チェヌンが始たりたす。これは、「ヘッド」、ヘッド芁玠、たたはリンクリストの最初の芁玠ず呌ばれたす。

リストの長さも远跡したす。

 class LinkedList { constructor() { this.head = null; this.length = 0; } // ... } 


たず、このポゞションの倀を取埗する方法が必芁です。

通垞のリストずは異なり、目的の䜍眮にゞャンプするこずはできたせん。代わりに、個々の頂点を通過する必芁がありたす。

 get(position) { //  ,        . if (position >= this.length) { throw new Error('    '); } //     . var current = this.head; //       node.next, //     . for (var index = 0; index < position; index++) { current = current.next; } //   . return current; } 


ここで、遞択した䜍眮に頂点を远加する方法が必芁です。

倀ず䜍眮を取埗するaddメ゜ッドを䜜成したす。

 add(value, position) { //   ,  . var node = { value: value, next: null }; //    ,     . //   «next»       //    . if (position === 0) { node.next = this.head; this.head = node; //        ,     //    current   previous. } else { //      . var prev = this.get(position - 1); var current = prev.next; //      ,   «next» //    current, //   «next»   previous —  . node.next = current; prev.next = node; } //   . this.length++; } 


最埌に必芁な方法はremoveです。䜍眮によっお頂点を芋぀けお、チェヌンから倖したす。

 remove(position) { //     ,    head //   . if (position === 0) { this.head = this.head.next; //          //     ,   . } else { var prev = this.get(position - 1); prev.next = prev.next.next; } //    . this.length--; } 


 ============================================================================ ,.-'`'-.,.-'`'-.,.-'`'-.,.-'`'-.,.-'`'-.,.-'`'-.,.-'`'-.,.-'`'-.,.-'`'-.,.-' ============================================================================ 
============================================================================ ,.-'`'-.,.-'`'-.,.-'`'-.,.-'`'-.,.-'`'-.,.-'`'-.,.-'`'-.,.-'`'-.,.-'`'-.,.-' ============================================================================


残りの2぀のデヌタ構造は、「ツリヌ」ファミリヌに属したす。

人生のように、倚くの異なるツリヌのようなデヌタ構造がありたす。

ご泚意翻蚳者たあ、いや、いや、...

バむナリツリヌ
AAツリヌ、AVLツリヌ、バむナリ怜玢ツリヌ、バむナリツリヌ、デカルトツリヌ、巊の子/右の兄匟ツリヌ、順序統蚈ツリヌ、パゎダ、...

Bツリヌ
Bツリヌ、B +ツリヌ、B *ツリヌ、Bシャヌプツリヌ、ダンスツリヌ、2〜3ツリヌ、...

ヒヌプ
ヒヌプ、バむナリヒヌプ、匱いヒヌプ、2項ヒヌプ、フィボナッチヒヌプ、レオナルドヒヌプ、2〜3ヒヌプ、゜フトヒヌプ、ペアリングヒヌプ、レフトヒヌプ、トレヌプ、...

ツリヌ
トラむ、基数ツリヌ、サフィックスツリヌ、サフィックスアレむ、FMむンデックス、Bトラむ、...

マルチりェむツリヌ
䞉元ツリヌ、K-aryツリヌ、およびORツリヌa、b-tree、Link / Cut Tree、...

スペヌス分割ツリヌ
セグメントツリヌ、むンタヌバルツリヌ、レンゞツリヌ、ビン、Kdツリヌ、クアッドツリヌ、オクトリヌ、Zオヌダヌ、UBツリヌ、Rツリヌ、Xツリヌ、メトリックツリヌ、カバヌツリヌ、...

アプリケヌション固有のツリヌ
抜象構文ツリヌ、解析ツリヌ、デシゞョンツリヌ、ミニマックスツリヌ、...

あなたが期埅しおいなかったのは、今日暹朚孊を勉匷するずいうこずです...そしおこれはすべおの朚ではありたせん。圌らに迷惑をかけないようにしたしょう。それらのほずんどはたったく意味がありたせん。人々が䜕らかの圢で候補者の孊䜍を擁護し、このために䜕かを蚌明するこずが必芁でした。

ツリヌはグラフたたはリンクリストに䌌おいたすが、「単方向」であるずいう違いがありたす。これは、埪環リンクがそれらの䞭に存圚できないこずを意味したす。



朚のおっぺんを䞀呚できたら...おめでずうございたす、しかしこれは朚ではありたせん。

ツリヌは倚くのタスクで䜿甚されたす。これらは、怜玢たたは゜ヌトを最適化するために䜿甚されたす。圌らはプログラムをより良く組織するこずができたす。䜜業しやすいプレれンテヌションを䜜成できたす。

 /*** ===================================================================== ***\ * ccee88oo \ | / * * C8O8O8Q8PoOb o8oo '-.;;;.-, ooooO8O8QOb o8bDbo * * dOB69QO8PdUOpugoO9bD -==;;;;;==-aadOB69QO8PdUOpugoO9bD * * CgggbU8OU qOp qOdoUOdcb .-';;;'-. CgggOU ddqOp qOdoUOdcb * * 6OuU /pu gcoUodpP / | \ jgs ooSec cdac pdadfoof * * \\\// /douUP ' \\\d\\\dp/pddoo * * \\\//// \\ \\//// * * |||/\ \\/// * * |||\/ |||| * * ||||| /||| * ** .............//||||\.......................//|||\\..................... ** \*** ===================================================================== ***/ 
/*** ===================================================================== ***\ * ccee88oo \ | / * * C8O8O8Q8PoOb o8oo '-.;;;.-, ooooO8O8QOb o8bDbo * * dOB69QO8PdUOpugoO9bD -==;;;;;==-aadOB69QO8PdUOpugoO9bD * * CgggbU8OU qOp qOdoUOdcb .-';;;'-. CgggOU ddqOp qOdoUOdcb * * 6OuU /pu gcoUodpP / | \ jgs ooSec cdac pdadfoof * * \\\// /douUP ' \\\d\\\dp/pddoo * * \\\//// \\ \\//// * * |||/\ \\/// * * |||\/ |||| * * ||||| /||| * ** .............//||||\.......................//|||\\..................... ** \*** ===================================================================== ***/

朚々


簡単なツリヌ構造から始めたしょう。特別なルヌルはありたせん。次のようになりたす。

 Tree { root: { value: 1, children: [{ value: 2, children: [...] }, { value: 3, children: [...] }] } } 


ツリヌは、ツリヌの「ルヌト」ずいう単䞀の芪で始たる必芁がありたす。

 class Tree { constructor() { this.root = null; } // ... } 


ツリヌをトラバヌスし、各頂点で特定の関数を呌び出す方法が必芁です。

 traverse(callback) { //    walk,     //    . function walk(node) { //   callback   . callback(node); //    walk    . node.children.forEach(walk); } //     . walk(this.root); } 


次に、ツリヌに頂点を远加する方法が必芁です。

 add(value, parentValue) { var newNode = { value: value, children: [] }; //    ,     . if (this.root === null) { this.root = newNode; return; } //      ,   //    parentValue     //   . this.traverse(function(node) { if (node.value === parentValue) { node.children.push(newNode); } }); } 


この単玔なツリヌは、衚瀺されたデヌタがそれに類䌌しおいる堎合にのみ圹立぀可胜性がありたす。

ただし、远加のルヌルがある堎合、ツリヌはさたざたなタスクを実行できたす。

 /*** ===================================================================== ***\ * 0 0 1 0 1 0 0 1 0 1 1 1 0 1 ,@@@@@@@@@@@@@@, 0 0 1 0 1 0 0 1 0 1 1 1 0 * * 0 1 0 1 0 1 0 1 1 0 1 1 0 @@` '@@ 0 1 0 1 0 1 1 0 1 0 1 0 * * 1 1 0 0 0 1 0 0 1 1 1 0 @@` 8O8PoOb o8o '@@ 0 0 1 0 0 1 0 0 1 1 1 * * 0 0 1 1 0 1 0 1 0 0 0 @@ dOB69QO8PdUgoO9bD @@ 1 0 1 1 0 1 0 1 0 0 * * ===================== @@ CgbU8OU qOp qOdOdcb @@ 0 1 1 0 1 0 1 0 1 0 * * @@ 6OU /pu gcoUpP @@ 1 0 1 1 0 1 0 0 1 1 * * ===================== @@ \\// /doP @@ 0 1 1 0 0 1 0 0 1 0 * * 1 1 0 0 1 1 0 1 1 0 0 @@ \\// @@ 1 0 1 0 0 1 1 0 1 1 * * 0 1 1 0 1 0 1 1 0 1 1 0 @@, ||| ,@@ 0 1 1 0 1 1 0 0 1 0 1 * * 1 0 1 0 1 1 0 0 1 0 0 1 0 @@, //|\ ,@@ 0 1 0 1 0 1 1 0 0 1 1 0 * ** 1 0 1 0 0 1 1 0 1 0 1 0 1 `@@@@@@@@@@@@@@' 0 1 1 1 0 0 1 0 1 0 1 1 ** \*** ===================================================================== ***/ 
/*** ===================================================================== ***\ * 0 0 1 0 1 0 0 1 0 1 1 1 0 1 ,@@@@@@@@@@@@@@, 0 0 1 0 1 0 0 1 0 1 1 1 0 * * 0 1 0 1 0 1 0 1 1 0 1 1 0 @@` '@@ 0 1 0 1 0 1 1 0 1 0 1 0 * * 1 1 0 0 0 1 0 0 1 1 1 0 @@` 8O8PoOb o8o '@@ 0 0 1 0 0 1 0 0 1 1 1 * * 0 0 1 1 0 1 0 1 0 0 0 @@ dOB69QO8PdUgoO9bD @@ 1 0 1 1 0 1 0 1 0 0 * * ===================== @@ CgbU8OU qOp qOdOdcb @@ 0 1 1 0 1 0 1 0 1 0 * * @@ 6OU /pu gcoUpP @@ 1 0 1 1 0 1 0 0 1 1 * * ===================== @@ \\// /doP @@ 0 1 1 0 0 1 0 0 1 0 * * 1 1 0 0 1 1 0 1 1 0 0 @@ \\// @@ 1 0 1 0 0 1 1 0 1 1 * * 0 1 1 0 1 0 1 1 0 1 1 0 @@, ||| ,@@ 0 1 1 0 1 1 0 0 1 0 1 * * 1 0 1 0 1 1 0 0 1 0 0 1 0 @@, //|\ ,@@ 0 1 0 1 0 1 1 0 0 1 1 0 * ** 1 0 1 0 0 1 1 0 1 0 1 0 1 `@@@@@@@@@@@@@@' 0 1 1 1 0 0 1 0 1 0 1 1 ** \*** ===================================================================== ***/

バむナリ怜玢ツリヌ


バむナリ怜玢ツリヌは、ツリヌの䞀般的な圢匏です。゜ヌトされた順序を維持しながら、倀を効率的に読み取り、怜玢、挿入、削陀できたす。

䞀連の数字があるず想像しおください。

 1 2 3 4 5 6 7 
1 2 3 4 5 6 7

䞭心からツリヌに展開したす。

 4 / \ 2 6 / \ / \ 1 3 5 7 -^--^--^--^--^--^--^- 1 2 3 4 5 6 7 
4 / \ 2 6 / \ / \ 1 3 5 7 -^--^--^--^--^--^--^- 1 2 3 4 5 6 7

次に、バむナリツリヌの仕組みの䟋を瀺したす。各頂点には2぀の子孫がありたす。

泚これが機胜するには、ツリヌ内のすべおの倀が䞀意である必芁がありたす。

これにより、倀を怜玢するずきにツリヌトラバヌサルが非垞に効果的になりたす。たずえば、ツリヌで5番を芋぀けようずしたす。

 (4) <--- 5 > 4,  . / \ 2 (6) <--- 5 < 6,  . / \ / \ 1 3 (5) 7 <---    5! 
(4) <--- 5 > 4, . / \ 2 (6) <--- 5 < 6, . / \ / \ 1 3 (5) 7 <--- 5!

5に到達するために必芁なチェックは3回だけでした。ツリヌが1000個の芁玠で構成されおいる堎合、パスは次のようになりたす。

 500 -> 250 -> 125 -> 62 -> 31 -> 15 -> 7 -> 3 -> 4 -> 5 
500 -> 250 -> 125 -> 62 -> 31 -> 15 -> 7 -> 3 -> 4 -> 5

1000個のアむテムに぀き10個のチェックのみ

バむナリ怜玢ツリヌのもう1぀の重芁な機胜は、リンクリストずの類䌌性です。倀を远加たたは削陀するずきに、すぐ呚囲の芁玠を曎新するだけで枈みたす。

前のセクションず同様に、たずバむナリ怜玢ツリヌの「ルヌト」を蚭定する必芁がありたす。

 class BinarySearchTree { constructor() { this.root = null; } // ... } 


倀がツリヌにあるかどうかを確認するには、ツリヌを怜玢する必芁がありたす。

 contains(value) { //   . var current = this.root; //    ,   ,   . //       ,  null,  . while (current) { //   value  current.value,  . if (value > current.value) { current = current.right; //   value  current.value,  . } else if (value < current.value) { current = current.left; //         true. } else { return true; } } //     ,  false. return false; } 


ツリヌに芁玠を远加するには、远加された倀よりも倧きいか小さいかに応じお、巊右の頂点を飛び越えお、以前ず同じトラバヌサルを行う必芁がありたす。

ただし、nullに等しい巊たたは右の頂点に到達したので、
この䜍眮に頂点を远加したす。

 add(value) { //    . var node = { value: value, left: null, right: null }; //  ,      —  . if (this.root === null) { this.root = node; return; } //    . var current = this.root; //        ,    //     ,      . while (true) { //   value  current.value,  . if (value > current.value) { //     ,     . if (!current.right) { current.right = node; break; } //       . current = current.right; //   value  current.value,  . } else if (value < current.value) { //     ,     . if (!current.left) { current.left = node; break; } //       . current = current.left; //       ,     //  ,     . } else { break; } } } 


 /*** ===================================================================== ***\ * .''. * * .''. *''* :_\/_: . * * :_\/_: . .:.*_\/_* : /\ : .'.:.'. * * .''.: /\ : _\(/_ ':'* /\ * : '..'. -=:o:=- * * :_\/_:'.:::. /)\*''* .|.* '.\'/.'_\(/_'.':'.' * * : /\ : ::::: '*_\/_* | | -= o =- /)\ ' * * * '..' ':::' * /\ * |'| .'/.\'. '._____ * * * __*..* | | : |. |' .---"| * * _* .-' '-. | | .--'| || | _| | * * .-'| _.| | || '-__ | | | || | * * |' | |. | || | | | | || | * * _____________| '-' ' "" '-' '-.' '` |____________ * ** jgs~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ** \*** ===================================================================== ***/ 
/*** ===================================================================== ***\ * .''. * * .''. *''* :_\/_: . * * :_\/_: . .:.*_\/_* : /\ : .'.:.'. * * .''.: /\ : _\(/_ ':'* /\ * : '..'. -=:o:=- * * :_\/_:'.:::. /)\*''* .|.* '.\'/.'_\(/_'.':'.' * * : /\ : ::::: '*_\/_* | | -= o =- /)\ ' * * * '..' ':::' * /\ * |'| .'/.\'. '._____ * * * __*..* | | : |. |' .---"| * * _* .-' '-. | | .--'| || | _| | * * .-'| _.| | || '-__ | | | || | * * |' | |. | || | | | | || | * * _____________| '-' ' "" '-' '-.' '` |____________ * ** jgs~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ** \*** ===================================================================== ***/

終わり


十分な知識が埗られれば幞いです。気に入った堎合
は、リポゞトリに星を付けおTwitterでフォロヌしおください。

たた、他の蚘事「The Super Tiny Compiler」を読むこずもできたすgithub.com/thejameskyle/the-super-tiny-compiler

 //    ... module.exports = { List: List, HashTable: HashTable, Stack: Stack, Queue: Queue, Graph: Graph, LinkedList: LinkedList, Tree: Tree, BinarySearchTree: BinarySearchTree }; 





たた、この蚘事はgithubで読むこずができたす。

翻蚳aalexeev、リビゞョンiamo0、Chursina Chaika。

Source: https://habr.com/ru/post/J310794/


All Articles