From 2b43ebd993cc152edbea7921b941d0e5f56cdc9f Mon Sep 17 00:00:00 2001 From: krahets Date: Sat, 23 Mar 2024 03:04:36 +0800 Subject: [PATCH] deploy --- .../array/index.html | 2 +- en/chapter_array_and_linkedlist/index.html | 2 +- .../linked_list/index.html | 2 +- .../list/index.html | 2 +- .../ram_and_cache/index.html | 2 +- .../summary/index.html | 2 +- .../index.html | 2 +- .../iteration_and_recursion/index.html | 2 +- .../performance_evaluation/index.html | 2 +- .../space_complexity/index.html | 2 +- .../summary/index.html | 2 +- .../time_complexity/index.html | 2 +- .../basic_data_types/index.html | 2 +- .../character_encoding/index.html | 2 +- .../index.html | 2 +- en/chapter_data_structure/index.html | 2 +- .../number_encoding/index.html | 2 +- en/chapter_data_structure/summary/index.html | 2 +- en/chapter_hashing/hash_algorithm/index.html | 2 +- en/chapter_hashing/hash_collision/index.html | 2 +- en/chapter_hashing/hash_map/index.html | 2 +- en/chapter_hashing/index.html | 2 +- en/chapter_hashing/summary/index.html | 2 +- .../algorithms_are_everywhere/index.html | 2 +- en/chapter_introduction/index.html | 2 +- en/chapter_introduction/summary/index.html | 2 +- .../what_is_dsa/index.html | 2 +- en/chapter_preface/about_the_book/index.html | 2 +- en/chapter_preface/index.html | 2 +- en/chapter_preface/suggestions/index.html | 2 +- en/chapter_preface/summary/index.html | 2 +- en/chapter_stack_and_queue/deque/index.html | 2 +- en/chapter_stack_and_queue/index.html | 2 +- en/chapter_stack_and_queue/queue/index.html | 2 +- en/chapter_stack_and_queue/stack/index.html | 2 +- en/chapter_stack_and_queue/summary/index.html | 2 +- en/index.assets/conceptual_rendering.png | Bin 83827 -> 0 bytes en/index.assets/hello_algo_header.png | Bin 71830 -> 140430 bytes en/index.assets/hello_algo_hero.jpg | Bin 264948 -> 0 bytes en/index.html | 1 - en/search/search_index.json | 2 +- en/sitemap.xml.gz | Bin 509 -> 509 bytes sitemap.xml.gz | Bin 1005 -> 1005 bytes 43 files changed, 37 insertions(+), 38 deletions(-) delete mode 100644 en/index.assets/conceptual_rendering.png delete mode 100644 en/index.assets/hello_algo_hero.jpg diff --git a/en/chapter_array_and_linkedlist/array/index.html b/en/chapter_array_and_linkedlist/array/index.html index 78b633156..be9f1ab01 100644 --- a/en/chapter_array_and_linkedlist/array/index.html +++ b/en/chapter_array_and_linkedlist/array/index.html @@ -1704,7 +1704,7 @@ diff --git a/en/chapter_array_and_linkedlist/index.html b/en/chapter_array_and_linkedlist/index.html index 96c0a7450..83f3eed70 100644 --- a/en/chapter_array_and_linkedlist/index.html +++ b/en/chapter_array_and_linkedlist/index.html @@ -1481,7 +1481,7 @@ diff --git a/en/chapter_array_and_linkedlist/linked_list/index.html b/en/chapter_array_and_linkedlist/linked_list/index.html index ee5ed1ef1..778e494a5 100644 --- a/en/chapter_array_and_linkedlist/linked_list/index.html +++ b/en/chapter_array_and_linkedlist/linked_list/index.html @@ -1686,7 +1686,7 @@ diff --git a/en/chapter_array_and_linkedlist/list/index.html b/en/chapter_array_and_linkedlist/list/index.html index 747d38ff2..94088ab9e 100644 --- a/en/chapter_array_and_linkedlist/list/index.html +++ b/en/chapter_array_and_linkedlist/list/index.html @@ -1668,7 +1668,7 @@ diff --git a/en/chapter_array_and_linkedlist/ram_and_cache/index.html b/en/chapter_array_and_linkedlist/ram_and_cache/index.html index 704e7fecb..05d5a1f0b 100644 --- a/en/chapter_array_and_linkedlist/ram_and_cache/index.html +++ b/en/chapter_array_and_linkedlist/ram_and_cache/index.html @@ -1566,7 +1566,7 @@ diff --git a/en/chapter_array_and_linkedlist/summary/index.html b/en/chapter_array_and_linkedlist/summary/index.html index 505763063..3bf704ffc 100644 --- a/en/chapter_array_and_linkedlist/summary/index.html +++ b/en/chapter_array_and_linkedlist/summary/index.html @@ -1548,7 +1548,7 @@ diff --git a/en/chapter_computational_complexity/index.html b/en/chapter_computational_complexity/index.html index 87fc78800..ea8239c24 100644 --- a/en/chapter_computational_complexity/index.html +++ b/en/chapter_computational_complexity/index.html @@ -1481,7 +1481,7 @@ diff --git a/en/chapter_computational_complexity/iteration_and_recursion/index.html b/en/chapter_computational_complexity/iteration_and_recursion/index.html index 56949f03e..db2c2af61 100644 --- a/en/chapter_computational_complexity/iteration_and_recursion/index.html +++ b/en/chapter_computational_complexity/iteration_and_recursion/index.html @@ -1698,7 +1698,7 @@ diff --git a/en/chapter_computational_complexity/performance_evaluation/index.html b/en/chapter_computational_complexity/performance_evaluation/index.html index 30aea88e5..5c0b5dcf3 100644 --- a/en/chapter_computational_complexity/performance_evaluation/index.html +++ b/en/chapter_computational_complexity/performance_evaluation/index.html @@ -1548,7 +1548,7 @@ diff --git a/en/chapter_computational_complexity/space_complexity/index.html b/en/chapter_computational_complexity/space_complexity/index.html index 528ce695e..fb4162b96 100644 --- a/en/chapter_computational_complexity/space_complexity/index.html +++ b/en/chapter_computational_complexity/space_complexity/index.html @@ -1686,7 +1686,7 @@ diff --git a/en/chapter_computational_complexity/summary/index.html b/en/chapter_computational_complexity/summary/index.html index eede33010..2c0c67507 100644 --- a/en/chapter_computational_complexity/summary/index.html +++ b/en/chapter_computational_complexity/summary/index.html @@ -1548,7 +1548,7 @@ diff --git a/en/chapter_computational_complexity/time_complexity/index.html b/en/chapter_computational_complexity/time_complexity/index.html index 1137d817f..9705073ee 100644 --- a/en/chapter_computational_complexity/time_complexity/index.html +++ b/en/chapter_computational_complexity/time_complexity/index.html @@ -1788,7 +1788,7 @@ diff --git a/en/chapter_data_structure/basic_data_types/index.html b/en/chapter_data_structure/basic_data_types/index.html index c201fbdee..d2b80e62c 100644 --- a/en/chapter_data_structure/basic_data_types/index.html +++ b/en/chapter_data_structure/basic_data_types/index.html @@ -1474,7 +1474,7 @@ diff --git a/en/chapter_data_structure/character_encoding/index.html b/en/chapter_data_structure/character_encoding/index.html index 9d4caa2be..f9fc17131 100644 --- a/en/chapter_data_structure/character_encoding/index.html +++ b/en/chapter_data_structure/character_encoding/index.html @@ -1602,7 +1602,7 @@ diff --git a/en/chapter_data_structure/classification_of_data_structure/index.html b/en/chapter_data_structure/classification_of_data_structure/index.html index e3285f926..c5b5c8bea 100644 --- a/en/chapter_data_structure/classification_of_data_structure/index.html +++ b/en/chapter_data_structure/classification_of_data_structure/index.html @@ -1548,7 +1548,7 @@ diff --git a/en/chapter_data_structure/index.html b/en/chapter_data_structure/index.html index c43d119ca..e864a479f 100644 --- a/en/chapter_data_structure/index.html +++ b/en/chapter_data_structure/index.html @@ -1481,7 +1481,7 @@ diff --git a/en/chapter_data_structure/number_encoding/index.html b/en/chapter_data_structure/number_encoding/index.html index b294d552b..ba00e43c1 100644 --- a/en/chapter_data_structure/number_encoding/index.html +++ b/en/chapter_data_structure/number_encoding/index.html @@ -1548,7 +1548,7 @@ diff --git a/en/chapter_data_structure/summary/index.html b/en/chapter_data_structure/summary/index.html index aa8a78dc7..b533a73e7 100644 --- a/en/chapter_data_structure/summary/index.html +++ b/en/chapter_data_structure/summary/index.html @@ -1548,7 +1548,7 @@ diff --git a/en/chapter_hashing/hash_algorithm/index.html b/en/chapter_hashing/hash_algorithm/index.html index cbee30678..344a1ee77 100644 --- a/en/chapter_hashing/hash_algorithm/index.html +++ b/en/chapter_hashing/hash_algorithm/index.html @@ -1566,7 +1566,7 @@ diff --git a/en/chapter_hashing/hash_collision/index.html b/en/chapter_hashing/hash_collision/index.html index 381a3f02c..8c84b7164 100644 --- a/en/chapter_hashing/hash_collision/index.html +++ b/en/chapter_hashing/hash_collision/index.html @@ -1632,7 +1632,7 @@ diff --git a/en/chapter_hashing/hash_map/index.html b/en/chapter_hashing/hash_map/index.html index fb176ddec..df00ad325 100644 --- a/en/chapter_hashing/hash_map/index.html +++ b/en/chapter_hashing/hash_map/index.html @@ -1566,7 +1566,7 @@ diff --git a/en/chapter_hashing/index.html b/en/chapter_hashing/index.html index 5f398101c..36f739ba5 100644 --- a/en/chapter_hashing/index.html +++ b/en/chapter_hashing/index.html @@ -1481,7 +1481,7 @@ diff --git a/en/chapter_hashing/summary/index.html b/en/chapter_hashing/summary/index.html index 7fcaf4449..94aaf297f 100644 --- a/en/chapter_hashing/summary/index.html +++ b/en/chapter_hashing/summary/index.html @@ -1546,7 +1546,7 @@ diff --git a/en/chapter_introduction/algorithms_are_everywhere/index.html b/en/chapter_introduction/algorithms_are_everywhere/index.html index 66a854ac4..872c9c9f4 100644 --- a/en/chapter_introduction/algorithms_are_everywhere/index.html +++ b/en/chapter_introduction/algorithms_are_everywhere/index.html @@ -1474,7 +1474,7 @@ diff --git a/en/chapter_introduction/index.html b/en/chapter_introduction/index.html index b8b2c96c9..7285d5585 100644 --- a/en/chapter_introduction/index.html +++ b/en/chapter_introduction/index.html @@ -1481,7 +1481,7 @@ diff --git a/en/chapter_introduction/summary/index.html b/en/chapter_introduction/summary/index.html index 8e98b5c22..fcebed6e6 100644 --- a/en/chapter_introduction/summary/index.html +++ b/en/chapter_introduction/summary/index.html @@ -1474,7 +1474,7 @@ diff --git a/en/chapter_introduction/what_is_dsa/index.html b/en/chapter_introduction/what_is_dsa/index.html index 41edb9d63..d08c13a88 100644 --- a/en/chapter_introduction/what_is_dsa/index.html +++ b/en/chapter_introduction/what_is_dsa/index.html @@ -1566,7 +1566,7 @@ diff --git a/en/chapter_preface/about_the_book/index.html b/en/chapter_preface/about_the_book/index.html index c0028a835..d4ce542cc 100644 --- a/en/chapter_preface/about_the_book/index.html +++ b/en/chapter_preface/about_the_book/index.html @@ -1566,7 +1566,7 @@ diff --git a/en/chapter_preface/index.html b/en/chapter_preface/index.html index 17a9e9350..1eb074b04 100644 --- a/en/chapter_preface/index.html +++ b/en/chapter_preface/index.html @@ -1479,7 +1479,7 @@ diff --git a/en/chapter_preface/suggestions/index.html b/en/chapter_preface/suggestions/index.html index ccfd346ed..1ead1988f 100644 --- a/en/chapter_preface/suggestions/index.html +++ b/en/chapter_preface/suggestions/index.html @@ -1602,7 +1602,7 @@ diff --git a/en/chapter_preface/summary/index.html b/en/chapter_preface/summary/index.html index c82374547..7f301f825 100644 --- a/en/chapter_preface/summary/index.html +++ b/en/chapter_preface/summary/index.html @@ -1474,7 +1474,7 @@ diff --git a/en/chapter_stack_and_queue/deque/index.html b/en/chapter_stack_and_queue/deque/index.html index 0e2f4ca67..c13b0dd70 100644 --- a/en/chapter_stack_and_queue/deque/index.html +++ b/en/chapter_stack_and_queue/deque/index.html @@ -1614,7 +1614,7 @@ diff --git a/en/chapter_stack_and_queue/index.html b/en/chapter_stack_and_queue/index.html index 0d50a619c..7fbee44a7 100644 --- a/en/chapter_stack_and_queue/index.html +++ b/en/chapter_stack_and_queue/index.html @@ -1481,7 +1481,7 @@ diff --git a/en/chapter_stack_and_queue/queue/index.html b/en/chapter_stack_and_queue/queue/index.html index e6b4686f4..1c1066889 100644 --- a/en/chapter_stack_and_queue/queue/index.html +++ b/en/chapter_stack_and_queue/queue/index.html @@ -1614,7 +1614,7 @@ diff --git a/en/chapter_stack_and_queue/stack/index.html b/en/chapter_stack_and_queue/stack/index.html index 42f5d2f0c..5d0934826 100644 --- a/en/chapter_stack_and_queue/stack/index.html +++ b/en/chapter_stack_and_queue/stack/index.html @@ -1632,7 +1632,7 @@ diff --git a/en/chapter_stack_and_queue/summary/index.html b/en/chapter_stack_and_queue/summary/index.html index c430458e2..8aafee1d0 100644 --- a/en/chapter_stack_and_queue/summary/index.html +++ b/en/chapter_stack_and_queue/summary/index.html @@ -1548,7 +1548,7 @@ diff --git a/en/index.assets/conceptual_rendering.png b/en/index.assets/conceptual_rendering.png deleted file mode 100644 index 4f9a14acb4398ea6496ca4d4e7d41ce65762ffd3..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 83827 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�#!M zOI6FS_^8zl;oSGF&p_IuU#KPJaKWRbIKZx+J2UDZ6V0SYMs1qG^#*>dBmJi=pd1i4 z2ZcyJ^DqAlJX(!ibWFcGW0`XSapvk3o-CS+w?~K@5#PlEB8~Sf7OoWw`1c!Tb<9qm znC?s2y^K)gbM*u|1|c)+Ep!C2SACr*Z9{&34+UbWrd+0)*P8< z!Huxtcu#1XJ6OB6l8XU(soyAyj8|Tv2t*PT8p&aMxLQ*HY1-8OXxvYom{@=g_Yj~| z&L6pDDJT?{f%^95?Bk?1rzLgGAIG_egV+9h$#X1t?#WKDFVPf z48W|AB3_IU;=Y;BZv?72PTIref&FPJSVxz3HRzaIAQ7_iiOlbvz!CmMAWArNRSoh< z^b%AfsP7_&s7xQ&>7`!Hc>;~&xK%=z!1otDBdWgl=g3fdX1xugQE{~(FI*nRh^kqh z0J09#8ewiv)#;Hz`quG(v8=W3=ZgHZ;qi|xJ_8(o!3*5!&X8hc$Z4->%rBs?^vTGd zi!Z^Ir$sxf0AE_Llji!r$kD+jqb9uzoW#`V_1;-$PUTq8-hLgQ&WXCLi8z?kz8}j2 zbh_W<9{p<5v~!0Z8SNzQ4&Z#(&qEABeB&gDBm)}n$oeBSUKZn{Du8j_KNjk=(xYXP zamEn#3V-BlT1;c#Hw0Ej0Y@jUl)2>4}SYV!lB>LV8+pPQ#Yj3Xc*HDG~IT!z|(#!9G zE)p)wG;N8M`r%!R`^DD0@E0`)#vc0oeU=0#Q7xon53{Um zA@9ai2eL~P5tpa;7d8^>fw)p7qO0pnIi3+a#HTGGXfqDv3AMjULbTaOr%*y5?b>uh zF_gT4A2RX7uY4E?SyQ)7llTHZMWO@&_&`XpcG!iW9PZHwDPl7{8hT&n#8T8#C%;b+ z5U&Ax42U!f*dfwrOv?wa6(`RCbi4$w>2_#(%xKI>p5Z(zW7Xq6^9u^9LM4PVuC;Bi zhM6RQlm=^cifL@t98o`Ahu(sXazTaJG(#UpUpT)2bg=!G>fWG7d=$L*lL09`#DElh z$nYukrkV)Q6!H-8fosF`OQNtA zZREhnf1gpyGJfIBRLHepQCOqcG(Z`4Zg#Em>iyCep zH;y(-g2u25egiQCeFj_AW*t^N;*$R({h*2k+=@IYU^?=$c*zhEgwOSy(KP4?_NZwJCuWx1+3yLUqc3k>@vih)id{+48)Aflj>x zji)3ck1e#r-#;dL2350kF@W}$xPCAMo5w%UE1h~@8gNAFs~62Cl#sv6uJ1-6bo8j`32b_(eUYtGs}&Xyz3A^nUr z4b-@J|2T-HU(q@nm13U10YuOOvAV(dX3>p+$JF7^@w&KOF*#>pv$b}AtqA8@Kny9u z#=us)igq9lnpXuTik$~T zwojSpYa)oeG5!&C)BFA{c~1*|w^aq%CIZKH0>mu1W2+gZ(ZQxxR!Ov;1g-aKWG0#YUQv^)Tcsg|@TcwYaN$L&d)3|axwOpn)hS|{IAPkklXfExZG zLjEG`#;aN7K7oBmard$(snOM{k1g{1Gy!QN;$6aym-^zX>(g0$ZFjfVZ{F;@GmLO( zT@kR@#;^6B@`uMIT$5Y@wcqQ^xql5zRmr3e0Cd=eoy=snz7Uu5*b*$ze(%kHEuHZ~ zuPzi|tMc2m!%xyx>Pk?nkwkkdAcF{S4^T1A1dKCQr7cY647H>U3$6f^4m^GzfyDNF z6NT@hDoBXD-jN}0q37FO!#@Hq6P>>4Rb4fv8M6%oeH*CIic7tiT-}pz$bcm==!=l) z?BdlTX>{&0KjdfYOf-G-fn`*ILxvZk3bbx-od4iY=Lefn?}2^244JYzMV6Ve=z%P!gTQ@J1Ga zkn$?pSlr{0`+u^>T>xv9qn@qee!~~^_h8FiWd$$O;mafA9C)ns=r>6T34WY}9fY`) zJZmylwOcRLHO@i&o?axQF;8SoKVV(*cb1h&@N(0|2$#@JJxY1eZY7Nz4FPc$5RpJy z9VbCJ0*YGE&d}1=H#!fb0Qt_cx5dT&xzHNnA6!TFdTlLyA4vqP|7|&HWRoF^WExiuCsHQZBehCf=_aQAMx{|2%lxl%AJu;+ z)BYMATrq|_m?<2v1gAyW+Jce0C{shB-wboEH~b?VfOu)QA;wq-9}NCW23oVMkP*M} z>ExF+6n)=mj(@QNjvHSqr zhDD&NtCf@d)yYYd5}JNA>oF}b&DJ#Npe|2efp)i z^o2TfjTX6y61VidO-QVrpX|Pp>tp6NVN;1nNa2$9aKq30$fWd=L;!L7PbjF4ex-coD;6!vucNS1_6?CvFXFK~oiZx9hr%Fj1 ze&qOSa_NnRk$2$-Se9|j!{4`BMGQqwrHWVgMhDqZilt5pq%T^}a#)bJmG7%djMv$8 zP!!W=hSu@m|Bme&jf7I9Hd{L-N8| zkCSFkAPCwy_z0T>Sc@EOq{(|4h*3a4GCV0Sai2a+^DBfYN9?V-7`E^DG;RM^0$Zj< zzM)FnbQzYyYOJqXE*MOMa1VvQ9TVDNaG1zXWpa5lx}#uh^hGds*-?V!RqwRi zzw4;(Kx*E;p)`jgZ710*oz(mZjwj+4kqSiPJ#ieYVJ>Earj=8sPCt(^k&>!WJ+$4T zB;Ow0zg-3B6!H2N{YmQ`ECmk~5|3e8zcgLq*UeOIr@c(_&Yn9(l@iI`ez0_p>nm3T z6t)wN2%5ziohyULRi@?!EKfL&7-iSZdP&fts!vt_ zVhYxD#qw*~-G23u%*>Ahs>iek-=2tvE4%M%o1Fv1>eaBQ^qYj7@P27uk z_q#AQVI}JQ48>HawI^(S$sd*bedr}?)`wChvUr%Um{%WY-Fp29ruoSXpwttvXutd+ z(vEzYG_IFMNFvg9nf8IeX5sQX>bY$tuZm*OCCZ|eMsRGn_%r7ryW*zD1;>dQCnyl1 zt{seYLGjnp zEmUJt_G&YRhi1xbQ&4=e;NR}PLFH7E%QsS?056{gz5U;rux2OqeBX6nSML`v|6e)4 z2p(ML!5gtrb{&l+%fi$CFmLWR0Fh6~EDHQ!J90tfYr{Y7d_S-KYa0qOqSbqMGC>lw z!5nvum=XhrZQe%F7FWbV5`n%Y7@S`9!vPtRT4$ow$Nt5B@+@Krhym)(zPPj5$6CNN z@`SqSr+VrE89u4PDekAcrPn=9mkExuM}(r?s`P8>5VMGp{Yl^o)$D`O7Vk(ai^QzK ztWU5X;~Ql!m7K>WDO9WwJPFry%8Z*?$330U-hWXR*x)|}aBZ&@qNSwuTi-`1I{pNj zn2g6O4; zf#|_W%n~yAU@iyj;QuQC2zD}N_(Vezgy$Aa^C^F|y1Pu0C}~N@hp~Bj?5jwSBXiZ; zyU0+xLV+qY(rAQol8{dIm(<185-?B=jZ-^UJYMZCbGLHridEkAYy7JWW0R(H?CMJ~ zbBO*PTGz{iJ%3qy@j~rOdWqMK`6n+(w;@eU{h^yJ?%y9+Z}Q?l)`d+kQ@sdCcOcCi zAclYIk=#wVJPYFC!ik|u4<`zQ@mLnS#snzMM`iwS`+3)2YjeF;?73WCoO04}6L#@I z4XqfwhrJt|+&KCtayES1SHqXI8WClG6S%$Ct7jeBGt1v&Dwr^@Q8`kZE%^ACzQz>2 ze)E&8Z1?=l*PDg?bz)4loe#2YCxWeNm_(dEySsDT6DW0^N2J|$pU-W4`PsI&cVa#( zMYQ-F?;YncWVsd=_HHA0Lr_XN_+l9z_9`6Gf5sq{!x^pmfiIxEc~WV1#Jtohk+-4B zWjbhOeMr0{!g&BQIPNO=v{eE94ISnJ##Jk9yyQ}s{_{Nqf==z%T+%pT;{>eGbmk2^ z+jszvPCd}E5E$jAc44~`ju}R0((3#3;vXZ4gHp}Dz>S_?S%S++CJ&*>cPu`0W}@M% znjCI&f&po6iOm(6y}7-#mv(nIo!llx5HzJRN#h^5fI#)yC`9B0^h~-e(ut`PB=!vl z{n>VXW#Td8^YyQCOia#Mc&-**Nv-E*8Oi8lAaAYeekr&g)9uD+`U60wp>g4=3@Ef5 zcb&`?DSnpf&Syl9c$RSV@YY(tktyB2@9xC#b z7vgcge|J%qn+*@Jz%e%HisY%->Ft02G08~1pqv0Ag|h|jRhLtt0{sd5ZJ9f*$&j&Z z&E5Skyw_WWP^4k*m{eINQOtPtl-owMg}94nj8?%*|B!MpP=(N#M9*i(IKy9P@2pwR z+H!ze;*Yyr{>KCY(Lx*Yu~s|34N0!@QhDwXr?U43&8Aglpra>a1TO)YfB9Nm3Gu4= zIer_&lQ!%KKD_Q#j07EA=De)#=jTy&C=b^D>IlZQ0pcE$P&z#kzKnVAEC(^g=@_|V!skqEX{;(GCssf(3nl(dCn!6&+B;hPlU`uRFKhkOKhh|S zu_bM?2VDx}L@=!X8f9HLMq<3l?oCjOBlpzUui6q29=Oywo8x?C$UCfB#8__z^y*LGwPo zjtF!9?*(7@XEk!CLN<0mLYVl*FUEZu!RKiD3xG}qtmAVETsQpSyDf?G;EyWd!h?)- zNv;i2@%So;qqS&$2qI)kH`-V1{aT&1=mS9}0H1|M^}0wF3@QKMdl7b>A1|#5Cb<|a zD$;oQ{n?hU^&9FLapBZ*uGSt$*(G`;osjTbSq)o}kA1Z0ilmq$ZuD9KJtgWXy)(LB zUBjOV4596oLwykv*$6-*GWhXULkJT*$dLz+s`xh4u@-n={Rn-n&NIviu#=HZxoP+n25T zP+c(;I-XFtf`~#lKWJoOYfBk`{gJC59x=Y!5_qs2llMQ*hx`92{sbcx@;FCjPJno+ zF`VsoLP#AixK)15c3&84SXMuww-yGQqi>0cj^B9Qw+5`2Lh*Q=RrE;4pK}Q|L_^0CVm0 zzH}?T#Npmpv`sH5Vx?DFkpVdx#)W_I;I$V6a*FW#{UAluBJn&V(*Z9x0B5@4`VOE& z)e#hT%QvSj1Bjmu>nr{Za=M%uZ6!j!m@p!e5EDI2J4zNb*F!DheoN%Q=_EWYHkYgXAihlKcoWOigVJYb~iMR58gC z2gJ36Li>f%uY$J^i`iBOTEHmY(;6Sh1~QPaAFKp$ief>faGZ*TT_FGYYoQh6IAzDX z5)gI`ZW+U53ug|rlO3IYu%7{7m_rj)bL|Wo=Eks`3OLLlX-e~Fj7~}``6Dh#^q-co zaKY(!cwJr2S` zTfKwwat!W-{om8Lu=PR-f}e?yMuS_VxCEFOs!+LQTnv?Y%-s1qv(<6y0Si*#G7OB& z*!0C0*L=cUV~S?LGM6b$LAoAW6J)^!Z3<||F(6+=%(=^P_^cC!yZRvCCo>=)2CXWV z%BwsH@}e<_mQP|kTg0FehECNZfa0^V95Ey_Y#WFvw!M?AKKrbFsR*@CDqeS|xqB_Q z!pyMLNQ)yz=F)aI65PWrjd^8Rgz{7Gn*}KA#=xxn_$<(AqnOQ$c|oH+-DsQ`N7P5Y zRnR@yWKr5&YO-*x!Q3WAo>`~7gD8Fo>RL{-NHea{}{puK!I}D zBPz_zsCx1vTZ2ojD>HT9zRw(XC90I>D@2U)b9^nLp=ST5K_<~+?pxYaW^M+du4AMZ9{}8kvl5slG^3*zmMDyfF8QKpDQWaHU{0q*P z;f*(_M*UcOlyZ^-UXHXd*(tVfOw5a%!Hg&)8mfs)UnaNkej3Gxz#HbP1P&$tye|vs z&)N@WwhTP)=<0en{H0K3c;hULSfhR<%5KMi$u+@lk_gmj6EK5ljsnK5h;uqxX>gXk zE-8%Zbw-j%MA2j+B+H72%bfjfEfVEh>IJ=dd(7G_HtvHSf+D=I?Vj zWtO%%`lnD1TANO4MvwG;I*h@-%_|p0y$1)$Ltu^Rc*}RLy0L!D+N%L#AjBGI*-Yf1 zp~!)w6yy41Hr|=%1N}#lYRrA}_Vqzgt0y6BNv1v|9SBnGWg*C3EbnVHL2UaqzJpnqJpSADC0Q4prjzHIO=KWUsh!6&f}9zg^%{4x+!%; z4oz>2+1g1}lK00f6tLC!>-Uh6+4y?S_QI71&8wBGZ?j;i!fF?Ga8HN0Dyu&)Kogco z(b?qJw3J}|5z3gy=A`Td&ig{^>R@Hb$VZ#Vrx&MDeOqa5x!A5UO^bZ+2cdv~(G~y^ ztm{O`x|Jyi&WqgrZ#WI@#0@|G4wIfO70UvkRxX^CDJ&kpzKQI6TrE;C7(z&+yW#xZX^EbX45Vd`H}_kCyW_Gd;?t z<~?Of7X}h_n+_{BqlhCAPY|K>PBgWt0ThZ$)h7cf&n_$E5asNLhJ20Eg1g zpIsXmD&ro!6bvJ7^DFcMu-lA836nPaBJ;}~69BNzAd!?s(QzNnX97f3tq(e29bmfEf_pd;!|OXm+$sSs zY{%dvhG5Hq=Zf+i&UM#e;2)v*Hz0Z$l%cIo^EQsoYoPzF$O@(MJ6E8#fA&R3dG)_1 z=!Zb&lp}!cU%i&!GLMI|AjiLuJ3VGX zBd1P4NvaWQmeaZ~5URA<4)b7jIZ&A5;Kh=e#h0Bx2KJwGv4Xt zF%M<$MC*Ma!Ku&Xlbwu57X%M+Rjv*m(qtd==j=P7r`DD`QKhWXl=3rBQ1qK~4E9az z*)=NE7(%FiyF&st!YJd#)J1yq2nKyIja_8!jD(8cpBzB{*YKym6%b1tRtz}sa)t$` zDy;32QvvaX#h-x%S@<07y}f#)fP(Y+BJpxSmr(q4DpTcf%eLi;p|hFx0GUUGMRYYo z<3bM(KC<9pZY2tAB}(bB&E?y4_5_QxsH0`+FLaxcuS}ph_SWGX z>ME44c{*k~BEb9*_vq1tO>$6OWU*l9Ln5No3Y>Xn^y{?AHH-IJUC-{`166|`IsPKO zCPql(Q>>R_KSco89Y=;JeI?&JCXlR36pIKlN1#i{@$zR$u+uZStr3hr0pcT}?Yhi6 zC<;b>f9cW33j2u5ODecOQ)hFu2^$J3tVoX>R<-mkYyUe~z_ap(1t7jxM@#zx|EpJ` zH!R;Q+e);Jw@x)wx&4D@A%{Nr8@0prTWGFFjaw>*ggbxKWJB%2tLtw!Y)bG#d-Cpg zox4K`E0xZyF`~@2sn%(XG%K%2&ZkZ%&My*ojLF0PGtXjN#WzmJsK|S(0D%y--VU?F zIBLxrf6*m2W|Za*IaUa&dD8hnBNkW?I;2Ji7%KoWz)+-oSTc=>fPECU%Q2xpa&Yy~ zYofDO?|ngyJdRBefXUDJgVWe=@I$7kSyrx4!$NmavUm4bxCeU9?Y)nO;0CY9DZ2iD z2f7vtW;^-3%iRBQQq?lXNcMR1M@!6gCRpy+IF7=1V6^8xQ?nlubHfII*Z61m)lV-% zSeD>3xlJ3k753DT=3{VY6fp9W=)Kzlz}9R$_K@DdU%b$8?)8w>>k$)8L*2KAvhfZ6 zJth(-7NC4kxED^LuL^{gs^>+IHM!vv( zN^TE4mPjD4iE%XyJEPn>A0RMj^3@)9T@&^}YuNXyZ^fkYVl8bJU~z3IN8EpF_h1}& ztbk3ref;_F2R_G*9kVcsLCKnbZeWgc1S5Qz)|9MKNBtTBu1o8&VPjHCO5q)Q&2OJ$ z#wqpyoj(Hiaq)g}r4vG^D!0L77dsA$S_d$=Pzwt3e~(FW+!OKIh9DMlRY^X{E_QGQ z36;X1Nxw$k&-M#@lJdxCJvYmCa=C__&VLwB)vJH+Ma~<3vs!vX5La96Cy~F@>|HpK z`;Y9QRp{ankB-jhrBP+h%zQbJ0fB-sna3-C>ZIiTc#-rWdo*7;?8dTt8yt#cpkQo*xH8rCl)pJ41~Jd=_1 zPv10zi>mfxmROrzH%B7GutgPe=x>n~&gi(xsV=u56E~jY_%Ex4Vy^=K?k1;q#L+`g z0Afm{s>q9CC6u}X`WKz7Nl-cHG?@J}Uk2e%LZk{=+dBS){d$hP8zsisN4(gdUK|3j zbM3eP86~;iLCKyU{&q8*0brk8Y9`K}G)I{q8Yl)`e_<-J`-K^p5ytk==%qDCi*M+| zXY402t&VU+&gyC38yA-OXc2kAkBy})sMoAdOKh%}Z|oOFD3G3lt)YWCavSrJt$R_< zj|y(xX(#pE@gU79<$sJBHoMzEO~FvzdC)0I)a{e~!FS9IU9xt!koK#+$-2qPZ= z)_QV7Yca)O+NY zFO7MC)=`cL%Fo7cr&JT*Bf?k;g;5cSH!#|KDr|QpMAQjdd43Ue@M#e+Ss?q)6Vh&Sd4Nh| zJbLftTVgB>CpP>;b(0-z$8)ADllIc(iYlycnP0GJ(AlwP@8r2WZD;89dE&c3Fy!ho z@!fMpK<)O?jfGSYvRMUM+X+mZ1tNYTXy+GMsxZO~$Sk{vo8+K({;4)^e3%icmoO5f z&6nqx?5k={o-hY!fASi232`|P<+@wqxqC9#a`fs2OPmZUj@5T9&vo@av-Vo{r(p$` z{kEN@4zi#iIq$nGv#5F^-UqR8&!!fCw%y1SzE@F6Q0~p5;0t3p0u-&9h@k!NS|Es| zmJE5nC>_KCgz+BkZW%6g2YKIX-iq&g8-5l~SX%DeWV4mcz_^>q$eeqRs?@h>RQbGZ zD=F#52!bfqZ=OEhc@-glc*B{RE7DQL78C?D2HC~vtfWw zrmma`k`ytMbe__JfmaOSU~-2sXLj zzB7vv^jb&Zu7a2PTpTaxW*|u2Id`kt^94}`RzmfU$|Y9`Tle7l!3BO$<-&fmWB<7 zZ~fpO(^XPHarfRTPs`IW+w(cU=}R-LH@oQDZ+-W!b3;!4vpAaKuw$=i&9Z3hBb8J- zS&cbu4k_@80y}X0A?OB#^tK%6J{j&v$f*6E@Qs~Kwqj5&p2ApRJkw}OxL#_s46dnF z>6n0A zOC>0E2gkv|V+>Ho%j9t&*=85KBdw41Ip}ToyL3-<;X?``Ugh)R4Kk$HUBI$S`*Wbv zc+mKwhc9?-0&K{z5aHKSR&6e-h)$;2;qLX=#f?i@uz77nk4vFQ5x?P1r&b$Ek2uyw z`rywuE9&8TP!1W!xx<^AzcX-|KgXUvUVVcr!k-RccD1sPUz*=N_23)fhJrYNY-|whQ$mE_Cx%<57 zTzP|jtJ~4jk|(HLy>;80EnVsp2ZTx@(5$#9)}2LQRE@n7L2CNU@o9LoIX^8=qNaA8 z;j5o_rj#o8Z_}lKY5Q0FM&SNz1?FGW|F<~p50S6gpd1DfwWl0$Q(qN_^I8hyhUF2S z?>8rk$>=C+&D#!4@ii(NBc&WLv$tAP`eRcn6rUTn+G+J%&jpS~BYA`)mJ0gV7TrGG z{0+Yo9$EFtewi5q2c&KtS?_LNOb;VNnWIt>zB0tkVO*nZGI^a>XvBTI2u!Tj{y^?4 z;Alii+%LsS0u32z%SXdMjg{xY&o-y*1m>b`E@WTZz~XlTw@hutUmGJegGwJ zbXO_P+K*W7emr%-t0J8)gonv4PwG(oCykR3Dx~V2Vuu&&FJ@%E@eCm@hESb`jHN%a zx0-)GpN1=g+uptp7)gT_!iSe|_ZNs%xV{3jW0&eQ^B?OPSh)#*hE{0T)4gw28ofLV zTOs;k9s!9(Pe5m|akw;ctW%LP8Xkx==7oH{?o|kju6Ei6E7!}R6wl;b&=o;pXOJre z4*+5~cfYP7ku?}aNojx{q1}*tb^cHO#e-el6xaiHY!9S{Rkp;NZak+9HRDp=kBNJv zkBuI2oR}4PIOvLT7d;IVo6tmKzh>gypEX86aYrG9QQK@twQ)6kL5`pYv%p5IJEEwQ z#vg&QWz}_0N%3Bfz&L>ye?Dgrxm}cM&8CB`)SxcIR%!ex^&2PNCBpH;4I5NbZ@m{P zW0lFnzHyhR$^tt};f$6g5M`odhEel!F_Zzi*a&+7M*QBGgQHgBVna5;P!woKrq%6> zAdoT_QsXk*5fut{bRK?IH`?{pg4*Nq-a*M*S90w51}+}{nb>WoAM>c;Z~6y<0^V=L zy~Y$21_UP2#$wYJ_zha)DN3hWbfd@XE&44)`ZO+>%(Umj(jl<*WTAdMmPjK1Za>4~LmBcdG8oQLV6RA6H zQo0QVe1O>|zkXg#sBxWseY+ERG(P>aJYR$kfa=u*;MfKin5GpExK^I>u6j7$BWwT` zcB~5=;|U*B#n=2ZPsq+-#VD-&Gb>x7XCPxU0fPL~p21uj^`{Ozs7`DCtnJs}4;N-T za)>D=4_~A@F>~EZA-%7s8`Pc`o<3w%GN{Z{FBHqZ1sjYK3@KL@PTl-AUevYrqE?oL zrvYs9cMoNG3j{gr^F420$^;y(`i>v~Vh=MPjlS2K_pDr{F)+ZQlHli>8&xs!Nr*6Y z<;H^q3df@;Vff68*|(b>ulUuM+=${2&bjV=&v~`VCTk5-VsvAKZsE_8Tp_jD@=pw} z>{D9gqw*XW#D^w+pz*=rbQ&VX;n{+Z7Qy)o)3emJ$({!<(f;MU-~z?~ASZ9+sPeIg zP}RuBV6}~CIT6A=?V{kh_3jKc{VFJf6HvdyWLq)bC%^gl zHW}P>ILwj>Mly12yTD=>*>RGxpFT^Wee3leT&604$m$m`1?r)rqmB z(`yyHiUnY#kAAN!O0&0vK=nt|y#+f|hHjTq21Rpvmz0%hOrR3UA@C+rr}+dLDk=jK zysKnQ0S)>@9_TxAT|W_9(N@+49qk%>OUYhutIYauTSXT4`;+2{sJne*t25MBNt%An zVaDRq(Gxad?1T9#m%e#MZABURpcQaG4s5m?I=v^ZiiV?~2v|XDFP=M?{qFzo>)>WGxSPI?Gd_Q3PjW<(u#@JHAcvI;SRyV<0fYJQW>w=5evag_wU(Prq4Ps6A9IvC{G!nDl2x_ZHbCHG&EKY*5$z1(PHh_BSEX_Q%1%Q~S1*mnYeHDs=whN_0-W;P z<)4WM70$>H?%I=56uLzKDE_|)Mo-gY?;4KUqr&Bw5$GGxtK`e$*-t$Orvdl}a{fiB z`oCNDcmH1hIvAMXd1rI2b3fw6yU(Vbze^p7uf>>*Huu3iy*z?tyRwSz(T$!@*`c+B zAYOfF9vG{aVc)msk#!&dzY{k6qz!p51)z<&Oo>-+D!bre0a&Zpm@ zp~^1MQ4i3xdeoLBI1^HwcW%2?2whf_C(XM1^-c*U^3QvE4}{DWFD^C<>;X7nSSJUT zW0_Mf%?WUE!q|@lov&k(+}SJW*#$Lzp2hbRZGExC3Bi#X_p2F!-2hHsuK&2I$9PV| zgaHva;`>jMb>{mu5AA}5(GcS0Nb4O&wp%r^h=+jP91Zw7Be=@E%JgTOaAV0sm1%ZFZB|p z-wt97gA*T4i2}yP@Gjqjn2I+!){ncO3W)XI2oi^9Sqr{|B8*O{mj`2ZPb?|}WpQmV zWEy+zkMHp~74-Y%$z%nQ)LqNSSNEp~yuXE0F|awIIEi2!22jwz8CT1ab5-+7X1w`9 zf+l4)Ts}(BSMgs-B@`Jt(O;AVQ~gm|^1(@phCR}lk69|I#L_0`5>Bh$QSi{H`NKW+ z&D)oN)a4UG!fq{c&fgXjxE%n(RO$_hRvk*XZ2ja{A*B#IlQIAB7D`u4t+=03Q2pX1 zPeD$=U#cGUVqVdu)wWKynGVy#XVEI_`*k)&xsjvExz-W|%-|7pum!YjFZ$z0A zRD5XMLUAV`pkA_dMg=uT?iB68B@d|e44bF^%_pvU06@KFAp`m<(F{m~`?cy$=74Yo zW$!1WDMpt1Md4g*xzrJDu`9*<*r3cqsz18r zEP(ATQ{H&K-|^s5Ni*VzDfbG^srn^{IWFh^X>`V;il>l*Q2P%LBtb=#94z5hHT{zF z<2d-qgJxUCZt#CYP^f(b3yoGH8Pfb~Jzd)K;^Vhl*-1?*y-y?B6*t<*;ue{;pBX1B zvmuHGa{n#vOybc+bOMmo^zDakaJu(3WIW3sn#1XQrt5`;una z{!)>Ut*u&~s&j0wmV(_8@9&IPl-`pdb^V)ewpniZ$(#kIw1o0}_Znm}wFGj6jy*6Z zu|;&NpcF|y&Ha8AxE}m(M1b|;5MmFoY7eYJ&@M;4ov6G4+Ot>mzsZ%|Ft=EriGkaQ zs&1Q;H4_KLvn?>?&CWxA=w`1vbV2`f67WGr^HRQDuBPCpXP<{bA~lf~37J<2oSoBA zEmEH_H0`4P-rMh&tii3fR}CZ}1OVjUU##OJs@mD{)iyLBr_?j^ZPLbg2%p*Bo|#!& z!=kflBp<1Ac{R6*hEcE`RpU#VYo}K2H-c**-Nr}MQgz4!1AVtr7$G}HjGI_5f zMI0^lzQ@HU98g^B7ZF-E4;$79G!6t|BjOOM06FJAt#?;&@@@zLIsd9{jpsk<)<+4v zW28u}$1Jdhky8SM;rX(MG9n;tl)J*o{_gMZ*f&6Rt9Bq^HyGJ^S;=M1a<~2aBOqSs zcsn5JJxTB9xVXEzb7<(bXf)33BYg)0dT*% zFN#-JZGMqd9;~7m!Ri6P!qQ8${xN2W#(0xy>YSr#bP!XrV;_FLOqGQ%#NODM${RU< zx5WeR$LL4J9c=rSTb;2US@+P`HBFevwKv^g-}x#N^C`93PA(#1f%9dA@SUN+=+K4M zr^~yBkgIpIPII4n-~go2hjZu8FcNxxUnCGL^UBe66xiJri5ozUVmH+0qa@}f)O62B z9uQ=yXGQxWvy;fxOMsMiBT_=D2|ysmvic)BcvX9<>`kPg5DOhSpA+hznL`n=Yhg)3 zNdgC-Zo;YrChj8#U+0!9Tj)x>ft26=DG{z(Y%(74|9JY!uqM3s?~MT)HAaKfXrvqI z(Fl@KQqmwO-MP`t5CIX85GfJq7NkR@k?!sg1f>4^{+{c4UhcZ~V(09{eeO>gPI=6f zj83AS7=N;XBXwT(gdQSdD9;*SJKfIBbBJ(tRdbH(BGvi?efL1xH8ql=3fFnDpr`HE zdvj#zyv6M$v~UBz1yGQFXmNFZJ_s-G<=SU%nH{UlWKhNj`fm&LzF$LP`?Fi-4uAh+ zW2V(x<|FCc9LJcu4XO~iWI|TIcV#r6bYOIQl*-UYT5I@O9^#s_w`xom zd*}v3RnR8ckol1)%Zu#H)Mv^PBJb+oD(Gc41+O(V@OBh{eIHlTe>24`bf_2lUNtT= zFVj-R6EIj4u09pVlK|R1q%uKMkf8E3%dFeS`JRjysUGGgbgy^j>p%T8aC_dl*0Xaz zHGz*9_s<2;(@n zxBw>im)Gn7-Q@+hMd-~Dkq@R233Uy!)SGt8xRUp7dGb_mvR|G!mN-vwxXi$))qvOF zV0>WdI*tmuHpIl^1_Ei$F?6o!WwmZHztt)FAQ$OgDT2?W9x|uF|DFFr-Id`$051h5 zLp#ErmR7~5F>s%;i8n*7Vfn6R5lng=YRcRE#Hb+f1#H5I@J%-F$Z-1R`Nhbe0as0A zw)sby7HMHABCiF2@c8qO>9#a9SJE|ood8x?E%ypG)NsyK~ z031eb82zD%Ba$CXY9`LGhX##3d;#UdC|?QJH?h@WpfjEK=RXkB=SUuK=Rsx1`tlRl z6gK2S!z=FEo%-`*OxwU|4H1wc@zQ5$Z^}Uw(69LJ-%8sVW_7I&H7P+l3fiogFCV+V zp;Gp4fo(+)$6)%Om~YVIGWjm@v0yWb;&uyM z3w)rW`Kf-e#9wqQbG4$%AkQ)!=s*g`yzHITdP1!jPqlYsbq@K=%gVckT?3RE!W; zjWGU+V$~yr1#D265N$kqf)!(^->vWj&B5plgm<#cDJ#3p6lKv*#J7j8d}_{_xskpFHf(hCq&FxHd@Ftt(>qJ71P=YXX6J$t}{ z?o(xswdR-LY5~FWj*mW{5i_W6SVtV64ix(=3xuk8alP|P>Yf|SERP}?LSHBUgmtcU zOG=weY=MI z7=nih&|pIiq5x!{3eqV1z_2ePcxmO0*L0l`GeNnN7;(B&yo4*({J&{{Z#1d0X_eEqq-00C&p65N^872u)s#T(h!ArHQwmj4h| zz3>YV#yr32+rJqVsEP_z3B_|{hf9l*3NUrNmLNGaWvq7#gey>h=u+|Kq~zxV|_ z8;bpQrc#Fi4%6AT8&5i_xECheKYm(0LbcGdr84>WVJa<5W9cw&NP=_4jZx#YMCDtO zB=-9sL&L<6-09r0PsRk1UKf3-AOj?8fF>ieFr`O)TNx%}sSH4)mXruXuv-7)1q+4C zH5-7#l1UM7Sx)HL5zQyhP0K+joYRudy^7Zdf>Z>(;E8X(io(W+1~iX8WTx!FdK0EBNN0saFon~{Y=p@~*v+KwxDv)0V8fCu zX8~c6vgxQrnUAp}Etp2C^RW<23w2f6iJu&;NMIOgaBnx~3dIiC7|MEiWdv12doWleq`gI?<>?Y=v~nX4*G(a&S81$wzbI<&M5G<^*;r= zPt?dtv$?}o5T3)xA;v`szyKigaPwa1VM^T`PHI^=$LAEt^=7ug5?k3lWAuw1>RbH? z{m-CO2+gn?IR!^1*kU5H@SnZ~rSKPmA#ii!+63+A&<(qwP7nCR1SahH-(yUKXX+r$u^p%yV7p*hWw?M@X+1Vt zhK4r#I&TvE`SC5*#!RZ#+M8i>jL{-CQaT6=7-5=Tj{VrjXC3tF+-b4mlPR-rYv=6u zUrpWMO$4W1Qpz<-o;mCfeGyN4M-#E+p8{fkYp<0BCa}<3xND| z9`6=x0*HR)8RL7m2BoY!H~V24CNsafc%v32HH$zOuVLPAdu0_T8=YT1RC23vV9w{a zTCCJ?JX}asga`Z+GByq5-_%aoImqhs&Cu#iwZ9`6r9w9lix-OYI7oC!`H_s0L2dQRzitm;?D952y#DQI_&JY;EDW{N| zScnIA-xYHXyE(YnMQnu%{`2z9dSoRCZ>J-UqT~Trzj|&r!Tu7{$R^OPJ3Ov=t`)i?PIVw?m%&*@5TtY?rIU z*%~5#way$sf(RIfguoJUy86P~?$^_b9!9MoG@e8W+0*l-F~aD|wNoIL+O)B3W(ijJ zEjF;*qF1BmJHO;_6xt$PZq$xzf;$7L#zr=nzKc-$-07+1A|OG{!Gls&^F^X{A z4942%(GJhY`O;aYBjw9zU|e3z5L{*e#xi^#jt6se!U9zBK$fbv5qt5KJ6@I=fZaNb zi?__HsXoQ&H^z*x0t2KmtK{U|)@^w@5No>XEXj9dz9UBhOiJh7qIIY($UV}@-C9pz zv6(pB^c>H3!JGfaGD1KW>P2xxDr+WL0+K*iC`rHg(z!Qct5Smhvvt=LlQ{rtike3C zYo|7kiz45p>Hg_c!Bt7Soq>E+f7VCF!eaBOTFx+lV4iGoA`D6XvD^`^?8=SMQ|BhY z`)*X=9CxRF7!rMbs?soOP4fH$P#Thw$_$C$Z_q*dDrdq(0R7bxz|Pn|POgf|l_uB_ zrVYc_o=YAOf|Z%TVzwL1U?4z=AHZIf?*ykmz!tTmK$Xe$a1yMk)$oZeLvbGI1AkA2 z7%JHf0#&ctgp8;15-{!~eHP_uoErY)CGT0gWa+d1>u`5;r@qS2kUFN|yLs80I(cDB zSd9JjFP^r>=AUMmX$j_1xxSQ%pHkx?ci})-Ka{1#7DOHPDmb!RJS$Zoe8c|zWalI= zsZHGd`M|S_2mJA;SgOp4!abEil4$>AE20a?vN~6%D#dTjmu=K|(Ue?ZEX^CUSlQQ? za154+37VC)%h zp4c|WKVLYv?`&EYTXni|)fe-025H~LqmF73s_6^nTDrOsJz81EAE1J$77-4=(b!?m z1(`yZ*%jToRX6gZ=4;H`q~a@pNk)&xMz2t{ShxYGXC2BCo` zni#j_NOrat$)UR@vTx$%9ob2@E;X0yZZYDULBe1K^UN_W#Jg)Bc#KtDQ=C!q&EDkS ze`8fzlCZ^S(5Y!;&!hAlf74$mV-5MjKkt92AzpMyzyiDDRHzWcr+8>29?aygd}(s) zx56n;=S4tOS)=2;0(|4s)K9GwA{g84Lb3*5Mim!k(w(AY%&CZJfcVn&f|UX3F(h$bUaOwr@(eG81{4OUq;-x1!#m3lRACCjtnu6Gwy$grK+eQj&)_@dYVLW zf<(sQ9Kkoo3C>u z-hlz=&>5-AT$M7;q`uJb<)iZCvG>osd#Ri>$9PFn@no&Z6(tEyHATva7b^9>s-ot;GBV`wy zw~xt;@jQ~CpN?)22YWcNU@o1#C=d8qk9+xcrGR!N2%#<$-G}lDr0c)4qwAM?f7ET0 z^E)HVr-gBVCG;a5WC~CtaIoH^P6uh=IX!NO_YbF9?F?3L+!>rW9h|DkNe*_KqIgsI zA6BZ+1a)bQmr{wLWelXD?MB}Q{3-HXmw}_k3@;r``B`)6ZMpw#b}1U%<-T(aoYHv; zwe*#M2|kaQa#MHy{D4vw>xYpqRndy?^h^bRb)4Gms!LeQ16Bc;VtV1~EL*#lt)xlZdP) zIvnH*Ca&ikS4`bk&u~I-`8?s)&9T7o zP#O&}4tr$nS0HTP3=2ZU!$hml zST<8|k#Vj0IAb{dPECdJ{(FUsMF_Jotvj5Q zd?qQ8h)C|vOSVkeiWdt~6-F6gl`kG$$%Wm2!x((N?@K`>c(?1xpuc}1BqQQ5YEH0V zK#BQ3!%tT+7C@iIo6U!VVI&LQEwyf|71|Bv>OqL0y)Mx==mG;)?Y-OHtW{a~Yw=4u z$d^(DtRW<$PS;iK{)GE-$=Q(yoVoA8!MT3U;fk07ROmy5d?tQZ^%am`_4oSKyEo)R z5tTZ+=KJG%?N$(J7ZKi<`8W(4c8$cO)l+&69jKC;eMX$jYZhI9>%I%(*k~X1^7^=_ zbEC#yY1u)7sbuK@e$JwA$907dL58nK=I4Gi1ln62K3 zBhWQBsBoczoaTe457ULZwK9LcHFs&;ulQb8#7W_+!SgG7Vy~VtXlLP2-f2gX;}YfV z3}k*={JVyvY4qEBaUmA<>MnjWc8G1hu-ibIlOpbc-j^M z&iX5QL$K2d-E|80qUR#A82iX)S5`R)*xe>E>5Pi2vwAZ(o-BcC#jkS=iayVOjzs&?Q9wX86$W{bTrXs6Rj)8(r^9d?A47 z)qX>aNU+F90{tT+*TN#c+)Oo`%iMb4LKMUZVI>5-56(G9ICncOtwd04Y>DQOsxB|G zsOo;8*i!&j2dBr&YqHAysZWArU4KVxUz9rXVg5>8koTy6@h|B&Bz_4T%!LcN3ozcZ^R8(j5JPU6$ zp%F~(PVC#4MDLS#6aOVFZX@UjIx!)tEpG^6PW(@y*vilRk+&%tNv_0*W@rh@nx>fm z-WLxPDt=N^WCn;8MmWN)Lcj4Cs!ZS4^L6~w1`6#p8(?A{H*L`LO&>DTKRm@(r`qtC zcv`nDU$?f5%yZ~}*C)T8P7z&h*?pvTdowk7hepw+-7$L7|2@%Yj8 z-pEUi3Go#KKFlAA8v$4g>V-yx8!OMk<^swpEqDlE-t=H=_^6j0QCYCNIha{^o8QKi z0q*o(csoyZ$!#q!nIV2^m#jG*# z3jx#1*RdcgEAsu)-AuFU{84IwSynkG^%x>2aY&9|QxZ95+90tN{p>v;+_n^ePC-FiqJO4ra`j!P)}Vv_6qddudYQSInHc&n zB!_&S1K1zTnyZ7MMqtDX8vujff}xZ)onQdH`tc@nQ|J5L*pVaK; zPMFr3c(p?v;rb=aYvX-;9pCN!+j|9{nuI<)DghdMSgIa#a}kINl0yr&mH5-*Lk5(j zn0py>hGI0ug602v1iO#$%NOPs<566+gkrny?B=g-_eNE2j{spsIOa3)Gjsdu1?@YS ze2_G(!u^(SM*;K#Sn-2^2o`gz@_m5P-9T@jK}d5{^_G74rcncd^J*>6DW@Do+-}OZ zd0t!Dg{zeXumq-~-ndRde}W96?(}YPS!@)QfPH)PR-)8aAsaL&2*q}o#Hec%tg(d$ z(@uv45b3`TvD6^RgUrZ?7y>9_%aDu^*1v|4HNX(YT;mX|xd8ClS;~uf(+&TQ+LN)W zj8wKzIe>})CrIxHjvo_>1V7?4xuUcq$0Qs7lJb0}Vl^isxF+43rj90u6R@#nn$>a~ z@>&?!dE#B`^F)2BTP~x>r5yjKAl*n}q}E5e`sDnHFKAFl7Sq~axEp+lt2_~ejkr1; z$!Ko*oQVMvrS5=OX<$elkAE35*aq7pz!^<@ zph{DP8Ev8eKs}r{18`T0UQ))k;~x9t=)>0Bp(#pu!LwdG%50SW^g5RDSgv z#A@pYB$d}6v_|#|?({H~H{s$!{Gr1rW3$N3v2-bPhC{N!J>hRwjBkqq7e#!Jo}mCM zPI&%>A|OhHy1vVi;%j}Emn^uG*(70=wcj%mM!95@ODrgIK>sPcHY0WC+cqW>Zy&HBpF7!SG;-8JetUwo zQ9%UU=)ywO9=9p1PLWZi*Ux{iFR_a?`&~N!{kQN*_@0mdilyjx4SOPw2Bo8Et?1z| zY+TYuAcEpS85*x2U2SSqogROkHxa|m$OAesGcSaZmDS2tK=@OA`MkIH=)54)1`~7tjsI^$($< z*BLb<7n$~SIC|CJ?C6g3a@t4hSQqMKdRzlkVtxlH#d+_@2MTEEas%s125HO6= zhr+aigD&QR>FEO{a?Z4Y9vr>d^Zrz|JpOI?H3c6^Z317ln=^y4^%@6#np~)+-#*^H z7C%8zyw$giKoUzkk4D0r{5P?{ZYv)y<*zIqH^he{t5)F=uHV|*Ld3Cb!4j}Bk(?cD z1pW|$znnpE2fhwtFN06K&ONy=6%7-nQk$3yUb5Lm_)XxdpQg%BQRL%-6oh}h6Zk|U zYWZ1&EmbI9(b)Yb4q6}^C%W=2^XU_gG0jwIY z^3yTFB6pFGQ8Smn@-%6#@k<1>zP?PlIsTlErv5b>UdaLo^EJ(|{nb)}ysGvc#qD2@ z=74G-TXi2gzy`jqWQg<747<`%RKnsR<)1=WpN9l2n%OJ`;}eeQhtT(%Q-H945w!<2 zS15kS#PBIhUdmnl%VGTfaHpMn_o8GTM}e=|{;=6R7EK#;vdY^WrY^i4^!L-Ff{o|~ zmyF_IzwPWlt@38(ccinyFj=}& zB0v%U>5Hd?e4rj-zA(~9HWT&*HMNd9oUgdqpNYg72^;Dpm+7)l#(|Ze8DO%nNnqhX z>r8hhU8aL{1$z5^bf;cmBq~A zJFUwv^K4G!VjqXVB`JMip9?8ga6!MatY{e1)Z|w`o;nRWHE0S6lR`Sm<97_*a|h<< z&PHKjR7J0FK>*yCDsSPjrq8XTdd#1@m1eNUHt>b%Ja~Tq-oZK)$Vc2ic9cr&yT`U_PuaI*)_aSx_`NovX zzFtPlj)+@9*?TZB;@=>`QBe+JG6V1@tE`l&uKgZ}3E_DQ>WJ;?_=(8kpT`ByXS4ou z-$48g3Osom&givlUMB<4efRZ;wm&$G^&jZAE@A?3$A zD_(=`xN4q%gpJH5EKC|Sio&CFo^PfVFY}qxVCtCo@7^u8($q`|#FQuyRb|-eszQuw zm${2k=T=uZtkqSeq1!FkROn@ z(O-~jE0(6P^S%VTUt~%%_rt4y>&d4@&&3dt3mCetXd?H-wzB8KPIwY1M z$n5|h_T#syf24tA!XvXF?_e2ftbW9{I)=n^MkJc&&>R;s1n23AD$hSMMB^`|@;mP_N2!>l|rYB8{wL9q@BbL&`!A1PHSL{w#7aHYD zfr5-TC+{rs51C-=&l}>?FlF~0>Er8F9JPURdC0t800K%EH_&l~VCbf8XEw5KA;z~{ zZ4QPik+A-HOEgo!Og4F>eJ-N!*W?zKQq40z`TQ$6CTjSRAv+1K zTJ@8#G?@AfpVeDEqHw7C=z*8wEdiMHSK;&3XX<2gYUBWke8=53tnX@#4N) zMPvJwoxX0uap|Q`9+??{OjqeR3c6R)alT6^04)@uwR!Kiq7Q_dTlQo{ukim{RwCkO z8*?7(C0xReEf;rAp=CnO?D_{%J8BHiNVZ7^O-svx{mJ+Ga(B^<4edXn7dCU1iF5o;_?)RPiM|g4PwX5@EdrxBmi#{Ls}#S1>LXw zunwK%2_NM_>nPYa<LiZ2}Z7I(DyXV|VOP8CPH&c%P}iYyxUvPP4@9GABRptqx6*G z0LM_)T~hFh-nh&3;^|aIhbV z!qF#{HVBg`Wv8BP5RL|d2!sz5b$k&(mz$N+NRw1}ZpOICVqF!@G*ah9sB{PO3D~8iE z1bH2_6wOZ$2_OdlS_b6|XK$0NmCpBY^+15)m<>SY#56!S7}B`!GaIzhdF6JiB8%*~ za$|{b^2J<(B2saSU_(+SR>om0p&hJEl4=7m9xnyWaxIgd2~Qq)-9$1KYHywXF;+Q0 z54P(E(^8D3jWK@QsjmD3haQR@(oN{(o(X!21B>inEOM;!n-uY0#4mGFo6uw{-yK_A zN4!3w6toFT#5L=~KHi36;M9MCkt$Y?0g8bzc2IvFYI_)93h(lvNh7schbsNb?tdQ~ z984q1z$oEv%~}#`T%;YJ-A}#h$i76S<$zIZRs)KG_IYZT{f_IMDK8e#pjXmDayL~u z;8#kLwz9-%xexaDXu!42KXMm*0Fc~F@;q;`Zipn!ru~ccKSScg1^jhiW_rDZqJ#7o zUL`V+(lxn^vUsAnGtb!J&jU%#5pcHjGRbsOQDSdx`^$QLyBb#qsg{;Y84&gb;(E887J>1Lweu-WOC%ju7ELd%g5AVd-rA07idNG68DF&+gm`Y9E=WoTm;w zR?}P;`C5p@72=A6`(GZYs9CK)%>lv88cdmyor%ehZsKc20rH&`Tk@2<=RG!@5=4*3 z$etwH;o9O=(8PlyW}_bztQBH$)>s7f4V4YZj=B&z26Vc?qagl>76oR8)c0e&zbZNv zKF&;TD9X_-89=)OPEMJ%2>pOU;vE40pez7$z+BU}b^i_}*@9y%^$=gM)*WlI%x0u~6I9f$LA0CnE%N z)O=#(r<0J3JNb}J7&#QUAveRE{X8rz50a?>%{=P9t_*ymBx%IF}?6*p@VNUjO$ zf$%7HuBnf<4)o0WdrL{fpErIT&hD9hG0AS6Qam(RoE;uU9ewy~YC7jUw?8jcGnJ|> zBUY;d(ZJehT4id$xh@7YdGaDBy#!>a8O7y1(UYxXFv>cfQ?X~P5l^mu>`~@0@H}s5 z@l9+t?@v8HQH&`zmtyH=WOVVeJXVIRcYO^ueGAh4MOdx~e?#rgMybx?XqRasY4;cd zY}QyRb&kD%Wr8_3st_h*0_04ZB`NSd1yB)8#Y~o#r~8fs5WjP!W)M+S(sINqIk50D z8zp;$)4#Whg@7_X_+Vz(WK|eFkk|N*vzXTtuFEQ`A`~2~^72{YXQlqhiRMRfI!^C% zl0%^zJ39wEeSiL&LE1MFjG5kVcV?2TJ8=2O9|1B|EaNudpdm+t$hl<-qym%h#{yYS zcR0vJQ+FCrs1-2_1y|n}^Lk&1&i-v4{(I0?_F7}n=D5z+_qcS~$lN>^2cge0JBvOT z>P#?OwrB@4mH&GkSTB=#_>nHKyn+YOyEJDEaSjJuxAuY=jV!#;1{b3$WtGj2hVNc3 z^3jWr5Z_=9hng*hfXa)Lm2fI4f+OCU&q*x@B5wN=ZkJo6L6hWBQ*+x=mHd&>U)&mc z59KPB%lzSUYOsiyQZ6^EqF*r#i7y@@NroeM-l3uhgA}op#O3icshspDR&~z(o`ea9 z$p^g`vK=%Z(+K%FY*E8KL6ZyOchUn88%-z!^5rIEy5087 z_=yq`<5Md>-Qc9_yS?qhhE)u|T?>z3xN|R)_j($kP)TFevdkRe5aRPIzX7*VMM~o@ma*_5OZC1fJd|( z0*kX%a;F2MeL1%9VO$!zws>eZzusy#F9K&+xGz?OcKMi|^)9+j(@-kA_7|VUnH&Wu zcYIM;YnO1Dcw59zI+TV{4gd zHQdG81R1zX`$&?~_O?$gEqr6&iz}R7uKjC%{VP~Bko}UU&N67hR`pU(fpz)ls61D{ z#(VLm*|f~LtcFFNXI6PhkR{Kde?OZkl$N>>rDKw#3?6rNBUqrHvV=;o`}r+ z(B}^SoAh-ut>bF*BI)sJ#r*fFdDo0l1sl26qwp3MA%%r)Sx%+RT&$)smzeH|5jRCnE!}g=vQJN+g5cL3lN-rxBvS3?lNYPjI}=J$ug=$ZrJvKCbbURE0>b!8+aKBtxyc~8w_jK# z8-yNjV?wTt0F-`zZP-Mq_zXtoIh#Xy!3DQUnVti9;xa!7)Pq+%n=4Ss3iyj(X(5be z4H_$M4bHv}LyM`yZ%7o(`efB1^}PcDJhPiSw77?{d=2T;__p9^dC z7j#HY5<3!h)NGa5czDdmL=|s1y04Z|07e|}+0_r;Xac|snUHKx_!qKmj1}z=s&NDG zNte#NGE-18{^@fV^K(mF^&-8$tmqPDPu#TXlv2-e)P|)9A}(s;C%3~0kJx59)d&wC zpH_}+OEuPnJg7v943mCjq)yjA9(ZXdRnxFEk)u3uo&MQHG({P*-}ZV@?>Df2LveBT z^~J}h2CN(gqPpZc+{=m6UqiD%r(nqHdT-FyZJ7gt&|b~c^N&0au?)Zb28K}uY~%EV ze$gEwHrk>iV7Qkp#;syQ;U_>JLRy0Evrku5)J{v~FW-AM+*m%9Bo~6iie(r0B2MJn z!ucX#JU_s{dAZjUoij`92beqq)TX_=VB2V)GK}#G;uvqaO0AedmcCzj#+T8Q$fClaxHT-NLb(hS6=Cmk3 zFW9K-<)%)cZ3@Y#II|;I`LR}RiVM>;=x+K#kB{z(HX>l+8MUrBkbwPZ#ZhB}veG5> zO{vYrsDO47yqO(83arN&n*udN)H4JF3w4KUrVfkVaYVBT9;9puDT3|GcZGeJ5&C2P z_V^h!4kPzi5ivDC2PS?#C*pqolRLh>d_(I&Xexqc@`h@JRYn3G6)kBcyqB`z*sgu> z<;#3{+!Ah3>+nn0H^`MEUY8DMjdE4-47-}dqmSMN zSwdnvj3QpHHpc*TCvnoMAKC6jjW7e32lziWYS>@-G)Ki$`;L2|hyUbfmg3)}Q+WVT zVGoaS^nnb|Hv$5uHrjsKyZ`lA#?R&iGhiI3lCo+l+3E@&OAhqnbHOWNKj!Cu^*?@q z4t}EIcvT{yl$hL+z81mcnMInjTIXW5>;(Nexg%WfH2>1G(qCu5lt zw=kn17j$>2Cmu}o#;0EzX4cwZvO5Yp9JB=lwiXJ*Oicfw^e$tG_bAP zBb8_#8xG2Xl3quh5-U8H8bh&CWl&|MkFaKBP-*k?iEmPB$G_}e-aho zY1s+)H;N%-C1MqpQWZzu451dxWFt0#{l<$I{nL8VTKpTvwPgWat)R{+8@cSCOWYcJKCy7SJs&oKjh=>8J}H=1W=*3D6~W(-s~?dB zzNbA`=z~h8Fz34msL}zXX#_>STzf*&HHGW7u3X$HM{jl1A0Hh@r}hp=s%;fg zV3z}lq0fIP!`D#052|{e&5mR(?%qwKvo^}%e*V0GOu$_v4gHu%S0!s55fwc~^2HjX zd-R_=L=0lF2Idn#ISI4n+lV6gR&{(bNbvY?*^S)o&fQB>yPt2lKl&BTqEu@dmigKs z3?Y$5a2)UNXYy*InDV}}6+rUPy!d?>19v6Bw!ojlD?+Z|@vBsA1v$3Lf-+AoQAA$B zcWsLhH2o36P|zSdf@DsCuw0Ao_kXUkfY4Z#linGHZZ zlp>{&ynH){a>g9Z4sVOUEG{5f!yRF0gg&j5eucfU;~bYfKHU^b|! z3j{m84s>;!;xjs;?5Thac&v8G_p>mDX!B|`&R5(_f+;Lcf0($grUiqUF%8Rh)+cA% za+NF|Fxj%ZeV;0apvJh0GgVwXMm|SB%xAlZ(WFyd$M=wkC(M_qG$lxrD+aOH#xPA^ z*dpEvJQ{zsK;VQOCMI<9Hr1xt^<7`nh$a$ACWg?; zmC3oiExzxj z-diyT3?=xeB`PXXybvdUkm-YAxH}BNO$z!EDrlw|3_C^kzZ)K*ouH$#I_)U ztF&|O)#wZZvZN^r|KY_Oe~2@+`}Are``Az5h7TS(R~k@7(kT{k+A+L7$4$*7rc}|i z6IYPVrtjHv6fV3io%_3OEscNeq8`Jw2`5=gCRR}+k(DO$eVl9YJX}h9)x~NdIOiMh5np^}gP(j1C$Z+}d=*VaFXoFk62dQQEPWn++EGxm)#lxDRo%qIANc*M zKl*E>M~hF^6R)Zi(BicFJ`sH?Ll}}UTl7+(8_#fnzIa$BvgJV5M;PJr5kwLdOxR(- zP>W%@47(yB7t%QW%Lh5_6)d9Uy*^LWsESl8cs@q}DQgG4^-QzBzasrO`&?qCL|lKdsrIV5}Xa zjD1-kO1@zYCA&|$RVc=~0Q~X!k~Fm?LGfD6lY`fLF7%CoFWx*}_4Fgx0Np3zVdEMv#*4x^Ut`?xc1={TO2vQ z=0ph2(4%XeajxE$F(Hl)Cb4rZVHDl0v(5Wt&2!m{X0m6_!aIVj^S@3{r3G~dmFK}_ zLwuPONA*|l9T+)|x-c4XV(|Zd4!1A-3r>G0YUo@hX+79`U7+W0Kuib?e13aFnj5@F zb=OxLU6);-Wx!!!M^#NX6GC0n!ZZK*cE2Bjz3b}kuwcuP-GtSyh|9{C~!B`=brx*!ypfDn7Vy-<)G&|JqHB0tM%JS5P zje<(ekG|^H84TcKW{+X#3cl$>S(XiCaz*|M*>b&2c7RODz2kuedlj-z z_6+Bv&H030 ziaH-~wIR~X8~&tsw`WsX%3(u?i3HH)f!=SQhPCKInl1wSVH zb(ps!+dcC*rNhm8g>Q*>XN-@)S65V0PPzY>pX9$iv}_`duqXuiU;Nx3IaNESrH_%t z=}*Ri8{Ht1WVRc(IxE*{82di{;j5ZREH5t_p3iZvrmFpY_)&HHS!t}`FCaacZmk`i z0Y=7{PNN_`N(Ov-N{HUj#AG4cN*ND6rqN^uzUB{7x*1dEZi9&UF$7bYpRlUj<{ak4 zlOWQHJTt#}P8IzbLMv|`O^OPB~*2vvH>0$tlc z(G7A7e6OV zvsd=khUAMrw&9^@>7>?werrmf`wC9fKW&|qK&t%j?)wqHi_<{=Z8wAI`pWxOdU)Qq z3ltCVj23I-wZ%=*(pb^fCYgb?g6O=Ws-(*L&sQxkYF(^!2X~4xrw-Qo3f5cWv5$LK z0($5-g9|kuiB&k%D#0^l%{f#Am_Fp0k4s4Vez)y{J~?<+E5!(qK#go*ueTDkv~iTz zDLl^q`m>tm3rQ~0hbr{cWKEv$zFxofT5 zfxN^jtXHr8e2w!I-`v=VuCIpZOMv`@d3o8ws+oCtG<9^z^B64H6Ef}%|4xsQ@mG50s}Ki0@91s^!YYFHD~_ zNlGGB#2z?zJHz42lxea9>+mlF*Dz#*)L^Z{Clp|ytaDmtBq*)(n(tZFdF_+=$c-QP zK`q?Hmx_<|3FVTU#di}xAZ+>}w>w!`?1EiE(osDas zC+GP6yFfFL3E8 zC+`$qoRa|BCBW}uvg%UmQLcp>^NG8Y%HVd?EctLVdf3B@#r5k;1jxgI+_l#3K-LP7 zE3>dZpT@a=e(N+|cNU`m@NWQ_ANheaSl|P-RlBDu59Y}qqYv74Q~$YEObNlYx3rYt zN^F%m6Yw==@{3EWOf8_i-UQuk0vK zcw`{!)5-zza3J@pYZ(Y`VZFIIM85)%PyP`gg&B41Zox;@mg8BCU+#vXM|qR_C;uFL zY-peIZ+TCY;v(6>Qs>&_wQOa>hbXjE+G-k+4gnnr+ZbbG*sF1efC$MB&KbpeXw1%2 z+jpE*agkISQuMKn&@oYvF_{b@l<4py#hK3ka_f@jBv}|WAaGI&&?7)b8$4L=RP^|_ z3N&3KsiomU;}c4dBDhUe#-S49s8@&L&FY2^-NwE(%6fqeeU=eWMV4IssVe03v0 zDnb^AeQe8>4NpFibWrS{9modN$8AG5jgP`cNY2X*ryJ5w-`OWeg;E4In=~lWBMtb* ze9^JA=fpG((#Hm?3Gm)RjJ~lw0^w9(0tvyvXv^t>oV6Vltpu0!-^uXghCJ7)dmcY>Z$ppBZ(bZnsokU7on>E@dA_ggi2krxj}D0C_l&JJq#D z!e8=SZSweD+O4(v8Ek+5l7k><6|_jhlY2fh9J8*3ZI}O!@_~c*u`N4lY|A;$&?&G z#*{Y1dQcQEPN^Ve55j9^j7&zgBc$j6j21+T*yeD1wIrd0L@X4v>{QkkwXUT?NP+JQC!#aqbc9JKv&i1W1j}DL*;hymF-3zB4@i zmG;A6QuuQEANUBSRuFG8K&aZqt&bZ!$Yj0FCMNkjMNzfEZj=xJR3*8Mp`j!;V>Sd3 z`lgXiklijxr9>Y$Viy`1#0fyU>_GNo@ZiRX@1-}v@HCo{rbJ_}6$wGJ&TAbkga{;o zj!_D5N-Kd>=oBtAE^0QjU5dhttXj9bbRR|fRMmZ)Fr*4_3+s`AtWPTk$iso$sjd!F z%(`KeNd);#Cc(E~-IRe8eAMKea(uzZskZR`lTZHX{e28ilXm-wAU=J!>En0J5E~y^ z9HN!pQGNgjrHyyo$=1fM+rc)XE$IynU}6-0r#Ww|4?czDx;`qMK%|{KoIF^%K_q@O z?130Z5hu!92rQ*G=tP7|RtB=SOe8JA=~lPMj0}rH453h>YB_NCx$UDMq%h>HZLm6z ze4XK=IFC6$9uDLIkUP}c9mrY%^8PL3+^<(*MG%{EuHfJ7oll4xRUF6Nu4~m@TeX$S zmZCA;8c#ObFvILbaF!7!2N_YMGzSSm{6p{%QF5rUw87#<(ZdE7tQSF~T9$$!;zDN+ zp1g@SFTtx`J^TI5ZzjLId9UflUNW=$&HQ;uR`B&@<}=^-`@Q#i?XPD5NH4*MwT2R7 z!&1W_;7K^TQ0nvvAQ1pE7!6CC(WpTVWXtu2=Y!^jsNHE?Y$4&+>V&rA*ik3u2i}E) zR?ryIKo4>tcBgEiziJEPKsuF%-8_#TDks`R45aUQxbKGz#{mFhe$XC7TcdI`DEk)i z#Orvl9{nZ^Mza|-!@$RX1WI6cd=d&9%nkF5R{)2^KD>Hnty&Iui2IPtD+zt5QhTo& z`xhVw4kX_yHbC~L1DRnxkbb}UO#5Q0TCdh7fLz%dK(xGFymj$j{Kxu;0g^b7QGWn{ zL?f?V>x>+4xaFXK3Net?aJW$pJ0TIM3i z%}xzSIEu;&Kq3OjsE^dEhSyHgc&$#K7U_s000b~94;-smcCA6Pxrr3oP2V3z8+{6X zH!RDgLFK+{I|0whOY@fCI3cD2FcEC^yWPO@6S+VJu_QJa8atBJq5z4+eqc8&bJ@L$K@6l+KouMy2M#2!nh_xX>Hz6C!nKQ<+PxkS^2wb6BIZL8 zFY`fQaP3wMkS=#&jTj)qa^IpqfNdB=HMk7`Bv{8Sx-|?PJjIv0tyYBic6TG}2JU*~ zSl|Iz;gWduTHM_olRyX@D1Ly)>bbAAL>Z--%1mD z_V=r6llaJRgj@lILt5qY7fPFha|DpYft-urKiuFMr)Ce!HHvl&wmjT4)PL0=FaG=50z0|kTo*x=74>q_WB_%ND} zP_rH;@4@gGcVR8;Gk_d8kbJAy0NIxgvO34It;JH7VlW#B^`hysw8 ze*X1Kw<`EBco3Rvmk5FwNUSkHFrb_Q78X!2jM^5|sB_rd#R1}_&tV=M9I_&G5MY=T zEI&OmIFg_T6@?#o!}thD3PL=3#nLC-m0=%TA_+p0k>+vHv|f}p>6J0~!MX|k)L6Rr z-u(s;av($y+=I@R3Mjfxsd{gmeW8c|nW*0LrQ)fQ)(=krg#yTg1NrLXZ&ZL_49M%3 zc6Lkvk;u7ad8_`s2ccV3XfgKY;L zMZyp@^D3A`NE-5x0yaSixsMDzaA@5&_A%y%P~#^On&!qM&`AQwev5%X&z?Q}bt;)0+4er{_^+bi@hFU!@}ruMJYGvWMgyTHfSmn(V#SN2_6vm zW0BdIRA!-b%E-;Q50N0mALGMUM3y5hiTe){}M4t7|q8^2#e?fIRibFMnTY10O8T+7*rGW0wU!yaXVa)O|GSb~j5M z#s>~0H$@0>Bf*CNL=YnQP!*&@KX7I_w6Pc*$uTgtyW&j$AmLS4MY(R<+kjl!VM~*!7!2L@EOsd`DQlS8{eC+6vBe=0H zQhRdi6$v0{zN6H9s9##WLIFf?zCr;+ns1R>4!0o&h$QT8V>;d&CV&7Rb@3fU3qeTQ zcZE;dqS{)uefibv*JFS@``hn?kD7>AjneUfjn(!EAl=Q)bCskEabVk^hlsF|o{1eI zhmQmW!G{qc>^|_9ng{XOX!sgB_#}C|=F}^hwZy~Al(?IeCfUKzxCv|^U=Ej&_>AMi zjEt62e&F|7WPsq8OOJE}j)kORRJVJJ0+8inkHS#l%3Qivsb4_=a=Yd$3P8B|n2TIH zsb2vAqBI}XjITQdAS^hLZKDI}H-n7jU}B{BAU2Tkh<8EATJ6fK*T4Vn=ih$)WEJKk zE22S~y({h`Jpmy7)>~4GN|zmof)Ezr!;BEz>hZOfbA@A?w~G_xWZ*$Zb{NKiA1qVe zZk(~3=I!bta_||V1Nn_xEI@;hAPnQkWLRRr5nqPoW zS4Z5FgGQwGGgJ@t%P&BdsiTqWr#GM6VV80W5H#OmX+Gnxb1}~V(VI^i&I}N8AbJes zM!$K+95}D`7$LT;kYfTN@Ap<;yZ+ags~q}BcM;Gb_z*EbE;KK0RW@lskZz;3?l~$v zIP`(rIfu>#9rWS?VZrP_IAb>rm^(T>00u+euE!fNfj5j0)3^^AKS*T>fP}1F77?SR zG2@Vl8Ha=!DKfM0BBvWG_f%!>tWw*g4=aZNsjS3TX3`O7tR56!sd)s* zo|+Gbg`5HePvm!MK5QtY{LdFarZ=CUagPpU=hUS$26pg?TnGXi2|m;=EIw7wocRHN zVoceM56;t0iVu|`*1G4`)}j%jAdw$a$I8k{#%xFrmczRf?}3k#mUAWe@U^tvK=O8R z(sHgc_%P?~GCtB}Ki1i8#K5?^5?(Y`Z_A zX>nakl`Dx?RG?CV4mvP5ByX1xBJ_|^gKEwd^FvR(LMX%&eAMZk2N@6|^CnVoV>h8j zxB+C`Ju~=aepbylKq@QgBM<5~?aqS}Z~QJV09i);xGP|q;ozfEzkC3svI0ZJPpq>w zUrqqBjOrPiZ+i9e0+5-nzG(mv2NKic+86I#{q~8s+qcCBTtf^A6&_=J^eihbRsjfA zwuC;Y#>6WIhKdiLLmvu4(qSK3=-h+2uu(_B zlyp^3CM4Nqg`t;(z=atmnUNvPz^1k(HoQ#AUks#@^sz3X(swc(dadOdZ(adHUF4Ls zvdFR3Y4y8Z7vwwxgqlx60JAqA^M7suLJI$l zZy^ArT5B5y4T2BA2MUA`{E0|i>?4hJC>BJGoYTA0cq>ZqVS_-Yo0cspS1dQhhhgN0 zmUtx$(MJucX}f&l&MSSsT~5oQa$Ky}$!F|_WHrLw5ZV|sV@e48knS_k8e?P#GmMRC zR=&Eh;w*X2#pUidb7kd`$0YuKE&)g5F>apHzteY4jOA5C>2J3B;>4?p_g+eGNXq6I%Rg7j=U#li^`U~}ICnYz<2R7`g z>!3NUa3Xf#H7U;6jgM;LF2KR;AmQsQI?^*N1j?pSA9Uae+cVDNIT{T}T~q)318fj8 z9wTH-XNEvSh@mnA+Z~y)PzZojl3ZLokl*g7YYG8~=G=jtTV9ba@~MVn*6Pg#Kq{G3 z>U(BwzBzXwlB+tU`LNIa>zoS*k{FH$CBku6%{RRZ3+ti(xqa!gtDpvU0f;jEyv;Px z^LBv?q6XumMupUUs0iUn+q1(y1R>Z`eCTp%AwVmew=3CKfhVzZHSda;!Lf11hlJ2m ze0V%~@VQuZ?xG@XsNsz1%+PJdbf1B3cI6@lLOD6qhm3y_rsIqefO&Ty%aY6)|KHDQ zIOg1e#Iuda6Zy=|H}4K)vLlYFpgWFK#zd8QcOaY*$5)@U-rY8zq+yu=vIByAeub%V z^#ctc=~P#Ui6`zuhX{F!TBh$x6?H@k2K@I5i%}XHTNH4XuK_eR({4yd9`kuG0 zG5~^D`7lQ{pt8*5tQ>*VHV6=8IAEW28!0@8>~;i_x^Hi7?sF>#g7$`p7gunf+Yt!6 zk0;_vbDs_nTJ7;|EXWY?uj6`{rp|j^T60dAU|{Ic2Nz!PNi#u6X5DUlj!;7vpb=9f zR*aCyY}ZZ)DIo@Zn#(?fAuU2i8~F?{g9Lb-tN?R9zQDP3{i4?8C_=T&gHzTz% zfatZjs(1=uy+icFO}j5B=swpYkYpxj`|jHaK-hf;CEb1Y2;}YeZ${9e|4IN!QXf*Z z+wU3CN0%23lJL=w1R0b3Fo~Cr^&mW2Kn40f6vE95)vR9F}SFwGYwP z1`w?~rPY1qn74j_@I30)@4gv;oP=i3AsXN(jHj^B@JjF2&e4WMAALRZfxj~`q;8i_ z01tEFM_PEr{Lq^1O1pL({fw0#JbBe>w$At3wyDx4s|EysdA0+mIsL3 znYRxpR?aHs4CKkPctq!91VUUqz?0`nc5XGun_S(5`)aEJL>{bEGG?)_^lN%;0C|$Q zZx8OXkI2h+9|L4+f}4D_qFAnIZb^$4iQeIqd;eIT4jTfZSi!JaFTVtLDwL zb(lxJ!4+|qyKfs;XS!Eb43Od2h(W&20A#@F5Sf=x@}QahUkUIcu%E) zoZUV?-I};>cJU{ylv11K!636@Yzs!p6Sj7}xOvi@GCQ7fz`S5d{!2yN-lBM_?-aedLI$1{yhT(Wj4X(x=GNA)T@gc^oJ-ONQu>1(0TjBVGKboEg$( zOHJJeK<0e%i2E$@q9g7LrtZ6u+dNJk&o$4b%TooZ`yS*3hkgGohM^PYvE%TpJ^mG% z1mO>Qjfca*N8~`V@WCJPia!G!TIz$}_310=c$I!m34%zYfmmb0*odMdDVtiM6Z)KX zQ#;5EUFoiNS8anJ-t5@kAJ5URDd!WG?#%hcoPo3UP2IPj%YA!`-KSi#F*UDta{>3c z7fufI+?qU?+IP4h9=6xwx|VWPQl0al9){tsK`40-Dc>Cr2g4yK!V!qzL(iOZ{S~z? zF_wKuyY@KO(KDitD8f6`Y&Kh+cB92=MA6Enwk9)zotm1;D<#+PoyUf>&5jq{nGOu; z=9vfkuHL+5SZ8iE?s!0DN=*rJm^otI4fnyk%m`9Sjprn&+%_+m*_HU7{qD0|o$kbo znM-)DKX_QLhXcZhXov&!7>{F)AP1tgzDnuQYbGsA@bk>*){Z|(<{TeD$Sgpbjdr{7 z>C>l1tVozqv=jQ`9hY2UclqLLm~>kb&D=mvwi>V6lSel%w(r`_``N{uX3dJj0hOt# z`wk5E*&3@>$$jyCyq|`UT6fB8R`ZnW=8^ZNPMMI0kLu$P zqA-L)kB{F79$&|?>LKUJwdkWaivJ?eptXY+w;Ci#!^Ei70y6&o{o80Xk%_qm;*Dt`CfgZqdZ^EcwCkoP3G0znue^%x?<0finkb%g`35D^Hk6YTaR z_aU2ou;>?VwJZ2wc67U4Km+=O^v3F?wlp)f%VkrdH3!lVK4WfFcfe{$$uo%T!%yID z$=F8R2L;a0~m8VW+?hGn@v^kV%n0Vm?~p>&+QCAA@iIs8QYBeAXQ=W zf*p5XFxPzv>#OQMH4`1z5{N(yks%l|7$${SVGIyK2;O=+K1L(rMHd=%n`h`Y#mulS z&nR3rCUSZXWCsA#*XDv0N8v=M6+Cvz<3NkX;qBl3Cf z+mV3d(wPStS7)UXIdi0h{hY>1Ba!O@kzq)x4@U9oa$tkg8K4G=t4>aqS)O6vq%ZL4 zj18!2nd4mA#buwD)qOi|UZ8gMI%NzR5YciX0Lc62BT}!2IOEYHAfwnWeb=m|wm#1A z@)YsfdF|-csRA2B@OBJdNZHg9OZu`)ZSlG+U$G^zw|r&rErFd3jwLDGee_5s`fvxG-ZUyV`nrd3kx|tcRG<+(j8U z{CYkwFE1}Ik&=`6wL6P?yu7@;yh@Og(@Wpc*2~Mw%gYxIdU<(yd3kwR^&ehjZCZNk Rf)M}!002ovPDHLkV1iLt;#U9w literal 71830 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 z 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 VD-eY_8c`se0*oFYFav(R{XfhVtNZ`} diff --git a/en/index.html b/en/index.html index 20b93009a..891a0b8f7 100644 --- a/en/index.html +++ b/en/index.html @@ -1491,7 +1491,6 @@

-

Quote

diff --git a/en/search/search_index.json b/en/search/search_index.json index 3fe6582ad..8d257fc34 100644 --- a/en/search/search_index.json +++ b/en/search/search_index.json @@ -1 +1 @@ -{"config":{"lang":["en"],"separator":"[\\s\\-]+","pipeline":["stopWordFilter"]},"docs":[{"location":"","title":"Home","text":"Hello Algo

Data Structures and Algorithms Crash Course with Animated Illustrations and Off-the-Shelf Code

Dive In Clone Repo Get PDF

The English edition is brewing...

Feel free to engage in Chinese-to-English translation and pull request review! For guidelines, please see #914.

Quote

\"An easy-to-understand book on data structures and algorithms, which guides readers to learn by minds-on and hands-on. Strongly recommended for algorithm beginners!\"

\u2014\u2014 Junhui Deng, Professor of Computer Science, Tsinghua University

Quote

\"If I had 'Hello Algo' when I was learning data structures and algorithms, it would have been 10 times easier!\"

\u2014\u2014 Mu Li, Senior Principal Scientist, Amazon

Animated illustrations

Easy to understandSmooth learning curve

\"A picture is worth a thousand words.\"

Off-the-Shelf Code

Multi programming languagesRun with one click

\"Talk is cheap. Show me the code.\"

Learning Together

Discussion and questions welcomeReaders progress together

\"Learning by teaching.\"

Preface

Two years ago, I shared the \"Sword Offer\" series of problem solutions on LeetCode, which received much love and support from many students. During my interactions with readers, the most common question I encountered was \"How to get started with algorithms.\" Gradually, I developed a deep interest in this question.

Blindly solving problems seems to be the most popular method, being simple, direct, and effective. However, problem-solving is like playing a \"Minesweeper\" game, where students with strong self-learning abilities can successfully clear the mines one by one, but those with insufficient foundations may end up bruised from explosions, retreating step by step in frustration. Thoroughly reading textbooks is also common, but for students aiming for job applications, the energy consumed by graduation, resume submissions, and preparing for written tests and interviews makes tackling thick books a daunting challenge.

If you are facing similar troubles, then you are lucky to have found this book. This book is my answer to this question, not necessarily the best solution, but at least an active attempt. Although this book won't directly land you an Offer, it will guide you through the \"knowledge map\" of data structures and algorithms, help you understand the shape, size, and distribution of different \"mines,\" and equip you with various \"demining methods.\" With these skills, I believe you can more comfortably solve problems and read literature, gradually building a complete knowledge system.

I deeply agree with Professor Feynman's saying: \"Knowledge isn't free. You have to pay attention.\" In this sense, this book is not entirely \"free.\" To not disappoint the precious \"attention\" you pay to this book, I will do my utmost, investing the greatest \"attention\" to complete the creation of this book.

Author

Yudong Jin(krahets), Senior Algorithm Engineer in a top tech company, Master's degree from Shanghai Jiao Tong University. The highest-read blogger across the entire LeetCode, his published \"Illustration of Algorithm Data Structures\" has been subscribed to by over 300k.

Contribution

This book is continuously improved with the joint efforts of many contributors from the open-source community. Thanks to each writer who invested their time and energy, listed in the order generated by GitHub:

The code review work for this book was completed by codingonion, Gonglja, gvenusleo, hpstory, justin\u2010tse, krahets, night-cruise, nuomi1, and Reanon (listed in alphabetical order). Thanks to them for their time and effort, ensuring the standardization and uniformity of the code in various languages.

codingonionRust, Zig GongljaC, C++ gvenusleoDart hpstoryC# justin-tseJS, TS krahetsJava, Python night-cruiseRust nuomi1Swift ReanonGo, C"},{"location":"chapter_array_and_linkedlist/","title":"Chapter 4. \u00a0 Arrays and Linked Lists","text":"

Abstract

The world of data structures resembles a sturdy brick wall.

In arrays, envision bricks snugly aligned, each resting seamlessly beside the next, creating a unified formation. Meanwhile, in linked lists, these bricks disperse freely, embraced by vines gracefully knitting connections between them.

"},{"location":"chapter_array_and_linkedlist/#chapter-contents","title":"Chapter Contents","text":"
  • 4.1 \u00a0 Array
  • 4.2 \u00a0 Linked List
  • 4.3 \u00a0 List
  • 4.4 \u00a0 Memory and Cache
  • 4.5 \u00a0 Summary
"},{"location":"chapter_array_and_linkedlist/array/","title":"4.1 \u00a0 Arrays","text":"

An \"array\" is a linear data structure that operates as a lineup of similar items, stored together in a computer's memory in contiguous spaces. It's like a sequence that maintains organized storage. Each item in this lineup has its unique 'spot' known as an \"index\". Please refer to the Figure 4-1 to observe how arrays work and grasp these key terms.

Figure 4-1 \u00a0 Array Definition and Storage Method

"},{"location":"chapter_array_and_linkedlist/array/#411-common-operations-on-arrays","title":"4.1.1 \u00a0 Common Operations on Arrays","text":""},{"location":"chapter_array_and_linkedlist/array/#1-initializing-arrays","title":"1. \u00a0 Initializing Arrays","text":"

Arrays can be initialized in two ways depending on the needs: either without initial values or with specified initial values. When initial values are not specified, most programming languages will set the array elements to \\(0\\):

PythonC++JavaC#GoSwiftJSTSDartRustCZig array.py
# Initialize array\narr: list[int] = [0] * 5  # [ 0, 0, 0, 0, 0 ]\nnums: list[int] = [1, 3, 2, 5, 4]\n
array.cpp
/* Initialize array */\n// Stored on stack\nint arr[5];\nint nums[5] = { 1, 3, 2, 5, 4 };\n// Stored on heap (manual memory release needed)\nint* arr1 = new int[5];\nint* nums1 = new int[5] { 1, 3, 2, 5, 4 };\n
array.java
/* Initialize array */\nint[] arr = new int[5]; // { 0, 0, 0, 0, 0 }\nint[] nums = { 1, 3, 2, 5, 4 };\n
array.cs
/* Initialize array */\nint[] arr = new int[5]; // [ 0, 0, 0, 0, 0 ]\nint[] nums = [1, 3, 2, 5, 4];\n
array.go
/* Initialize array */\nvar arr [5]int\n// In Go, specifying the length ([5]int) denotes an array, while not specifying it ([]int) denotes a slice.\n// Since Go's arrays are designed to have compile-time fixed length, only constants can be used to specify the length.\n// For convenience in implementing the extend() method, the Slice will be considered as an Array here.\nnums := []int{1, 3, 2, 5, 4}\n
array.swift
/* Initialize array */\nlet arr = Array(repeating: 0, count: 5) // [0, 0, 0, 0, 0]\nlet nums = [1, 3, 2, 5, 4]\n
array.js
/* Initialize array */\nvar arr = new Array(5).fill(0);\nvar nums = [1, 3, 2, 5, 4];\n
array.ts
/* Initialize array */\nlet arr: number[] = new Array(5).fill(0);\nlet nums: number[] = [1, 3, 2, 5, 4];\n
array.dart
/* Initialize array */\nList<int> arr = List.filled(5, 0); // [0, 0, 0, 0, 0]\nList<int> nums = [1, 3, 2, 5, 4];\n
array.rs
/* Initialize array */\nlet arr: Vec<i32> = vec![0; 5]; // [0, 0, 0, 0, 0]\nlet nums: Vec<i32> = vec![1, 3, 2, 5, 4];\n
array.c
/* Initialize array */\nint arr[5] = { 0 }; // { 0, 0, 0, 0, 0 }\nint nums[5] = { 1, 3, 2, 5, 4 };\n
array.zig
// Initialize array\nvar arr = [_]i32{0} ** 5; // { 0, 0, 0, 0, 0 }\nvar nums = [_]i32{ 1, 3, 2, 5, 4 };\n
"},{"location":"chapter_array_and_linkedlist/array/#2-accessing-elements","title":"2. \u00a0 Accessing Elements","text":"

Elements in an array are stored in contiguous memory spaces, making it simpler to compute each element's memory address. The formula shown in the Figure below aids in determining an element's memory address, utilizing the array's memory address (specifically, the first element's address) and the element's index. This computation streamlines direct access to the desired element.

Figure 4-2 \u00a0 Memory Address Calculation for Array Elements

As observed in the above illustration, array indexing conventionally begins at \\(0\\). While this might appear counterintuitive, considering counting usually starts at \\(1\\), within the address calculation formula, an index is essentially an offset from the memory address. For the first element's address, this offset is \\(0\\), validating its index as \\(0\\).

Accessing elements in an array is highly efficient, allowing us to randomly access any element in \\(O(1)\\) time.

PythonC++JavaC#GoSwiftJSTSDartRustCZig array.py
def random_access(nums: list[int]) -> int:\n    \"\"\"\u968f\u673a\u8bbf\u95ee\u5143\u7d20\"\"\"\n    # \u5728\u533a\u95f4 [0, len(nums)-1] \u4e2d\u968f\u673a\u62bd\u53d6\u4e00\u4e2a\u6570\u5b57\n    random_index = random.randint(0, len(nums) - 1)\n    # \u83b7\u53d6\u5e76\u8fd4\u56de\u968f\u673a\u5143\u7d20\n    random_num = nums[random_index]\n    return random_num\n
array.cpp
/* \u968f\u673a\u8bbf\u95ee\u5143\u7d20 */\nint randomAccess(int *nums, int size) {\n    // \u5728\u533a\u95f4 [0, size) \u4e2d\u968f\u673a\u62bd\u53d6\u4e00\u4e2a\u6570\u5b57\n    int randomIndex = rand() % size;\n    // \u83b7\u53d6\u5e76\u8fd4\u56de\u968f\u673a\u5143\u7d20\n    int randomNum = nums[randomIndex];\n    return randomNum;\n}\n
array.java
/* \u968f\u673a\u8bbf\u95ee\u5143\u7d20 */\nint randomAccess(int[] nums) {\n    // \u5728\u533a\u95f4 [0, nums.length) \u4e2d\u968f\u673a\u62bd\u53d6\u4e00\u4e2a\u6570\u5b57\n    int randomIndex = ThreadLocalRandom.current().nextInt(0, nums.length);\n    // \u83b7\u53d6\u5e76\u8fd4\u56de\u968f\u673a\u5143\u7d20\n    int randomNum = nums[randomIndex];\n    return randomNum;\n}\n
array.cs
/* \u968f\u673a\u8bbf\u95ee\u5143\u7d20 */\nint RandomAccess(int[] nums) {\n    Random random = new();\n    // \u5728\u533a\u95f4 [0, nums.Length) \u4e2d\u968f\u673a\u62bd\u53d6\u4e00\u4e2a\u6570\u5b57\n    int randomIndex = random.Next(nums.Length);\n    // \u83b7\u53d6\u5e76\u8fd4\u56de\u968f\u673a\u5143\u7d20\n    int randomNum = nums[randomIndex];\n    return randomNum;\n}\n
array.go
/* \u968f\u673a\u8bbf\u95ee\u5143\u7d20 */\nfunc randomAccess(nums []int) (randomNum int) {\n    // \u5728\u533a\u95f4 [0, nums.length) \u4e2d\u968f\u673a\u62bd\u53d6\u4e00\u4e2a\u6570\u5b57\n    randomIndex := rand.Intn(len(nums))\n    // \u83b7\u53d6\u5e76\u8fd4\u56de\u968f\u673a\u5143\u7d20\n    randomNum = nums[randomIndex]\n    return\n}\n
array.swift
/* \u968f\u673a\u8bbf\u95ee\u5143\u7d20 */\nfunc randomAccess(nums: [Int]) -> Int {\n    // \u5728\u533a\u95f4 [0, nums.count) \u4e2d\u968f\u673a\u62bd\u53d6\u4e00\u4e2a\u6570\u5b57\n    let randomIndex = nums.indices.randomElement()!\n    // \u83b7\u53d6\u5e76\u8fd4\u56de\u968f\u673a\u5143\u7d20\n    let randomNum = nums[randomIndex]\n    return randomNum\n}\n
array.js
/* \u968f\u673a\u8bbf\u95ee\u5143\u7d20 */\nfunction randomAccess(nums) {\n    // \u5728\u533a\u95f4 [0, nums.length) \u4e2d\u968f\u673a\u62bd\u53d6\u4e00\u4e2a\u6570\u5b57\n    const random_index = Math.floor(Math.random() * nums.length);\n    // \u83b7\u53d6\u5e76\u8fd4\u56de\u968f\u673a\u5143\u7d20\n    const random_num = nums[random_index];\n    return random_num;\n}\n
array.ts
/* \u968f\u673a\u8bbf\u95ee\u5143\u7d20 */\nfunction randomAccess(nums: number[]): number {\n    // \u5728\u533a\u95f4 [0, nums.length) \u4e2d\u968f\u673a\u62bd\u53d6\u4e00\u4e2a\u6570\u5b57\n    const random_index = Math.floor(Math.random() * nums.length);\n    // \u83b7\u53d6\u5e76\u8fd4\u56de\u968f\u673a\u5143\u7d20\n    const random_num = nums[random_index];\n    return random_num;\n}\n
array.dart
/* \u968f\u673a\u8bbf\u95ee\u5143\u7d20 */\nint randomAccess(List<int> nums) {\n  // \u5728\u533a\u95f4 [0, nums.length) \u4e2d\u968f\u673a\u62bd\u53d6\u4e00\u4e2a\u6570\u5b57\n  int randomIndex = Random().nextInt(nums.length);\n  // \u83b7\u53d6\u5e76\u8fd4\u56de\u968f\u673a\u5143\u7d20\n  int randomNum = nums[randomIndex];\n  return randomNum;\n}\n
array.rs
/* \u968f\u673a\u8bbf\u95ee\u5143\u7d20 */\nfn random_access(nums: &[i32]) -> i32 {\n    // \u5728\u533a\u95f4 [0, nums.len()) \u4e2d\u968f\u673a\u62bd\u53d6\u4e00\u4e2a\u6570\u5b57\n    let random_index = rand::thread_rng().gen_range(0..nums.len());\n    // \u83b7\u53d6\u5e76\u8fd4\u56de\u968f\u673a\u5143\u7d20\n    let random_num = nums[random_index];\n    random_num\n}\n
array.c
/* \u968f\u673a\u8bbf\u95ee\u5143\u7d20 */\nint randomAccess(int *nums, int size) {\n    // \u5728\u533a\u95f4 [0, size) \u4e2d\u968f\u673a\u62bd\u53d6\u4e00\u4e2a\u6570\u5b57\n    int randomIndex = rand() % size;\n    // \u83b7\u53d6\u5e76\u8fd4\u56de\u968f\u673a\u5143\u7d20\n    int randomNum = nums[randomIndex];\n    return randomNum;\n}\n
array.zig
// \u968f\u673a\u8bbf\u95ee\u5143\u7d20\nfn randomAccess(nums: []i32) i32 {\n    // \u5728\u533a\u95f4 [0, nums.len) \u4e2d\u968f\u673a\u62bd\u53d6\u4e00\u4e2a\u6574\u6570\n    var randomIndex = std.crypto.random.intRangeLessThan(usize, 0, nums.len);\n    // \u83b7\u53d6\u5e76\u8fd4\u56de\u968f\u673a\u5143\u7d20\n    var randomNum = nums[randomIndex];\n    return randomNum;\n}\n
Code Visualization

Full Screen >

"},{"location":"chapter_array_and_linkedlist/array/#3-inserting-elements","title":"3. \u00a0 Inserting Elements","text":"

Array elements are tightly packed in memory, with no space available to accommodate additional data between them. Illustrated in Figure below, inserting an element in the middle of an array requires shifting all subsequent elements back by one position to create room for the new element.

Figure 4-3 \u00a0 Array Element Insertion Example

It's important to note that due to the fixed length of an array, inserting an element will unavoidably result in the loss of the last element in the array. Solutions to address this issue will be explored in the \"List\" chapter.

PythonC++JavaC#GoSwiftJSTSDartRustCZig array.py
def insert(nums: list[int], num: int, index: int):\n    \"\"\"\u5728\u6570\u7ec4\u7684\u7d22\u5f15 index \u5904\u63d2\u5165\u5143\u7d20 num\"\"\"\n    # \u628a\u7d22\u5f15 index \u4ee5\u53ca\u4e4b\u540e\u7684\u6240\u6709\u5143\u7d20\u5411\u540e\u79fb\u52a8\u4e00\u4f4d\n    for i in range(len(nums) - 1, index, -1):\n        nums[i] = nums[i - 1]\n    # \u5c06 num \u8d4b\u7ed9 index \u5904\u7684\u5143\u7d20\n    nums[index] = num\n
array.cpp
/* \u5728\u6570\u7ec4\u7684\u7d22\u5f15 index \u5904\u63d2\u5165\u5143\u7d20 num */\nvoid insert(int *nums, int size, int num, int index) {\n    // \u628a\u7d22\u5f15 index \u4ee5\u53ca\u4e4b\u540e\u7684\u6240\u6709\u5143\u7d20\u5411\u540e\u79fb\u52a8\u4e00\u4f4d\n    for (int i = size - 1; i > index; i--) {\n        nums[i] = nums[i - 1];\n    }\n    // \u5c06 num \u8d4b\u7ed9 index \u5904\u7684\u5143\u7d20\n    nums[index] = num;\n}\n
array.java
/* \u5728\u6570\u7ec4\u7684\u7d22\u5f15 index \u5904\u63d2\u5165\u5143\u7d20 num */\nvoid insert(int[] nums, int num, int index) {\n    // \u628a\u7d22\u5f15 index \u4ee5\u53ca\u4e4b\u540e\u7684\u6240\u6709\u5143\u7d20\u5411\u540e\u79fb\u52a8\u4e00\u4f4d\n    for (int i = nums.length - 1; i > index; i--) {\n        nums[i] = nums[i - 1];\n    }\n    // \u5c06 num \u8d4b\u7ed9 index \u5904\u7684\u5143\u7d20\n    nums[index] = num;\n}\n
array.cs
/* \u5728\u6570\u7ec4\u7684\u7d22\u5f15 index \u5904\u63d2\u5165\u5143\u7d20 num */\nvoid Insert(int[] nums, int num, int index) {\n    // \u628a\u7d22\u5f15 index \u4ee5\u53ca\u4e4b\u540e\u7684\u6240\u6709\u5143\u7d20\u5411\u540e\u79fb\u52a8\u4e00\u4f4d\n    for (int i = nums.Length - 1; i > index; i--) {\n        nums[i] = nums[i - 1];\n    }\n    // \u5c06 num \u8d4b\u7ed9 index \u5904\u7684\u5143\u7d20\n    nums[index] = num;\n}\n
array.go
/* \u5728\u6570\u7ec4\u7684\u7d22\u5f15 index \u5904\u63d2\u5165\u5143\u7d20 num */\nfunc insert(nums []int, num int, index int) {\n    // \u628a\u7d22\u5f15 index \u4ee5\u53ca\u4e4b\u540e\u7684\u6240\u6709\u5143\u7d20\u5411\u540e\u79fb\u52a8\u4e00\u4f4d\n    for i := len(nums) - 1; i > index; i-- {\n        nums[i] = nums[i-1]\n    }\n    // \u5c06 num \u8d4b\u7ed9 index \u5904\u7684\u5143\u7d20\n    nums[index] = num\n}\n
array.swift
/* \u5728\u6570\u7ec4\u7684\u7d22\u5f15 index \u5904\u63d2\u5165\u5143\u7d20 num */\nfunc insert(nums: inout [Int], num: Int, index: Int) {\n    // \u628a\u7d22\u5f15 index \u4ee5\u53ca\u4e4b\u540e\u7684\u6240\u6709\u5143\u7d20\u5411\u540e\u79fb\u52a8\u4e00\u4f4d\n    for i in nums.indices.dropFirst(index).reversed() {\n        nums[i] = nums[i - 1]\n    }\n    // \u5c06 num \u8d4b\u7ed9 index \u5904\u7684\u5143\u7d20\n    nums[index] = num\n}\n
array.js
/* \u5728\u6570\u7ec4\u7684\u7d22\u5f15 index \u5904\u63d2\u5165\u5143\u7d20 num */\nfunction insert(nums, num, index) {\n    // \u628a\u7d22\u5f15 index \u4ee5\u53ca\u4e4b\u540e\u7684\u6240\u6709\u5143\u7d20\u5411\u540e\u79fb\u52a8\u4e00\u4f4d\n    for (let i = nums.length - 1; i > index; i--) {\n        nums[i] = nums[i - 1];\n    }\n    // \u5c06 num \u8d4b\u7ed9 index \u5904\u7684\u5143\u7d20\n    nums[index] = num;\n}\n
array.ts
/* \u5728\u6570\u7ec4\u7684\u7d22\u5f15 index \u5904\u63d2\u5165\u5143\u7d20 num */\nfunction insert(nums: number[], num: number, index: number): void {\n    // \u628a\u7d22\u5f15 index \u4ee5\u53ca\u4e4b\u540e\u7684\u6240\u6709\u5143\u7d20\u5411\u540e\u79fb\u52a8\u4e00\u4f4d\n    for (let i = nums.length - 1; i > index; i--) {\n        nums[i] = nums[i - 1];\n    }\n    // \u5c06 num \u8d4b\u7ed9 index \u5904\u7684\u5143\u7d20\n    nums[index] = num;\n}\n
array.dart
/* \u5728\u6570\u7ec4\u7684\u7d22\u5f15 index \u5904\u63d2\u5165\u5143\u7d20 _num */\nvoid insert(List<int> nums, int _num, int index) {\n  // \u628a\u7d22\u5f15 index \u4ee5\u53ca\u4e4b\u540e\u7684\u6240\u6709\u5143\u7d20\u5411\u540e\u79fb\u52a8\u4e00\u4f4d\n  for (var i = nums.length - 1; i > index; i--) {\n    nums[i] = nums[i - 1];\n  }\n  // \u5c06 _num \u8d4b\u7ed9 index \u5904\u5143\u7d20\n  nums[index] = _num;\n}\n
array.rs
/* \u5728\u6570\u7ec4\u7684\u7d22\u5f15 index \u5904\u63d2\u5165\u5143\u7d20 num */\nfn insert(nums: &mut Vec<i32>, num: i32, index: usize) {\n    // \u628a\u7d22\u5f15 index \u4ee5\u53ca\u4e4b\u540e\u7684\u6240\u6709\u5143\u7d20\u5411\u540e\u79fb\u52a8\u4e00\u4f4d\n    for i in (index + 1..nums.len()).rev() {\n        nums[i] = nums[i - 1];\n    }\n    // \u5c06 num \u8d4b\u7ed9 index \u5904\u7684\u5143\u7d20\n    nums[index] = num;\n}\n
array.c
/* \u5728\u6570\u7ec4\u7684\u7d22\u5f15 index \u5904\u63d2\u5165\u5143\u7d20 num */\nvoid insert(int *nums, int size, int num, int index) {\n    // \u628a\u7d22\u5f15 index \u4ee5\u53ca\u4e4b\u540e\u7684\u6240\u6709\u5143\u7d20\u5411\u540e\u79fb\u52a8\u4e00\u4f4d\n    for (int i = size - 1; i > index; i--) {\n        nums[i] = nums[i - 1];\n    }\n    // \u5c06 num \u8d4b\u7ed9 index \u5904\u7684\u5143\u7d20\n    nums[index] = num;\n}\n
array.zig
// \u5728\u6570\u7ec4\u7684\u7d22\u5f15 index \u5904\u63d2\u5165\u5143\u7d20 num\nfn insert(nums: []i32, num: i32, index: usize) void {\n    // \u628a\u7d22\u5f15 index \u4ee5\u53ca\u4e4b\u540e\u7684\u6240\u6709\u5143\u7d20\u5411\u540e\u79fb\u52a8\u4e00\u4f4d\n    var i = nums.len - 1;\n    while (i > index) : (i -= 1) {\n        nums[i] = nums[i - 1];\n    }\n    // \u5c06 num \u8d4b\u7ed9 index \u5904\u7684\u5143\u7d20\n    nums[index] = num;\n}\n
Code Visualization

Full Screen >

"},{"location":"chapter_array_and_linkedlist/array/#4-deleting-elements","title":"4. \u00a0 Deleting Elements","text":"

Similarly, as depicted in the Figure 4-4 , to delete an element at index \\(i\\), all elements following index \\(i\\) must be moved forward by one position.

Figure 4-4 \u00a0 Array Element Deletion Example

Please note that after deletion, the former last element becomes \"meaningless,\" hence requiring no specific modification.

PythonC++JavaC#GoSwiftJSTSDartRustCZig array.py
def remove(nums: list[int], index: int):\n    \"\"\"\u5220\u9664\u7d22\u5f15 index \u5904\u7684\u5143\u7d20\"\"\"\n    # \u628a\u7d22\u5f15 index \u4e4b\u540e\u7684\u6240\u6709\u5143\u7d20\u5411\u524d\u79fb\u52a8\u4e00\u4f4d\n    for i in range(index, len(nums) - 1):\n        nums[i] = nums[i + 1]\n
array.cpp
/* \u5220\u9664\u7d22\u5f15 index \u5904\u7684\u5143\u7d20 */\nvoid remove(int *nums, int size, int index) {\n    // \u628a\u7d22\u5f15 index \u4e4b\u540e\u7684\u6240\u6709\u5143\u7d20\u5411\u524d\u79fb\u52a8\u4e00\u4f4d\n    for (int i = index; i < size - 1; i++) {\n        nums[i] = nums[i + 1];\n    }\n}\n
array.java
/* \u5220\u9664\u7d22\u5f15 index \u5904\u7684\u5143\u7d20 */\nvoid remove(int[] nums, int index) {\n    // \u628a\u7d22\u5f15 index \u4e4b\u540e\u7684\u6240\u6709\u5143\u7d20\u5411\u524d\u79fb\u52a8\u4e00\u4f4d\n    for (int i = index; i < nums.length - 1; i++) {\n        nums[i] = nums[i + 1];\n    }\n}\n
array.cs
/* \u5220\u9664\u7d22\u5f15 index \u5904\u7684\u5143\u7d20 */\nvoid Remove(int[] nums, int index) {\n    // \u628a\u7d22\u5f15 index \u4e4b\u540e\u7684\u6240\u6709\u5143\u7d20\u5411\u524d\u79fb\u52a8\u4e00\u4f4d\n    for (int i = index; i < nums.Length - 1; i++) {\n        nums[i] = nums[i + 1];\n    }\n}\n
array.go
/* \u5220\u9664\u7d22\u5f15 index \u5904\u7684\u5143\u7d20 */\nfunc remove(nums []int, index int) {\n    // \u628a\u7d22\u5f15 index \u4e4b\u540e\u7684\u6240\u6709\u5143\u7d20\u5411\u524d\u79fb\u52a8\u4e00\u4f4d\n    for i := index; i < len(nums)-1; i++ {\n        nums[i] = nums[i+1]\n    }\n}\n
array.swift
/* \u5220\u9664\u7d22\u5f15 index \u5904\u7684\u5143\u7d20 */\nfunc remove(nums: inout [Int], index: Int) {\n    // \u628a\u7d22\u5f15 index \u4e4b\u540e\u7684\u6240\u6709\u5143\u7d20\u5411\u524d\u79fb\u52a8\u4e00\u4f4d\n    for i in nums.indices.dropFirst(index).dropLast() {\n        nums[i] = nums[i + 1]\n    }\n}\n
array.js
/* \u5220\u9664\u7d22\u5f15 index \u5904\u7684\u5143\u7d20 */\nfunction remove(nums, index) {\n    // \u628a\u7d22\u5f15 index \u4e4b\u540e\u7684\u6240\u6709\u5143\u7d20\u5411\u524d\u79fb\u52a8\u4e00\u4f4d\n    for (let i = index; i < nums.length - 1; i++) {\n        nums[i] = nums[i + 1];\n    }\n}\n
array.ts
/* \u5220\u9664\u7d22\u5f15 index \u5904\u7684\u5143\u7d20 */\nfunction remove(nums: number[], index: number): void {\n    // \u628a\u7d22\u5f15 index \u4e4b\u540e\u7684\u6240\u6709\u5143\u7d20\u5411\u524d\u79fb\u52a8\u4e00\u4f4d\n    for (let i = index; i < nums.length - 1; i++) {\n        nums[i] = nums[i + 1];\n    }\n}\n
array.dart
/* \u5220\u9664\u7d22\u5f15 index \u5904\u7684\u5143\u7d20 */\nvoid remove(List<int> nums, int index) {\n  // \u628a\u7d22\u5f15 index \u4e4b\u540e\u7684\u6240\u6709\u5143\u7d20\u5411\u524d\u79fb\u52a8\u4e00\u4f4d\n  for (var i = index; i < nums.length - 1; i++) {\n    nums[i] = nums[i + 1];\n  }\n}\n
array.rs
/* \u5220\u9664\u7d22\u5f15 index \u5904\u7684\u5143\u7d20 */\nfn remove(nums: &mut Vec<i32>, index: usize) {\n    // \u628a\u7d22\u5f15 index \u4e4b\u540e\u7684\u6240\u6709\u5143\u7d20\u5411\u524d\u79fb\u52a8\u4e00\u4f4d\n    for i in index..nums.len() - 1 {\n        nums[i] = nums[i + 1];\n    }\n}\n
array.c
/* \u5220\u9664\u7d22\u5f15 index \u5904\u7684\u5143\u7d20 */\n// \u6ce8\u610f\uff1astdio.h \u5360\u7528\u4e86 remove \u5173\u952e\u8bcd\nvoid removeItem(int *nums, int size, int index) {\n    // \u628a\u7d22\u5f15 index \u4e4b\u540e\u7684\u6240\u6709\u5143\u7d20\u5411\u524d\u79fb\u52a8\u4e00\u4f4d\n    for (int i = index; i < size - 1; i++) {\n        nums[i] = nums[i + 1];\n    }\n}\n
array.zig
// \u5220\u9664\u7d22\u5f15 index \u5904\u7684\u5143\u7d20\nfn remove(nums: []i32, index: usize) void {\n    // \u628a\u7d22\u5f15 index \u4e4b\u540e\u7684\u6240\u6709\u5143\u7d20\u5411\u524d\u79fb\u52a8\u4e00\u4f4d\n    var i = index;\n    while (i < nums.len - 1) : (i += 1) {\n        nums[i] = nums[i + 1];\n    }\n}\n
Code Visualization

Full Screen >

In summary, the insertion and deletion operations in arrays present the following disadvantages:

  • High Time Complexity: Both insertion and deletion in an array have an average time complexity of \\(O(n)\\), where \\(n\\) is the length of the array.
  • Loss of Elements: Due to the fixed length of arrays, elements that exceed the array's capacity are lost during insertion.
  • Waste of Memory: Initializing a longer array and utilizing only the front part results in \"meaningless\" end elements during insertion, leading to some wasted memory space.
"},{"location":"chapter_array_and_linkedlist/array/#5-traversing-arrays","title":"5. \u00a0 Traversing Arrays","text":"

In most programming languages, we can traverse an array either by using indices or by directly iterating over each element:

PythonC++JavaC#GoSwiftJSTSDartRustCZig array.py
def traverse(nums: list[int]):\n    \"\"\"\u904d\u5386\u6570\u7ec4\"\"\"\n    count = 0\n    # \u901a\u8fc7\u7d22\u5f15\u904d\u5386\u6570\u7ec4\n    for i in range(len(nums)):\n        count += nums[i]\n    # \u76f4\u63a5\u904d\u5386\u6570\u7ec4\u5143\u7d20\n    for num in nums:\n        count += num\n    # \u540c\u65f6\u904d\u5386\u6570\u636e\u7d22\u5f15\u548c\u5143\u7d20\n    for i, num in enumerate(nums):\n        count += nums[i]\n        count += num\n
array.cpp
/* \u904d\u5386\u6570\u7ec4 */\nvoid traverse(int *nums, int size) {\n    int count = 0;\n    // \u901a\u8fc7\u7d22\u5f15\u904d\u5386\u6570\u7ec4\n    for (int i = 0; i < size; i++) {\n        count += nums[i];\n    }\n}\n
array.java
/* \u904d\u5386\u6570\u7ec4 */\nvoid traverse(int[] nums) {\n    int count = 0;\n    // \u901a\u8fc7\u7d22\u5f15\u904d\u5386\u6570\u7ec4\n    for (int i = 0; i < nums.length; i++) {\n        count += nums[i];\n    }\n    // \u76f4\u63a5\u904d\u5386\u6570\u7ec4\u5143\u7d20\n    for (int num : nums) {\n        count += num;\n    }\n}\n
array.cs
/* \u904d\u5386\u6570\u7ec4 */\nvoid Traverse(int[] nums) {\n    int count = 0;\n    // \u901a\u8fc7\u7d22\u5f15\u904d\u5386\u6570\u7ec4\n    for (int i = 0; i < nums.Length; i++) {\n        count += nums[i];\n    }\n    // \u76f4\u63a5\u904d\u5386\u6570\u7ec4\u5143\u7d20\n    foreach (int num in nums) {\n        count += num;\n    }\n}\n
array.go
/* \u904d\u5386\u6570\u7ec4 */\nfunc traverse(nums []int) {\n    count := 0\n    // \u901a\u8fc7\u7d22\u5f15\u904d\u5386\u6570\u7ec4\n    for i := 0; i < len(nums); i++ {\n        count += nums[i]\n    }\n    count = 0\n    // \u76f4\u63a5\u904d\u5386\u6570\u7ec4\u5143\u7d20\n    for _, num := range nums {\n        count += num\n    }\n    // \u540c\u65f6\u904d\u5386\u6570\u636e\u7d22\u5f15\u548c\u5143\u7d20\n    for i, num := range nums {\n        count += nums[i]\n        count += num\n    }\n}\n
array.swift
/* \u904d\u5386\u6570\u7ec4 */\nfunc traverse(nums: [Int]) {\n    var count = 0\n    // \u901a\u8fc7\u7d22\u5f15\u904d\u5386\u6570\u7ec4\n    for i in nums.indices {\n        count += nums[i]\n    }\n    // \u76f4\u63a5\u904d\u5386\u6570\u7ec4\u5143\u7d20\n    for num in nums {\n        count += num\n    }\n    // \u540c\u65f6\u904d\u5386\u6570\u636e\u7d22\u5f15\u548c\u5143\u7d20\n    for (i, num) in nums.enumerated() {\n        count += nums[i]\n        count += num\n    }\n}\n
array.js
/* \u904d\u5386\u6570\u7ec4 */\nfunction traverse(nums) {\n    let count = 0;\n    // \u901a\u8fc7\u7d22\u5f15\u904d\u5386\u6570\u7ec4\n    for (let i = 0; i < nums.length; i++) {\n        count += nums[i];\n    }\n    // \u76f4\u63a5\u904d\u5386\u6570\u7ec4\u5143\u7d20\n    for (const num of nums) {\n        count += num;\n    }\n}\n
array.ts
/* \u904d\u5386\u6570\u7ec4 */\nfunction traverse(nums: number[]): void {\n    let count = 0;\n    // \u901a\u8fc7\u7d22\u5f15\u904d\u5386\u6570\u7ec4\n    for (let i = 0; i < nums.length; i++) {\n        count += nums[i];\n    }\n    // \u76f4\u63a5\u904d\u5386\u6570\u7ec4\u5143\u7d20\n    for (const num of nums) {\n        count += num;\n    }\n}\n
array.dart
/* \u904d\u5386\u6570\u7ec4\u5143\u7d20 */\nvoid traverse(List<int> nums) {\n  int count = 0;\n  // \u901a\u8fc7\u7d22\u5f15\u904d\u5386\u6570\u7ec4\n  for (var i = 0; i < nums.length; i++) {\n    count += nums[i];\n  }\n  // \u76f4\u63a5\u904d\u5386\u6570\u7ec4\u5143\u7d20\n  for (int _num in nums) {\n    count += _num;\n  }\n  // \u901a\u8fc7 forEach \u65b9\u6cd5\u904d\u5386\u6570\u7ec4\n  nums.forEach((_num) {\n    count += _num;\n  });\n}\n
array.rs
/* \u904d\u5386\u6570\u7ec4 */\nfn traverse(nums: &[i32]) {\n    let mut _count = 0;\n    // \u901a\u8fc7\u7d22\u5f15\u904d\u5386\u6570\u7ec4\n    for i in 0..nums.len() {\n        _count += nums[i];\n    }\n    // \u76f4\u63a5\u904d\u5386\u6570\u7ec4\u5143\u7d20\n    for num in nums {\n        _count += num;\n    }\n}\n
array.c
/* \u904d\u5386\u6570\u7ec4 */\nvoid traverse(int *nums, int size) {\n    int count = 0;\n    // \u901a\u8fc7\u7d22\u5f15\u904d\u5386\u6570\u7ec4\n    for (int i = 0; i < size; i++) {\n        count += nums[i];\n    }\n}\n
array.zig
// \u904d\u5386\u6570\u7ec4\nfn traverse(nums: []i32) void {\n    var count: i32 = 0;\n    // \u901a\u8fc7\u7d22\u5f15\u904d\u5386\u6570\u7ec4\n    var i: i32 = 0;\n    while (i < nums.len) : (i += 1) {\n        count += nums[i];\n    }\n    count = 0;\n    // \u76f4\u63a5\u904d\u5386\u6570\u7ec4\u5143\u7d20\n    for (nums) |num| {\n        count += num;\n    }\n}\n
Code Visualization

Full Screen >

"},{"location":"chapter_array_and_linkedlist/array/#6-finding-elements","title":"6. \u00a0 Finding Elements","text":"

Locating a specific element within an array involves iterating through the array, checking each element to determine if it matches the desired value.

Because arrays are linear data structures, this operation is commonly referred to as \"linear search.\"

PythonC++JavaC#GoSwiftJSTSDartRustCZig array.py
def find(nums: list[int], target: int) -> int:\n    \"\"\"\u5728\u6570\u7ec4\u4e2d\u67e5\u627e\u6307\u5b9a\u5143\u7d20\"\"\"\n    for i in range(len(nums)):\n        if nums[i] == target:\n            return i\n    return -1\n
array.cpp
/* \u5728\u6570\u7ec4\u4e2d\u67e5\u627e\u6307\u5b9a\u5143\u7d20 */\nint find(int *nums, int size, int target) {\n    for (int i = 0; i < size; i++) {\n        if (nums[i] == target)\n            return i;\n    }\n    return -1;\n}\n
array.java
/* \u5728\u6570\u7ec4\u4e2d\u67e5\u627e\u6307\u5b9a\u5143\u7d20 */\nint find(int[] nums, int target) {\n    for (int i = 0; i < nums.length; i++) {\n        if (nums[i] == target)\n            return i;\n    }\n    return -1;\n}\n
array.cs
/* \u5728\u6570\u7ec4\u4e2d\u67e5\u627e\u6307\u5b9a\u5143\u7d20 */\nint Find(int[] nums, int target) {\n    for (int i = 0; i < nums.Length; i++) {\n        if (nums[i] == target)\n            return i;\n    }\n    return -1;\n}\n
array.go
/* \u5728\u6570\u7ec4\u4e2d\u67e5\u627e\u6307\u5b9a\u5143\u7d20 */\nfunc find(nums []int, target int) (index int) {\n    index = -1\n    for i := 0; i < len(nums); i++ {\n        if nums[i] == target {\n            index = i\n            break\n        }\n    }\n    return\n}\n
array.swift
/* \u5728\u6570\u7ec4\u4e2d\u67e5\u627e\u6307\u5b9a\u5143\u7d20 */\nfunc find(nums: [Int], target: Int) -> Int {\n    for i in nums.indices {\n        if nums[i] == target {\n            return i\n        }\n    }\n    return -1\n}\n
array.js
/* \u5728\u6570\u7ec4\u4e2d\u67e5\u627e\u6307\u5b9a\u5143\u7d20 */\nfunction find(nums, target) {\n    for (let i = 0; i < nums.length; i++) {\n        if (nums[i] === target) return i;\n    }\n    return -1;\n}\n
array.ts
/* \u5728\u6570\u7ec4\u4e2d\u67e5\u627e\u6307\u5b9a\u5143\u7d20 */\nfunction find(nums: number[], target: number): number {\n    for (let i = 0; i < nums.length; i++) {\n        if (nums[i] === target) {\n            return i;\n        }\n    }\n    return -1;\n}\n
array.dart
/* \u5728\u6570\u7ec4\u4e2d\u67e5\u627e\u6307\u5b9a\u5143\u7d20 */\nint find(List<int> nums, int target) {\n  for (var i = 0; i < nums.length; i++) {\n    if (nums[i] == target) return i;\n  }\n  return -1;\n}\n
array.rs
/* \u5728\u6570\u7ec4\u4e2d\u67e5\u627e\u6307\u5b9a\u5143\u7d20 */\nfn find(nums: &[i32], target: i32) -> Option<usize> {\n    for i in 0..nums.len() {\n        if nums[i] == target {\n            return Some(i);\n        }\n    }\n    None\n}\n
array.c
/* \u5728\u6570\u7ec4\u4e2d\u67e5\u627e\u6307\u5b9a\u5143\u7d20 */\nint find(int *nums, int size, int target) {\n    for (int i = 0; i < size; i++) {\n        if (nums[i] == target)\n            return i;\n    }\n    return -1;\n}\n
array.zig
// \u5728\u6570\u7ec4\u4e2d\u67e5\u627e\u6307\u5b9a\u5143\u7d20\nfn find(nums: []i32, target: i32) i32 {\n    for (nums, 0..) |num, i| {\n        if (num == target) return @intCast(i);\n    }\n    return -1;\n}\n
Code Visualization

Full Screen >

"},{"location":"chapter_array_and_linkedlist/array/#7-expanding-arrays","title":"7. \u00a0 Expanding Arrays","text":"

In complex system environments, ensuring the availability of memory space after an array for safe capacity extension becomes challenging. Consequently, in most programming languages, the length of an array is immutable.

To expand an array, it's necessary to create a larger array and then copy the elements from the original array. This operation has a time complexity of \\(O(n)\\) and can be time-consuming for large arrays. The code are as follows:

PythonC++JavaC#GoSwiftJSTSDartRustCZig array.py
def extend(nums: list[int], enlarge: int) -> list[int]:\n    \"\"\"\u6269\u5c55\u6570\u7ec4\u957f\u5ea6\"\"\"\n    # \u521d\u59cb\u5316\u4e00\u4e2a\u6269\u5c55\u957f\u5ea6\u540e\u7684\u6570\u7ec4\n    res = [0] * (len(nums) + enlarge)\n    # \u5c06\u539f\u6570\u7ec4\u4e2d\u7684\u6240\u6709\u5143\u7d20\u590d\u5236\u5230\u65b0\u6570\u7ec4\n    for i in range(len(nums)):\n        res[i] = nums[i]\n    # \u8fd4\u56de\u6269\u5c55\u540e\u7684\u65b0\u6570\u7ec4\n    return res\n
array.cpp
/* \u6269\u5c55\u6570\u7ec4\u957f\u5ea6 */\nint *extend(int *nums, int size, int enlarge) {\n    // \u521d\u59cb\u5316\u4e00\u4e2a\u6269\u5c55\u957f\u5ea6\u540e\u7684\u6570\u7ec4\n    int *res = new int[size + enlarge];\n    // \u5c06\u539f\u6570\u7ec4\u4e2d\u7684\u6240\u6709\u5143\u7d20\u590d\u5236\u5230\u65b0\u6570\u7ec4\n    for (int i = 0; i < size; i++) {\n        res[i] = nums[i];\n    }\n    // \u91ca\u653e\u5185\u5b58\n    delete[] nums;\n    // \u8fd4\u56de\u6269\u5c55\u540e\u7684\u65b0\u6570\u7ec4\n    return res;\n}\n
array.java
/* \u6269\u5c55\u6570\u7ec4\u957f\u5ea6 */\nint[] extend(int[] nums, int enlarge) {\n    // \u521d\u59cb\u5316\u4e00\u4e2a\u6269\u5c55\u957f\u5ea6\u540e\u7684\u6570\u7ec4\n    int[] res = new int[nums.length + enlarge];\n    // \u5c06\u539f\u6570\u7ec4\u4e2d\u7684\u6240\u6709\u5143\u7d20\u590d\u5236\u5230\u65b0\u6570\u7ec4\n    for (int i = 0; i < nums.length; i++) {\n        res[i] = nums[i];\n    }\n    // \u8fd4\u56de\u6269\u5c55\u540e\u7684\u65b0\u6570\u7ec4\n    return res;\n}\n
array.cs
/* \u6269\u5c55\u6570\u7ec4\u957f\u5ea6 */\nint[] Extend(int[] nums, int enlarge) {\n    // \u521d\u59cb\u5316\u4e00\u4e2a\u6269\u5c55\u957f\u5ea6\u540e\u7684\u6570\u7ec4\n    int[] res = new int[nums.Length + enlarge];\n    // \u5c06\u539f\u6570\u7ec4\u4e2d\u7684\u6240\u6709\u5143\u7d20\u590d\u5236\u5230\u65b0\u6570\u7ec4\n    for (int i = 0; i < nums.Length; i++) {\n        res[i] = nums[i];\n    }\n    // \u8fd4\u56de\u6269\u5c55\u540e\u7684\u65b0\u6570\u7ec4\n    return res;\n}\n
array.go
/* \u6269\u5c55\u6570\u7ec4\u957f\u5ea6 */\nfunc extend(nums []int, enlarge int) []int {\n    // \u521d\u59cb\u5316\u4e00\u4e2a\u6269\u5c55\u957f\u5ea6\u540e\u7684\u6570\u7ec4\n    res := make([]int, len(nums)+enlarge)\n    // \u5c06\u539f\u6570\u7ec4\u4e2d\u7684\u6240\u6709\u5143\u7d20\u590d\u5236\u5230\u65b0\u6570\u7ec4\n    for i, num := range nums {\n        res[i] = num\n    }\n    // \u8fd4\u56de\u6269\u5c55\u540e\u7684\u65b0\u6570\u7ec4\n    return res\n}\n
array.swift
/* \u6269\u5c55\u6570\u7ec4\u957f\u5ea6 */\nfunc extend(nums: [Int], enlarge: Int) -> [Int] {\n    // \u521d\u59cb\u5316\u4e00\u4e2a\u6269\u5c55\u957f\u5ea6\u540e\u7684\u6570\u7ec4\n    var res = Array(repeating: 0, count: nums.count + enlarge)\n    // \u5c06\u539f\u6570\u7ec4\u4e2d\u7684\u6240\u6709\u5143\u7d20\u590d\u5236\u5230\u65b0\u6570\u7ec4\n    for i in nums.indices {\n        res[i] = nums[i]\n    }\n    // \u8fd4\u56de\u6269\u5c55\u540e\u7684\u65b0\u6570\u7ec4\n    return res\n}\n
array.js
/* \u6269\u5c55\u6570\u7ec4\u957f\u5ea6 */\n// \u8bf7\u6ce8\u610f\uff0cJavaScript \u7684 Array \u662f\u52a8\u6001\u6570\u7ec4\uff0c\u53ef\u4ee5\u76f4\u63a5\u6269\u5c55\n// \u4e3a\u4e86\u65b9\u4fbf\u5b66\u4e60\uff0c\u672c\u51fd\u6570\u5c06 Array \u770b\u4f5c\u957f\u5ea6\u4e0d\u53ef\u53d8\u7684\u6570\u7ec4\nfunction extend(nums, enlarge) {\n    // \u521d\u59cb\u5316\u4e00\u4e2a\u6269\u5c55\u957f\u5ea6\u540e\u7684\u6570\u7ec4\n    const res = new Array(nums.length + enlarge).fill(0);\n    // \u5c06\u539f\u6570\u7ec4\u4e2d\u7684\u6240\u6709\u5143\u7d20\u590d\u5236\u5230\u65b0\u6570\u7ec4\n    for (let i = 0; i < nums.length; i++) {\n        res[i] = nums[i];\n    }\n    // \u8fd4\u56de\u6269\u5c55\u540e\u7684\u65b0\u6570\u7ec4\n    return res;\n}\n
array.ts
/* \u6269\u5c55\u6570\u7ec4\u957f\u5ea6 */\n// \u8bf7\u6ce8\u610f\uff0cTypeScript \u7684 Array \u662f\u52a8\u6001\u6570\u7ec4\uff0c\u53ef\u4ee5\u76f4\u63a5\u6269\u5c55\n// \u4e3a\u4e86\u65b9\u4fbf\u5b66\u4e60\uff0c\u672c\u51fd\u6570\u5c06 Array \u770b\u4f5c\u957f\u5ea6\u4e0d\u53ef\u53d8\u7684\u6570\u7ec4\nfunction extend(nums: number[], enlarge: number): number[] {\n    // \u521d\u59cb\u5316\u4e00\u4e2a\u6269\u5c55\u957f\u5ea6\u540e\u7684\u6570\u7ec4\n    const res = new Array(nums.length + enlarge).fill(0);\n    // \u5c06\u539f\u6570\u7ec4\u4e2d\u7684\u6240\u6709\u5143\u7d20\u590d\u5236\u5230\u65b0\u6570\u7ec4\n    for (let i = 0; i < nums.length; i++) {\n        res[i] = nums[i];\n    }\n    // \u8fd4\u56de\u6269\u5c55\u540e\u7684\u65b0\u6570\u7ec4\n    return res;\n}\n
array.dart
/* \u6269\u5c55\u6570\u7ec4\u957f\u5ea6 */\nList<int> extend(List<int> nums, int enlarge) {\n  // \u521d\u59cb\u5316\u4e00\u4e2a\u6269\u5c55\u957f\u5ea6\u540e\u7684\u6570\u7ec4\n  List<int> res = List.filled(nums.length + enlarge, 0);\n  // \u5c06\u539f\u6570\u7ec4\u4e2d\u7684\u6240\u6709\u5143\u7d20\u590d\u5236\u5230\u65b0\u6570\u7ec4\n  for (var i = 0; i < nums.length; i++) {\n    res[i] = nums[i];\n  }\n  // \u8fd4\u56de\u6269\u5c55\u540e\u7684\u65b0\u6570\u7ec4\n  return res;\n}\n
array.rs
/* \u6269\u5c55\u6570\u7ec4\u957f\u5ea6 */\nfn extend(nums: Vec<i32>, enlarge: usize) -> Vec<i32> {\n    // \u521d\u59cb\u5316\u4e00\u4e2a\u6269\u5c55\u957f\u5ea6\u540e\u7684\u6570\u7ec4\n    let mut res: Vec<i32> = vec![0; nums.len() + enlarge];\n    // \u5c06\u539f\u6570\u7ec4\u4e2d\u7684\u6240\u6709\u5143\u7d20\u590d\u5236\u5230\u65b0\n    for i in 0..nums.len() {\n        res[i] = nums[i];\n    }\n    // \u8fd4\u56de\u6269\u5c55\u540e\u7684\u65b0\u6570\u7ec4\n    res\n}\n
array.c
/* \u6269\u5c55\u6570\u7ec4\u957f\u5ea6 */\nint *extend(int *nums, int size, int enlarge) {\n    // \u521d\u59cb\u5316\u4e00\u4e2a\u6269\u5c55\u957f\u5ea6\u540e\u7684\u6570\u7ec4\n    int *res = (int *)malloc(sizeof(int) * (size + enlarge));\n    // \u5c06\u539f\u6570\u7ec4\u4e2d\u7684\u6240\u6709\u5143\u7d20\u590d\u5236\u5230\u65b0\u6570\u7ec4\n    for (int i = 0; i < size; i++) {\n        res[i] = nums[i];\n    }\n    // \u521d\u59cb\u5316\u6269\u5c55\u540e\u7684\u7a7a\u95f4\n    for (int i = size; i < size + enlarge; i++) {\n        res[i] = 0;\n    }\n    // \u8fd4\u56de\u6269\u5c55\u540e\u7684\u65b0\u6570\u7ec4\n    return res;\n}\n
array.zig
// \u6269\u5c55\u6570\u7ec4\u957f\u5ea6\nfn extend(mem_allocator: std.mem.Allocator, nums: []i32, enlarge: usize) ![]i32 {\n    // \u521d\u59cb\u5316\u4e00\u4e2a\u6269\u5c55\u957f\u5ea6\u540e\u7684\u6570\u7ec4\n    var res = try mem_allocator.alloc(i32, nums.len + enlarge);\n    @memset(res, 0);\n    // \u5c06\u539f\u6570\u7ec4\u4e2d\u7684\u6240\u6709\u5143\u7d20\u590d\u5236\u5230\u65b0\u6570\u7ec4\n    std.mem.copy(i32, res, nums);\n    // \u8fd4\u56de\u6269\u5c55\u540e\u7684\u65b0\u6570\u7ec4\n    return res;\n}\n
Code Visualization

Full Screen >

"},{"location":"chapter_array_and_linkedlist/array/#412-advantages-and-limitations-of-arrays","title":"4.1.2 \u00a0 Advantages and Limitations of Arrays","text":"

Arrays are stored in contiguous memory spaces and consist of elements of the same type. This approach provides substantial prior information that systems can leverage to optimize the efficiency of data structure operations.

  • High Space Efficiency: Arrays allocate a contiguous block of memory for data, eliminating the need for additional structural overhead.
  • Support for Random Access: Arrays allow \\(O(1)\\) time access to any element.
  • Cache Locality: When accessing array elements, the computer not only loads them but also caches the surrounding data, utilizing high-speed cache to enchance subsequent operation speeds.

However, continuous space storage is a double-edged sword, with the following limitations:

  • Low Efficiency in Insertion and Deletion: As arrays accumulate many elements, inserting or deleting elements requires shifting a large number of elements.
  • Fixed Length: The length of an array is fixed after initialization. Expanding an array requires copying all data to a new array, incurring significant costs.
  • Space Wastage: If the allocated array size exceeds the what is necessary, the extra space is wasted.
"},{"location":"chapter_array_and_linkedlist/array/#413-typical-applications-of-arrays","title":"4.1.3 \u00a0 Typical Applications of Arrays","text":"

Arrays are fundamental and widely used data structures. They find frequent application in various algorithms and serve in the implementation of complex data structures.

  • Random Access: Arrays are ideal for storing data when random sampling is required. By generating a random sequence based on indices, we can achieve random sampling efficiently.
  • Sorting and Searching: Arrays are the most commonly used data structure for sorting and searching algorithms. Techniques like quick sort, merge sort, binary search, etc., are primarily operate on arrays.
  • Lookup Tables: Arrays serve as efficient lookup tables for quick element or relationship retrieval. For instance, mapping characters to ASCII codes becomes seamless by using the ASCII code values as indices and storing corresponding elements in the array.
  • Machine Learning: Within the domain of neural networks, arrays play a pivotal role in executing crucial linear algebra operations involving vectors, matrices, and tensors. Arrays serve as the primary and most extensively used data structure in neural network programming.
  • Data Structure Implementation: Arrays serve as the building blocks for implementing various data structures like stacks, queues, hash tables, heaps, graphs, etc. For instance, the adjacency matrix representation of a graph is essentially a two-dimensional array.
"},{"location":"chapter_array_and_linkedlist/linked_list/","title":"4.2 \u00a0 Linked Lists","text":"

Memory space is a shared resource among all programs. In a complex system environment, available memory can be dispersed throughout the memory space. We understand that the memory allocated for an array must be continuous. However, for very large arrays, finding a sufficiently large contiguous memory space might be challenging. This is where the flexible advantage of linked lists becomes evident.

A \"linked list\" is a linear data structure in which each element is a node object, and the nodes are interconnected through \"references\". These references hold the memory addresses of subsequent nodes, enabling navigation from one node to the next.

The design of linked lists allows for their nodes to be distributed across memory locations without requiring contiguous memory addresses.

Figure 4-5 \u00a0 Linked List Definition and Storage Method

As shown in the figure, we see that the basic building block of a linked list is the \"node\" object. Each node comprises two key components: the node's \"value\" and a \"reference\" to the next node.

  • The first node in a linked list is the \"head node\", and the final one is the \"tail node\".
  • The tail node points to \"null\", designated as null in Java, nullptr in C++, and None in Python.
  • In languages that support pointers, like C, C++, Go, and Rust, this \"reference\" is typically implemented as a \"pointer\".

As the code below illustrates, a ListNode in a linked list, besides holding a value, must also maintain an additional reference (or pointer). Therefore, a linked list occupies more memory space than an array when storing the same quantity of data..

PythonC++JavaC#GoSwiftJSTSDartRustCZig
class ListNode:\n    \"\"\"Linked List Node Class\"\"\"\n    def __init__(self, val: int):\n        self.val: int = val               # Node value\n        self.next: ListNode | None = None # Reference to the next node\n
/* Linked List Node Structure */\nstruct ListNode {\n    int val;         // Node value\n    ListNode *next;  // Pointer to the next node\n    ListNode(int x) : val(x), next(nullptr) {}  // Constructor\n};\n
/* Linked List Node Class */\nclass ListNode {\n    int val;        // Node value\n    ListNode next;  // Reference to the next node\n    ListNode(int x) { val = x; }  // Constructor\n}\n
/* Linked List Node Class */\nclass ListNode(int x) {  // Constructor\n    int val = x;         // Node value\n    ListNode? next;      // Reference to the next node\n}\n
/* Linked List Node Structure */\ntype ListNode struct {\n    Val  int       // Node value\n    Next *ListNode // Pointer to the next node\n}\n\n// NewListNode Constructor, creates a new linked list\nfunc NewListNode(val int) *ListNode {\n    return &ListNode{\n        Val:  val,\n        Next: nil,\n    }\n}\n
/* Linked List Node Class */\nclass ListNode {\n    var val: Int // Node value\n    var next: ListNode? // Reference to the next node\n\n    init(x: Int) { // Constructor\n        val = x\n    }\n}\n
/* Linked List Node Class */\nclass ListNode {\n    constructor(val, next) {\n        this.val = (val === undefined ? 0 : val);       // Node value\n        this.next = (next === undefined ? null : next); // Reference to the next node\n    }\n}\n
/* Linked List Node Class */\nclass ListNode {\n    val: number;\n    next: ListNode | null;\n    constructor(val?: number, next?: ListNode | null) {\n        this.val = val === undefined ? 0 : val;        // Node value\n        this.next = next === undefined ? null : next;  // Reference to the next node\n    }\n}\n
/* \u94fe\u8868\u8282\u70b9\u7c7b */\nclass ListNode {\n  int val; // Node value\n  ListNode? next; // Reference to the next node\n  ListNode(this.val, [this.next]); // Constructor\n}\n
use std::rc::Rc;\nuse std::cell::RefCell;\n/* Linked List Node Class */\n#[derive(Debug)]\nstruct ListNode {\n    val: i32, // Node value\n    next: Option<Rc<RefCell<ListNode>>>, // Pointer to the next node\n}\n
/* Linked List Node Structure */\ntypedef struct ListNode {\n    int val;               // Node value\n    struct ListNode *next; // Pointer to the next node\n} ListNode;\n\n/* Constructor */\nListNode *newListNode(int val) {\n    ListNode *node;\n    node = (ListNode *) malloc(sizeof(ListNode));\n    node->val = val;\n    node->next = NULL;\n    return node;\n}\n
// Linked List Node Class\npub fn ListNode(comptime T: type) type {\n    return struct {\n        const Self = @This();\n\n        val: T = 0, // Node value\n        next: ?*Self = null, // Pointer to the next node\n\n        // Constructor\n        pub fn init(self: *Self, x: i32) void {\n            self.val = x;\n            self.next = null;\n        }\n    };\n}\n
"},{"location":"chapter_array_and_linkedlist/linked_list/#421-common-operations-on-linked-lists","title":"4.2.1 \u00a0 Common Operations on Linked Lists","text":""},{"location":"chapter_array_and_linkedlist/linked_list/#1-initializing-a-linked-list","title":"1. \u00a0 Initializing a Linked List","text":"

Constructing a linked list is a two-step process: first, initializing each node object, and second, forming the reference links between the nodes. After initialization, we can traverse all nodes sequentially from the head node by following the next reference.

PythonC++JavaC#GoSwiftJSTSDartRustCZig linked_list.py
# Initialize linked list: 1 -> 3 -> 2 -> 5 -> 4\n# Initialize each node\nn0 = ListNode(1)\nn1 = ListNode(3)\nn2 = ListNode(2)\nn3 = ListNode(5)\nn4 = ListNode(4)\n# Build references between nodes\nn0.next = n1\nn1.next = n2\nn2.next = n3\nn3.next = n4\n
linked_list.cpp
/* Initialize linked list: 1 -> 3 -> 2 -> 5 -> 4 */\n// Initialize each node\nListNode* n0 = new ListNode(1);\nListNode* n1 = new ListNode(3);\nListNode* n2 = new ListNode(2);\nListNode* n3 = new ListNode(5);\nListNode* n4 = new ListNode(4);\n// Build references between nodes\nn0->next = n1;\nn1->next = n2;\nn2->next = n3;\nn3->next = n4;\n
linked_list.java
/* Initialize linked list: 1 -> 3 -> 2 -> 5 -> 4 */\n// Initialize each node\nListNode n0 = new ListNode(1);\nListNode n1 = new ListNode(3);\nListNode n2 = new ListNode(2);\nListNode n3 = new ListNode(5);\nListNode n4 = new ListNode(4);\n// Build references between nodes\nn0.next = n1;\nn1.next = n2;\nn2.next = n3;\nn3.next = n4;\n
linked_list.cs
/* Initialize linked list: 1 -> 3 -> 2 -> 5 -> 4 */\n// Initialize each node\nListNode n0 = new(1);\nListNode n1 = new(3);\nListNode n2 = new(2);\nListNode n3 = new(5);\nListNode n4 = new(4);\n// Build references between nodes\nn0.next = n1;\nn1.next = n2;\nn2.next = n3;\nn3.next = n4;\n
linked_list.go
/* Initialize linked list: 1 -> 3 -> 2 -> 5 -> 4 */\n// Initialize each node\nn0 := NewListNode(1)\nn1 := NewListNode(3)\nn2 := NewListNode(2)\nn3 := NewListNode(5)\nn4 := NewListNode(4)\n// Build references between nodes\nn0.Next = n1\nn1.Next = n2\nn2.Next = n3\nn3.Next = n4\n
linked_list.swift
/* Initialize linked list: 1 -> 3 -> 2 -> 5 -> 4 */\n// Initialize each node\nlet n0 = ListNode(x: 1)\nlet n1 = ListNode(x: 3)\nlet n2 = ListNode(x: 2)\nlet n3 = ListNode(x: 5)\nlet n4 = ListNode(x: 4)\n// Build references between nodes\nn0.next = n1\nn1.next = n2\nn2.next = n3\nn3.next = n4\n
linked_list.js
/* Initialize linked list: 1 -> 3 -> 2 -> 5 -> 4 */\n// Initialize each node\nconst n0 = new ListNode(1);\nconst n1 = new ListNode(3);\nconst n2 = new ListNode(2);\nconst n3 = new ListNode(5);\nconst n4 = new ListNode(4);\n// Build references between nodes\nn0.next = n1;\nn1.next = n2;\nn2.next = n3;\nn3.next = n4;\n
linked_list.ts
/* Initialize linked list: 1 -> 3 -> 2 -> 5 -> 4 */\n// Initialize each node\nconst n0 = new ListNode(1);\nconst n1 = new ListNode(3);\nconst n2 = new ListNode(2);\nconst n3 = new ListNode(5);\nconst n4 = new ListNode(4);\n// Build references between nodes\nn0.next = n1;\nn1.next = n2;\nn2.next = n3;\nn3.next = n4;\n
linked_list.dart
/* Initialize linked list: 1 -> 3 -> 2 -> 5 -> 4 */\n// Initialize each node\nListNode n0 = ListNode(1);\nListNode n1 = ListNode(3);\nListNode n2 = ListNode(2);\nListNode n3 = ListNode(5);\nListNode n4 = ListNode(4);\n// Build references between nodes\nn0.next = n1;\nn1.next = n2;\nn2.next = n3;\nn3.next = n4;\n
linked_list.rs
/* Initialize linked list: 1 -> 3 -> 2 -> 5 -> 4 */\n// Initialize each node\nlet n0 = Rc::new(RefCell::new(ListNode { val: 1, next: None }));\nlet n1 = Rc::new(RefCell::new(ListNode { val: 3, next: None }));\nlet n2 = Rc::new(RefCell::new(ListNode { val: 2, next: None }));\nlet n3 = Rc::new(RefCell::new(ListNode { val: 5, next: None }));\nlet n4 = Rc::new(RefCell::new(ListNode { val: 4, next: None }));\n\n// Build references between nodes\nn0.borrow_mut().next = Some(n1.clone());\nn1.borrow_mut().next = Some(n2.clone());\nn2.borrow_mut().next = Some(n3.clone());\nn3.borrow_mut().next = Some(n4.clone());\n
linked_list.c
/* Initialize linked list: 1 -> 3 -> 2 -> 5 -> 4 */\n// Initialize each node\nListNode* n0 = newListNode(1);\nListNode* n1 = newListNode(3);\nListNode* n2 = newListNode(2);\nListNode* n3 = newListNode(5);\nListNode* n4 = newListNode(4);\n// Build references between nodes\nn0->next = n1;\nn1->next = n2;\nn2->next = n3;\nn3->next = n4;\n
linked_list.zig
// Initialize linked list\n// Initialize each node\nvar n0 = inc.ListNode(i32){.val = 1};\nvar n1 = inc.ListNode(i32){.val = 3};\nvar n2 = inc.ListNode(i32){.val = 2};\nvar n3 = inc.ListNode(i32){.val = 5};\nvar n4 = inc.ListNode(i32){.val = 4};\n// Build references between nodes\nn0.next = &n1;\nn1.next = &n2;\nn2.next = &n3;\nn3.next = &n4;\n

The array as a whole is a variable, for instance, the array nums includes elements like nums[0], nums[1], and so on, whereas a linked list is made up of several distinct node objects. We typically refer to a linked list by its head node, for example, the linked list in the previous code snippet is referred to as n0.

"},{"location":"chapter_array_and_linkedlist/linked_list/#2-inserting-a-node","title":"2. \u00a0 Inserting a Node","text":"

Inserting a node into a linked list is very easy. As shown in the figure, let's assume we aim to insert a new node P between two adjacent nodes n0 and n1. This can be achieved by simply modifying two node references (pointers), with a time complexity of \\(O(1)\\).

By comparison, inserting an element into an array has a time complexity of \\(O(n)\\), which becomes less efficient when dealing with large data volumes.

Figure 4-6 \u00a0 Linked List Node Insertion Example

PythonC++JavaC#GoSwiftJSTSDartRustCZig linked_list.py
def insert(n0: ListNode, P: ListNode):\n    \"\"\"\u5728\u94fe\u8868\u7684\u8282\u70b9 n0 \u4e4b\u540e\u63d2\u5165\u8282\u70b9 P\"\"\"\n    n1 = n0.next\n    P.next = n1\n    n0.next = P\n
linked_list.cpp
/* \u5728\u94fe\u8868\u7684\u8282\u70b9 n0 \u4e4b\u540e\u63d2\u5165\u8282\u70b9 P */\nvoid insert(ListNode *n0, ListNode *P) {\n    ListNode *n1 = n0->next;\n    P->next = n1;\n    n0->next = P;\n}\n
linked_list.java
/* \u5728\u94fe\u8868\u7684\u8282\u70b9 n0 \u4e4b\u540e\u63d2\u5165\u8282\u70b9 P */\nvoid insert(ListNode n0, ListNode P) {\n    ListNode n1 = n0.next;\n    P.next = n1;\n    n0.next = P;\n}\n
linked_list.cs
/* \u5728\u94fe\u8868\u7684\u8282\u70b9 n0 \u4e4b\u540e\u63d2\u5165\u8282\u70b9 P */\nvoid Insert(ListNode n0, ListNode P) {\n    ListNode? n1 = n0.next;\n    P.next = n1;\n    n0.next = P;\n}\n
linked_list.go
/* \u5728\u94fe\u8868\u7684\u8282\u70b9 n0 \u4e4b\u540e\u63d2\u5165\u8282\u70b9 P */\nfunc insertNode(n0 *ListNode, P *ListNode) {\n    n1 := n0.Next\n    P.Next = n1\n    n0.Next = P\n}\n
linked_list.swift
/* \u5728\u94fe\u8868\u7684\u8282\u70b9 n0 \u4e4b\u540e\u63d2\u5165\u8282\u70b9 P */\nfunc insert(n0: ListNode, P: ListNode) {\n    let n1 = n0.next\n    P.next = n1\n    n0.next = P\n}\n
linked_list.js
/* \u5728\u94fe\u8868\u7684\u8282\u70b9 n0 \u4e4b\u540e\u63d2\u5165\u8282\u70b9 P */\nfunction insert(n0, P) {\n    const n1 = n0.next;\n    P.next = n1;\n    n0.next = P;\n}\n
linked_list.ts
/* \u5728\u94fe\u8868\u7684\u8282\u70b9 n0 \u4e4b\u540e\u63d2\u5165\u8282\u70b9 P */\nfunction insert(n0: ListNode, P: ListNode): void {\n    const n1 = n0.next;\n    P.next = n1;\n    n0.next = P;\n}\n
linked_list.dart
/* \u5728\u94fe\u8868\u7684\u8282\u70b9 n0 \u4e4b\u540e\u63d2\u5165\u8282\u70b9 P */\nvoid insert(ListNode n0, ListNode P) {\n  ListNode? n1 = n0.next;\n  P.next = n1;\n  n0.next = P;\n}\n
linked_list.rs
/* \u5728\u94fe\u8868\u7684\u8282\u70b9 n0 \u4e4b\u540e\u63d2\u5165\u8282\u70b9 P */\n#[allow(non_snake_case)]\npub fn insert<T>(n0: &Rc<RefCell<ListNode<T>>>, P: Rc<RefCell<ListNode<T>>>) {\n    let n1 = n0.borrow_mut().next.take();\n    P.borrow_mut().next = n1;\n    n0.borrow_mut().next = Some(P);\n}\n
linked_list.c
/* \u5728\u94fe\u8868\u7684\u8282\u70b9 n0 \u4e4b\u540e\u63d2\u5165\u8282\u70b9 P */\nvoid insert(ListNode *n0, ListNode *P) {\n    ListNode *n1 = n0->next;\n    P->next = n1;\n    n0->next = P;\n}\n
linked_list.zig
// \u5728\u94fe\u8868\u7684\u8282\u70b9 n0 \u4e4b\u540e\u63d2\u5165\u8282\u70b9 P\nfn insert(n0: ?*inc.ListNode(i32), P: ?*inc.ListNode(i32)) void {\n    var n1 = n0.?.next;\n    P.?.next = n1;\n    n0.?.next = P;\n}\n
Code Visualization

Full Screen >

"},{"location":"chapter_array_and_linkedlist/linked_list/#3-deleting-a-node","title":"3. \u00a0 Deleting a Node","text":"

As shown in the figure, deleting a node from a linked list is also very easy, involving only the modification of a single node's reference (pointer).

It's important to note that even though node P continues to point to n1 after being deleted, it becomes inaccessible during linked list traversal. This effectively means that P is no longer a part of the linked list.

Figure 4-7 \u00a0 Linked List Node Deletion

PythonC++JavaC#GoSwiftJSTSDartRustCZig linked_list.py
def remove(n0: ListNode):\n    \"\"\"\u5220\u9664\u94fe\u8868\u7684\u8282\u70b9 n0 \u4e4b\u540e\u7684\u9996\u4e2a\u8282\u70b9\"\"\"\n    if not n0.next:\n        return\n    # n0 -> P -> n1\n    P = n0.next\n    n1 = P.next\n    n0.next = n1\n
linked_list.cpp
/* \u5220\u9664\u94fe\u8868\u7684\u8282\u70b9 n0 \u4e4b\u540e\u7684\u9996\u4e2a\u8282\u70b9 */\nvoid remove(ListNode *n0) {\n    if (n0->next == nullptr)\n        return;\n    // n0 -> P -> n1\n    ListNode *P = n0->next;\n    ListNode *n1 = P->next;\n    n0->next = n1;\n    // \u91ca\u653e\u5185\u5b58\n    delete P;\n}\n
linked_list.java
/* \u5220\u9664\u94fe\u8868\u7684\u8282\u70b9 n0 \u4e4b\u540e\u7684\u9996\u4e2a\u8282\u70b9 */\nvoid remove(ListNode n0) {\n    if (n0.next == null)\n        return;\n    // n0 -> P -> n1\n    ListNode P = n0.next;\n    ListNode n1 = P.next;\n    n0.next = n1;\n}\n
linked_list.cs
/* \u5220\u9664\u94fe\u8868\u7684\u8282\u70b9 n0 \u4e4b\u540e\u7684\u9996\u4e2a\u8282\u70b9 */\nvoid Remove(ListNode n0) {\n    if (n0.next == null)\n        return;\n    // n0 -> P -> n1\n    ListNode P = n0.next;\n    ListNode? n1 = P.next;\n    n0.next = n1;\n}\n
linked_list.go
/* \u5220\u9664\u94fe\u8868\u7684\u8282\u70b9 n0 \u4e4b\u540e\u7684\u9996\u4e2a\u8282\u70b9 */\nfunc removeItem(n0 *ListNode) {\n    if n0.Next == nil {\n        return\n    }\n    // n0 -> P -> n1\n    P := n0.Next\n    n1 := P.Next\n    n0.Next = n1\n}\n
linked_list.swift
/* \u5220\u9664\u94fe\u8868\u7684\u8282\u70b9 n0 \u4e4b\u540e\u7684\u9996\u4e2a\u8282\u70b9 */\nfunc remove(n0: ListNode) {\n    if n0.next == nil {\n        return\n    }\n    // n0 -> P -> n1\n    let P = n0.next\n    let n1 = P?.next\n    n0.next = n1\n}\n
linked_list.js
/* \u5220\u9664\u94fe\u8868\u7684\u8282\u70b9 n0 \u4e4b\u540e\u7684\u9996\u4e2a\u8282\u70b9 */\nfunction remove(n0) {\n    if (!n0.next) return;\n    // n0 -> P -> n1\n    const P = n0.next;\n    const n1 = P.next;\n    n0.next = n1;\n}\n
linked_list.ts
/* \u5220\u9664\u94fe\u8868\u7684\u8282\u70b9 n0 \u4e4b\u540e\u7684\u9996\u4e2a\u8282\u70b9 */\nfunction remove(n0: ListNode): void {\n    if (!n0.next) {\n        return;\n    }\n    // n0 -> P -> n1\n    const P = n0.next;\n    const n1 = P.next;\n    n0.next = n1;\n}\n
linked_list.dart
/* \u5220\u9664\u94fe\u8868\u7684\u8282\u70b9 n0 \u4e4b\u540e\u7684\u9996\u4e2a\u8282\u70b9 */\nvoid remove(ListNode n0) {\n  if (n0.next == null) return;\n  // n0 -> P -> n1\n  ListNode P = n0.next!;\n  ListNode? n1 = P.next;\n  n0.next = n1;\n}\n
linked_list.rs
/* \u5220\u9664\u94fe\u8868\u7684\u8282\u70b9 n0 \u4e4b\u540e\u7684\u9996\u4e2a\u8282\u70b9 */\n#[allow(non_snake_case)]\npub fn remove<T>(n0: &Rc<RefCell<ListNode<T>>>) {\n    if n0.borrow().next.is_none() {\n        return;\n    };\n    // n0 -> P -> n1\n    let P = n0.borrow_mut().next.take();\n    if let Some(node) = P {\n        let n1 = node.borrow_mut().next.take();\n        n0.borrow_mut().next = n1;\n    }\n}\n
linked_list.c
/* \u5220\u9664\u94fe\u8868\u7684\u8282\u70b9 n0 \u4e4b\u540e\u7684\u9996\u4e2a\u8282\u70b9 */\n// \u6ce8\u610f\uff1astdio.h \u5360\u7528\u4e86 remove \u5173\u952e\u8bcd\nvoid removeItem(ListNode *n0) {\n    if (!n0->next)\n        return;\n    // n0 -> P -> n1\n    ListNode *P = n0->next;\n    ListNode *n1 = P->next;\n    n0->next = n1;\n    // \u91ca\u653e\u5185\u5b58\n    free(P);\n}\n
linked_list.zig
// \u5220\u9664\u94fe\u8868\u7684\u8282\u70b9 n0 \u4e4b\u540e\u7684\u9996\u4e2a\u8282\u70b9\nfn remove(n0: ?*inc.ListNode(i32)) void {\n    if (n0.?.next == null) return;\n    // n0 -> P -> n1\n    var P = n0.?.next;\n    var n1 = P.?.next;\n    n0.?.next = n1;\n}\n
Code Visualization

Full Screen >

"},{"location":"chapter_array_and_linkedlist/linked_list/#4-accessing-nodes","title":"4. \u00a0 Accessing Nodes","text":"

Accessing nodes in a linked list is less efficient. As previously mentioned, any element in an array can be accessed in \\(O(1)\\) time. In contrast, with a linked list, the program involves starting from the head node and sequentially traversing through the nodes until the desired node is found. In other words, to access the \\(i\\)-th node in a linked list, the program must iterate through \\(i - 1\\) nodes, resulting in a time complexity of \\(O(n)\\).

PythonC++JavaC#GoSwiftJSTSDartRustCZig linked_list.py
def access(head: ListNode, index: int) -> ListNode | None:\n    \"\"\"\u8bbf\u95ee\u94fe\u8868\u4e2d\u7d22\u5f15\u4e3a index \u7684\u8282\u70b9\"\"\"\n    for _ in range(index):\n        if not head:\n            return None\n        head = head.next\n    return head\n
linked_list.cpp
/* \u8bbf\u95ee\u94fe\u8868\u4e2d\u7d22\u5f15\u4e3a index \u7684\u8282\u70b9 */\nListNode *access(ListNode *head, int index) {\n    for (int i = 0; i < index; i++) {\n        if (head == nullptr)\n            return nullptr;\n        head = head->next;\n    }\n    return head;\n}\n
linked_list.java
/* \u8bbf\u95ee\u94fe\u8868\u4e2d\u7d22\u5f15\u4e3a index \u7684\u8282\u70b9 */\nListNode access(ListNode head, int index) {\n    for (int i = 0; i < index; i++) {\n        if (head == null)\n            return null;\n        head = head.next;\n    }\n    return head;\n}\n
linked_list.cs
/* \u8bbf\u95ee\u94fe\u8868\u4e2d\u7d22\u5f15\u4e3a index \u7684\u8282\u70b9 */\nListNode? Access(ListNode? head, int index) {\n    for (int i = 0; i < index; i++) {\n        if (head == null)\n            return null;\n        head = head.next;\n    }\n    return head;\n}\n
linked_list.go
/* \u8bbf\u95ee\u94fe\u8868\u4e2d\u7d22\u5f15\u4e3a index \u7684\u8282\u70b9 */\nfunc access(head *ListNode, index int) *ListNode {\n    for i := 0; i < index; i++ {\n        if head == nil {\n            return nil\n        }\n        head = head.Next\n    }\n    return head\n}\n
linked_list.swift
/* \u8bbf\u95ee\u94fe\u8868\u4e2d\u7d22\u5f15\u4e3a index \u7684\u8282\u70b9 */\nfunc access(head: ListNode, index: Int) -> ListNode? {\n    var head: ListNode? = head\n    for _ in 0 ..< index {\n        if head == nil {\n            return nil\n        }\n        head = head?.next\n    }\n    return head\n}\n
linked_list.js
/* \u8bbf\u95ee\u94fe\u8868\u4e2d\u7d22\u5f15\u4e3a index \u7684\u8282\u70b9 */\nfunction access(head, index) {\n    for (let i = 0; i < index; i++) {\n        if (!head) {\n            return null;\n        }\n        head = head.next;\n    }\n    return head;\n}\n
linked_list.ts
/* \u8bbf\u95ee\u94fe\u8868\u4e2d\u7d22\u5f15\u4e3a index \u7684\u8282\u70b9 */\nfunction access(head: ListNode | null, index: number): ListNode | null {\n    for (let i = 0; i < index; i++) {\n        if (!head) {\n            return null;\n        }\n        head = head.next;\n    }\n    return head;\n}\n
linked_list.dart
/* \u8bbf\u95ee\u94fe\u8868\u4e2d\u7d22\u5f15\u4e3a index \u7684\u8282\u70b9 */\nListNode? access(ListNode? head, int index) {\n  for (var i = 0; i < index; i++) {\n    if (head == null) return null;\n    head = head.next;\n  }\n  return head;\n}\n
linked_list.rs
/* \u8bbf\u95ee\u94fe\u8868\u4e2d\u7d22\u5f15\u4e3a index \u7684\u8282\u70b9 */\npub fn access<T>(head: Rc<RefCell<ListNode<T>>>, index: i32) -> Rc<RefCell<ListNode<T>>> {\n    if index <= 0 {\n        return head;\n    };\n    if let Some(node) = &head.borrow().next {\n        return access(node.clone(), index - 1);\n    }\n\n    return head;\n}\n
linked_list.c
/* \u8bbf\u95ee\u94fe\u8868\u4e2d\u7d22\u5f15\u4e3a index \u7684\u8282\u70b9 */\nListNode *access(ListNode *head, int index) {\n    for (int i = 0; i < index; i++) {\n        if (head == NULL)\n            return NULL;\n        head = head->next;\n    }\n    return head;\n}\n
linked_list.zig
// \u8bbf\u95ee\u94fe\u8868\u4e2d\u7d22\u5f15\u4e3a index \u7684\u8282\u70b9\nfn access(node: ?*inc.ListNode(i32), index: i32) ?*inc.ListNode(i32) {\n    var head = node;\n    var i: i32 = 0;\n    while (i < index) : (i += 1) {\n        head = head.?.next;\n        if (head == null) return null;\n    }\n    return head;\n}\n
Code Visualization

Full Screen >

"},{"location":"chapter_array_and_linkedlist/linked_list/#5-finding-nodes","title":"5. \u00a0 Finding Nodes","text":"

Traverse the linked list to locate a node whose value matches target, and then output the index of that node within the linked list. This procedure is also an example of linear search. The corresponding code is provided below:

PythonC++JavaC#GoSwiftJSTSDartRustCZig linked_list.py
def find(head: ListNode, target: int) -> int:\n    \"\"\"\u5728\u94fe\u8868\u4e2d\u67e5\u627e\u503c\u4e3a target \u7684\u9996\u4e2a\u8282\u70b9\"\"\"\n    index = 0\n    while head:\n        if head.val == target:\n            return index\n        head = head.next\n        index += 1\n    return -1\n
linked_list.cpp
/* \u5728\u94fe\u8868\u4e2d\u67e5\u627e\u503c\u4e3a target \u7684\u9996\u4e2a\u8282\u70b9 */\nint find(ListNode *head, int target) {\n    int index = 0;\n    while (head != nullptr) {\n        if (head->val == target)\n            return index;\n        head = head->next;\n        index++;\n    }\n    return -1;\n}\n
linked_list.java
/* \u5728\u94fe\u8868\u4e2d\u67e5\u627e\u503c\u4e3a target \u7684\u9996\u4e2a\u8282\u70b9 */\nint find(ListNode head, int target) {\n    int index = 0;\n    while (head != null) {\n        if (head.val == target)\n            return index;\n        head = head.next;\n        index++;\n    }\n    return -1;\n}\n
linked_list.cs
/* \u5728\u94fe\u8868\u4e2d\u67e5\u627e\u503c\u4e3a target \u7684\u9996\u4e2a\u8282\u70b9 */\nint Find(ListNode? head, int target) {\n    int index = 0;\n    while (head != null) {\n        if (head.val == target)\n            return index;\n        head = head.next;\n        index++;\n    }\n    return -1;\n}\n
linked_list.go
/* \u5728\u94fe\u8868\u4e2d\u67e5\u627e\u503c\u4e3a target \u7684\u9996\u4e2a\u8282\u70b9 */\nfunc findNode(head *ListNode, target int) int {\n    index := 0\n    for head != nil {\n        if head.Val == target {\n            return index\n        }\n        head = head.Next\n        index++\n    }\n    return -1\n}\n
linked_list.swift
/* \u5728\u94fe\u8868\u4e2d\u67e5\u627e\u503c\u4e3a target \u7684\u9996\u4e2a\u8282\u70b9 */\nfunc find(head: ListNode, target: Int) -> Int {\n    var head: ListNode? = head\n    var index = 0\n    while head != nil {\n        if head?.val == target {\n            return index\n        }\n        head = head?.next\n        index += 1\n    }\n    return -1\n}\n
linked_list.js
/* \u5728\u94fe\u8868\u4e2d\u67e5\u627e\u503c\u4e3a target \u7684\u9996\u4e2a\u8282\u70b9 */\nfunction find(head, target) {\n    let index = 0;\n    while (head !== null) {\n        if (head.val === target) {\n            return index;\n        }\n        head = head.next;\n        index += 1;\n    }\n    return -1;\n}\n
linked_list.ts
/* \u5728\u94fe\u8868\u4e2d\u67e5\u627e\u503c\u4e3a target \u7684\u9996\u4e2a\u8282\u70b9 */\nfunction find(head: ListNode | null, target: number): number {\n    let index = 0;\n    while (head !== null) {\n        if (head.val === target) {\n            return index;\n        }\n        head = head.next;\n        index += 1;\n    }\n    return -1;\n}\n
linked_list.dart
/* \u5728\u94fe\u8868\u4e2d\u67e5\u627e\u503c\u4e3a target \u7684\u9996\u4e2a\u8282\u70b9 */\nint find(ListNode? head, int target) {\n  int index = 0;\n  while (head != null) {\n    if (head.val == target) {\n      return index;\n    }\n    head = head.next;\n    index++;\n  }\n  return -1;\n}\n
linked_list.rs
/* \u5728\u94fe\u8868\u4e2d\u67e5\u627e\u503c\u4e3a target \u7684\u9996\u4e2a\u8282\u70b9 */\npub fn find<T: PartialEq>(head: Rc<RefCell<ListNode<T>>>, target: T, index: i32) -> i32 {\n    if head.borrow().val == target {\n        return index;\n    };\n    if let Some(node) = &head.borrow_mut().next {\n        return find(node.clone(), target, index + 1);\n    }\n    return -1;\n}\n
linked_list.c
/* \u5728\u94fe\u8868\u4e2d\u67e5\u627e\u503c\u4e3a target \u7684\u9996\u4e2a\u8282\u70b9 */\nint find(ListNode *head, int target) {\n    int index = 0;\n    while (head) {\n        if (head->val == target)\n            return index;\n        head = head->next;\n        index++;\n    }\n    return -1;\n}\n
linked_list.zig
// \u5728\u94fe\u8868\u4e2d\u67e5\u627e\u503c\u4e3a target \u7684\u9996\u4e2a\u8282\u70b9\nfn find(node: ?*inc.ListNode(i32), target: i32) i32 {\n    var head = node;\n    var index: i32 = 0;\n    while (head != null) {\n        if (head.?.val == target) return index;\n        head = head.?.next;\n        index += 1;\n    }\n    return -1;\n}\n
Code Visualization

Full Screen >

"},{"location":"chapter_array_and_linkedlist/linked_list/#422-arrays-vs-linked-lists","title":"4.2.2 \u00a0 Arrays vs. Linked Lists","text":"

The Table 4-1 summarizes the characteristics of arrays and linked lists, and it also compares their efficiencies in various operations. Because they utilize opposing storage strategies, their respective properties and operational efficiencies exhibit distinct contrasts.

Table 4-1 \u00a0 Efficiency Comparison of Arrays and Linked Lists

Arrays Linked Lists Storage Contiguous Memory Space Dispersed Memory Space Capacity Expansion Fixed Length Flexible Expansion Memory Efficiency Less Memory per Element, Potential Space Wastage More Memory per Element Accessing Elements \\(O(1)\\) \\(O(n)\\) Adding Elements \\(O(n)\\) \\(O(1)\\) Deleting Elements \\(O(n)\\) \\(O(1)\\)"},{"location":"chapter_array_and_linkedlist/linked_list/#423-common-types-of-linked-lists","title":"4.2.3 \u00a0 Common Types of Linked Lists","text":"

As shown in the figure, there are three common types of linked lists.

  • Singly Linked List: This is the standard linked list described earlier. Nodes in a singly linked list include a value and a reference to the next node. The first node is known as the head node, and the last node, which points to null (None), is the tail node.
  • Circular Linked List: This is formed when the tail node of a singly linked list points back to the head node, creating a loop. In a circular linked list, any node can function as the head node.
  • Doubly Linked List: In contrast to a singly linked list, a doubly linked list maintains references in two directions. Each node contains references (pointer) to both its successor (the next node) and predecessor (the previous node). Although doubly linked lists offer more flexibility for traversing in either direction, they also consume more memory space.
PythonC++JavaC#GoSwiftJSTSDartRustCZig
class ListNode:\n    \"\"\"Bidirectional linked list node class\"\"\"\"\n    def __init__(self, val: int):\n        self.val: int = val                # Node value\n        self.next: ListNode | None = None  # Reference to the successor node\n        self.prev: ListNode | None = None  # Reference to a predecessor node\n
/* Bidirectional linked list node structure */\nstruct ListNode {\n    int val;         // Node value\n    ListNode *next;  // Pointer to the successor node\n    ListNode *prev;  // Pointer to the predecessor node\n    ListNode(int x) : val(x), next(nullptr), prev(nullptr) {}  // Constructor\n};\n
/* Bidirectional linked list node class */\nclass ListNode {\n    int val;        // Node value\n    ListNode next;  // Reference to the next node\n    ListNode prev;  // Reference to the predecessor node\n    ListNode(int x) { val = x; }  // Constructor\n}\n
/* Bidirectional linked list node class */\nclass ListNode(int x) {  // Constructor\n    int val = x;    // Node value\n    ListNode next;  // Reference to the next node\n    ListNode prev;  // Reference to the predecessor node\n}\n
/* Bidirectional linked list node structure */\ntype DoublyListNode struct {\n    Val  int             // Node value\n    Next *DoublyListNode // Pointer to the successor node\n    Prev *DoublyListNode // Pointer to the predecessor node\n}\n\n// NewDoublyListNode initialization\nfunc NewDoublyListNode(val int) *DoublyListNode {\n    return &DoublyListNode{\n        Val:  val,\n        Next: nil,\n        Prev: nil,\n    }\n}\n
/* Bidirectional linked list node class */\nclass ListNode {\n    var val: Int // Node value\n    var next: ListNode? // Reference to the next node\n    var prev: ListNode? // Reference to the predecessor node\n\n    init(x: Int) { // Constructor\n        val = x\n    }\n}\n
/* Bidirectional linked list node class */\nclass ListNode {\n    constructor(val, next, prev) {\n        this.val = val  ===  undefined ? 0 : val;        // Node value\n        this.next = next  ===  undefined ? null : next;  // Reference to the successor node\n        this.prev = prev  ===  undefined ? null : prev;  // Reference to the predecessor node\n    }\n}\n
/* Bidirectional linked list node class */\nclass ListNode {\n    val: number;\n    next: ListNode | null;\n    prev: ListNode | null;\n    constructor(val?: number, next?: ListNode | null, prev?: ListNode | null) {\n        this.val = val  ===  undefined ? 0 : val;        // Node value\n        this.next = next  ===  undefined ? null : next;  // Reference to the successor node\n        this.prev = prev  ===  undefined ? null : prev;  // Reference to the predecessor node\n    }\n}\n
/* Bidirectional linked list node class */\nclass ListNode {\n    int val;        // Node value\n    ListNode next;  // Reference to the next node\n    ListNode prev;  // Reference to the predecessor node\n    ListNode(this.val, [this.next, this.prev]);  // Constructor\n}\n
use std::rc::Rc;\nuse std::cell::RefCell;\n\n/* Bidirectional linked list node type */\n#[derive(Debug)]\nstruct ListNode {\n    val: i32, // Node value\n    next: Option<Rc<RefCell<ListNode>>>, // Pointer to successor node\n    prev: Option<Rc<RefCell<ListNode>>>, // Pointer to predecessor node\n}\n\n/* Constructors */\nimpl ListNode {\n    fn new(val: i32) -> Self {\n        ListNode {\n            val,\n            next: None,\n            prev: None,\n        }\n    }\n}\n
/* Bidirectional linked list node structure */\ntypedef struct ListNode {\n    int val;               // Node value\n    struct ListNode *next; // Pointer to the successor node\n    struct ListNode *prev; // Pointer to the predecessor node\n} ListNode;\n\n/* Constructors */\nListNode *newListNode(int val) {\n    ListNode *node, *next;\n    node = (ListNode *) malloc(sizeof(ListNode));\n    node->val = val;\n    node->next = NULL;\n    node->prev = NULL;\n    return node;\n}\n
// Bidirectional linked list node class\npub fn ListNode(comptime T: type) type {\n    return struct {\n        const Self = @This();\n\n        val: T = 0, // Node value\n        next: ?*Self = null, // Pointer to the successor node\n        prev: ?*Self = null, // Pointer to the predecessor node\n\n        // Constructor\n        pub fn init(self: *Self, x: i32) void {\n            self.val = x;\n            self.next = null;\n            self.prev = null;\n        }\n    };\n}\n

Figure 4-8 \u00a0 Common Types of Linked Lists

"},{"location":"chapter_array_and_linkedlist/linked_list/#424-typical-applications-of-linked-lists","title":"4.2.4 \u00a0 Typical Applications of Linked Lists","text":"

Singly linked lists are frequently utilized in implementing stacks, queues, hash tables, and graphs.

  • Stacks and Queues: In singly linked lists, if insertions and deletions occur at the same end, it behaves like a stack (last-in-first-out). Conversely, if insertions are at one end and deletions at the other, it functions like a queue (first-in-first-out).
  • Hash Tables: Linked lists are used in chaining, a popular method for resolving hash collisions. Here, all collided elements are grouped into a linked list.
  • Graphs: Adjacency lists, a standard method for graph representation, associate each graph vertex with a linked list. This list contains elements that represent vertices connected to the corresponding vertex.

Doubly linked lists are ideal for scenarios requiring rapid access to preceding and succeeding elements.

  • Advanced Data Structures: In structures like red-black trees and B-trees, accessing a node's parent is essential. This is achieved by incorporating a reference to the parent node in each node, akin to a doubly linked list.
  • Browser History: In web browsers, doubly linked lists facilitate navigating the history of visited pages when users click forward or back.
  • LRU Algorithm: Doubly linked lists are apt for Least Recently Used (LRU) cache eviction algorithms, enabling swift identification of the least recently used data and facilitating fast node addition and removal.

Circular linked lists are ideal for applications that require periodic operations, such as resource scheduling in operating systems.

  • Round-Robin Scheduling Algorithm: In operating systems, the round-robin scheduling algorithm is a common CPU scheduling method, requiring cycling through a group of processes. Each process is assigned a time slice, and upon expiration, the CPU rotates to the next process. This cyclical operation can be efficiently realized using a circular linked list, allowing for a fair and time-shared system among all processes.
  • Data Buffers: Circular linked lists are also used in data buffers, like in audio and video players, where the data stream is divided into multiple buffer blocks arranged in a circular fashion for seamless playback.
"},{"location":"chapter_array_and_linkedlist/list/","title":"4.3 \u00a0 List","text":"

A \"list\" is an abstract data structure concept that represents an ordered collection of elements, supporting operations such as element access, modification, addition, deletion, and traversal, without requiring users to consider capacity limitations. Lists can be implemented based on linked lists or arrays.

  • A linked list inherently serves as a list, supporting operations for adding, deleting, searching, and modifying elements, with the flexibility to dynamically adjust its size.
  • Arrays also support these operations, but due to their immutable length, they can be considered as a list with a length limit.

When implementing lists using arrays, the immutability of length reduces the practicality of the list. This is because predicting the amount of data to be stored in advance is often challenging, making it difficult to choose an appropriate list length. If the length is too small, it may not meet the requirements; if too large, it may waste memory space.

To solve this problem, we can implement lists using a \"dynamic array.\" It inherits the advantages of arrays and can dynamically expand during program execution.

In fact, many programming languages' standard libraries implement lists using dynamic arrays, such as Python's list, Java's ArrayList, C++'s vector, and C#'s List. In the following discussion, we will consider \"list\" and \"dynamic array\" as synonymous concepts.

"},{"location":"chapter_array_and_linkedlist/list/#431-common-list-operations","title":"4.3.1 \u00a0 Common List Operations","text":""},{"location":"chapter_array_and_linkedlist/list/#1-initializing-a-list","title":"1. \u00a0 Initializing a List","text":"

We typically use two initialization methods: \"without initial values\" and \"with initial values\".

PythonC++JavaC#GoSwiftJSTSDartRustCZig list.py
# Initialize list\n# Without initial values\nnums1: list[int] = []\n# With initial values\nnums: list[int] = [1, 3, 2, 5, 4]\n
list.cpp
/* Initialize list */\n// Note, in C++ the vector is the equivalent of nums described here\n// Without initial values\nvector<int> nums1;\n// With initial values\nvector<int> nums = { 1, 3, 2, 5, 4 };\n
list.java
/* Initialize list */\n// Without initial values\nList<Integer> nums1 = new ArrayList<>();\n// With initial values (note the element type should be the wrapper class Integer[] for int[])\nInteger[] numbers = new Integer[] { 1, 3, 2, 5, 4 };\nList<Integer> nums = new ArrayList<>(Arrays.asList(numbers));\n
list.cs
/* Initialize list */\n// Without initial values\nList<int> nums1 = [];\n// With initial values\nint[] numbers = [1, 3, 2, 5, 4];\nList<int> nums = [.. numbers];\n
list_test.go
/* Initialize list */\n// Without initial values\nnums1 := []int{}\n// With initial values\nnums := []int{1, 3, 2, 5, 4}\n
list.swift
/* Initialize list */\n// Without initial values\nlet nums1: [Int] = []\n// With initial values\nvar nums = [1, 3, 2, 5, 4]\n
list.js
/* Initialize list */\n// Without initial values\nconst nums1 = [];\n// With initial values\nconst nums = [1, 3, 2, 5, 4];\n
list.ts
/* Initialize list */\n// Without initial values\nconst nums1: number[] = [];\n// With initial values\nconst nums: number[] = [1, 3, 2, 5, 4];\n
list.dart
/* Initialize list */\n// Without initial values\nList<int> nums1 = [];\n// With initial values\nList<int> nums = [1, 3, 2, 5, 4];\n
list.rs
/* Initialize list */\n// Without initial values\nlet nums1: Vec<i32> = Vec::new();\n// With initial values\nlet nums: Vec<i32> = vec![1, 3, 2, 5, 4];\n
list.c
// C does not provide built-in dynamic arrays\n
list.zig
// Initialize list\nvar nums = std.ArrayList(i32).init(std.heap.page_allocator);\ndefer nums.deinit();\ntry nums.appendSlice(&[_]i32{ 1, 3, 2, 5, 4 });\n
"},{"location":"chapter_array_and_linkedlist/list/#2-accessing-elements","title":"2. \u00a0 Accessing Elements","text":"

Lists are essentially arrays, thus they can access and update elements in \\(O(1)\\) time, which is very efficient.

PythonC++JavaC#GoSwiftJSTSDartRustCZig list.py
# Access elements\nnum: int = nums[1]  # Access the element at index 1\n\n# Update elements\nnums[1] = 0    # Update the element at index 1 to 0\n
list.cpp
/* Access elements */\nint num = nums[1];  // Access the element at index 1\n\n/* Update elements */\nnums[1] = 0;  // Update the element at index 1 to 0\n
list.java
/* Access elements */\nint num = nums.get(1);  // Access the element at index 1\n\n/* Update elements */\nnums.set(1, 0);  // Update the element at index 1 to 0\n
list.cs
/* Access elements */\nint num = nums[1];  // Access the element at index 1\n\n/* Update elements */\nnums[1] = 0;  // Update the element at index 1 to 0\n
list_test.go
/* Access elements */\nnum := nums[1]  // Access the element at index 1\n\n/* Update elements */\nnums[1] = 0     // Update the element at index 1 to 0\n
list.swift
/* Access elements */\nlet num = nums[1] // Access the element at index 1\n\n/* Update elements */\nnums[1] = 0 // Update the element at index 1 to 0\n
list.js
/* Access elements */\nconst num = nums[1];  // Access the element at index 1\n\n/* Update elements */\nnums[1] = 0;  // Update the element at index 1 to 0\n
list.ts
/* Access elements */\nconst num: number = nums[1];  // Access the element at index 1\n\n/* Update elements */\nnums[1] = 0;  // Update the element at index 1 to 0\n
list.dart
/* Access elements */\nint num = nums[1];  // Access the element at index 1\n\n/* Update elements */\nnums[1] = 0;  // Update the element at index 1 to 0\n
list.rs
/* Access elements */\nlet num: i32 = nums[1];  // Access the element at index 1\n/* Update elements */\nnums[1] = 0;             // Update the element at index 1 to 0\n
list.c
// C does not provide built-in dynamic arrays\n
list.zig
// Access elements\nvar num = nums.items[1]; // Access the element at index 1\n\n// Update elements\nnums.items[1] = 0; // Update the element at index 1 to 0  \n
"},{"location":"chapter_array_and_linkedlist/list/#3-inserting-and-removing-elements","title":"3. \u00a0 Inserting and Removing Elements","text":"

Compared to arrays, lists offer more flexibility in adding and removing elements. While adding elements to the end of a list is an \\(O(1)\\) operation, the efficiency of inserting and removing elements elsewhere in the list remains the same as in arrays, with a time complexity of \\(O(n)\\).

PythonC++JavaC#GoSwiftJSTSDartRustCZig list.py
# Clear list\nnums.clear()\n\n# Append elements at the end\nnums.append(1)\nnums.append(3)\nnums.append(2)\nnums.append(5)\nnums.append(4)\n\n# Insert element in the middle\nnums.insert(3, 6)  # Insert number 6 at index 3\n\n# Remove elements\nnums.pop(3)        # Remove the element at index 3\n
list.cpp
/* Clear list */\nnums.clear();\n\n/* Append elements at the end */\nnums.push_back(1);\nnums.push_back(3);\nnums.push_back(2);\nnums.push_back(5);\nnums.push_back(4);\n\n/* Insert element in the middle */\nnums.insert(nums.begin() + 3, 6);  // Insert number 6 at index 3\n\n/* Remove elements */\nnums.erase(nums.begin() + 3);      // Remove the element at index 3\n
list.java
/* Clear list */\nnums.clear();\n\n/* Append elements at the end */\nnums.add(1);\nnums.add(3);\nnums.add(2);\nnums.add(5);\nnums.add(4);\n\n/* Insert element in the middle */\nnums.add(3, 6);  // Insert number 6 at index 3\n\n/* Remove elements */\nnums.remove(3);  // Remove the element at index 3\n
list.cs
/* Clear list */\nnums.Clear();\n\n/* Append elements at the end */\nnums.Add(1);\nnums.Add(3);\nnums.Add(2);\nnums.Add(5);\nnums.Add(4);\n\n/* Insert element in the middle */\nnums.Insert(3, 6);\n\n/* Remove elements */\nnums.RemoveAt(3);\n
list_test.go
/* Clear list */\nnums = nil\n\n/* Append elements at the end */\nnums = append(nums, 1)\nnums = append(nums, 3)\nnums = append(nums, 2)\nnums = append(nums, 5)\nnums = append(nums, 4)\n\n/* Insert element in the middle */\nnums = append(nums[:3], append([]int{6}, nums[3:]...)...) // Insert number 6 at index 3\n\n/* Remove elements */\nnums = append(nums[:3], nums[4:]...) // Remove the element at index 3\n
list.swift
/* Clear list */\nnums.removeAll()\n\n/* Append elements at the end */\nnums.append(1)\nnums.append(3)\nnums.append(2)\nnums.append(5)\nnums.append(4)\n\n/* Insert element in the middle */\nnums.insert(6, at: 3) // Insert number 6 at index 3\n\n/* Remove elements */\nnums.remove(at: 3) // Remove the element at index 3\n
list.js
/* Clear list */\nnums.length = 0;\n\n/* Append elements at the end */\nnums.push(1);\nnums.push(3);\nnums.push(2);\nnums.push(5);\nnums.push(4);\n\n/* Insert element in the middle */\nnums.splice(3, 0, 6);\n\n/* Remove elements */\nnums.splice(3, 1);\n
list.ts
/* Clear list */\nnums.length = 0;\n\n/* Append elements at the end */\nnums.push(1);\nnums.push(3);\nnums.push(2);\nnums.push(5);\nnums.push(4);\n\n/* Insert element in the middle */\nnums.splice(3, 0, 6);\n\n/* Remove elements */\nnums.splice(3, 1);\n
list.dart
/* Clear list */\nnums.clear();\n\n/* Append elements at the end */\nnums.add(1);\nnums.add(3);\nnums.add(2);\nnums.add(5);\nnums.add(4);\n\n/* Insert element in the middle */\nnums.insert(3, 6); // Insert number 6 at index 3\n\n/* Remove elements */\nnums.removeAt(3); // Remove the element at index 3\n
list.rs
/* Clear list */\nnums.clear();\n\n/* Append elements at the end */\nnums.push(1);\nnums.push(3);\nnums.push(2);\nnums.push(5);\nnums.push(4);\n\n/* Insert element in the middle */\nnums.insert(3, 6);  // Insert number 6 at index 3\n\n/* Remove elements */\nnums.remove(3);    // Remove the element at index 3\n
list.c
// C does not provide built-in dynamic arrays\n
list.zig
// Clear list\nnums.clearRetainingCapacity();\n\n// Append elements at the end\ntry nums.append(1);\ntry nums.append(3);\ntry nums.append(2);\ntry nums.append(5);\ntry nums.append(4);\n\n// Insert element in the middle\ntry nums.insert(3, 6); // Insert number 6 at index 3\n\n// Remove elements\n_ = nums.orderedRemove(3); // Remove the element at index 3\n
"},{"location":"chapter_array_and_linkedlist/list/#4-iterating-the-list","title":"4. \u00a0 Iterating the List","text":"

Similar to arrays, lists can be iterated either by using indices or by directly iterating through each element.

PythonC++JavaC#GoSwiftJSTSDartRustCZig list.py
# Iterate through the list by index\ncount = 0\nfor i in range(len(nums)):\n    count += nums[i]\n\n# Iterate directly through list elements\nfor num in nums:\n    count += num\n
list.cpp
/* Iterate through the list by index */\nint count = 0;\nfor (int i = 0; i < nums.size(); i++) {\n    count += nums[i];\n}\n\n/* Iterate directly through list elements */\ncount = 0;\nfor (int num : nums) {\n    count += num;\n}\n
list.java
/* Iterate through the list by index */\nint count = 0;\nfor (int i = 0; i < nums.size(); i++) {\n    count += nums.get(i);\n}\n\n/* Iterate directly through list elements */\nfor (int num : nums) {\n    count += num;\n}\n
list.cs
/* Iterate through the list by index */\nint count = 0;\nfor (int i = 0; i < nums.Count; i++) {\n    count += nums[i];\n}\n\n/* Iterate directly through list elements */\ncount = 0;\nforeach (int num in nums) {\n    count += num;\n}\n
list_test.go
/* Iterate through the list by index */\ncount := 0\nfor i := 0; i < len(nums); i++ {\n    count += nums[i]\n}\n\n/* Iterate directly through list elements */\ncount = 0\nfor _, num := range nums {\n    count += num\n}\n
list.swift
/* Iterate through the list by index */\nvar count = 0\nfor i in nums.indices {\n    count += nums[i]\n}\n\n/* Iterate directly through list elements */\ncount = 0\nfor num in nums {\n    count += num\n}\n
list.js
/* Iterate through the list by index */\nlet count = 0;\nfor (let i = 0; i < nums.length; i++) {\n    count += nums[i];\n}\n\n/* Iterate directly through list elements */\ncount = 0;\nfor (const num of nums) {\n    count += num;\n}\n
list.ts
/* Iterate through the list by index */\nlet count = 0;\nfor (let i = 0; i < nums.length; i++) {\n    count += nums[i];\n}\n\n/* Iterate directly through list elements */\ncount = 0;\nfor (const num of nums) {\n    count += num;\n}\n
list.dart
/* Iterate through the list by index */\nint count = 0;\nfor (var i = 0; i < nums.length; i++) {\n    count += nums[i];\n}\n\n/* Iterate directly through list elements */\ncount = 0;\nfor (var num in nums) {\n    count += num;\n}\n
list.rs
// Iterate through the list by index\nlet mut _count = 0;\nfor i in 0..nums.len() {\n    _count += nums[i];\n}\n\n// Iterate directly through list elements\n_count = 0;\nfor num in &nums {\n    _count += num;\n}\n
list.c
// C does not provide built-in dynamic arrays\n
list.zig
// Iterate through the list by index\nvar count: i32 = 0;\nvar i: i32 = 0;\nwhile (i < nums.items.len) : (i += 1) {\n    count += nums[i];\n}\n\n// Iterate directly through list elements\ncount = 0;\nfor (nums.items) |num| {\n    count += num;\n}\n
"},{"location":"chapter_array_and_linkedlist/list/#5-concatenating-lists","title":"5. \u00a0 Concatenating Lists","text":"

Given a new list nums1, we can append it to the end of the original list.

PythonC++JavaC#GoSwiftJSTSDartRustCZig list.py
# Concatenate two lists\nnums1: list[int] = [6, 8, 7, 10, 9]\nnums += nums1  # Concatenate nums1 to the end of nums\n
list.cpp
/* Concatenate two lists */\nvector<int> nums1 = { 6, 8, 7, 10, 9 };\n// Concatenate nums1 to the end of nums\nnums.insert(nums.end(), nums1.begin(), nums1.end());\n
list.java
/* Concatenate two lists */\nList<Integer> nums1 = new ArrayList<>(Arrays.asList(new Integer[] { 6, 8, 7, 10, 9 }));\nnums.addAll(nums1);  // Concatenate nums1 to the end of nums\n
list.cs
/* Concatenate two lists */\nList<int> nums1 = [6, 8, 7, 10, 9];\nnums.AddRange(nums1);  // Concatenate nums1 to the end of nums\n
list_test.go
/* Concatenate two lists */\nnums1 := []int{6, 8, 7, 10, 9}\nnums = append(nums, nums1...)  // Concatenate nums1 to the end of nums\n
list.swift
/* Concatenate two lists */\nlet nums1 = [6, 8, 7, 10, 9]\nnums.append(contentsOf: nums1) // Concatenate nums1 to the end of nums\n
list.js
/* Concatenate two lists */\nconst nums1 = [6, 8, 7, 10, 9];\nnums.push(...nums1);  // Concatenate nums1 to the end of nums\n
list.ts
/* Concatenate two lists */\nconst nums1: number[] = [6, 8, 7, 10, 9];\nnums.push(...nums1);  // Concatenate nums1 to the end of nums\n
list.dart
/* Concatenate two lists */\nList<int> nums1 = [6, 8, 7, 10, 9];\nnums.addAll(nums1);  // Concatenate nums1 to the end of nums\n
list.rs
/* Concatenate two lists */\nlet nums1: Vec<i32> = vec![6, 8, 7, 10, 9];\nnums.extend(nums1);\n
list.c
// C does not provide built-in dynamic arrays\n
list.zig
// Concatenate two lists\nvar nums1 = std.ArrayList(i32).init(std.heap.page_allocator);\ndefer nums1.deinit();\ntry nums1.appendSlice(&[_]i32{ 6, 8, 7, 10, 9 });\ntry nums.insertSlice(nums.items.len, nums1.items); // Concatenate nums1 to the end of nums\n
"},{"location":"chapter_array_and_linkedlist/list/#6-sorting-the-list","title":"6. \u00a0 Sorting the List","text":"

Once the list is sorted, we can employ algorithms commonly used in array-related algorithm problems, such as \"binary search\" and \"two-pointer\" algorithms.

PythonC++JavaC#GoSwiftJSTSDartRustCZig list.py
# Sort the list\nnums.sort()  # After sorting, the list elements are in ascending order\n
list.cpp
/* Sort the list */\nsort(nums.begin(), nums.end());  // After sorting, the list elements are in ascending order\n
list.java
/* Sort the list */\nCollections.sort(nums);  // After sorting, the list elements are in ascending order\n
list.cs
/* Sort the list */\nnums.Sort(); // After sorting, the list elements are in ascending order\n
list_test.go
/* Sort the list */\nsort.Ints(nums)  // After sorting, the list elements are in ascending order\n
list.swift
/* Sort the list */\nnums.sort() // After sorting, the list elements are in ascending order\n
list.js
/* Sort the list */  \nnums.sort((a, b) => a - b);  // After sorting, the list elements are in ascending order\n
list.ts
/* Sort the list */\nnums.sort((a, b) => a - b);  // After sorting, the list elements are in ascending order\n
list.dart
/* Sort the list */\nnums.sort(); // After sorting, the list elements are in ascending order\n
list.rs
/* Sort the list */\nnums.sort(); // After sorting, the list elements are in ascending order\n
list.c
// C does not provide built-in dynamic arrays\n
list.zig
// Sort the list\nstd.sort.sort(i32, nums.items, {}, comptime std.sort.asc(i32));\n
"},{"location":"chapter_array_and_linkedlist/list/#432-list-implementation","title":"4.3.2 \u00a0 List Implementation","text":"

Many programming languages come with built-in lists, including Java, C++, Python, etc. Their implementations tend to be intricate, featuring carefully considered settings for various parameters, like initial capacity and expansion factors. Readers who are curious can delve into the source code for further learning.

To enhance our understanding of how lists work, we will attempt to implement a simplified version of a list, focusing on three crucial design aspects:

  • Initial Capacity: Choose a reasonable initial capacity for the array. In this example, we choose 10 as the initial capacity.
  • Size Recording: Declare a variable size to record the current number of elements in the list, updating in real-time with element insertion and deletion. With this variable, we can locate the end of the list and determine whether expansion is needed.
  • Expansion Mechanism: If the list reaches full capacity upon an element insertion, an expansion process is required. This involves creating a larger array based on the expansion factor, and then transferring all elements from the current array to the new one. In this example, we stipulate that the array size should double with each expansion.
PythonC++JavaC#GoSwiftJSTSDartRustCZig my_list.py
class MyList:\n    \"\"\"\u5217\u8868\u7c7b\"\"\"\n\n    def __init__(self):\n        \"\"\"\u6784\u9020\u65b9\u6cd5\"\"\"\n        self._capacity: int = 10  # \u5217\u8868\u5bb9\u91cf\n        self._arr: list[int] = [0] * self._capacity  # \u6570\u7ec4\uff08\u5b58\u50a8\u5217\u8868\u5143\u7d20\uff09\n        self._size: int = 0  # \u5217\u8868\u957f\u5ea6\uff08\u5f53\u524d\u5143\u7d20\u6570\u91cf\uff09\n        self._extend_ratio: int = 2  # \u6bcf\u6b21\u5217\u8868\u6269\u5bb9\u7684\u500d\u6570\n\n    def size(self) -> int:\n        \"\"\"\u83b7\u53d6\u5217\u8868\u957f\u5ea6\uff08\u5f53\u524d\u5143\u7d20\u6570\u91cf\uff09\"\"\"\n        return self._size\n\n    def capacity(self) -> int:\n        \"\"\"\u83b7\u53d6\u5217\u8868\u5bb9\u91cf\"\"\"\n        return self._capacity\n\n    def get(self, index: int) -> int:\n        \"\"\"\u8bbf\u95ee\u5143\u7d20\"\"\"\n        # \u7d22\u5f15\u5982\u679c\u8d8a\u754c\uff0c\u5219\u629b\u51fa\u5f02\u5e38\uff0c\u4e0b\u540c\n        if index < 0 or index >= self._size:\n            raise IndexError(\"\u7d22\u5f15\u8d8a\u754c\")\n        return self._arr[index]\n\n    def set(self, num: int, index: int):\n        \"\"\"\u66f4\u65b0\u5143\u7d20\"\"\"\n        if index < 0 or index >= self._size:\n            raise IndexError(\"\u7d22\u5f15\u8d8a\u754c\")\n        self._arr[index] = num\n\n    def add(self, num: int):\n        \"\"\"\u5728\u5c3e\u90e8\u6dfb\u52a0\u5143\u7d20\"\"\"\n        # \u5143\u7d20\u6570\u91cf\u8d85\u51fa\u5bb9\u91cf\u65f6\uff0c\u89e6\u53d1\u6269\u5bb9\u673a\u5236\n        if self.size() == self.capacity():\n            self.extend_capacity()\n        self._arr[self._size] = num\n        self._size += 1\n\n    def insert(self, num: int, index: int):\n        \"\"\"\u5728\u4e2d\u95f4\u63d2\u5165\u5143\u7d20\"\"\"\n        if index < 0 or index >= self._size:\n            raise IndexError(\"\u7d22\u5f15\u8d8a\u754c\")\n        # \u5143\u7d20\u6570\u91cf\u8d85\u51fa\u5bb9\u91cf\u65f6\uff0c\u89e6\u53d1\u6269\u5bb9\u673a\u5236\n        if self._size == self.capacity():\n            self.extend_capacity()\n        # \u5c06\u7d22\u5f15 index \u4ee5\u53ca\u4e4b\u540e\u7684\u5143\u7d20\u90fd\u5411\u540e\u79fb\u52a8\u4e00\u4f4d\n        for j in range(self._size - 1, index - 1, -1):\n            self._arr[j + 1] = self._arr[j]\n        self._arr[index] = num\n        # \u66f4\u65b0\u5143\u7d20\u6570\u91cf\n        self._size += 1\n\n    def remove(self, index: int) -> int:\n        \"\"\"\u5220\u9664\u5143\u7d20\"\"\"\n        if index < 0 or index >= self._size:\n            raise IndexError(\"\u7d22\u5f15\u8d8a\u754c\")\n        num = self._arr[index]\n        # \u5c06\u7d22\u5f15 index \u4e4b\u540e\u7684\u5143\u7d20\u90fd\u5411\u524d\u79fb\u52a8\u4e00\u4f4d\n        for j in range(index, self._size - 1):\n            self._arr[j] = self._arr[j + 1]\n        # \u66f4\u65b0\u5143\u7d20\u6570\u91cf\n        self._size -= 1\n        # \u8fd4\u56de\u88ab\u5220\u9664\u7684\u5143\u7d20\n        return num\n\n    def extend_capacity(self):\n        \"\"\"\u5217\u8868\u6269\u5bb9\"\"\"\n        # \u65b0\u5efa\u4e00\u4e2a\u957f\u5ea6\u4e3a\u539f\u6570\u7ec4 _extend_ratio \u500d\u7684\u65b0\u6570\u7ec4\uff0c\u5e76\u5c06\u539f\u6570\u7ec4\u590d\u5236\u5230\u65b0\u6570\u7ec4\n        self._arr = self._arr + [0] * self.capacity() * (self._extend_ratio - 1)\n        # \u66f4\u65b0\u5217\u8868\u5bb9\u91cf\n        self._capacity = len(self._arr)\n\n    def to_array(self) -> list[int]:\n        \"\"\"\u8fd4\u56de\u6709\u6548\u957f\u5ea6\u7684\u5217\u8868\"\"\"\n        return self._arr[: self._size]\n
my_list.cpp
/* \u5217\u8868\u7c7b */\nclass MyList {\n  private:\n    int *arr;             // \u6570\u7ec4\uff08\u5b58\u50a8\u5217\u8868\u5143\u7d20\uff09\n    int arrCapacity = 10; // \u5217\u8868\u5bb9\u91cf\n    int arrSize = 0;      // \u5217\u8868\u957f\u5ea6\uff08\u5f53\u524d\u5143\u7d20\u6570\u91cf\uff09\n    int extendRatio = 2;   // \u6bcf\u6b21\u5217\u8868\u6269\u5bb9\u7684\u500d\u6570\n\n  public:\n    /* \u6784\u9020\u65b9\u6cd5 */\n    MyList() {\n        arr = new int[arrCapacity];\n    }\n\n    /* \u6790\u6784\u65b9\u6cd5 */\n    ~MyList() {\n        delete[] arr;\n    }\n\n    /* \u83b7\u53d6\u5217\u8868\u957f\u5ea6\uff08\u5f53\u524d\u5143\u7d20\u6570\u91cf\uff09*/\n    int size() {\n        return arrSize;\n    }\n\n    /* \u83b7\u53d6\u5217\u8868\u5bb9\u91cf */\n    int capacity() {\n        return arrCapacity;\n    }\n\n    /* \u8bbf\u95ee\u5143\u7d20 */\n    int get(int index) {\n        // \u7d22\u5f15\u5982\u679c\u8d8a\u754c\uff0c\u5219\u629b\u51fa\u5f02\u5e38\uff0c\u4e0b\u540c\n        if (index < 0 || index >= size())\n            throw out_of_range(\"\u7d22\u5f15\u8d8a\u754c\");\n        return arr[index];\n    }\n\n    /* \u66f4\u65b0\u5143\u7d20 */\n    void set(int index, int num) {\n        if (index < 0 || index >= size())\n            throw out_of_range(\"\u7d22\u5f15\u8d8a\u754c\");\n        arr[index] = num;\n    }\n\n    /* \u5728\u5c3e\u90e8\u6dfb\u52a0\u5143\u7d20 */\n    void add(int num) {\n        // \u5143\u7d20\u6570\u91cf\u8d85\u51fa\u5bb9\u91cf\u65f6\uff0c\u89e6\u53d1\u6269\u5bb9\u673a\u5236\n        if (size() == capacity())\n            extendCapacity();\n        arr[size()] = num;\n        // \u66f4\u65b0\u5143\u7d20\u6570\u91cf\n        arrSize++;\n    }\n\n    /* \u5728\u4e2d\u95f4\u63d2\u5165\u5143\u7d20 */\n    void insert(int index, int num) {\n        if (index < 0 || index >= size())\n            throw out_of_range(\"\u7d22\u5f15\u8d8a\u754c\");\n        // \u5143\u7d20\u6570\u91cf\u8d85\u51fa\u5bb9\u91cf\u65f6\uff0c\u89e6\u53d1\u6269\u5bb9\u673a\u5236\n        if (size() == capacity())\n            extendCapacity();\n        // \u5c06\u7d22\u5f15 index \u4ee5\u53ca\u4e4b\u540e\u7684\u5143\u7d20\u90fd\u5411\u540e\u79fb\u52a8\u4e00\u4f4d\n        for (int j = size() - 1; j >= index; j--) {\n            arr[j + 1] = arr[j];\n        }\n        arr[index] = num;\n        // \u66f4\u65b0\u5143\u7d20\u6570\u91cf\n        arrSize++;\n    }\n\n    /* \u5220\u9664\u5143\u7d20 */\n    int remove(int index) {\n        if (index < 0 || index >= size())\n            throw out_of_range(\"\u7d22\u5f15\u8d8a\u754c\");\n        int num = arr[index];\n        // \u5c06\u7d22\u5f15 index \u4e4b\u540e\u7684\u5143\u7d20\u90fd\u5411\u524d\u79fb\u52a8\u4e00\u4f4d\n        for (int j = index; j < size() - 1; j++) {\n            arr[j] = arr[j + 1];\n        }\n        // \u66f4\u65b0\u5143\u7d20\u6570\u91cf\n        arrSize--;\n        // \u8fd4\u56de\u88ab\u5220\u9664\u7684\u5143\u7d20\n        return num;\n    }\n\n    /* \u5217\u8868\u6269\u5bb9 */\n    void extendCapacity() {\n        // \u65b0\u5efa\u4e00\u4e2a\u957f\u5ea6\u4e3a\u539f\u6570\u7ec4 extendRatio \u500d\u7684\u65b0\u6570\u7ec4\n        int newCapacity = capacity() * extendRatio;\n        int *tmp = arr;\n        arr = new int[newCapacity];\n        // \u5c06\u539f\u6570\u7ec4\u4e2d\u7684\u6240\u6709\u5143\u7d20\u590d\u5236\u5230\u65b0\u6570\u7ec4\n        for (int i = 0; i < size(); i++) {\n            arr[i] = tmp[i];\n        }\n        // \u91ca\u653e\u5185\u5b58\n        delete[] tmp;\n        arrCapacity = newCapacity;\n    }\n\n    /* \u5c06\u5217\u8868\u8f6c\u6362\u4e3a Vector \u7528\u4e8e\u6253\u5370 */\n    vector<int> toVector() {\n        // \u4ec5\u8f6c\u6362\u6709\u6548\u957f\u5ea6\u8303\u56f4\u5185\u7684\u5217\u8868\u5143\u7d20\n        vector<int> vec(size());\n        for (int i = 0; i < size(); i++) {\n            vec[i] = arr[i];\n        }\n        return vec;\n    }\n};\n
my_list.java
/* \u5217\u8868\u7c7b */\nclass MyList {\n    private int[] arr; // \u6570\u7ec4\uff08\u5b58\u50a8\u5217\u8868\u5143\u7d20\uff09\n    private int capacity = 10; // \u5217\u8868\u5bb9\u91cf\n    private int size = 0; // \u5217\u8868\u957f\u5ea6\uff08\u5f53\u524d\u5143\u7d20\u6570\u91cf\uff09\n    private int extendRatio = 2; // \u6bcf\u6b21\u5217\u8868\u6269\u5bb9\u7684\u500d\u6570\n\n    /* \u6784\u9020\u65b9\u6cd5 */\n    public MyList() {\n        arr = new int[capacity];\n    }\n\n    /* \u83b7\u53d6\u5217\u8868\u957f\u5ea6\uff08\u5f53\u524d\u5143\u7d20\u6570\u91cf\uff09 */\n    public int size() {\n        return size;\n    }\n\n    /* \u83b7\u53d6\u5217\u8868\u5bb9\u91cf */\n    public int capacity() {\n        return capacity;\n    }\n\n    /* \u8bbf\u95ee\u5143\u7d20 */\n    public int get(int index) {\n        // \u7d22\u5f15\u5982\u679c\u8d8a\u754c\uff0c\u5219\u629b\u51fa\u5f02\u5e38\uff0c\u4e0b\u540c\n        if (index < 0 || index >= size)\n            throw new IndexOutOfBoundsException(\"\u7d22\u5f15\u8d8a\u754c\");\n        return arr[index];\n    }\n\n    /* \u66f4\u65b0\u5143\u7d20 */\n    public void set(int index, int num) {\n        if (index < 0 || index >= size)\n            throw new IndexOutOfBoundsException(\"\u7d22\u5f15\u8d8a\u754c\");\n        arr[index] = num;\n    }\n\n    /* \u5728\u5c3e\u90e8\u6dfb\u52a0\u5143\u7d20 */\n    public void add(int num) {\n        // \u5143\u7d20\u6570\u91cf\u8d85\u51fa\u5bb9\u91cf\u65f6\uff0c\u89e6\u53d1\u6269\u5bb9\u673a\u5236\n        if (size == capacity())\n            extendCapacity();\n        arr[size] = num;\n        // \u66f4\u65b0\u5143\u7d20\u6570\u91cf\n        size++;\n    }\n\n    /* \u5728\u4e2d\u95f4\u63d2\u5165\u5143\u7d20 */\n    public void insert(int index, int num) {\n        if (index < 0 || index >= size)\n            throw new IndexOutOfBoundsException(\"\u7d22\u5f15\u8d8a\u754c\");\n        // \u5143\u7d20\u6570\u91cf\u8d85\u51fa\u5bb9\u91cf\u65f6\uff0c\u89e6\u53d1\u6269\u5bb9\u673a\u5236\n        if (size == capacity())\n            extendCapacity();\n        // \u5c06\u7d22\u5f15 index \u4ee5\u53ca\u4e4b\u540e\u7684\u5143\u7d20\u90fd\u5411\u540e\u79fb\u52a8\u4e00\u4f4d\n        for (int j = size - 1; j >= index; j--) {\n            arr[j + 1] = arr[j];\n        }\n        arr[index] = num;\n        // \u66f4\u65b0\u5143\u7d20\u6570\u91cf\n        size++;\n    }\n\n    /* \u5220\u9664\u5143\u7d20 */\n    public int remove(int index) {\n        if (index < 0 || index >= size)\n            throw new IndexOutOfBoundsException(\"\u7d22\u5f15\u8d8a\u754c\");\n        int num = arr[index];\n        // \u5c06\u5c06\u7d22\u5f15 index \u4e4b\u540e\u7684\u5143\u7d20\u90fd\u5411\u524d\u79fb\u52a8\u4e00\u4f4d\n        for (int j = index; j < size - 1; j++) {\n            arr[j] = arr[j + 1];\n        }\n        // \u66f4\u65b0\u5143\u7d20\u6570\u91cf\n        size--;\n        // \u8fd4\u56de\u88ab\u5220\u9664\u7684\u5143\u7d20\n        return num;\n    }\n\n    /* \u5217\u8868\u6269\u5bb9 */\n    public void extendCapacity() {\n        // \u65b0\u5efa\u4e00\u4e2a\u957f\u5ea6\u4e3a\u539f\u6570\u7ec4 extendRatio \u500d\u7684\u65b0\u6570\u7ec4\uff0c\u5e76\u5c06\u539f\u6570\u7ec4\u590d\u5236\u5230\u65b0\u6570\u7ec4\n        arr = Arrays.copyOf(arr, capacity() * extendRatio);\n        // \u66f4\u65b0\u5217\u8868\u5bb9\u91cf\n        capacity = arr.length;\n    }\n\n    /* \u5c06\u5217\u8868\u8f6c\u6362\u4e3a\u6570\u7ec4 */\n    public int[] toArray() {\n        int size = size();\n        // \u4ec5\u8f6c\u6362\u6709\u6548\u957f\u5ea6\u8303\u56f4\u5185\u7684\u5217\u8868\u5143\u7d20\n        int[] arr = new int[size];\n        for (int i = 0; i < size; i++) {\n            arr[i] = get(i);\n        }\n        return arr;\n    }\n}\n
my_list.cs
/* \u5217\u8868\u7c7b */\nclass MyList {\n    private int[] arr;           // \u6570\u7ec4\uff08\u5b58\u50a8\u5217\u8868\u5143\u7d20\uff09\n    private int arrCapacity = 10;    // \u5217\u8868\u5bb9\u91cf\n    private int arrSize = 0;         // \u5217\u8868\u957f\u5ea6\uff08\u5f53\u524d\u5143\u7d20\u6570\u91cf\uff09\n    private readonly int extendRatio = 2;  // \u6bcf\u6b21\u5217\u8868\u6269\u5bb9\u7684\u500d\u6570\n\n    /* \u6784\u9020\u65b9\u6cd5 */\n    public MyList() {\n        arr = new int[arrCapacity];\n    }\n\n    /* \u83b7\u53d6\u5217\u8868\u957f\u5ea6\uff08\u5f53\u524d\u5143\u7d20\u6570\u91cf\uff09*/\n    public int Size() {\n        return arrSize;\n    }\n\n    /* \u83b7\u53d6\u5217\u8868\u5bb9\u91cf */\n    public int Capacity() {\n        return arrCapacity;\n    }\n\n    /* \u8bbf\u95ee\u5143\u7d20 */\n    public int Get(int index) {\n        // \u7d22\u5f15\u5982\u679c\u8d8a\u754c\uff0c\u5219\u629b\u51fa\u5f02\u5e38\uff0c\u4e0b\u540c\n        if (index < 0 || index >= arrSize)\n            throw new IndexOutOfRangeException(\"\u7d22\u5f15\u8d8a\u754c\");\n        return arr[index];\n    }\n\n    /* \u66f4\u65b0\u5143\u7d20 */\n    public void Set(int index, int num) {\n        if (index < 0 || index >= arrSize)\n            throw new IndexOutOfRangeException(\"\u7d22\u5f15\u8d8a\u754c\");\n        arr[index] = num;\n    }\n\n    /* \u5728\u5c3e\u90e8\u6dfb\u52a0\u5143\u7d20 */\n    public void Add(int num) {\n        // \u5143\u7d20\u6570\u91cf\u8d85\u51fa\u5bb9\u91cf\u65f6\uff0c\u89e6\u53d1\u6269\u5bb9\u673a\u5236\n        if (arrSize == arrCapacity)\n            ExtendCapacity();\n        arr[arrSize] = num;\n        // \u66f4\u65b0\u5143\u7d20\u6570\u91cf\n        arrSize++;\n    }\n\n    /* \u5728\u4e2d\u95f4\u63d2\u5165\u5143\u7d20 */\n    public void Insert(int index, int num) {\n        if (index < 0 || index >= arrSize)\n            throw new IndexOutOfRangeException(\"\u7d22\u5f15\u8d8a\u754c\");\n        // \u5143\u7d20\u6570\u91cf\u8d85\u51fa\u5bb9\u91cf\u65f6\uff0c\u89e6\u53d1\u6269\u5bb9\u673a\u5236\n        if (arrSize == arrCapacity)\n            ExtendCapacity();\n        // \u5c06\u7d22\u5f15 index \u4ee5\u53ca\u4e4b\u540e\u7684\u5143\u7d20\u90fd\u5411\u540e\u79fb\u52a8\u4e00\u4f4d\n        for (int j = arrSize - 1; j >= index; j--) {\n            arr[j + 1] = arr[j];\n        }\n        arr[index] = num;\n        // \u66f4\u65b0\u5143\u7d20\u6570\u91cf\n        arrSize++;\n    }\n\n    /* \u5220\u9664\u5143\u7d20 */\n    public int Remove(int index) {\n        if (index < 0 || index >= arrSize)\n            throw new IndexOutOfRangeException(\"\u7d22\u5f15\u8d8a\u754c\");\n        int num = arr[index];\n        // \u5c06\u5c06\u7d22\u5f15 index \u4e4b\u540e\u7684\u5143\u7d20\u90fd\u5411\u524d\u79fb\u52a8\u4e00\u4f4d\n        for (int j = index; j < arrSize - 1; j++) {\n            arr[j] = arr[j + 1];\n        }\n        // \u66f4\u65b0\u5143\u7d20\u6570\u91cf\n        arrSize--;\n        // \u8fd4\u56de\u88ab\u5220\u9664\u7684\u5143\u7d20\n        return num;\n    }\n\n    /* \u5217\u8868\u6269\u5bb9 */\n    public void ExtendCapacity() {\n        // \u65b0\u5efa\u4e00\u4e2a\u957f\u5ea6\u4e3a arrCapacity * extendRatio \u7684\u6570\u7ec4\uff0c\u5e76\u5c06\u539f\u6570\u7ec4\u590d\u5236\u5230\u65b0\u6570\u7ec4\n        Array.Resize(ref arr, arrCapacity * extendRatio);\n        // \u66f4\u65b0\u5217\u8868\u5bb9\u91cf\n        arrCapacity = arr.Length;\n    }\n\n    /* \u5c06\u5217\u8868\u8f6c\u6362\u4e3a\u6570\u7ec4 */\n    public int[] ToArray() {\n        // \u4ec5\u8f6c\u6362\u6709\u6548\u957f\u5ea6\u8303\u56f4\u5185\u7684\u5217\u8868\u5143\u7d20\n        int[] arr = new int[arrSize];\n        for (int i = 0; i < arrSize; i++) {\n            arr[i] = Get(i);\n        }\n        return arr;\n    }\n}\n
my_list.go
/* \u5217\u8868\u7c7b */\ntype myList struct {\n    arrCapacity int\n    arr         []int\n    arrSize     int\n    extendRatio int\n}\n\n/* \u6784\u9020\u51fd\u6570 */\nfunc newMyList() *myList {\n    return &myList{\n        arrCapacity: 10,              // \u5217\u8868\u5bb9\u91cf\n        arr:         make([]int, 10), // \u6570\u7ec4\uff08\u5b58\u50a8\u5217\u8868\u5143\u7d20\uff09\n        arrSize:     0,               // \u5217\u8868\u957f\u5ea6\uff08\u5f53\u524d\u5143\u7d20\u6570\u91cf\uff09\n        extendRatio: 2,               // \u6bcf\u6b21\u5217\u8868\u6269\u5bb9\u7684\u500d\u6570\n    }\n}\n\n/* \u83b7\u53d6\u5217\u8868\u957f\u5ea6\uff08\u5f53\u524d\u5143\u7d20\u6570\u91cf\uff09 */\nfunc (l *myList) size() int {\n    return l.arrSize\n}\n\n/*  \u83b7\u53d6\u5217\u8868\u5bb9\u91cf */\nfunc (l *myList) capacity() int {\n    return l.arrCapacity\n}\n\n/* \u8bbf\u95ee\u5143\u7d20 */\nfunc (l *myList) get(index int) int {\n    // \u7d22\u5f15\u5982\u679c\u8d8a\u754c\uff0c\u5219\u629b\u51fa\u5f02\u5e38\uff0c\u4e0b\u540c\n    if index < 0 || index >= l.arrSize {\n        panic(\"\u7d22\u5f15\u8d8a\u754c\")\n    }\n    return l.arr[index]\n}\n\n/* \u66f4\u65b0\u5143\u7d20 */\nfunc (l *myList) set(num, index int) {\n    if index < 0 || index >= l.arrSize {\n        panic(\"\u7d22\u5f15\u8d8a\u754c\")\n    }\n    l.arr[index] = num\n}\n\n/* \u5728\u5c3e\u90e8\u6dfb\u52a0\u5143\u7d20 */\nfunc (l *myList) add(num int) {\n    // \u5143\u7d20\u6570\u91cf\u8d85\u51fa\u5bb9\u91cf\u65f6\uff0c\u89e6\u53d1\u6269\u5bb9\u673a\u5236\n    if l.arrSize == l.arrCapacity {\n        l.extendCapacity()\n    }\n    l.arr[l.arrSize] = num\n    // \u66f4\u65b0\u5143\u7d20\u6570\u91cf\n    l.arrSize++\n}\n\n/* \u5728\u4e2d\u95f4\u63d2\u5165\u5143\u7d20 */\nfunc (l *myList) insert(num, index int) {\n    if index < 0 || index >= l.arrSize {\n        panic(\"\u7d22\u5f15\u8d8a\u754c\")\n    }\n    // \u5143\u7d20\u6570\u91cf\u8d85\u51fa\u5bb9\u91cf\u65f6\uff0c\u89e6\u53d1\u6269\u5bb9\u673a\u5236\n    if l.arrSize == l.arrCapacity {\n        l.extendCapacity()\n    }\n    // \u5c06\u7d22\u5f15 index \u4ee5\u53ca\u4e4b\u540e\u7684\u5143\u7d20\u90fd\u5411\u540e\u79fb\u52a8\u4e00\u4f4d\n    for j := l.arrSize - 1; j >= index; j-- {\n        l.arr[j+1] = l.arr[j]\n    }\n    l.arr[index] = num\n    // \u66f4\u65b0\u5143\u7d20\u6570\u91cf\n    l.arrSize++\n}\n\n/* \u5220\u9664\u5143\u7d20 */\nfunc (l *myList) remove(index int) int {\n    if index < 0 || index >= l.arrSize {\n        panic(\"\u7d22\u5f15\u8d8a\u754c\")\n    }\n    num := l.arr[index]\n    // \u5c06\u7d22\u5f15 index \u4e4b\u540e\u7684\u5143\u7d20\u90fd\u5411\u524d\u79fb\u52a8\u4e00\u4f4d\n    for j := index; j < l.arrSize-1; j++ {\n        l.arr[j] = l.arr[j+1]\n    }\n    // \u66f4\u65b0\u5143\u7d20\u6570\u91cf\n    l.arrSize--\n    // \u8fd4\u56de\u88ab\u5220\u9664\u7684\u5143\u7d20\n    return num\n}\n\n/* \u5217\u8868\u6269\u5bb9 */\nfunc (l *myList) extendCapacity() {\n    // \u65b0\u5efa\u4e00\u4e2a\u957f\u5ea6\u4e3a\u539f\u6570\u7ec4 extendRatio \u500d\u7684\u65b0\u6570\u7ec4\uff0c\u5e76\u5c06\u539f\u6570\u7ec4\u590d\u5236\u5230\u65b0\u6570\u7ec4\n    l.arr = append(l.arr, make([]int, l.arrCapacity*(l.extendRatio-1))...)\n    // \u66f4\u65b0\u5217\u8868\u5bb9\u91cf\n    l.arrCapacity = len(l.arr)\n}\n\n/* \u8fd4\u56de\u6709\u6548\u957f\u5ea6\u7684\u5217\u8868 */\nfunc (l *myList) toArray() []int {\n    // \u4ec5\u8f6c\u6362\u6709\u6548\u957f\u5ea6\u8303\u56f4\u5185\u7684\u5217\u8868\u5143\u7d20\n    return l.arr[:l.arrSize]\n}\n
my_list.swift
/* \u5217\u8868\u7c7b */\nclass MyList {\n    private var arr: [Int] // \u6570\u7ec4\uff08\u5b58\u50a8\u5217\u8868\u5143\u7d20\uff09\n    private var _capacity: Int // \u5217\u8868\u5bb9\u91cf\n    private var _size: Int // \u5217\u8868\u957f\u5ea6\uff08\u5f53\u524d\u5143\u7d20\u6570\u91cf\uff09\n    private let extendRatio: Int // \u6bcf\u6b21\u5217\u8868\u6269\u5bb9\u7684\u500d\u6570\n\n    /* \u6784\u9020\u65b9\u6cd5 */\n    init() {\n        _capacity = 10\n        _size = 0\n        extendRatio = 2\n        arr = Array(repeating: 0, count: _capacity)\n    }\n\n    /* \u83b7\u53d6\u5217\u8868\u957f\u5ea6\uff08\u5f53\u524d\u5143\u7d20\u6570\u91cf\uff09*/\n    func size() -> Int {\n        _size\n    }\n\n    /* \u83b7\u53d6\u5217\u8868\u5bb9\u91cf */\n    func capacity() -> Int {\n        _capacity\n    }\n\n    /* \u8bbf\u95ee\u5143\u7d20 */\n    func get(index: Int) -> Int {\n        // \u7d22\u5f15\u5982\u679c\u8d8a\u754c\u5219\u629b\u51fa\u9519\u8bef\uff0c\u4e0b\u540c\n        if index < 0 || index >= size() {\n            fatalError(\"\u7d22\u5f15\u8d8a\u754c\")\n        }\n        return arr[index]\n    }\n\n    /* \u66f4\u65b0\u5143\u7d20 */\n    func set(index: Int, num: Int) {\n        if index < 0 || index >= size() {\n            fatalError(\"\u7d22\u5f15\u8d8a\u754c\")\n        }\n        arr[index] = num\n    }\n\n    /* \u5728\u5c3e\u90e8\u6dfb\u52a0\u5143\u7d20 */\n    func add(num: Int) {\n        // \u5143\u7d20\u6570\u91cf\u8d85\u51fa\u5bb9\u91cf\u65f6\uff0c\u89e6\u53d1\u6269\u5bb9\u673a\u5236\n        if size() == capacity() {\n            extendCapacity()\n        }\n        arr[size()] = num\n        // \u66f4\u65b0\u5143\u7d20\u6570\u91cf\n        _size += 1\n    }\n\n    /* \u5728\u4e2d\u95f4\u63d2\u5165\u5143\u7d20 */\n    func insert(index: Int, num: Int) {\n        if index < 0 || index >= size() {\n            fatalError(\"\u7d22\u5f15\u8d8a\u754c\")\n        }\n        // \u5143\u7d20\u6570\u91cf\u8d85\u51fa\u5bb9\u91cf\u65f6\uff0c\u89e6\u53d1\u6269\u5bb9\u673a\u5236\n        if size() == capacity() {\n            extendCapacity()\n        }\n        // \u5c06\u7d22\u5f15 index \u4ee5\u53ca\u4e4b\u540e\u7684\u5143\u7d20\u90fd\u5411\u540e\u79fb\u52a8\u4e00\u4f4d\n        for j in (index ..< size()).reversed() {\n            arr[j + 1] = arr[j]\n        }\n        arr[index] = num\n        // \u66f4\u65b0\u5143\u7d20\u6570\u91cf\n        _size += 1\n    }\n\n    /* \u5220\u9664\u5143\u7d20 */\n    @discardableResult\n    func remove(index: Int) -> Int {\n        if index < 0 || index >= size() {\n            fatalError(\"\u7d22\u5f15\u8d8a\u754c\")\n        }\n        let num = arr[index]\n        // \u5c06\u5c06\u7d22\u5f15 index \u4e4b\u540e\u7684\u5143\u7d20\u90fd\u5411\u524d\u79fb\u52a8\u4e00\u4f4d\n        for j in index ..< (size() - 1) {\n            arr[j] = arr[j + 1]\n        }\n        // \u66f4\u65b0\u5143\u7d20\u6570\u91cf\n        _size -= 1\n        // \u8fd4\u56de\u88ab\u5220\u9664\u7684\u5143\u7d20\n        return num\n    }\n\n    /* \u5217\u8868\u6269\u5bb9 */\n    func extendCapacity() {\n        // \u65b0\u5efa\u4e00\u4e2a\u957f\u5ea6\u4e3a\u539f\u6570\u7ec4 extendRatio \u500d\u7684\u65b0\u6570\u7ec4\uff0c\u5e76\u5c06\u539f\u6570\u7ec4\u590d\u5236\u5230\u65b0\u6570\u7ec4\n        arr = arr + Array(repeating: 0, count: capacity() * (extendRatio - 1))\n        // \u66f4\u65b0\u5217\u8868\u5bb9\u91cf\n        _capacity = arr.count\n    }\n\n    /* \u5c06\u5217\u8868\u8f6c\u6362\u4e3a\u6570\u7ec4 */\n    func toArray() -> [Int] {\n        Array(arr.prefix(size()))\n    }\n}\n
my_list.js
/* \u5217\u8868\u7c7b */\nclass MyList {\n    #arr = new Array(); // \u6570\u7ec4\uff08\u5b58\u50a8\u5217\u8868\u5143\u7d20\uff09\n    #capacity = 10; // \u5217\u8868\u5bb9\u91cf\n    #size = 0; // \u5217\u8868\u957f\u5ea6\uff08\u5f53\u524d\u5143\u7d20\u6570\u91cf\uff09\n    #extendRatio = 2; // \u6bcf\u6b21\u5217\u8868\u6269\u5bb9\u7684\u500d\u6570\n\n    /* \u6784\u9020\u65b9\u6cd5 */\n    constructor() {\n        this.#arr = new Array(this.#capacity);\n    }\n\n    /* \u83b7\u53d6\u5217\u8868\u957f\u5ea6\uff08\u5f53\u524d\u5143\u7d20\u6570\u91cf\uff09*/\n    size() {\n        return this.#size;\n    }\n\n    /* \u83b7\u53d6\u5217\u8868\u5bb9\u91cf */\n    capacity() {\n        return this.#capacity;\n    }\n\n    /* \u8bbf\u95ee\u5143\u7d20 */\n    get(index) {\n        // \u7d22\u5f15\u5982\u679c\u8d8a\u754c\uff0c\u5219\u629b\u51fa\u5f02\u5e38\uff0c\u4e0b\u540c\n        if (index < 0 || index >= this.#size) throw new Error('\u7d22\u5f15\u8d8a\u754c');\n        return this.#arr[index];\n    }\n\n    /* \u66f4\u65b0\u5143\u7d20 */\n    set(index, num) {\n        if (index < 0 || index >= this.#size) throw new Error('\u7d22\u5f15\u8d8a\u754c');\n        this.#arr[index] = num;\n    }\n\n    /* \u5728\u5c3e\u90e8\u6dfb\u52a0\u5143\u7d20 */\n    add(num) {\n        // \u5982\u679c\u957f\u5ea6\u7b49\u4e8e\u5bb9\u91cf\uff0c\u5219\u9700\u8981\u6269\u5bb9\n        if (this.#size === this.#capacity) {\n            this.extendCapacity();\n        }\n        // \u5c06\u65b0\u5143\u7d20\u6dfb\u52a0\u5230\u5217\u8868\u5c3e\u90e8\n        this.#arr[this.#size] = num;\n        this.#size++;\n    }\n\n    /* \u5728\u4e2d\u95f4\u63d2\u5165\u5143\u7d20 */\n    insert(index, num) {\n        if (index < 0 || index >= this.#size) throw new Error('\u7d22\u5f15\u8d8a\u754c');\n        // \u5143\u7d20\u6570\u91cf\u8d85\u51fa\u5bb9\u91cf\u65f6\uff0c\u89e6\u53d1\u6269\u5bb9\u673a\u5236\n        if (this.#size === this.#capacity) {\n            this.extendCapacity();\n        }\n        // \u5c06\u7d22\u5f15 index \u4ee5\u53ca\u4e4b\u540e\u7684\u5143\u7d20\u90fd\u5411\u540e\u79fb\u52a8\u4e00\u4f4d\n        for (let j = this.#size - 1; j >= index; j--) {\n            this.#arr[j + 1] = this.#arr[j];\n        }\n        // \u66f4\u65b0\u5143\u7d20\u6570\u91cf\n        this.#arr[index] = num;\n        this.#size++;\n    }\n\n    /* \u5220\u9664\u5143\u7d20 */\n    remove(index) {\n        if (index < 0 || index >= this.#size) throw new Error('\u7d22\u5f15\u8d8a\u754c');\n        let num = this.#arr[index];\n        // \u5c06\u5c06\u7d22\u5f15 index \u4e4b\u540e\u7684\u5143\u7d20\u90fd\u5411\u524d\u79fb\u52a8\u4e00\u4f4d\n        for (let j = index; j < this.#size - 1; j++) {\n            this.#arr[j] = this.#arr[j + 1];\n        }\n        // \u66f4\u65b0\u5143\u7d20\u6570\u91cf\n        this.#size--;\n        // \u8fd4\u56de\u88ab\u5220\u9664\u7684\u5143\u7d20\n        return num;\n    }\n\n    /* \u5217\u8868\u6269\u5bb9 */\n    extendCapacity() {\n        // \u65b0\u5efa\u4e00\u4e2a\u957f\u5ea6\u4e3a\u539f\u6570\u7ec4 extendRatio \u500d\u7684\u65b0\u6570\u7ec4\uff0c\u5e76\u5c06\u539f\u6570\u7ec4\u590d\u5236\u5230\u65b0\u6570\u7ec4\n        this.#arr = this.#arr.concat(\n            new Array(this.capacity() * (this.#extendRatio - 1))\n        );\n        // \u66f4\u65b0\u5217\u8868\u5bb9\u91cf\n        this.#capacity = this.#arr.length;\n    }\n\n    /* \u5c06\u5217\u8868\u8f6c\u6362\u4e3a\u6570\u7ec4 */\n    toArray() {\n        let size = this.size();\n        // \u4ec5\u8f6c\u6362\u6709\u6548\u957f\u5ea6\u8303\u56f4\u5185\u7684\u5217\u8868\u5143\u7d20\n        const arr = new Array(size);\n        for (let i = 0; i < size; i++) {\n            arr[i] = this.get(i);\n        }\n        return arr;\n    }\n}\n
my_list.ts
/* \u5217\u8868\u7c7b */\nclass MyList {\n    private arr: Array<number>; // \u6570\u7ec4\uff08\u5b58\u50a8\u5217\u8868\u5143\u7d20\uff09\n    private _capacity: number = 10; // \u5217\u8868\u5bb9\u91cf\n    private _size: number = 0; // \u5217\u8868\u957f\u5ea6\uff08\u5f53\u524d\u5143\u7d20\u6570\u91cf\uff09\n    private extendRatio: number = 2; // \u6bcf\u6b21\u5217\u8868\u6269\u5bb9\u7684\u500d\u6570\n\n    /* \u6784\u9020\u65b9\u6cd5 */\n    constructor() {\n        this.arr = new Array(this._capacity);\n    }\n\n    /* \u83b7\u53d6\u5217\u8868\u957f\u5ea6\uff08\u5f53\u524d\u5143\u7d20\u6570\u91cf\uff09*/\n    public size(): number {\n        return this._size;\n    }\n\n    /* \u83b7\u53d6\u5217\u8868\u5bb9\u91cf */\n    public capacity(): number {\n        return this._capacity;\n    }\n\n    /* \u8bbf\u95ee\u5143\u7d20 */\n    public get(index: number): number {\n        // \u7d22\u5f15\u5982\u679c\u8d8a\u754c\uff0c\u5219\u629b\u51fa\u5f02\u5e38\uff0c\u4e0b\u540c\n        if (index < 0 || index >= this._size) throw new Error('\u7d22\u5f15\u8d8a\u754c');\n        return this.arr[index];\n    }\n\n    /* \u66f4\u65b0\u5143\u7d20 */\n    public set(index: number, num: number): void {\n        if (index < 0 || index >= this._size) throw new Error('\u7d22\u5f15\u8d8a\u754c');\n        this.arr[index] = num;\n    }\n\n    /* \u5728\u5c3e\u90e8\u6dfb\u52a0\u5143\u7d20 */\n    public add(num: number): void {\n        // \u5982\u679c\u957f\u5ea6\u7b49\u4e8e\u5bb9\u91cf\uff0c\u5219\u9700\u8981\u6269\u5bb9\n        if (this._size === this._capacity) this.extendCapacity();\n        // \u5c06\u65b0\u5143\u7d20\u6dfb\u52a0\u5230\u5217\u8868\u5c3e\u90e8\n        this.arr[this._size] = num;\n        this._size++;\n    }\n\n    /* \u5728\u4e2d\u95f4\u63d2\u5165\u5143\u7d20 */\n    public insert(index: number, num: number): void {\n        if (index < 0 || index >= this._size) throw new Error('\u7d22\u5f15\u8d8a\u754c');\n        // \u5143\u7d20\u6570\u91cf\u8d85\u51fa\u5bb9\u91cf\u65f6\uff0c\u89e6\u53d1\u6269\u5bb9\u673a\u5236\n        if (this._size === this._capacity) {\n            this.extendCapacity();\n        }\n        // \u5c06\u7d22\u5f15 index \u4ee5\u53ca\u4e4b\u540e\u7684\u5143\u7d20\u90fd\u5411\u540e\u79fb\u52a8\u4e00\u4f4d\n        for (let j = this._size - 1; j >= index; j--) {\n            this.arr[j + 1] = this.arr[j];\n        }\n        // \u66f4\u65b0\u5143\u7d20\u6570\u91cf\n        this.arr[index] = num;\n        this._size++;\n    }\n\n    /* \u5220\u9664\u5143\u7d20 */\n    public remove(index: number): number {\n        if (index < 0 || index >= this._size) throw new Error('\u7d22\u5f15\u8d8a\u754c');\n        let num = this.arr[index];\n        // \u5c06\u5c06\u7d22\u5f15 index \u4e4b\u540e\u7684\u5143\u7d20\u90fd\u5411\u524d\u79fb\u52a8\u4e00\u4f4d\n        for (let j = index; j < this._size - 1; j++) {\n            this.arr[j] = this.arr[j + 1];\n        }\n        // \u66f4\u65b0\u5143\u7d20\u6570\u91cf\n        this._size--;\n        // \u8fd4\u56de\u88ab\u5220\u9664\u7684\u5143\u7d20\n        return num;\n    }\n\n    /* \u5217\u8868\u6269\u5bb9 */\n    public extendCapacity(): void {\n        // \u65b0\u5efa\u4e00\u4e2a\u957f\u5ea6\u4e3a size \u7684\u6570\u7ec4\uff0c\u5e76\u5c06\u539f\u6570\u7ec4\u590d\u5236\u5230\u65b0\u6570\u7ec4\n        this.arr = this.arr.concat(\n            new Array(this.capacity() * (this.extendRatio - 1))\n        );\n        // \u66f4\u65b0\u5217\u8868\u5bb9\u91cf\n        this._capacity = this.arr.length;\n    }\n\n    /* \u5c06\u5217\u8868\u8f6c\u6362\u4e3a\u6570\u7ec4 */\n    public toArray(): number[] {\n        let size = this.size();\n        // \u4ec5\u8f6c\u6362\u6709\u6548\u957f\u5ea6\u8303\u56f4\u5185\u7684\u5217\u8868\u5143\u7d20\n        const arr = new Array(size);\n        for (let i = 0; i < size; i++) {\n            arr[i] = this.get(i);\n        }\n        return arr;\n    }\n}\n
my_list.dart
/* \u5217\u8868\u7c7b */\nclass MyList {\n  late List<int> _arr; // \u6570\u7ec4\uff08\u5b58\u50a8\u5217\u8868\u5143\u7d20\uff09\n  int _capacity = 10; // \u5217\u8868\u5bb9\u91cf\n  int _size = 0; // \u5217\u8868\u957f\u5ea6\uff08\u5f53\u524d\u5143\u7d20\u6570\u91cf\uff09\n  int _extendRatio = 2; // \u6bcf\u6b21\u5217\u8868\u6269\u5bb9\u7684\u500d\u6570\n\n  /* \u6784\u9020\u65b9\u6cd5 */\n  MyList() {\n    _arr = List.filled(_capacity, 0);\n  }\n\n  /* \u83b7\u53d6\u5217\u8868\u957f\u5ea6\uff08\u5f53\u524d\u5143\u7d20\u6570\u91cf\uff09*/\n  int size() => _size;\n\n  /* \u83b7\u53d6\u5217\u8868\u5bb9\u91cf */\n  int capacity() => _capacity;\n\n  /* \u8bbf\u95ee\u5143\u7d20 */\n  int get(int index) {\n    if (index >= _size) throw RangeError('\u7d22\u5f15\u8d8a\u754c');\n    return _arr[index];\n  }\n\n  /* \u66f4\u65b0\u5143\u7d20 */\n  void set(int index, int _num) {\n    if (index >= _size) throw RangeError('\u7d22\u5f15\u8d8a\u754c');\n    _arr[index] = _num;\n  }\n\n  /* \u5728\u5c3e\u90e8\u6dfb\u52a0\u5143\u7d20 */\n  void add(int _num) {\n    // \u5143\u7d20\u6570\u91cf\u8d85\u51fa\u5bb9\u91cf\u65f6\uff0c\u89e6\u53d1\u6269\u5bb9\u673a\u5236\n    if (_size == _capacity) extendCapacity();\n    _arr[_size] = _num;\n    // \u66f4\u65b0\u5143\u7d20\u6570\u91cf\n    _size++;\n  }\n\n  /* \u5728\u4e2d\u95f4\u63d2\u5165\u5143\u7d20 */\n  void insert(int index, int _num) {\n    if (index >= _size) throw RangeError('\u7d22\u5f15\u8d8a\u754c');\n    // \u5143\u7d20\u6570\u91cf\u8d85\u51fa\u5bb9\u91cf\u65f6\uff0c\u89e6\u53d1\u6269\u5bb9\u673a\u5236\n    if (_size == _capacity) extendCapacity();\n    // \u5c06\u7d22\u5f15 index \u4ee5\u53ca\u4e4b\u540e\u7684\u5143\u7d20\u90fd\u5411\u540e\u79fb\u52a8\u4e00\u4f4d\n    for (var j = _size - 1; j >= index; j--) {\n      _arr[j + 1] = _arr[j];\n    }\n    _arr[index] = _num;\n    // \u66f4\u65b0\u5143\u7d20\u6570\u91cf\n    _size++;\n  }\n\n  /* \u5220\u9664\u5143\u7d20 */\n  int remove(int index) {\n    if (index >= _size) throw RangeError('\u7d22\u5f15\u8d8a\u754c');\n    int _num = _arr[index];\n    // \u5c06\u5c06\u7d22\u5f15 index \u4e4b\u540e\u7684\u5143\u7d20\u90fd\u5411\u524d\u79fb\u52a8\u4e00\u4f4d\n    for (var j = index; j < _size - 1; j++) {\n      _arr[j] = _arr[j + 1];\n    }\n    // \u66f4\u65b0\u5143\u7d20\u6570\u91cf\n    _size--;\n    // \u8fd4\u56de\u88ab\u5220\u9664\u7684\u5143\u7d20\n    return _num;\n  }\n\n  /* \u5217\u8868\u6269\u5bb9 */\n  void extendCapacity() {\n    // \u65b0\u5efa\u4e00\u4e2a\u957f\u5ea6\u4e3a\u539f\u6570\u7ec4 _extendRatio \u500d\u7684\u65b0\u6570\u7ec4\n    final _newNums = List.filled(_capacity * _extendRatio, 0);\n    // \u5c06\u539f\u6570\u7ec4\u590d\u5236\u5230\u65b0\u6570\u7ec4\n    List.copyRange(_newNums, 0, _arr);\n    // \u66f4\u65b0 _arr \u7684\u5f15\u7528\n    _arr = _newNums;\n    // \u66f4\u65b0\u5217\u8868\u5bb9\u91cf\n    _capacity = _arr.length;\n  }\n\n  /* \u5c06\u5217\u8868\u8f6c\u6362\u4e3a\u6570\u7ec4 */\n  List<int> toArray() {\n    List<int> arr = [];\n    for (var i = 0; i < _size; i++) {\n      arr.add(get(i));\n    }\n    return arr;\n  }\n}\n
my_list.rs
/* \u5217\u8868\u7c7b */\n#[allow(dead_code)]\nstruct MyList {\n    arr: Vec<i32>,       // \u6570\u7ec4\uff08\u5b58\u50a8\u5217\u8868\u5143\u7d20\uff09\n    capacity: usize,     // \u5217\u8868\u5bb9\u91cf\n    size: usize,         // \u5217\u8868\u957f\u5ea6\uff08\u5f53\u524d\u5143\u7d20\u6570\u91cf\uff09\n    extend_ratio: usize, // \u6bcf\u6b21\u5217\u8868\u6269\u5bb9\u7684\u500d\u6570\n}\n\n#[allow(unused, unused_comparisons)]\nimpl MyList {\n    /* \u6784\u9020\u65b9\u6cd5 */\n    pub fn new(capacity: usize) -> Self {\n        let mut vec = Vec::new();\n        vec.resize(capacity, 0);\n        Self {\n            arr: vec,\n            capacity,\n            size: 0,\n            extend_ratio: 2,\n        }\n    }\n\n    /* \u83b7\u53d6\u5217\u8868\u957f\u5ea6\uff08\u5f53\u524d\u5143\u7d20\u6570\u91cf\uff09*/\n    pub fn size(&self) -> usize {\n        return self.size;\n    }\n\n    /* \u83b7\u53d6\u5217\u8868\u5bb9\u91cf */\n    pub fn capacity(&self) -> usize {\n        return self.capacity;\n    }\n\n    /* \u8bbf\u95ee\u5143\u7d20 */\n    pub fn get(&self, index: usize) -> i32 {\n        // \u7d22\u5f15\u5982\u679c\u8d8a\u754c\uff0c\u5219\u629b\u51fa\u5f02\u5e38\uff0c\u4e0b\u540c\n        if index >= self.size {\n            panic!(\"\u7d22\u5f15\u8d8a\u754c\")\n        };\n        return self.arr[index];\n    }\n\n    /* \u66f4\u65b0\u5143\u7d20 */\n    pub fn set(&mut self, index: usize, num: i32) {\n        if index >= self.size {\n            panic!(\"\u7d22\u5f15\u8d8a\u754c\")\n        };\n        self.arr[index] = num;\n    }\n\n    /* \u5728\u5c3e\u90e8\u6dfb\u52a0\u5143\u7d20 */\n    pub fn add(&mut self, num: i32) {\n        // \u5143\u7d20\u6570\u91cf\u8d85\u51fa\u5bb9\u91cf\u65f6\uff0c\u89e6\u53d1\u6269\u5bb9\u673a\u5236\n        if self.size == self.capacity() {\n            self.extend_capacity();\n        }\n        self.arr[self.size] = num;\n        // \u66f4\u65b0\u5143\u7d20\u6570\u91cf\n        self.size += 1;\n    }\n\n    /* \u5728\u4e2d\u95f4\u63d2\u5165\u5143\u7d20 */\n    pub fn insert(&mut self, index: usize, num: i32) {\n        if index >= self.size() {\n            panic!(\"\u7d22\u5f15\u8d8a\u754c\")\n        };\n        // \u5143\u7d20\u6570\u91cf\u8d85\u51fa\u5bb9\u91cf\u65f6\uff0c\u89e6\u53d1\u6269\u5bb9\u673a\u5236\n        if self.size == self.capacity() {\n            self.extend_capacity();\n        }\n        // \u5c06\u7d22\u5f15 index \u4ee5\u53ca\u4e4b\u540e\u7684\u5143\u7d20\u90fd\u5411\u540e\u79fb\u52a8\u4e00\u4f4d\n        for j in (index..self.size).rev() {\n            self.arr[j + 1] = self.arr[j];\n        }\n        self.arr[index] = num;\n        // \u66f4\u65b0\u5143\u7d20\u6570\u91cf\n        self.size += 1;\n    }\n\n    /* \u5220\u9664\u5143\u7d20 */\n    pub fn remove(&mut self, index: usize) -> i32 {\n        if index >= self.size() {\n            panic!(\"\u7d22\u5f15\u8d8a\u754c\")\n        };\n        let num = self.arr[index];\n        // \u5c06\u5c06\u7d22\u5f15 index \u4e4b\u540e\u7684\u5143\u7d20\u90fd\u5411\u524d\u79fb\u52a8\u4e00\u4f4d\n        for j in (index..self.size - 1) {\n            self.arr[j] = self.arr[j + 1];\n        }\n        // \u66f4\u65b0\u5143\u7d20\u6570\u91cf\n        self.size -= 1;\n        // \u8fd4\u56de\u88ab\u5220\u9664\u7684\u5143\u7d20\n        return num;\n    }\n\n    /* \u5217\u8868\u6269\u5bb9 */\n    pub fn extend_capacity(&mut self) {\n        // \u65b0\u5efa\u4e00\u4e2a\u957f\u5ea6\u4e3a\u539f\u6570\u7ec4 extend_ratio \u500d\u7684\u65b0\u6570\u7ec4\uff0c\u5e76\u5c06\u539f\u6570\u7ec4\u590d\u5236\u5230\u65b0\u6570\u7ec4\n        let new_capacity = self.capacity * self.extend_ratio;\n        self.arr.resize(new_capacity, 0);\n        // \u66f4\u65b0\u5217\u8868\u5bb9\u91cf\n        self.capacity = new_capacity;\n    }\n\n    /* \u5c06\u5217\u8868\u8f6c\u6362\u4e3a\u6570\u7ec4 */\n    pub fn to_array(&mut self) -> Vec<i32> {\n        // \u4ec5\u8f6c\u6362\u6709\u6548\u957f\u5ea6\u8303\u56f4\u5185\u7684\u5217\u8868\u5143\u7d20\n        let mut arr = Vec::new();\n        for i in 0..self.size {\n            arr.push(self.get(i));\n        }\n        arr\n    }\n}\n
my_list.c
/* \u5217\u8868\u7c7b */\ntypedef struct {\n    int *arr;        // \u6570\u7ec4\uff08\u5b58\u50a8\u5217\u8868\u5143\u7d20\uff09\n    int capacity;    // \u5217\u8868\u5bb9\u91cf\n    int size;        // \u5217\u8868\u5927\u5c0f\n    int extendRatio; // \u5217\u8868\u6bcf\u6b21\u6269\u5bb9\u7684\u500d\u6570\n} MyList;\n\n/* \u6784\u9020\u51fd\u6570 */\nMyList *newMyList() {\n    MyList *nums = malloc(sizeof(MyList));\n    nums->capacity = 10;\n    nums->arr = malloc(sizeof(int) * nums->capacity);\n    nums->size = 0;\n    nums->extendRatio = 2;\n    return nums;\n}\n\n/* \u6790\u6784\u51fd\u6570 */\nvoid delMyList(MyList *nums) {\n    free(nums->arr);\n    free(nums);\n}\n\n/* \u83b7\u53d6\u5217\u8868\u957f\u5ea6 */\nint size(MyList *nums) {\n    return nums->size;\n}\n\n/* \u83b7\u53d6\u5217\u8868\u5bb9\u91cf */\nint capacity(MyList *nums) {\n    return nums->capacity;\n}\n\n/* \u8bbf\u95ee\u5143\u7d20 */\nint get(MyList *nums, int index) {\n    assert(index >= 0 && index < nums->size);\n    return nums->arr[index];\n}\n\n/* \u66f4\u65b0\u5143\u7d20 */\nvoid set(MyList *nums, int index, int num) {\n    assert(index >= 0 && index < nums->size);\n    nums->arr[index] = num;\n}\n\n/* \u5728\u5c3e\u90e8\u6dfb\u52a0\u5143\u7d20 */\nvoid add(MyList *nums, int num) {\n    if (size(nums) == capacity(nums)) {\n        extendCapacity(nums); // \u6269\u5bb9\n    }\n    nums->arr[size(nums)] = num;\n    nums->size++;\n}\n\n/* \u5728\u4e2d\u95f4\u63d2\u5165\u5143\u7d20 */\nvoid insert(MyList *nums, int index, int num) {\n    assert(index >= 0 && index < size(nums));\n    // \u5143\u7d20\u6570\u91cf\u8d85\u51fa\u5bb9\u91cf\u65f6\uff0c\u89e6\u53d1\u6269\u5bb9\u673a\u5236\n    if (size(nums) == capacity(nums)) {\n        extendCapacity(nums); // \u6269\u5bb9\n    }\n    for (int i = size(nums); i > index; --i) {\n        nums->arr[i] = nums->arr[i - 1];\n    }\n    nums->arr[index] = num;\n    nums->size++;\n}\n\n/* \u5220\u9664\u5143\u7d20 */\n// \u6ce8\u610f\uff1astdio.h \u5360\u7528\u4e86 remove \u5173\u952e\u8bcd\nint removeItem(MyList *nums, int index) {\n    assert(index >= 0 && index < size(nums));\n    int num = nums->arr[index];\n    for (int i = index; i < size(nums) - 1; i++) {\n        nums->arr[i] = nums->arr[i + 1];\n    }\n    nums->size--;\n    return num;\n}\n\n/* \u5217\u8868\u6269\u5bb9 */\nvoid extendCapacity(MyList *nums) {\n    // \u5148\u5206\u914d\u7a7a\u95f4\n    int newCapacity = capacity(nums) * nums->extendRatio;\n    int *extend = (int *)malloc(sizeof(int) * newCapacity);\n    int *temp = nums->arr;\n\n    // \u62f7\u8d1d\u65e7\u6570\u636e\u5230\u65b0\u6570\u636e\n    for (int i = 0; i < size(nums); i++)\n        extend[i] = nums->arr[i];\n\n    // \u91ca\u653e\u65e7\u6570\u636e\n    free(temp);\n\n    // \u66f4\u65b0\u65b0\u6570\u636e\n    nums->arr = extend;\n    nums->capacity = newCapacity;\n}\n\n/* \u5c06\u5217\u8868\u8f6c\u6362\u4e3a Array \u7528\u4e8e\u6253\u5370 */\nint *toArray(MyList *nums) {\n    return nums->arr;\n}\n
my_list.zig
// \u5217\u8868\u7c7b\nfn MyList(comptime T: type) type {\n    return struct {\n        const Self = @This();\n\n        arr: []T = undefined,                        // \u6570\u7ec4\uff08\u5b58\u50a8\u5217\u8868\u5143\u7d20\uff09\n        arrCapacity: usize = 10,                     // \u5217\u8868\u5bb9\u91cf\n        numSize: usize = 0,                           // \u5217\u8868\u957f\u5ea6\uff08\u5f53\u524d\u5143\u7d20\u6570\u91cf\uff09\n        extendRatio: usize = 2,                       // \u6bcf\u6b21\u5217\u8868\u6269\u5bb9\u7684\u500d\u6570\n        mem_arena: ?std.heap.ArenaAllocator = null,\n        mem_allocator: std.mem.Allocator = undefined, // \u5185\u5b58\u5206\u914d\u5668\n\n        // \u6784\u9020\u51fd\u6570\uff08\u5206\u914d\u5185\u5b58+\u521d\u59cb\u5316\u5217\u8868\uff09\n        pub fn init(self: *Self, allocator: std.mem.Allocator) !void {\n            if (self.mem_arena == null) {\n                self.mem_arena = std.heap.ArenaAllocator.init(allocator);\n                self.mem_allocator = self.mem_arena.?.allocator();\n            }\n            self.arr = try self.mem_allocator.alloc(T, self.arrCapacity);\n            @memset(self.arr, @as(T, 0));\n        }\n\n        // \u6790\u6784\u51fd\u6570\uff08\u91ca\u653e\u5185\u5b58\uff09\n        pub fn deinit(self: *Self) void {\n            if (self.mem_arena == null) return;\n            self.mem_arena.?.deinit();\n        }\n\n        // \u83b7\u53d6\u5217\u8868\u957f\u5ea6\uff08\u5f53\u524d\u5143\u7d20\u6570\u91cf\uff09\n        pub fn size(self: *Self) usize {\n            return self.numSize;\n        }\n\n        // \u83b7\u53d6\u5217\u8868\u5bb9\u91cf\n        pub fn capacity(self: *Self) usize {\n            return self.arrCapacity;\n        }\n\n        // \u8bbf\u95ee\u5143\u7d20\n        pub fn get(self: *Self, index: usize) T {\n            // \u7d22\u5f15\u5982\u679c\u8d8a\u754c\uff0c\u5219\u629b\u51fa\u5f02\u5e38\uff0c\u4e0b\u540c\n            if (index < 0 or index >= self.size()) @panic(\"\u7d22\u5f15\u8d8a\u754c\");\n            return self.arr[index];\n        }  \n\n        // \u66f4\u65b0\u5143\u7d20\n        pub fn set(self: *Self, index: usize, num: T) void {\n            // \u7d22\u5f15\u5982\u679c\u8d8a\u754c\uff0c\u5219\u629b\u51fa\u5f02\u5e38\uff0c\u4e0b\u540c\n            if (index < 0 or index >= self.size()) @panic(\"\u7d22\u5f15\u8d8a\u754c\");\n            self.arr[index] = num;\n        }  \n\n        // \u5728\u5c3e\u90e8\u6dfb\u52a0\u5143\u7d20\n        pub fn add(self: *Self, num: T) !void {\n            // \u5143\u7d20\u6570\u91cf\u8d85\u51fa\u5bb9\u91cf\u65f6\uff0c\u89e6\u53d1\u6269\u5bb9\u673a\u5236\n            if (self.size() == self.capacity()) try self.extendCapacity();\n            self.arr[self.size()] = num;\n            // \u66f4\u65b0\u5143\u7d20\u6570\u91cf\n            self.numSize += 1;\n        }  \n\n        // \u5728\u4e2d\u95f4\u63d2\u5165\u5143\u7d20\n        pub fn insert(self: *Self, index: usize, num: T) !void {\n            if (index < 0 or index >= self.size()) @panic(\"\u7d22\u5f15\u8d8a\u754c\");\n            // \u5143\u7d20\u6570\u91cf\u8d85\u51fa\u5bb9\u91cf\u65f6\uff0c\u89e6\u53d1\u6269\u5bb9\u673a\u5236\n            if (self.size() == self.capacity()) try self.extendCapacity();\n            // \u5c06\u7d22\u5f15 index \u4ee5\u53ca\u4e4b\u540e\u7684\u5143\u7d20\u90fd\u5411\u540e\u79fb\u52a8\u4e00\u4f4d\n            var j = self.size() - 1;\n            while (j >= index) : (j -= 1) {\n                self.arr[j + 1] = self.arr[j];\n            }\n            self.arr[index] = num;\n            // \u66f4\u65b0\u5143\u7d20\u6570\u91cf\n            self.numSize += 1;\n        }\n\n        // \u5220\u9664\u5143\u7d20\n        pub fn remove(self: *Self, index: usize) T {\n            if (index < 0 or index >= self.size()) @panic(\"\u7d22\u5f15\u8d8a\u754c\");\n            var num = self.arr[index];\n            // \u5c06\u7d22\u5f15 index \u4e4b\u540e\u7684\u5143\u7d20\u90fd\u5411\u524d\u79fb\u52a8\u4e00\u4f4d\n            var j = index;\n            while (j < self.size() - 1) : (j += 1) {\n                self.arr[j] = self.arr[j + 1];\n            }\n            // \u66f4\u65b0\u5143\u7d20\u6570\u91cf\n            self.numSize -= 1;\n            // \u8fd4\u56de\u88ab\u5220\u9664\u7684\u5143\u7d20\n            return num;\n        }\n\n        // \u5217\u8868\u6269\u5bb9\n        pub fn extendCapacity(self: *Self) !void {\n            // \u65b0\u5efa\u4e00\u4e2a\u957f\u5ea6\u4e3a size * extendRatio \u7684\u6570\u7ec4\uff0c\u5e76\u5c06\u539f\u6570\u7ec4\u590d\u5236\u5230\u65b0\u6570\u7ec4\n            var newCapacity = self.capacity() * self.extendRatio;\n            var extend = try self.mem_allocator.alloc(T, newCapacity);\n            @memset(extend, @as(T, 0));\n            // \u5c06\u539f\u6570\u7ec4\u4e2d\u7684\u6240\u6709\u5143\u7d20\u590d\u5236\u5230\u65b0\u6570\u7ec4\n            std.mem.copy(T, extend, self.arr);\n            self.arr = extend;\n            // \u66f4\u65b0\u5217\u8868\u5bb9\u91cf\n            self.arrCapacity = newCapacity;\n        }\n\n        // \u5c06\u5217\u8868\u8f6c\u6362\u4e3a\u6570\u7ec4\n        pub fn toArray(self: *Self) ![]T {\n            // \u4ec5\u8f6c\u6362\u6709\u6548\u957f\u5ea6\u8303\u56f4\u5185\u7684\u5217\u8868\u5143\u7d20\n            var arr = try self.mem_allocator.alloc(T, self.size());\n           @memset(arr, @as(T, 0));\n            for (arr, 0..) |*num, i| {\n                num.* = self.get(i);\n            }\n            return arr;\n        }\n    };\n}\n
Code Visualization

Full Screen >

"},{"location":"chapter_array_and_linkedlist/ram_and_cache/","title":"4.4 \u00a0 Memory and Cache *","text":"

In the first two sections of this chapter, we explored arrays and linked lists, two fundamental and important data structures, representing \"continuous storage\" and \"dispersed storage\" respectively.

In fact, the physical structure largely determines the efficiency of a program's use of memory and cache, which in turn affects the overall performance of the algorithm.

"},{"location":"chapter_array_and_linkedlist/ram_and_cache/#441-computer-storage-devices","title":"4.4.1 \u00a0 Computer Storage Devices","text":"

There are three types of storage devices in computers: \"hard disk,\" \"random-access memory (RAM),\" and \"cache memory.\" The following table shows their different roles and performance characteristics in computer systems.

Table 4-2 \u00a0 Computer Storage Devices

Hard Disk Memory Cache Usage Long-term storage of data, including OS, programs, files, etc. Temporary storage of currently running programs and data being processed Stores frequently accessed data and instructions, reducing the number of CPU accesses to memory Volatility Data is not lost after power off Data is lost after power off Data is lost after power off Capacity Larger, TB level Smaller, GB level Very small, MB level Speed Slower, several hundred to thousands MB/s Faster, several tens of GB/s Very fast, several tens to hundreds of GB/s Price Cheaper, several cents to yuan / GB More expensive, tens to hundreds of yuan / GB Very expensive, priced with CPU

We can imagine the computer storage system as a pyramid structure shown in the Figure 4-9 . The storage devices closer to the top of the pyramid are faster, have smaller capacity, and are more costly. This multi-level design is not accidental, but the result of careful consideration by computer scientists and engineers.

  • Hard disks are difficult to replace with memory. Firstly, data in memory is lost after power off, making it unsuitable for long-term data storage; secondly, the cost of memory is dozens of times that of hard disks, making it difficult to popularize in the consumer market.
  • It is difficult for caches to have both large capacity and high speed. As the capacity of L1, L2, L3 caches gradually increases, their physical size becomes larger, increasing the physical distance from the CPU core, leading to increased data transfer time and higher element access latency. Under current technology, a multi-level cache structure is the best balance between capacity, speed, and cost.

Figure 4-9 \u00a0 Computer Storage System

Note

The storage hierarchy of computers reflects a delicate balance between speed, capacity, and cost. In fact, this kind of trade-off is common in all industrial fields, requiring us to find the best balance between different advantages and limitations.

Overall, hard disks are used for long-term storage of large amounts of data, memory is used for temporary storage of data being processed during program execution, and cache is used to store frequently accessed data and instructions to improve program execution efficiency. Together, they ensure the efficient operation of computer systems.

As shown in the Figure 4-10 , during program execution, data is read from the hard disk into memory for CPU computation. The cache can be considered a part of the CPU, smartly loading data from memory to provide fast data access to the CPU, significantly enhancing program execution efficiency and reducing reliance on slower memory.

Figure 4-10 \u00a0 Data Flow Between Hard Disk, Memory, and Cache

"},{"location":"chapter_array_and_linkedlist/ram_and_cache/#442-memory-efficiency-of-data-structures","title":"4.4.2 \u00a0 Memory Efficiency of Data Structures","text":"

In terms of memory space utilization, arrays and linked lists have their advantages and limitations.

On one hand, memory is limited and cannot be shared by multiple programs, so we hope that data structures can use space as efficiently as possible. The elements of an array are tightly packed without extra space for storing references (pointers) between linked list nodes, making them more space-efficient. However, arrays require allocating sufficient continuous memory space at once, which may lead to memory waste, and array expansion also requires additional time and space costs. In contrast, linked lists allocate and reclaim memory dynamically on a per-node basis, providing greater flexibility.

On the other hand, during program execution, as memory is repeatedly allocated and released, the degree of fragmentation of free memory becomes higher, leading to reduced memory utilization efficiency. Arrays, due to their continuous storage method, are relatively less likely to cause memory fragmentation. In contrast, the elements of a linked list are dispersedly stored, and frequent insertion and deletion operations make memory fragmentation more likely.

"},{"location":"chapter_array_and_linkedlist/ram_and_cache/#443-cache-efficiency-of-data-structures","title":"4.4.3 \u00a0 Cache Efficiency of Data Structures","text":"

Although caches are much smaller in space capacity than memory, they are much faster and play a crucial role in program execution speed. Since the cache's capacity is limited and can only store a small part of frequently accessed data, when the CPU tries to access data not in the cache, a \"cache miss\" occurs, forcing the CPU to load the needed data from slower memory.

Clearly, the fewer the cache misses, the higher the CPU's data read-write efficiency, and the better the program performance. The proportion of successful data retrieval from the cache by the CPU is called the \"cache hit rate,\" a metric often used to measure cache efficiency.

To achieve higher efficiency, caches adopt the following data loading mechanisms.

  • Cache Lines: Caches don't store and load data byte by byte but in units of cache lines. Compared to byte-by-byte transfer, the transmission of cache lines is more efficient.
  • Prefetch Mechanism: Processors try to predict data access patterns (such as sequential access, fixed stride jumping access, etc.) and load data into the cache according to specific patterns to improve the hit rate.
  • Spatial Locality: If data is accessed, data nearby is likely to be accessed in the near future. Therefore, when loading certain data, the cache also loads nearby data to improve the hit rate.
  • Temporal Locality: If data is accessed, it's likely to be accessed again in the near future. Caches use this principle to retain recently accessed data to improve the hit rate.

In fact, arrays and linked lists have different cache utilization efficiencies, mainly reflected in the following aspects.

  • Occupied Space: Linked list elements occupy more space than array elements, resulting in less effective data volume in the cache.
  • Cache Lines: Linked list data is scattered throughout memory, and since caches load \"by line,\" the proportion of loading invalid data is higher.
  • Prefetch Mechanism: The data access pattern of arrays is more \"predictable\" than that of linked lists, meaning the system is more likely to guess which data will be loaded next.
  • Spatial Locality: Arrays are stored in concentrated memory spaces, so the data near the loaded data is more likely to be accessed next.

Overall, arrays have a higher cache hit rate and are generally more efficient in operation than linked lists. This makes data structures based on arrays more popular in solving algorithmic problems.

It should be noted that high cache efficiency does not mean that arrays are always better than linked lists. Which data structure to choose in actual applications should be based on specific requirements. For example, both arrays and linked lists can implement the \"stack\" data structure (which will be detailed in the next chapter), but they are suitable for different scenarios.

  • In algorithm problems, we tend to choose stacks based on arrays because they provide higher operational efficiency and random access capabilities, with the only cost being the need to pre-allocate a certain amount of memory space for the array.
  • If the data volume is very large, highly dynamic, and the expected size of the stack is difficult to estimate, then a stack based on a linked list is more appropriate. Linked lists can disperse a large amount of data in different parts of the memory and avoid the additional overhead of array expansion.
"},{"location":"chapter_array_and_linkedlist/summary/","title":"4.5 \u00a0 Summary","text":""},{"location":"chapter_array_and_linkedlist/summary/#1-key-review","title":"1. \u00a0 Key Review","text":"
  • Arrays and linked lists are two basic data structures, representing two storage methods in computer memory: contiguous space storage and non-contiguous space storage. Their characteristics complement each other.
  • Arrays support random access and use less memory; however, they are inefficient in inserting and deleting elements and have a fixed length after initialization.
  • Linked lists implement efficient node insertion and deletion through changing references (pointers) and can flexibly adjust their length; however, they have lower node access efficiency and consume more memory.
  • Common types of linked lists include singly linked lists, circular linked lists, and doubly linked lists, each with its own application scenarios.
  • Lists are ordered collections of elements that support addition, deletion, and modification, typically implemented based on dynamic arrays, retaining the advantages of arrays while allowing flexible length adjustment.
  • The advent of lists significantly enhanced the practicality of arrays but may lead to some memory space wastage.
  • During program execution, data is mainly stored in memory. Arrays provide higher memory space efficiency, while linked lists are more flexible in memory usage.
  • Caches provide fast data access to CPUs through mechanisms like cache lines, prefetching, spatial locality, and temporal locality, significantly enhancing program execution efficiency.
  • Due to higher cache hit rates, arrays are generally more efficient than linked lists. When choosing a data structure, the appropriate choice should be made based on specific needs and scenarios.
"},{"location":"chapter_array_and_linkedlist/summary/#2-q-a","title":"2. \u00a0 Q & A","text":"

Q: Does storing arrays on the stack versus the heap affect time and space efficiency?

Arrays stored on both the stack and heap are stored in contiguous memory spaces, and data operation efficiency is essentially the same. However, stacks and heaps have their own characteristics, leading to the following differences.

  1. Allocation and release efficiency: The stack is a smaller memory block, allocated automatically by the compiler; the heap memory is relatively larger and can be dynamically allocated in the code, more prone to fragmentation. Therefore, allocation and release operations on the heap are generally slower than on the stack.
  2. Size limitation: Stack memory is relatively small, while the heap size is generally limited by available memory. Therefore, the heap is more suitable for storing large arrays.
  3. Flexibility: The size of arrays on the stack needs to be determined at compile-time, while the size of arrays on the heap can be dynamically determined at runtime.

Q: Why do arrays require elements of the same type, while linked lists do not emphasize same-type elements?

Linked lists consist of nodes connected by references (pointers), and each node can store data of different types, such as int, double, string, object, etc.

In contrast, array elements must be of the same type, allowing the calculation of offsets to access the corresponding element positions. For example, an array containing both int and long types, with single elements occupying 4 bytes and 8 bytes respectively, cannot use the following formula to calculate offsets, as the array contains elements of two different lengths.

# Element memory address = Array memory address + Element length * Element index\n

Q: After deleting a node, is it necessary to set P.next to None?

Not modifying P.next is also acceptable. From the perspective of the linked list, traversing from the head node to the tail node will no longer encounter P. This means that node P has been effectively removed from the list, and where P points no longer affects the list.

From a garbage collection perspective, for languages with automatic garbage collection mechanisms like Java, Python, and Go, whether node P is collected depends on whether there are still references pointing to it, not on the value of P.next. In languages like C and C++, we need to manually free the node's memory.

Q: In linked lists, the time complexity for insertion and deletion operations is O(1). But searching for the element before insertion or deletion takes O(n) time, so why isn't the time complexity O(n)?

If an element is searched first and then deleted, the time complexity is indeed O(n). However, the O(1) advantage of linked lists in insertion and deletion can be realized in other applications. For example, in the implementation of double-ended queues using linked lists, we maintain pointers always pointing to the head and tail nodes, making each insertion and deletion operation O(1).

Q: In the image \"Linked List Definition and Storage Method\", do the light blue storage nodes occupy a single memory address, or do they share half with the node value?

The diagram is just a qualitative representation; quantitative analysis depends on specific situations.

  • Different types of node values occupy different amounts of space, such as int, long, double, and object instances.
  • The memory space occupied by pointer variables depends on the operating system and compilation environment used, usually 8 bytes or 4 bytes.

Q: Is adding elements to the end of a list always O(1)?

If adding an element exceeds the list length, the list needs to be expanded first. The system will request a new memory block and move all elements of the original list over, in which case the time complexity becomes O(n).

Q: The statement \"The emergence of lists greatly improves the practicality of arrays, but may lead to some memory space wastage\" - does this refer to the memory occupied by additional variables like capacity, length, and expansion multiplier?

The space wastage here mainly refers to two aspects: on the one hand, lists are set with an initial length, which we may not always need; on the other hand, to prevent frequent expansion, expansion usually multiplies by a coefficient, such as \\(\\times 1.5\\). This results in many empty slots, which we typically cannot fully fill.

Q: In Python, after initializing n = [1, 2, 3], the addresses of these 3 elements are contiguous, but initializing m = [2, 1, 3] shows that each element's id is not consecutive but identical to those in n. If the addresses of these elements are not contiguous, is m still an array?

If we replace list elements with linked list nodes n = [n1, n2, n3, n4, n5], these 5 node objects are also typically dispersed throughout memory. However, given a list index, we can still access the node's memory address in O(1) time, thereby accessing the corresponding node. This is because the array stores references to the nodes, not the nodes themselves.

Unlike many languages, in Python, numbers are also wrapped as objects, and lists store references to these numbers, not the numbers themselves. Therefore, we find that the same number in two arrays has the same id, and these numbers' memory addresses need not be contiguous.

Q: The std::list in C++ STL has already implemented a doubly linked list, but it seems that some algorithm books don't directly use it. Is there any limitation?

On the one hand, we often prefer to use arrays to implement algorithms, only using linked lists when necessary, mainly for two reasons.

  • Space overhead: Since each element requires two additional pointers (one for the previous element and one for the next), std::list usually occupies more space than std::vector.
  • Cache unfriendly: As the data is not stored continuously, std::list has a lower cache utilization rate. Generally, std::vector performs better.

On the other hand, linked lists are primarily necessary for binary trees and graphs. Stacks and queues are often implemented using the programming language's stack and queue classes, rather than linked lists.

Q: Does initializing a list res = [0] * self.size() result in each element of res referencing the same address?

No. However, this issue arises with two-dimensional arrays, for example, initializing a two-dimensional list res = [[0] * self.size()] would reference the same list [0] multiple times.

Q: In deleting a node, is it necessary to break the reference to its successor node?

From the perspective of data structures and algorithms (problem-solving), it's okay not to break the link, as long as the program's logic is correct. From the perspective of standard libraries, breaking the link is safer and more logically clear. If the link is not broken, and the deleted node is not properly recycled, it could affect the recycling of the successor node's memory.

"},{"location":"chapter_computational_complexity/","title":"Chapter 2. \u00a0 Complexity Analysis","text":"

Abstract

Complexity analysis is like a space-time navigator in the vast universe of algorithms.

It guides us in exploring deeper within the the dimensions of time and space, seeking more elegant solutions.

"},{"location":"chapter_computational_complexity/#chapter-contents","title":"Chapter Contents","text":"
  • 2.1 \u00a0 Algorithm Efficiency Assessment
  • 2.2 \u00a0 Iteration and Recursion
  • 2.3 \u00a0 Time Complexity
  • 2.4 \u00a0 Space Complexity
  • 2.5 \u00a0 Summary
"},{"location":"chapter_computational_complexity/iteration_and_recursion/","title":"2.2 \u00a0 Iteration and Recursion","text":"

In algorithms, the repeated execution of a task is quite common and is closely related to the analysis of complexity. Therefore, before delving into the concepts of time complexity and space complexity, let's first explore how to implement repetitive tasks in programming. This involves understanding two fundamental programming control structures: iteration and recursion.

"},{"location":"chapter_computational_complexity/iteration_and_recursion/#221-iteration","title":"2.2.1 \u00a0 Iteration","text":"

\"Iteration\" is a control structure for repeatedly performing a task. In iteration, a program repeats a block of code as long as a certain condition is met until this condition is no longer satisfied.

"},{"location":"chapter_computational_complexity/iteration_and_recursion/#1-for-loops","title":"1. \u00a0 For Loops","text":"

The for loop is one of the most common forms of iteration, and it's particularly suitable when the number of iterations is known in advance.

The following function uses a for loop to perform a summation of \\(1 + 2 + \\dots + n\\), with the sum being stored in the variable res. It's important to note that in Python, range(a, b) creates an interval that is inclusive of a but exclusive of b, meaning it iterates over the range from \\(a\\) up to \\(b\u22121\\).

PythonC++JavaC#GoSwiftJSTSDartRustCZig iteration.py
def for_loop(n: int) -> int:\n    \"\"\"for \u5faa\u73af\"\"\"\n    res = 0\n    # \u5faa\u73af\u6c42\u548c 1, 2, ..., n-1, n\n    for i in range(1, n + 1):\n        res += i\n    return res\n
iteration.cpp
/* for \u5faa\u73af */\nint forLoop(int n) {\n    int res = 0;\n    // \u5faa\u73af\u6c42\u548c 1, 2, ..., n-1, n\n    for (int i = 1; i <= n; ++i) {\n        res += i;\n    }\n    return res;\n}\n
iteration.java
/* for \u5faa\u73af */\nint forLoop(int n) {\n    int res = 0;\n    // \u5faa\u73af\u6c42\u548c 1, 2, ..., n-1, n\n    for (int i = 1; i <= n; i++) {\n        res += i;\n    }\n    return res;\n}\n
iteration.cs
/* for \u5faa\u73af */\nint ForLoop(int n) {\n    int res = 0;\n    // \u5faa\u73af\u6c42\u548c 1, 2, ..., n-1, n\n    for (int i = 1; i <= n; i++) {\n        res += i;\n    }\n    return res;\n}\n
iteration.go
/* for \u5faa\u73af */\nfunc forLoop(n int) int {\n    res := 0\n    // \u5faa\u73af\u6c42\u548c 1, 2, ..., n-1, n\n    for i := 1; i <= n; i++ {\n        res += i\n    }\n    return res\n}\n
iteration.swift
/* for \u5faa\u73af */\nfunc forLoop(n: Int) -> Int {\n    var res = 0\n    // \u5faa\u73af\u6c42\u548c 1, 2, ..., n-1, n\n    for i in 1 ... n {\n        res += i\n    }\n    return res\n}\n
iteration.js
/* for \u5faa\u73af */\nfunction forLoop(n) {\n    let res = 0;\n    // \u5faa\u73af\u6c42\u548c 1, 2, ..., n-1, n\n    for (let i = 1; i <= n; i++) {\n        res += i;\n    }\n    return res;\n}\n
iteration.ts
/* for \u5faa\u73af */\nfunction forLoop(n: number): number {\n    let res = 0;\n    // \u5faa\u73af\u6c42\u548c 1, 2, ..., n-1, n\n    for (let i = 1; i <= n; i++) {\n        res += i;\n    }\n    return res;\n}\n
iteration.dart
/* for \u5faa\u73af */\nint forLoop(int n) {\n  int res = 0;\n  // \u5faa\u73af\u6c42\u548c 1, 2, ..., n-1, n\n  for (int i = 1; i <= n; i++) {\n    res += i;\n  }\n  return res;\n}\n
iteration.rs
/* for \u5faa\u73af */\nfn for_loop(n: i32) -> i32 {\n    let mut res = 0;\n    // \u5faa\u73af\u6c42\u548c 1, 2, ..., n-1, n\n    for i in 1..=n {\n        res += i;\n    }\n    res\n}\n
iteration.c
/* for \u5faa\u73af */\nint forLoop(int n) {\n    int res = 0;\n    // \u5faa\u73af\u6c42\u548c 1, 2, ..., n-1, n\n    for (int i = 1; i <= n; i++) {\n        res += i;\n    }\n    return res;\n}\n
iteration.zig
// for \u5faa\u73af\nfn forLoop(n: usize) i32 {\n    var res: i32 = 0;\n    // \u5faa\u73af\u6c42\u548c 1, 2, ..., n-1, n\n    for (1..n+1) |i| {\n        res = res + @as(i32, @intCast(i));\n    }\n    return res;\n} \n
Code Visualization

Full Screen >

The flowchart below represents this sum function.

Figure 2-1 \u00a0 Flowchart of the Sum Function

The number of operations in this summation function is proportional to the size of the input data \\(n\\), or in other words, it has a \"linear relationship.\" This \"linear relationship\" is what time complexity describes. This topic will be discussed in more detail in the next section.

"},{"location":"chapter_computational_complexity/iteration_and_recursion/#2-while-loops","title":"2. \u00a0 While Loops","text":"

Similar to for loops, while loops are another approach for implementing iteration. In a while loop, the program checks a condition at the beginning of each iteration; if the condition is true, the execution continues, otherwise, the loop ends.

Below we use a while loop to implement the sum \\(1 + 2 + \\dots + n\\).

PythonC++JavaC#GoSwiftJSTSDartRustCZig iteration.py
def while_loop(n: int) -> int:\n    \"\"\"while \u5faa\u73af\"\"\"\n    res = 0\n    i = 1  # \u521d\u59cb\u5316\u6761\u4ef6\u53d8\u91cf\n    # \u5faa\u73af\u6c42\u548c 1, 2, ..., n-1, n\n    while i <= n:\n        res += i\n        i += 1  # \u66f4\u65b0\u6761\u4ef6\u53d8\u91cf\n    return res\n
iteration.cpp
/* while \u5faa\u73af */\nint whileLoop(int n) {\n    int res = 0;\n    int i = 1; // \u521d\u59cb\u5316\u6761\u4ef6\u53d8\u91cf\n    // \u5faa\u73af\u6c42\u548c 1, 2, ..., n-1, n\n    while (i <= n) {\n        res += i;\n        i++; // \u66f4\u65b0\u6761\u4ef6\u53d8\u91cf\n    }\n    return res;\n}\n
iteration.java
/* while \u5faa\u73af */\nint whileLoop(int n) {\n    int res = 0;\n    int i = 1; // \u521d\u59cb\u5316\u6761\u4ef6\u53d8\u91cf\n    // \u5faa\u73af\u6c42\u548c 1, 2, ..., n-1, n\n    while (i <= n) {\n        res += i;\n        i++; // \u66f4\u65b0\u6761\u4ef6\u53d8\u91cf\n    }\n    return res;\n}\n
iteration.cs
/* while \u5faa\u73af */\nint WhileLoop(int n) {\n    int res = 0;\n    int i = 1; // \u521d\u59cb\u5316\u6761\u4ef6\u53d8\u91cf\n    // \u5faa\u73af\u6c42\u548c 1, 2, ..., n-1, n\n    while (i <= n) {\n        res += i;\n        i += 1; // \u66f4\u65b0\u6761\u4ef6\u53d8\u91cf\n    }\n    return res;\n}\n
iteration.go
/* while \u5faa\u73af */\nfunc whileLoop(n int) int {\n    res := 0\n    // \u521d\u59cb\u5316\u6761\u4ef6\u53d8\u91cf\n    i := 1\n    // \u5faa\u73af\u6c42\u548c 1, 2, ..., n-1, n\n    for i <= n {\n        res += i\n        // \u66f4\u65b0\u6761\u4ef6\u53d8\u91cf\n        i++\n    }\n    return res\n}\n
iteration.swift
/* while \u5faa\u73af */\nfunc whileLoop(n: Int) -> Int {\n    var res = 0\n    var i = 1 // \u521d\u59cb\u5316\u6761\u4ef6\u53d8\u91cf\n    // \u5faa\u73af\u6c42\u548c 1, 2, ..., n-1, n\n    while i <= n {\n        res += i\n        i += 1 // \u66f4\u65b0\u6761\u4ef6\u53d8\u91cf\n    }\n    return res\n}\n
iteration.js
/* while \u5faa\u73af */\nfunction whileLoop(n) {\n    let res = 0;\n    let i = 1; // \u521d\u59cb\u5316\u6761\u4ef6\u53d8\u91cf\n    // \u5faa\u73af\u6c42\u548c 1, 2, ..., n-1, n\n    while (i <= n) {\n        res += i;\n        i++; // \u66f4\u65b0\u6761\u4ef6\u53d8\u91cf\n    }\n    return res;\n}\n
iteration.ts
/* while \u5faa\u73af */\nfunction whileLoop(n: number): number {\n    let res = 0;\n    let i = 1; // \u521d\u59cb\u5316\u6761\u4ef6\u53d8\u91cf\n    // \u5faa\u73af\u6c42\u548c 1, 2, ..., n-1, n\n    while (i <= n) {\n        res += i;\n        i++; // \u66f4\u65b0\u6761\u4ef6\u53d8\u91cf\n    }\n    return res;\n}\n
iteration.dart
/* while \u5faa\u73af */\nint whileLoop(int n) {\n  int res = 0;\n  int i = 1; // \u521d\u59cb\u5316\u6761\u4ef6\u53d8\u91cf\n  // \u5faa\u73af\u6c42\u548c 1, 2, ..., n-1, n\n  while (i <= n) {\n    res += i;\n    i++; // \u66f4\u65b0\u6761\u4ef6\u53d8\u91cf\n  }\n  return res;\n}\n
iteration.rs
/* while \u5faa\u73af */\nfn while_loop(n: i32) -> i32 {\n    let mut res = 0;\n    let mut i = 1; // \u521d\u59cb\u5316\u6761\u4ef6\u53d8\u91cf\n\n    // \u5faa\u73af\u6c42\u548c 1, 2, ..., n-1, n\n    while i <= n {\n        res += i;\n        i += 1; // \u66f4\u65b0\u6761\u4ef6\u53d8\u91cf\n    }\n    res\n}\n
iteration.c
/* while \u5faa\u73af */\nint whileLoop(int n) {\n    int res = 0;\n    int i = 1; // \u521d\u59cb\u5316\u6761\u4ef6\u53d8\u91cf\n    // \u5faa\u73af\u6c42\u548c 1, 2, ..., n-1, n\n    while (i <= n) {\n        res += i;\n        i++; // \u66f4\u65b0\u6761\u4ef6\u53d8\u91cf\n    }\n    return res;\n}\n
iteration.zig
// while \u5faa\u73af\nfn whileLoop(n: i32) i32 {\n    var res: i32 = 0;\n    var i: i32 = 1; // \u521d\u59cb\u5316\u6761\u4ef6\u53d8\u91cf\n    // \u5faa\u73af\u6c42\u548c 1, 2, ..., n-1, n\n    while (i <= n) {\n        res += @intCast(i);\n        i += 1;\n    }\n    return res;\n}\n
Code Visualization

Full Screen >

While loops provide more flexibility than for loops, especially since they allow for custom initialization and modification of the condition variable at each step.

For example, in the following code, the condition variable \\(i\\) is updated twice each round, which would be inconvenient to implement with a for loop.

PythonC++JavaC#GoSwiftJSTSDartRustCZig iteration.py
def while_loop_ii(n: int) -> int:\n    \"\"\"while \u5faa\u73af\uff08\u4e24\u6b21\u66f4\u65b0\uff09\"\"\"\n    res = 0\n    i = 1  # \u521d\u59cb\u5316\u6761\u4ef6\u53d8\u91cf\n    # \u5faa\u73af\u6c42\u548c 1, 4, 10, ...\n    while i <= n:\n        res += i\n        # \u66f4\u65b0\u6761\u4ef6\u53d8\u91cf\n        i += 1\n        i *= 2\n    return res\n
iteration.cpp
/* while \u5faa\u73af\uff08\u4e24\u6b21\u66f4\u65b0\uff09 */\nint whileLoopII(int n) {\n    int res = 0;\n    int i = 1; // \u521d\u59cb\u5316\u6761\u4ef6\u53d8\u91cf\n    // \u5faa\u73af\u6c42\u548c 1, 4, 10, ...\n    while (i <= n) {\n        res += i;\n        // \u66f4\u65b0\u6761\u4ef6\u53d8\u91cf\n        i++;\n        i *= 2;\n    }\n    return res;\n}\n
iteration.java
/* while \u5faa\u73af\uff08\u4e24\u6b21\u66f4\u65b0\uff09 */\nint whileLoopII(int n) {\n    int res = 0;\n    int i = 1; // \u521d\u59cb\u5316\u6761\u4ef6\u53d8\u91cf\n    // \u5faa\u73af\u6c42\u548c 1, 4, 10, ...\n    while (i <= n) {\n        res += i;\n        // \u66f4\u65b0\u6761\u4ef6\u53d8\u91cf\n        i++;\n        i *= 2;\n    }\n    return res;\n}\n
iteration.cs
/* while \u5faa\u73af\uff08\u4e24\u6b21\u66f4\u65b0\uff09 */\nint WhileLoopII(int n) {\n    int res = 0;\n    int i = 1; // \u521d\u59cb\u5316\u6761\u4ef6\u53d8\u91cf\n    // \u5faa\u73af\u6c42\u548c 1, 4, 10, ...\n    while (i <= n) {\n        res += i;\n        // \u66f4\u65b0\u6761\u4ef6\u53d8\u91cf\n        i += 1; \n        i *= 2;\n    }\n    return res;\n}\n
iteration.go
/* while \u5faa\u73af\uff08\u4e24\u6b21\u66f4\u65b0\uff09 */\nfunc whileLoopII(n int) int {\n    res := 0\n    // \u521d\u59cb\u5316\u6761\u4ef6\u53d8\u91cf\n    i := 1\n    // \u5faa\u73af\u6c42\u548c 1, 4, 10, ...\n    for i <= n {\n        res += i\n        // \u66f4\u65b0\u6761\u4ef6\u53d8\u91cf\n        i++\n        i *= 2\n    }\n    return res\n}\n
iteration.swift
/* while \u5faa\u73af\uff08\u4e24\u6b21\u66f4\u65b0\uff09 */\nfunc whileLoopII(n: Int) -> Int {\n    var res = 0\n    var i = 1 // \u521d\u59cb\u5316\u6761\u4ef6\u53d8\u91cf\n    // \u5faa\u73af\u6c42\u548c 1, 4, 10, ...\n    while i <= n {\n        res += i\n        // \u66f4\u65b0\u6761\u4ef6\u53d8\u91cf\n        i += 1\n        i *= 2\n    }\n    return res\n}\n
iteration.js
/* while \u5faa\u73af\uff08\u4e24\u6b21\u66f4\u65b0\uff09 */\nfunction whileLoopII(n) {\n    let res = 0;\n    let i = 1; // \u521d\u59cb\u5316\u6761\u4ef6\u53d8\u91cf\n    // \u5faa\u73af\u6c42\u548c 1, 4, 10, ...\n    while (i <= n) {\n        res += i;\n        // \u66f4\u65b0\u6761\u4ef6\u53d8\u91cf\n        i++;\n        i *= 2;\n    }\n    return res;\n}\n
iteration.ts
/* while \u5faa\u73af\uff08\u4e24\u6b21\u66f4\u65b0\uff09 */\nfunction whileLoopII(n: number): number {\n    let res = 0;\n    let i = 1; // \u521d\u59cb\u5316\u6761\u4ef6\u53d8\u91cf\n    // \u5faa\u73af\u6c42\u548c 1, 4, 10, ...\n    while (i <= n) {\n        res += i;\n        // \u66f4\u65b0\u6761\u4ef6\u53d8\u91cf\n        i++;\n        i *= 2;\n    }\n    return res;\n}\n
iteration.dart
/* while \u5faa\u73af\uff08\u4e24\u6b21\u66f4\u65b0\uff09 */\nint whileLoopII(int n) {\n  int res = 0;\n  int i = 1; // \u521d\u59cb\u5316\u6761\u4ef6\u53d8\u91cf\n  // \u5faa\u73af\u6c42\u548c 1, 4, 10, ...\n  while (i <= n) {\n    res += i;\n    // \u66f4\u65b0\u6761\u4ef6\u53d8\u91cf\n    i++;\n    i *= 2;\n  }\n  return res;\n}\n
iteration.rs
/* while \u5faa\u73af\uff08\u4e24\u6b21\u66f4\u65b0\uff09 */\nfn while_loop_ii(n: i32) -> i32 {\n    let mut res = 0;\n    let mut i = 1; // \u521d\u59cb\u5316\u6761\u4ef6\u53d8\u91cf\n\n    // \u5faa\u73af\u6c42\u548c 1, 4, 10, ...\n    while i <= n {\n        res += i;\n        // \u66f4\u65b0\u6761\u4ef6\u53d8\u91cf\n        i += 1;\n        i *= 2;\n    }\n    res\n}\n
iteration.c
/* while \u5faa\u73af\uff08\u4e24\u6b21\u66f4\u65b0\uff09 */\nint whileLoopII(int n) {\n    int res = 0;\n    int i = 1; // \u521d\u59cb\u5316\u6761\u4ef6\u53d8\u91cf\n    // \u5faa\u73af\u6c42\u548c 1, 4, 10, ...\n    while (i <= n) {\n        res += i;\n        // \u66f4\u65b0\u6761\u4ef6\u53d8\u91cf\n        i++;\n        i *= 2;\n    }\n    return res;\n}\n
iteration.zig
//  while \u5faa\u73af\uff08\u4e24\u6b21\u66f4\u65b0\uff09\nfn whileLoopII(n: i32) i32 {\n    var res: i32 = 0;\n    var i: i32 = 1; // \u521d\u59cb\u5316\u6761\u4ef6\u53d8\u91cf\n    // \u5faa\u73af\u6c42\u548c 1, 4, 10, ...\n    while (i <= n) {\n        res += @intCast(i);\n        // \u66f4\u65b0\u6761\u4ef6\u53d8\u91cf\n        i += 1;\n        i *= 2;\n    }\n    return res;\n}\n
Code Visualization

Full Screen >

Overall, for loops are more concise, while while loops are more flexible. Both can implement iterative structures. Which one to use should be determined based on the specific requirements of the problem.

"},{"location":"chapter_computational_complexity/iteration_and_recursion/#3-nested-loops","title":"3. \u00a0 Nested Loops","text":"

We can nest one loop structure within another. Below is an example using for loops:

PythonC++JavaC#GoSwiftJSTSDartRustCZig iteration.py
def nested_for_loop(n: int) -> str:\n    \"\"\"\u53cc\u5c42 for \u5faa\u73af\"\"\"\n    res = \"\"\n    # \u5faa\u73af i = 1, 2, ..., n-1, n\n    for i in range(1, n + 1):\n        # \u5faa\u73af j = 1, 2, ..., n-1, n\n        for j in range(1, n + 1):\n            res += f\"({i}, {j}), \"\n    return res\n
iteration.cpp
/* \u53cc\u5c42 for \u5faa\u73af */\nstring nestedForLoop(int n) {\n    ostringstream res;\n    // \u5faa\u73af i = 1, 2, ..., n-1, n\n    for (int i = 1; i <= n; ++i) {\n        // \u5faa\u73af j = 1, 2, ..., n-1, n\n        for (int j = 1; j <= n; ++j) {\n            res << \"(\" << i << \", \" << j << \"), \";\n        }\n    }\n    return res.str();\n}\n
iteration.java
/* \u53cc\u5c42 for \u5faa\u73af */\nString nestedForLoop(int n) {\n    StringBuilder res = new StringBuilder();\n    // \u5faa\u73af i = 1, 2, ..., n-1, n\n    for (int i = 1; i <= n; i++) {\n        // \u5faa\u73af j = 1, 2, ..., n-1, n\n        for (int j = 1; j <= n; j++) {\n            res.append(\"(\" + i + \", \" + j + \"), \");\n        }\n    }\n    return res.toString();\n}\n
iteration.cs
/* \u53cc\u5c42 for \u5faa\u73af */\nstring NestedForLoop(int n) {\n    StringBuilder res = new();\n    // \u5faa\u73af i = 1, 2, ..., n-1, n\n    for (int i = 1; i <= n; i++) {\n        // \u5faa\u73af j = 1, 2, ..., n-1, n\n        for (int j = 1; j <= n; j++) {\n            res.Append($\"({i}, {j}), \");\n        }\n    }\n    return res.ToString();\n}\n
iteration.go
/* \u53cc\u5c42 for \u5faa\u73af */\nfunc nestedForLoop(n int) string {\n    res := \"\"\n    // \u5faa\u73af i = 1, 2, ..., n-1, n\n    for i := 1; i <= n; i++ {\n        for j := 1; j <= n; j++ {\n            // \u5faa\u73af j = 1, 2, ..., n-1, n\n            res += fmt.Sprintf(\"(%d, %d), \", i, j)\n        }\n    }\n    return res\n}\n
iteration.swift
/* \u53cc\u5c42 for \u5faa\u73af */\nfunc nestedForLoop(n: Int) -> String {\n    var res = \"\"\n    // \u5faa\u73af i = 1, 2, ..., n-1, n\n    for i in 1 ... n {\n        // \u5faa\u73af j = 1, 2, ..., n-1, n\n        for j in 1 ... n {\n            res.append(\"(\\(i), \\(j)), \")\n        }\n    }\n    return res\n}\n
iteration.js
/* \u53cc\u5c42 for \u5faa\u73af */\nfunction nestedForLoop(n) {\n    let res = '';\n    // \u5faa\u73af i = 1, 2, ..., n-1, n\n    for (let i = 1; i <= n; i++) {\n        // \u5faa\u73af j = 1, 2, ..., n-1, n\n        for (let j = 1; j <= n; j++) {\n            res += `(${i}, ${j}), `;\n        }\n    }\n    return res;\n}\n
iteration.ts
/* \u53cc\u5c42 for \u5faa\u73af */\nfunction nestedForLoop(n: number): string {\n    let res = '';\n    // \u5faa\u73af i = 1, 2, ..., n-1, n\n    for (let i = 1; i <= n; i++) {\n        // \u5faa\u73af j = 1, 2, ..., n-1, n\n        for (let j = 1; j <= n; j++) {\n            res += `(${i}, ${j}), `;\n        }\n    }\n    return res;\n}\n
iteration.dart
/* \u53cc\u5c42 for \u5faa\u73af */\nString nestedForLoop(int n) {\n  String res = \"\";\n  // \u5faa\u73af i = 1, 2, ..., n-1, n\n  for (int i = 1; i <= n; i++) {\n    // \u5faa\u73af j = 1, 2, ..., n-1, n\n    for (int j = 1; j <= n; j++) {\n      res += \"($i, $j), \";\n    }\n  }\n  return res;\n}\n
iteration.rs
/* \u53cc\u5c42 for \u5faa\u73af */\nfn nested_for_loop(n: i32) -> String {\n    let mut res = vec![];\n    // \u5faa\u73af i = 1, 2, ..., n-1, n\n    for i in 1..=n {\n        // \u5faa\u73af j = 1, 2, ..., n-1, n\n        for j in 1..=n {\n            res.push(format!(\"({}, {}), \", i, j));\n        }\n    }\n    res.join(\"\")\n}\n
iteration.c
/* \u53cc\u5c42 for \u5faa\u73af */\nchar *nestedForLoop(int n) {\n    // n * n \u4e3a\u5bf9\u5e94\u70b9\u6570\u91cf\uff0c\"(i, j), \" \u5bf9\u5e94\u5b57\u7b26\u4e32\u957f\u6700\u5927\u4e3a 6+10*2\uff0c\u52a0\u4e0a\u6700\u540e\u4e00\u4e2a\u7a7a\u5b57\u7b26 \\0 \u7684\u989d\u5916\u7a7a\u95f4\n    int size = n * n * 26 + 1;\n    char *res = malloc(size * sizeof(char));\n    // \u5faa\u73af i = 1, 2, ..., n-1, n\n    for (int i = 1; i <= n; i++) {\n        // \u5faa\u73af j = 1, 2, ..., n-1, n\n        for (int j = 1; j <= n; j++) {\n            char tmp[26];\n            snprintf(tmp, sizeof(tmp), \"(%d, %d), \", i, j);\n            strncat(res, tmp, size - strlen(res) - 1);\n        }\n    }\n    return res;\n}\n
iteration.zig
// \u53cc\u5c42 for \u5faa\u73af\nfn nestedForLoop(allocator: Allocator, n: usize) ![]const u8 {\n    var res = std.ArrayList(u8).init(allocator);\n    defer res.deinit();\n    var buffer: [20]u8 = undefined;\n    // \u5faa\u73af i = 1, 2, ..., n-1, n\n    for (1..n+1) |i| {\n        // \u5faa\u73af j = 1, 2, ..., n-1, n\n        for (1..n+1) |j| {\n            var _str = try std.fmt.bufPrint(&buffer, \"({d}, {d}), \", .{i, j});\n            try res.appendSlice(_str);\n        }\n    }\n    return res.toOwnedSlice();\n}\n
Code Visualization

Full Screen >

The flowchart below represents this nested loop.

Figure 2-2 \u00a0 Flowchart of the Nested Loop

In such cases, the number of operations of the function is proportional to \\(n^2\\), meaning the algorithm's runtime and the size of the input data \\(n\\) has a 'quadratic relationship.'

We can further increase the complexity by adding more nested loops, each level of nesting effectively \"increasing the dimension,\" which raises the time complexity to \"cubic,\" \"quartic,\" and so on.

"},{"location":"chapter_computational_complexity/iteration_and_recursion/#222-recursion","title":"2.2.2 \u00a0 Recursion","text":"

\"Recursion\" is an algorithmic strategy where a function solves a problem by calling itself. It primarily involves two phases:

  1. Calling: This is where the program repeatedly calls itself, often with progressively smaller or simpler arguments, moving towards the \"termination condition.\"
  2. Returning: Upon triggering the \"termination condition,\" the program begins to return from the deepest recursive function, aggregating the results of each layer.

From an implementation perspective, recursive code mainly includes three elements.

  1. Termination Condition: Determines when to switch from \"calling\" to \"returning.\"
  2. Recursive Call: Corresponds to \"calling,\" where the function calls itself, usually with smaller or more simplified parameters.
  3. Return Result: Corresponds to \"returning,\" where the result of the current recursion level is returned to the previous layer.

Observe the following code, where simply calling the function recur(n) can compute the sum of \\(1 + 2 + \\dots + n\\):

PythonC++JavaC#GoSwiftJSTSDartRustCZig recursion.py
def recur(n: int) -> int:\n    \"\"\"\u9012\u5f52\"\"\"\n    # \u7ec8\u6b62\u6761\u4ef6\n    if n == 1:\n        return 1\n    # \u9012\uff1a\u9012\u5f52\u8c03\u7528\n    res = recur(n - 1)\n    # \u5f52\uff1a\u8fd4\u56de\u7ed3\u679c\n    return n + res\n
recursion.cpp
/* \u9012\u5f52 */\nint recur(int n) {\n    // \u7ec8\u6b62\u6761\u4ef6\n    if (n == 1)\n        return 1;\n    // \u9012\uff1a\u9012\u5f52\u8c03\u7528\n    int res = recur(n - 1);\n    // \u5f52\uff1a\u8fd4\u56de\u7ed3\u679c\n    return n + res;\n}\n
recursion.java
/* \u9012\u5f52 */\nint recur(int n) {\n    // \u7ec8\u6b62\u6761\u4ef6\n    if (n == 1)\n        return 1;\n    // \u9012\uff1a\u9012\u5f52\u8c03\u7528\n    int res = recur(n - 1);\n    // \u5f52\uff1a\u8fd4\u56de\u7ed3\u679c\n    return n + res;\n}\n
recursion.cs
/* \u9012\u5f52 */\nint Recur(int n) {\n    // \u7ec8\u6b62\u6761\u4ef6\n    if (n == 1)\n        return 1;\n    // \u9012\uff1a\u9012\u5f52\u8c03\u7528\n    int res = Recur(n - 1);\n    // \u5f52\uff1a\u8fd4\u56de\u7ed3\u679c\n    return n + res;\n}\n
recursion.go
/* \u9012\u5f52 */\nfunc recur(n int) int {\n    // \u7ec8\u6b62\u6761\u4ef6\n    if n == 1 {\n        return 1\n    }\n    // \u9012\uff1a\u9012\u5f52\u8c03\u7528\n    res := recur(n - 1)\n    // \u5f52\uff1a\u8fd4\u56de\u7ed3\u679c\n    return n + res\n}\n
recursion.swift
/* \u9012\u5f52 */\nfunc recur(n: Int) -> Int {\n    // \u7ec8\u6b62\u6761\u4ef6\n    if n == 1 {\n        return 1\n    }\n    // \u9012\uff1a\u9012\u5f52\u8c03\u7528\n    let res = recur(n: n - 1)\n    // \u5f52\uff1a\u8fd4\u56de\u7ed3\u679c\n    return n + res\n}\n
recursion.js
/* \u9012\u5f52 */\nfunction recur(n) {\n    // \u7ec8\u6b62\u6761\u4ef6\n    if (n === 1) return 1;\n    // \u9012\uff1a\u9012\u5f52\u8c03\u7528\n    const res = recur(n - 1);\n    // \u5f52\uff1a\u8fd4\u56de\u7ed3\u679c\n    return n + res;\n}\n
recursion.ts
/* \u9012\u5f52 */\nfunction recur(n: number): number {\n    // \u7ec8\u6b62\u6761\u4ef6\n    if (n === 1) return 1;\n    // \u9012\uff1a\u9012\u5f52\u8c03\u7528\n    const res = recur(n - 1);\n    // \u5f52\uff1a\u8fd4\u56de\u7ed3\u679c\n    return n + res;\n}\n
recursion.dart
/* \u9012\u5f52 */\nint recur(int n) {\n  // \u7ec8\u6b62\u6761\u4ef6\n  if (n == 1) return 1;\n  // \u9012\uff1a\u9012\u5f52\u8c03\u7528\n  int res = recur(n - 1);\n  // \u5f52\uff1a\u8fd4\u56de\u7ed3\u679c\n  return n + res;\n}\n
recursion.rs
/* \u9012\u5f52 */\nfn recur(n: i32) -> i32 {\n    // \u7ec8\u6b62\u6761\u4ef6\n    if n == 1 {\n        return 1;\n    }\n    // \u9012\uff1a\u9012\u5f52\u8c03\u7528\n    let res = recur(n - 1);\n    // \u5f52\uff1a\u8fd4\u56de\u7ed3\u679c\n    n + res\n}\n
recursion.c
/* \u9012\u5f52 */\nint recur(int n) {\n    // \u7ec8\u6b62\u6761\u4ef6\n    if (n == 1)\n        return 1;\n    // \u9012\uff1a\u9012\u5f52\u8c03\u7528\n    int res = recur(n - 1);\n    // \u5f52\uff1a\u8fd4\u56de\u7ed3\u679c\n    return n + res;\n}\n
recursion.zig
// \u9012\u5f52\u51fd\u6570\nfn recur(n: i32) i32 {\n    // \u7ec8\u6b62\u6761\u4ef6\n    if (n == 1) {\n        return 1;\n    }\n    // \u9012\uff1a\u9012\u5f52\u8c03\u7528\n    var res: i32 = recur(n - 1);\n    // \u5f52\uff1a\u8fd4\u56de\u7ed3\u679c\n    return n + res;\n}\n
Code Visualization

Full Screen >

The Figure 2-3 shows the recursive process of this function.

Figure 2-3 \u00a0 Recursive Process of the Sum Function

Although iteration and recursion can achieve the same results from a computational standpoint, they represent two entirely different paradigms of thinking and problem-solving.

  • Iteration: Solves problems \"from the bottom up.\" It starts with the most basic steps, and then repeatedly adds or accumulates these steps until the task is complete.
  • Recursion: Solves problems \"from the top down.\" It breaks down the original problem into smaller sub-problems, each of which has the same form as the original problem. These sub-problems are then further decomposed into even smaller sub-problems, stopping at the base case whose solution is known.

Let's take the earlier example of the summation function, defined as \\(f(n) = 1 + 2 + \\dots + n\\).

  • Iteration: In this approach, we simulate the summation process within a loop. Starting from \\(1\\) and traversing to \\(n\\), we perform the summation operation in each iteration to eventually compute \\(f(n)\\).
  • Recursion: Here, the problem is broken down into a sub-problem: \\(f(n) = n + f(n-1)\\). This decomposition continues recursively until reaching the base case, \\(f(1) = 1\\), at which point the recursion terminates.
"},{"location":"chapter_computational_complexity/iteration_and_recursion/#1-call-stack","title":"1. \u00a0 Call Stack","text":"

Every time a recursive function calls itself, the system allocates memory for the newly initiated function to store local variables, the return address, and other relevant information. This leads to two primary outcomes.

  • The function's context data is stored in a memory area called \"stack frame space\" and is only released after the function returns. Therefore, recursion generally consumes more memory space than iteration.
  • Recursive calls introduce additional overhead. Hence, recursion is usually less time-efficient than loops.

As shown in the Figure 2-4 , there are \\(n\\) unreturned recursive functions before triggering the termination condition, indicating a recursion depth of \\(n\\).

Figure 2-4 \u00a0 Recursion Call Depth

In practice, the depth of recursion allowed by programming languages is usually limited, and excessively deep recursion can lead to stack overflow errors.

"},{"location":"chapter_computational_complexity/iteration_and_recursion/#2-tail-recursion","title":"2. \u00a0 Tail Recursion","text":"

Interestingly, if a function performs its recursive call as the very last step before returning, it can be optimized by the compiler or interpreter to be as space-efficient as iteration. This scenario is known as \"tail recursion.\"

  • Regular Recursion: In standard recursion, when the function returns to the previous level, it continues to execute more code, requiring the system to save the context of the previous call.
  • Tail Recursion: Here, the recursive call is the final operation before the function returns. This means that upon returning to the previous level, no further actions are needed, so the system does not need to save the context of the previous level.

For example, in calculating \\(1 + 2 + \\dots + n\\), we can make the result variable res a parameter of the function, thereby achieving tail recursion:

PythonC++JavaC#GoSwiftJSTSDartRustCZig recursion.py
def tail_recur(n, res):\n    \"\"\"\u5c3e\u9012\u5f52\"\"\"\n    # \u7ec8\u6b62\u6761\u4ef6\n    if n == 0:\n        return res\n    # \u5c3e\u9012\u5f52\u8c03\u7528\n    return tail_recur(n - 1, res + n)\n
recursion.cpp
/* \u5c3e\u9012\u5f52 */\nint tailRecur(int n, int res) {\n    // \u7ec8\u6b62\u6761\u4ef6\n    if (n == 0)\n        return res;\n    // \u5c3e\u9012\u5f52\u8c03\u7528\n    return tailRecur(n - 1, res + n);\n}\n
recursion.java
/* \u5c3e\u9012\u5f52 */\nint tailRecur(int n, int res) {\n    // \u7ec8\u6b62\u6761\u4ef6\n    if (n == 0)\n        return res;\n    // \u5c3e\u9012\u5f52\u8c03\u7528\n    return tailRecur(n - 1, res + n);\n}\n
recursion.cs
/* \u5c3e\u9012\u5f52 */\nint TailRecur(int n, int res) {\n    // \u7ec8\u6b62\u6761\u4ef6\n    if (n == 0)\n        return res;\n    // \u5c3e\u9012\u5f52\u8c03\u7528\n    return TailRecur(n - 1, res + n);\n}\n
recursion.go
/* \u5c3e\u9012\u5f52 */\nfunc tailRecur(n int, res int) int {\n    // \u7ec8\u6b62\u6761\u4ef6\n    if n == 0 {\n        return res\n    }\n    // \u5c3e\u9012\u5f52\u8c03\u7528\n    return tailRecur(n-1, res+n)\n}\n
recursion.swift
/* \u5c3e\u9012\u5f52 */\nfunc tailRecur(n: Int, res: Int) -> Int {\n    // \u7ec8\u6b62\u6761\u4ef6\n    if n == 0 {\n        return res\n    }\n    // \u5c3e\u9012\u5f52\u8c03\u7528\n    return tailRecur(n: n - 1, res: res + n)\n}\n
recursion.js
/* \u5c3e\u9012\u5f52 */\nfunction tailRecur(n, res) {\n    // \u7ec8\u6b62\u6761\u4ef6\n    if (n === 0) return res;\n    // \u5c3e\u9012\u5f52\u8c03\u7528\n    return tailRecur(n - 1, res + n);\n}\n
recursion.ts
/* \u5c3e\u9012\u5f52 */\nfunction tailRecur(n: number, res: number): number {\n    // \u7ec8\u6b62\u6761\u4ef6\n    if (n === 0) return res;\n    // \u5c3e\u9012\u5f52\u8c03\u7528\n    return tailRecur(n - 1, res + n);\n}\n
recursion.dart
/* \u5c3e\u9012\u5f52 */\nint tailRecur(int n, int res) {\n  // \u7ec8\u6b62\u6761\u4ef6\n  if (n == 0) return res;\n  // \u5c3e\u9012\u5f52\u8c03\u7528\n  return tailRecur(n - 1, res + n);\n}\n
recursion.rs
/* \u5c3e\u9012\u5f52 */\nfn tail_recur(n: i32, res: i32) -> i32 {\n    // \u7ec8\u6b62\u6761\u4ef6\n    if n == 0 {\n        return res;\n    }\n    // \u5c3e\u9012\u5f52\u8c03\u7528\n    tail_recur(n - 1, res + n)\n}\n
recursion.c
/* \u5c3e\u9012\u5f52 */\nint tailRecur(int n, int res) {\n    // \u7ec8\u6b62\u6761\u4ef6\n    if (n == 0)\n        return res;\n    // \u5c3e\u9012\u5f52\u8c03\u7528\n    return tailRecur(n - 1, res + n);\n}\n
recursion.zig
// \u5c3e\u9012\u5f52\u51fd\u6570\nfn tailRecur(n: i32, res: i32) i32 {\n    // \u7ec8\u6b62\u6761\u4ef6\n    if (n == 0) {\n        return res;\n    }\n    // \u5c3e\u9012\u5f52\u8c03\u7528\n    return tailRecur(n - 1, res + n);\n}\n
Code Visualization

Full Screen >

The execution process of tail recursion is shown in the following figure. Comparing regular recursion and tail recursion, the point of the summation operation is different.

  • Regular Recursion: The summation operation occurs during the \"returning\" phase, requiring another summation after each layer returns.
  • Tail Recursion: The summation operation occurs during the \"calling\" phase, and the \"returning\" phase only involves returning through each layer.

Figure 2-5 \u00a0 Tail Recursion Process

Tip

Note that many compilers or interpreters do not support tail recursion optimization. For example, Python does not support tail recursion optimization by default, so even if the function is in the form of tail recursion, it may still encounter stack overflow issues.

"},{"location":"chapter_computational_complexity/iteration_and_recursion/#3-recursion-tree","title":"3. \u00a0 Recursion Tree","text":"

When dealing with algorithms related to \"divide and conquer\", recursion often offers a more intuitive approach and more readable code than iteration. Take the \"Fibonacci sequence\" as an example.

Question

Given a Fibonacci sequence \\(0, 1, 1, 2, 3, 5, 8, 13, \\dots\\), find the \\(n\\)th number in the sequence.

Let the \\(n\\)th number of the Fibonacci sequence be \\(f(n)\\), it's easy to deduce two conclusions:

  • The first two numbers of the sequence are \\(f(1) = 0\\) and \\(f(2) = 1\\).
  • Each number in the sequence is the sum of the two preceding ones, that is, \\(f(n) = f(n - 1) + f(n - 2)\\).

Using the recursive relation, and considering the first two numbers as termination conditions, we can write the recursive code. Calling fib(n) will yield the \\(n\\)th number of the Fibonacci sequence:

PythonC++JavaC#GoSwiftJSTSDartRustCZig recursion.py
def fib(n: int) -> int:\n    \"\"\"\u6590\u6ce2\u90a3\u5951\u6570\u5217\uff1a\u9012\u5f52\"\"\"\n    # \u7ec8\u6b62\u6761\u4ef6 f(1) = 0, f(2) = 1\n    if n == 1 or n == 2:\n        return n - 1\n    # \u9012\u5f52\u8c03\u7528 f(n) = f(n-1) + f(n-2)\n    res = fib(n - 1) + fib(n - 2)\n    # \u8fd4\u56de\u7ed3\u679c f(n)\n    return res\n
recursion.cpp
/* \u6590\u6ce2\u90a3\u5951\u6570\u5217\uff1a\u9012\u5f52 */\nint fib(int n) {\n    // \u7ec8\u6b62\u6761\u4ef6 f(1) = 0, f(2) = 1\n    if (n == 1 || n == 2)\n        return n - 1;\n    // \u9012\u5f52\u8c03\u7528 f(n) = f(n-1) + f(n-2)\n    int res = fib(n - 1) + fib(n - 2);\n    // \u8fd4\u56de\u7ed3\u679c f(n)\n    return res;\n}\n
recursion.java
/* \u6590\u6ce2\u90a3\u5951\u6570\u5217\uff1a\u9012\u5f52 */\nint fib(int n) {\n    // \u7ec8\u6b62\u6761\u4ef6 f(1) = 0, f(2) = 1\n    if (n == 1 || n == 2)\n        return n - 1;\n    // \u9012\u5f52\u8c03\u7528 f(n) = f(n-1) + f(n-2)\n    int res = fib(n - 1) + fib(n - 2);\n    // \u8fd4\u56de\u7ed3\u679c f(n)\n    return res;\n}\n
recursion.cs
/* \u6590\u6ce2\u90a3\u5951\u6570\u5217\uff1a\u9012\u5f52 */\nint Fib(int n) {\n    // \u7ec8\u6b62\u6761\u4ef6 f(1) = 0, f(2) = 1\n    if (n == 1 || n == 2)\n        return n - 1;\n    // \u9012\u5f52\u8c03\u7528 f(n) = f(n-1) + f(n-2)\n    int res = Fib(n - 1) + Fib(n - 2);\n    // \u8fd4\u56de\u7ed3\u679c f(n)\n    return res;\n}\n
recursion.go
/* \u6590\u6ce2\u90a3\u5951\u6570\u5217\uff1a\u9012\u5f52 */\nfunc fib(n int) int {\n    // \u7ec8\u6b62\u6761\u4ef6 f(1) = 0, f(2) = 1\n    if n == 1 || n == 2 {\n        return n - 1\n    }\n    // \u9012\u5f52\u8c03\u7528 f(n) = f(n-1) + f(n-2)\n    res := fib(n-1) + fib(n-2)\n    // \u8fd4\u56de\u7ed3\u679c f(n)\n    return res\n}\n
recursion.swift
/* \u6590\u6ce2\u90a3\u5951\u6570\u5217\uff1a\u9012\u5f52 */\nfunc fib(n: Int) -> Int {\n    // \u7ec8\u6b62\u6761\u4ef6 f(1) = 0, f(2) = 1\n    if n == 1 || n == 2 {\n        return n - 1\n    }\n    // \u9012\u5f52\u8c03\u7528 f(n) = f(n-1) + f(n-2)\n    let res = fib(n: n - 1) + fib(n: n - 2)\n    // \u8fd4\u56de\u7ed3\u679c f(n)\n    return res\n}\n
recursion.js
/* \u6590\u6ce2\u90a3\u5951\u6570\u5217\uff1a\u9012\u5f52 */\nfunction fib(n) {\n    // \u7ec8\u6b62\u6761\u4ef6 f(1) = 0, f(2) = 1\n    if (n === 1 || n === 2) return n - 1;\n    // \u9012\u5f52\u8c03\u7528 f(n) = f(n-1) + f(n-2)\n    const res = fib(n - 1) + fib(n - 2);\n    // \u8fd4\u56de\u7ed3\u679c f(n)\n    return res;\n}\n
recursion.ts
/* \u6590\u6ce2\u90a3\u5951\u6570\u5217\uff1a\u9012\u5f52 */\nfunction fib(n: number): number {\n    // \u7ec8\u6b62\u6761\u4ef6 f(1) = 0, f(2) = 1\n    if (n === 1 || n === 2) return n - 1;\n    // \u9012\u5f52\u8c03\u7528 f(n) = f(n-1) + f(n-2)\n    const res = fib(n - 1) + fib(n - 2);\n    // \u8fd4\u56de\u7ed3\u679c f(n)\n    return res;\n}\n
recursion.dart
/* \u6590\u6ce2\u90a3\u5951\u6570\u5217\uff1a\u9012\u5f52 */\nint fib(int n) {\n  // \u7ec8\u6b62\u6761\u4ef6 f(1) = 0, f(2) = 1\n  if (n == 1 || n == 2) return n - 1;\n  // \u9012\u5f52\u8c03\u7528 f(n) = f(n-1) + f(n-2)\n  int res = fib(n - 1) + fib(n - 2);\n  // \u8fd4\u56de\u7ed3\u679c f(n)\n  return res;\n}\n
recursion.rs
/* \u6590\u6ce2\u90a3\u5951\u6570\u5217\uff1a\u9012\u5f52 */\nfn fib(n: i32) -> i32 {\n    // \u7ec8\u6b62\u6761\u4ef6 f(1) = 0, f(2) = 1\n    if n == 1 || n == 2 {\n        return n - 1;\n    }\n    // \u9012\u5f52\u8c03\u7528 f(n) = f(n-1) + f(n-2)\n    let res = fib(n - 1) + fib(n - 2);\n    // \u8fd4\u56de\u7ed3\u679c\n    res\n}\n
recursion.c
/* \u6590\u6ce2\u90a3\u5951\u6570\u5217\uff1a\u9012\u5f52 */\nint fib(int n) {\n    // \u7ec8\u6b62\u6761\u4ef6 f(1) = 0, f(2) = 1\n    if (n == 1 || n == 2)\n        return n - 1;\n    // \u9012\u5f52\u8c03\u7528 f(n) = f(n-1) + f(n-2)\n    int res = fib(n - 1) + fib(n - 2);\n    // \u8fd4\u56de\u7ed3\u679c f(n)\n    return res;\n}\n
recursion.zig
// \u6590\u6ce2\u90a3\u5951\u6570\u5217\nfn fib(n: i32) i32 {\n    // \u7ec8\u6b62\u6761\u4ef6 f(1) = 0, f(2) = 1\n    if (n == 1 or n == 2) {\n        return n - 1;\n    }\n    // \u9012\u5f52\u8c03\u7528 f(n) = f(n-1) + f(n-2)\n    var res: i32 = fib(n - 1) + fib(n - 2);\n    // \u8fd4\u56de\u7ed3\u679c f(n)\n    return res;\n}\n
Code Visualization

Full Screen >

Observing the above code, we see that it recursively calls two functions within itself, meaning that one call generates two branching calls. As illustrated below, this continuous recursive calling eventually creates a \"recursion tree\" with a depth of \\(n\\).

Figure 2-6 \u00a0 Fibonacci Sequence Recursion Tree

Fundamentally, recursion embodies the paradigm of \"breaking down a problem into smaller sub-problems.\" This divide-and-conquer strategy is crucial.

  • From an algorithmic perspective, many important strategies like searching, sorting, backtracking, divide-and-conquer, and dynamic programming directly or indirectly use this way of thinking.
  • From a data structure perspective, recursion is naturally suited for dealing with linked lists, trees, and graphs, as they are well suited for analysis using the divide-and-conquer approach.
"},{"location":"chapter_computational_complexity/iteration_and_recursion/#223-comparison","title":"2.2.3 \u00a0 Comparison","text":"

Summarizing the above content, the following table shows the differences between iteration and recursion in terms of implementation, performance, and applicability.

Table: Comparison of Iteration and Recursion Characteristics

Iteration Recursion Approach Loop structure Function calls itself Time Efficiency Generally higher efficiency, no function call overhead Each function call generates overhead Memory Usage Typically uses a fixed size of memory space Accumulative function calls can use a substantial amount of stack frame space Suitable Problems Suitable for simple loop tasks, intuitive and readable code Suitable for problem decomposition, like trees, graphs, divide-and-conquer, backtracking, etc., concise and clear code structure

Tip

If you find the following content difficult to understand, consider revisiting it after reading the \"Stack\" chapter.

So, what is the intrinsic connection between iteration and recursion? Taking the above recursive function as an example, the summation operation occurs during the recursion's \"return\" phase. This means that the initially called function is the last to complete its summation operation, mirroring the \"last in, first out\" principle of a stack.

Recursive terms like \"call stack\" and \"stack frame space\" hint at the close relationship between recursion and stacks.

  1. Calling: When a function is called, the system allocates a new stack frame on the \"call stack\" for that function, storing local variables, parameters, return addresses, and other data.
  2. Returning: When a function completes execution and returns, the corresponding stack frame is removed from the \"call stack,\" restoring the execution environment of the previous function.

Therefore, we can use an explicit stack to simulate the behavior of the call stack, thus transforming recursion into an iterative form:

PythonC++JavaC#GoSwiftJSTSDartRustCZig recursion.py
def for_loop_recur(n: int) -> int:\n    \"\"\"\u4f7f\u7528\u8fed\u4ee3\u6a21\u62df\u9012\u5f52\"\"\"\n    # \u4f7f\u7528\u4e00\u4e2a\u663e\u5f0f\u7684\u6808\u6765\u6a21\u62df\u7cfb\u7edf\u8c03\u7528\u6808\n    stack = []\n    res = 0\n    # \u9012\uff1a\u9012\u5f52\u8c03\u7528\n    for i in range(n, 0, -1):\n        # \u901a\u8fc7\u201c\u5165\u6808\u64cd\u4f5c\u201d\u6a21\u62df\u201c\u9012\u201d\n        stack.append(i)\n    # \u5f52\uff1a\u8fd4\u56de\u7ed3\u679c\n    while stack:\n        # \u901a\u8fc7\u201c\u51fa\u6808\u64cd\u4f5c\u201d\u6a21\u62df\u201c\u5f52\u201d\n        res += stack.pop()\n    # res = 1+2+3+...+n\n    return res\n
recursion.cpp
/* \u4f7f\u7528\u8fed\u4ee3\u6a21\u62df\u9012\u5f52 */\nint forLoopRecur(int n) {\n    // \u4f7f\u7528\u4e00\u4e2a\u663e\u5f0f\u7684\u6808\u6765\u6a21\u62df\u7cfb\u7edf\u8c03\u7528\u6808\n    stack<int> stack;\n    int res = 0;\n    // \u9012\uff1a\u9012\u5f52\u8c03\u7528\n    for (int i = n; i > 0; i--) {\n        // \u901a\u8fc7\u201c\u5165\u6808\u64cd\u4f5c\u201d\u6a21\u62df\u201c\u9012\u201d\n        stack.push(i);\n    }\n    // \u5f52\uff1a\u8fd4\u56de\u7ed3\u679c\n    while (!stack.empty()) {\n        // \u901a\u8fc7\u201c\u51fa\u6808\u64cd\u4f5c\u201d\u6a21\u62df\u201c\u5f52\u201d\n        res += stack.top();\n        stack.pop();\n    }\n    // res = 1+2+3+...+n\n    return res;\n}\n
recursion.java
/* \u4f7f\u7528\u8fed\u4ee3\u6a21\u62df\u9012\u5f52 */\nint forLoopRecur(int n) {\n    // \u4f7f\u7528\u4e00\u4e2a\u663e\u5f0f\u7684\u6808\u6765\u6a21\u62df\u7cfb\u7edf\u8c03\u7528\u6808\n    Stack<Integer> stack = new Stack<>();\n    int res = 0;\n    // \u9012\uff1a\u9012\u5f52\u8c03\u7528\n    for (int i = n; i > 0; i--) {\n        // \u901a\u8fc7\u201c\u5165\u6808\u64cd\u4f5c\u201d\u6a21\u62df\u201c\u9012\u201d\n        stack.push(i);\n    }\n    // \u5f52\uff1a\u8fd4\u56de\u7ed3\u679c\n    while (!stack.isEmpty()) {\n        // \u901a\u8fc7\u201c\u51fa\u6808\u64cd\u4f5c\u201d\u6a21\u62df\u201c\u5f52\u201d\n        res += stack.pop();\n    }\n    // res = 1+2+3+...+n\n    return res;\n}\n
recursion.cs
/* \u4f7f\u7528\u8fed\u4ee3\u6a21\u62df\u9012\u5f52 */\nint ForLoopRecur(int n) {\n    // \u4f7f\u7528\u4e00\u4e2a\u663e\u5f0f\u7684\u6808\u6765\u6a21\u62df\u7cfb\u7edf\u8c03\u7528\u6808\n    Stack<int> stack = new();\n    int res = 0;\n    // \u9012\uff1a\u9012\u5f52\u8c03\u7528\n    for (int i = n; i > 0; i--) {\n        // \u901a\u8fc7\u201c\u5165\u6808\u64cd\u4f5c\u201d\u6a21\u62df\u201c\u9012\u201d\n        stack.Push(i);\n    }\n    // \u5f52\uff1a\u8fd4\u56de\u7ed3\u679c\n    while (stack.Count > 0) {\n        // \u901a\u8fc7\u201c\u51fa\u6808\u64cd\u4f5c\u201d\u6a21\u62df\u201c\u5f52\u201d\n        res += stack.Pop();\n    }\n    // res = 1+2+3+...+n\n    return res;\n}\n
recursion.go
/* \u4f7f\u7528\u8fed\u4ee3\u6a21\u62df\u9012\u5f52 */\nfunc forLoopRecur(n int) int {\n    // \u4f7f\u7528\u4e00\u4e2a\u663e\u5f0f\u7684\u6808\u6765\u6a21\u62df\u7cfb\u7edf\u8c03\u7528\u6808\n    stack := list.New()\n    res := 0\n    // \u9012\uff1a\u9012\u5f52\u8c03\u7528\n    for i := n; i > 0; i-- {\n        // \u901a\u8fc7\u201c\u5165\u6808\u64cd\u4f5c\u201d\u6a21\u62df\u201c\u9012\u201d\n        stack.PushBack(i)\n    }\n    // \u5f52\uff1a\u8fd4\u56de\u7ed3\u679c\n    for stack.Len() != 0 {\n        // \u901a\u8fc7\u201c\u51fa\u6808\u64cd\u4f5c\u201d\u6a21\u62df\u201c\u5f52\u201d\n        res += stack.Back().Value.(int)\n        stack.Remove(stack.Back())\n    }\n    // res = 1+2+3+...+n\n    return res\n}\n
recursion.swift
/* \u4f7f\u7528\u8fed\u4ee3\u6a21\u62df\u9012\u5f52 */\nfunc forLoopRecur(n: Int) -> Int {\n    // \u4f7f\u7528\u4e00\u4e2a\u663e\u5f0f\u7684\u6808\u6765\u6a21\u62df\u7cfb\u7edf\u8c03\u7528\u6808\n    var stack: [Int] = []\n    var res = 0\n    // \u9012\uff1a\u9012\u5f52\u8c03\u7528\n    for i in (1 ... n).reversed() {\n        // \u901a\u8fc7\u201c\u5165\u6808\u64cd\u4f5c\u201d\u6a21\u62df\u201c\u9012\u201d\n        stack.append(i)\n    }\n    // \u5f52\uff1a\u8fd4\u56de\u7ed3\u679c\n    while !stack.isEmpty {\n        // \u901a\u8fc7\u201c\u51fa\u6808\u64cd\u4f5c\u201d\u6a21\u62df\u201c\u5f52\u201d\n        res += stack.removeLast()\n    }\n    // res = 1+2+3+...+n\n    return res\n}\n
recursion.js
/* \u4f7f\u7528\u8fed\u4ee3\u6a21\u62df\u9012\u5f52 */\nfunction forLoopRecur(n) {\n    // \u4f7f\u7528\u4e00\u4e2a\u663e\u5f0f\u7684\u6808\u6765\u6a21\u62df\u7cfb\u7edf\u8c03\u7528\u6808\n    const stack = [];\n    let res = 0;\n    // \u9012\uff1a\u9012\u5f52\u8c03\u7528\n    for (let i = n; i > 0; i--) {\n        // \u901a\u8fc7\u201c\u5165\u6808\u64cd\u4f5c\u201d\u6a21\u62df\u201c\u9012\u201d\n        stack.push(i);\n    }\n    // \u5f52\uff1a\u8fd4\u56de\u7ed3\u679c\n    while (stack.length) {\n        // \u901a\u8fc7\u201c\u51fa\u6808\u64cd\u4f5c\u201d\u6a21\u62df\u201c\u5f52\u201d\n        res += stack.pop();\n    }\n    // res = 1+2+3+...+n\n    return res;\n}\n
recursion.ts
/* \u4f7f\u7528\u8fed\u4ee3\u6a21\u62df\u9012\u5f52 */\nfunction forLoopRecur(n: number): number {\n    // \u4f7f\u7528\u4e00\u4e2a\u663e\u5f0f\u7684\u6808\u6765\u6a21\u62df\u7cfb\u7edf\u8c03\u7528\u6808 \n    const stack: number[] = [];\n    let res: number = 0;\n    // \u9012\uff1a\u9012\u5f52\u8c03\u7528\n    for (let i = n; i > 0; i--) {\n        // \u901a\u8fc7\u201c\u5165\u6808\u64cd\u4f5c\u201d\u6a21\u62df\u201c\u9012\u201d\n        stack.push(i);\n    }\n    // \u5f52\uff1a\u8fd4\u56de\u7ed3\u679c\n    while (stack.length) {\n        // \u901a\u8fc7\u201c\u51fa\u6808\u64cd\u4f5c\u201d\u6a21\u62df\u201c\u5f52\u201d\n        res += stack.pop();\n    }\n    // res = 1+2+3+...+n\n    return res;\n}\n
recursion.dart
/* \u4f7f\u7528\u8fed\u4ee3\u6a21\u62df\u9012\u5f52 */\nint forLoopRecur(int n) {\n  // \u4f7f\u7528\u4e00\u4e2a\u663e\u5f0f\u7684\u6808\u6765\u6a21\u62df\u7cfb\u7edf\u8c03\u7528\u6808\n  List<int> stack = [];\n  int res = 0;\n  // \u9012\uff1a\u9012\u5f52\u8c03\u7528\n  for (int i = n; i > 0; i--) {\n    // \u901a\u8fc7\u201c\u5165\u6808\u64cd\u4f5c\u201d\u6a21\u62df\u201c\u9012\u201d\n    stack.add(i);\n  }\n  // \u5f52\uff1a\u8fd4\u56de\u7ed3\u679c\n  while (!stack.isEmpty) {\n    // \u901a\u8fc7\u201c\u51fa\u6808\u64cd\u4f5c\u201d\u6a21\u62df\u201c\u5f52\u201d\n    res += stack.removeLast();\n  }\n  // res = 1+2+3+...+n\n  return res;\n}\n
recursion.rs
/* \u4f7f\u7528\u8fed\u4ee3\u6a21\u62df\u9012\u5f52 */\nfn for_loop_recur(n: i32) -> i32 {\n    // \u4f7f\u7528\u4e00\u4e2a\u663e\u5f0f\u7684\u6808\u6765\u6a21\u62df\u7cfb\u7edf\u8c03\u7528\u6808\n    let mut stack = Vec::new();\n    let mut res = 0;\n    // \u9012\uff1a\u9012\u5f52\u8c03\u7528\n    for i in (1..=n).rev() {\n        // \u901a\u8fc7\u201c\u5165\u6808\u64cd\u4f5c\u201d\u6a21\u62df\u201c\u9012\u201d\n        stack.push(i);\n    }\n    // \u5f52\uff1a\u8fd4\u56de\u7ed3\u679c\n    while !stack.is_empty() {\n        // \u901a\u8fc7\u201c\u51fa\u6808\u64cd\u4f5c\u201d\u6a21\u62df\u201c\u5f52\u201d\n        res += stack.pop().unwrap();\n    }\n    // res = 1+2+3+...+n\n    res\n}\n
recursion.c
/* \u4f7f\u7528\u8fed\u4ee3\u6a21\u62df\u9012\u5f52 */\nint forLoopRecur(int n) {\n    int stack[1000]; // \u501f\u52a9\u4e00\u4e2a\u5927\u6570\u7ec4\u6765\u6a21\u62df\u6808\n    int top = -1;    // \u6808\u9876\u7d22\u5f15\n    int res = 0;\n    // \u9012\uff1a\u9012\u5f52\u8c03\u7528\n    for (int i = n; i > 0; i--) {\n        // \u901a\u8fc7\u201c\u5165\u6808\u64cd\u4f5c\u201d\u6a21\u62df\u201c\u9012\u201d\n        stack[1 + top++] = i;\n    }\n    // \u5f52\uff1a\u8fd4\u56de\u7ed3\u679c\n    while (top >= 0) {\n        // \u901a\u8fc7\u201c\u51fa\u6808\u64cd\u4f5c\u201d\u6a21\u62df\u201c\u5f52\u201d\n        res += stack[top--];\n    }\n    // res = 1+2+3+...+n\n    return res;\n}\n
recursion.zig
// \u4f7f\u7528\u8fed\u4ee3\u6a21\u62df\u9012\u5f52\nfn forLoopRecur(comptime n: i32) i32 {\n    // \u4f7f\u7528\u4e00\u4e2a\u663e\u5f0f\u7684\u6808\u6765\u6a21\u62df\u7cfb\u7edf\u8c03\u7528\u6808\n    var stack: [n]i32 = undefined;\n    var res: i32 = 0;\n    // \u9012\uff1a\u9012\u5f52\u8c03\u7528\n    var i: usize = n;\n    while (i > 0) {\n        stack[i - 1] = @intCast(i);\n        i -= 1;\n    }\n    // \u5f52\uff1a\u8fd4\u56de\u7ed3\u679c\n    var index: usize = n;\n    while (index > 0) {\n        index -= 1;\n        res += stack[index];\n    }\n    // res = 1+2+3+...+n\n    return res;\n}\n
Code Visualization

Full Screen >

Observing the above code, when recursion is transformed into iteration, the code becomes more complex. Although iteration and recursion can often be transformed into each other, it's not always advisable to do so for two reasons:

  • The transformed code may become more challenging to understand and less readable.
  • For some complex problems, simulating the behavior of the system's call stack can be quite challenging.

In conclusion, whether to choose iteration or recursion depends on the specific nature of the problem. In programming practice, it's crucial to weigh the pros and cons of both and choose the most suitable approach for the situation at hand.

"},{"location":"chapter_computational_complexity/performance_evaluation/","title":"2.1 \u00a0 Algorithm Efficiency Assessment","text":"

In algorithm design, we pursue the following two objectives in sequence.

  1. Finding a Solution to the Problem: The algorithm should reliably find the correct solution within the stipulated range of inputs.
  2. Seeking the Optimal Solution: For the same problem, multiple solutions might exist, and we aim to find the most efficient algorithm possible.

In other words, under the premise of being able to solve the problem, algorithm efficiency has become the main criterion for evaluating the merits of an algorithm, which includes the following two dimensions.

  • Time Efficiency: The speed at which an algorithm runs.
  • Space Efficiency: The size of the memory space occupied by an algorithm.

In short, our goal is to design data structures and algorithms that are both fast and memory-efficient. Effectively assessing algorithm efficiency is crucial because only then can we compare various algorithms and guide the process of algorithm design and optimization.

There are mainly two methods of efficiency assessment: actual testing and theoretical estimation.

"},{"location":"chapter_computational_complexity/performance_evaluation/#211-actual-testing","title":"2.1.1 \u00a0 Actual Testing","text":"

Suppose we have algorithms A and B, both capable of solving the same problem, and we need to compare their efficiencies. The most direct method is to use a computer to run these two algorithms and monitor and record their runtime and memory usage. This assessment method reflects the actual situation but has significant limitations.

On one hand, it's difficult to eliminate interference from the testing environment. Hardware configurations can affect algorithm performance. For example, algorithm A might run faster than B on one computer, but the opposite result may occur on another computer with different configurations. This means we would need to test on a variety of machines to calculate average efficiency, which is impractical.

On the other hand, conducting a full test is very resource-intensive. As the volume of input data changes, the efficiency of the algorithms may vary. For example, with smaller data volumes, algorithm A might run faster than B, but the opposite might be true with larger data volumes. Therefore, to draw convincing conclusions, we need to test a wide range of input data sizes, which requires significant computational resources.

"},{"location":"chapter_computational_complexity/performance_evaluation/#212-theoretical-estimation","title":"2.1.2 \u00a0 Theoretical Estimation","text":"

Due to the significant limitations of actual testing, we can consider evaluating algorithm efficiency solely through calculations. This estimation method is known as \"asymptotic complexity analysis,\" or simply \"complexity analysis.\"

Complexity analysis reflects the relationship between the time and space resources required for algorithm execution and the size of the input data. It describes the trend of growth in the time and space required by the algorithm as the size of the input data increases. This definition might sound complex, but we can break it down into three key points to understand it better.

  • \"Time and space resources\" correspond to \"time complexity\" and \"space complexity,\" respectively.
  • \"As the size of input data increases\" means that complexity reflects the relationship between algorithm efficiency and the volume of input data.
  • \"The trend of growth in time and space\" indicates that complexity analysis focuses not on the specific values of runtime or space occupied but on the \"rate\" at which time or space grows.

Complexity analysis overcomes the disadvantages of actual testing methods, reflected in the following aspects:

  • It is independent of the testing environment and applicable to all operating platforms.
  • It can reflect algorithm efficiency under different data volumes, especially in the performance of algorithms with large data volumes.

Tip

If you're still confused about the concept of complexity, don't worry. We will introduce it in detail in subsequent chapters.

Complexity analysis provides us with a \"ruler\" to measure the time and space resources needed to execute an algorithm and compare the efficiency between different algorithms.

Complexity is a mathematical concept and may be abstract and challenging for beginners. From this perspective, complexity analysis might not be the best content to introduce first. However, when discussing the characteristics of a particular data structure or algorithm, it's hard to avoid analyzing its speed and space usage.

In summary, it's recommended that you establish a preliminary understanding of complexity analysis before diving deep into data structures and algorithms, so that you can carry out simple complexity analyses of algorithms.

"},{"location":"chapter_computational_complexity/space_complexity/","title":"2.4 \u00a0 Space Complexity","text":"

\"Space complexity\" is used to measure the growth trend of the memory space occupied by an algorithm as the amount of data increases. This concept is very similar to time complexity, except that \"running time\" is replaced with \"occupied memory space\".

"},{"location":"chapter_computational_complexity/space_complexity/#241-space-related-to-algorithms","title":"2.4.1 \u00a0 Space Related to Algorithms","text":"

The memory space used by an algorithm during its execution mainly includes the following types.

  • Input Space: Used to store the input data of the algorithm.
  • Temporary Space: Used to store variables, objects, function contexts, and other data during the algorithm's execution.
  • Output Space: Used to store the output data of the algorithm.

Generally, the scope of space complexity statistics includes both \"Temporary Space\" and \"Output Space\".

Temporary space can be further divided into three parts.

  • Temporary Data: Used to save various constants, variables, objects, etc., during the algorithm's execution.
  • Stack Frame Space: Used to save the context data of the called function. The system creates a stack frame at the top of the stack each time a function is called, and the stack frame space is released after the function returns.
  • Instruction Space: Used to store compiled program instructions, which are usually negligible in actual statistics.

When analyzing the space complexity of a program, we typically count the Temporary Data, Stack Frame Space, and Output Data, as shown in the Figure 2-15 .

Figure 2-15 \u00a0 Space Types Used in Algorithms

The relevant code is as follows:

PythonC++JavaC#GoSwiftJSTSDartRustCZig
class Node:\n    \"\"\"Classes\"\"\"\"\n    def __init__(self, x: int):\n        self.val: int = x               # node value\n        self.next: Node | None = None   # reference to the next node\n\ndef function() -> int:\n    \"\"\"\"Functions\"\"\"\"\"\n    # Perform certain operations...\n    return 0\n\ndef algorithm(n) -> int:    # input data\n    A = 0                   # temporary data (constant, usually in uppercase)\n    b = 0                   # temporary data (variable)\n    node = Node(0)          # temporary data (object)\n    c = function()          # Stack frame space (call function)\n    return A + b + c        # output data\n
/* Structures */\nstruct Node {\n    int val;\n    Node *next;\n    Node(int x) : val(x), next(nullptr) {}\n};\n\n/* Functions */\nint func() {\n    // Perform certain operations...\n    return 0;\n}\n\nint algorithm(int n) {          // input data\n    const int a = 0;            // temporary data (constant)\n    int b = 0;                  // temporary data (variable)\n    Node* node = new Node(0);   // temporary data (object)\n    int c = func();             // stack frame space (call function)\n    return a + b + c;           // output data\n}\n
/* Classes */\nclass Node {\n    int val;\n    Node next;\n    Node(int x) { val = x; }\n}\n\n/* Functions */\nint function() {\n    // Perform certain operations...\n    return 0;\n}\n\nint algorithm(int n) {          // input data\n    final int a = 0;            // temporary data (constant)\n    int b = 0;                  // temporary data (variable)\n    Node node = new Node(0);    // temporary data (object)\n    int c = function();         // stack frame space (call function)\n    return a + b + c;           // output data\n}\n
/* Classes */\nclass Node {\n    int val;\n    Node next;\n    Node(int x) { val = x; }\n}\n\n/* Functions */\nint Function() {\n    // Perform certain operations...\n    return 0;\n}\n\nint Algorithm(int n) {  // input data\n    const int a = 0;    // temporary data (constant)\n    int b = 0;          // temporary data (variable)\n    Node node = new(0); // temporary data (object)\n    int c = Function(); // stack frame space (call function)\n    return a + b + c;   // output data\n}\n
/* Structures */\ntype node struct {\n    val  int\n    next *node\n}\n\n/* Create node structure */\nfunc newNode(val int) *node {\n    return &node{val: val}\n}\n\n/* Functions */\nfunc function() int {\n    // Perform certain operations...\n    return 0\n}\n\nfunc algorithm(n int) int { // input data\n    const a = 0             // temporary data (constant)\n    b := 0                  // temporary storage of data (variable)\n    newNode(0)              // temporary data (object)\n    c := function()         // stack frame space (call function)\n    return a + b + c        // output data\n}\n
/* Classes */\nclass Node {\n    var val: Int\n    var next: Node?\n\n    init(x: Int) {\n        val = x\n    }\n}\n\n/* Functions */\nfunc function() -> Int {\n    // Perform certain operations...\n    return 0\n}\n\nfunc algorithm(n: Int) -> Int { // input data\n    let a = 0                   // temporary data (constant)\n    var b = 0                   // temporary data (variable)\n    let node = Node(x: 0)       // temporary data (object)\n    let c = function()          // stack frame space (call function)\n    return a + b + c            // output data\n}\n
/* Classes */\nclass Node {\n    val;\n    next;\n    constructor(val) {\n        this.val = val === undefined ? 0 : val; // node value\n        this.next = null;                       // reference to the next node\n    }\n}\n\n/* Functions */\nfunction constFunc() {\n    // Perform certain operations\n    return 0;\n}\n\nfunction algorithm(n) {         // input data\n    const a = 0;                // temporary data (constant)\n    let b = 0;                  // temporary data (variable)\n    const node = new Node(0);   // temporary data (object)\n    const c = constFunc();      // Stack frame space (calling function)\n    return a + b + c;           // output data\n}\n
/* Classes */\nclass Node {\n    val: number;\n    next: Node | null;\n    constructor(val?: number) {\n        this.val = val === undefined ? 0 : val; // node value\n        this.next = null;                       // reference to the next node\n    }\n}\n\n/* Functions */\nfunction constFunc(): number {\n    // Perform certain operations\n    return 0;\n}\n\nfunction algorithm(n: number): number { // input data\n    const a = 0;                        // temporary data (constant)\n    let b = 0;                          // temporary data (variable)\n    const node = new Node(0);           // temporary data (object)\n    const c = constFunc();              // Stack frame space (calling function)\n    return a + b + c;                   // output data\n}\n
/* Classes */\nclass Node {\n  int val;\n  Node next;\n  Node(this.val, [this.next]);\n}\n\n/* Functions */\nint function() {\n  // Perform certain operations...\n  return 0;\n}\n\nint algorithm(int n) {  // input data\n  const int a = 0;      // temporary data (constant)\n  int b = 0;            // temporary data (variable)\n  Node node = Node(0);  // temporary data (object)\n  int c = function();   // stack frame space (call function)\n  return a + b + c;     // output data\n}\n
use std::rc::Rc;\nuse std::cell::RefCell;\n\n/* Structures */\nstruct Node {\n    val: i32,\n    next: Option<Rc<RefCell<Node>>>,\n}\n\n/* Creating a Node structure */\nimpl Node {\n    fn new(val: i32) -> Self {\n        Self { val: val, next: None }\n    }\n}\n\n/* Functions */\nfn function() -> i32 {     \n    // Perform certain operations...\n    return 0;\n}\n\nfn algorithm(n: i32) -> i32 {   // input data\n    const a: i32 = 0;           // temporary data (constant)\n    let mut b = 0;              // temporary data (variable)\n    let node = Node::new(0);    // temporary data (object)\n    let c = function();         // stack frame space (call function)\n    return a + b + c;           // output data\n}\n
/* Functions */\nint func() {\n    // Perform certain operations...\n    return 0;\n}\n\nint algorithm(int n) {  // input data\n    const int a = 0;    // temporary data (constant)\n    int b = 0;          // temporary data (variable)\n    int c = func();     // stack frame space (call function)\n    return a + b + c;   // output data\n}\n
\n
"},{"location":"chapter_computational_complexity/space_complexity/#242-calculation-method","title":"2.4.2 \u00a0 Calculation Method","text":"

The method for calculating space complexity is roughly similar to that of time complexity, with the only change being the shift of the statistical object from \"number of operations\" to \"size of used space\".

However, unlike time complexity, we usually only focus on the worst-case space complexity. This is because memory space is a hard requirement, and we must ensure that there is enough memory space reserved under all input data.

Consider the following code, the term \"worst-case\" in worst-case space complexity has two meanings.

  1. Based on the worst input data: When \\(n < 10\\), the space complexity is \\(O(1)\\); but when \\(n > 10\\), the initialized array nums occupies \\(O(n)\\) space, thus the worst-case space complexity is \\(O(n)\\).
  2. Based on the peak memory used during the algorithm's execution: For example, before executing the last line, the program occupies \\(O(1)\\) space; when initializing the array nums, the program occupies \\(O(n)\\) space, hence the worst-case space complexity is \\(O(n)\\).
PythonC++JavaC#GoSwiftJSTSDartRustCZig
def algorithm(n: int):\n    a = 0               # O(1)\n    b = [0] * 10000     # O(1)\n    if n > 10:\n        nums = [0] * n  # O(n)\n
void algorithm(int n) {\n    int a = 0;               // O(1)\n    vector<int> b(10000);    // O(1)\n    if (n > 10)\n        vector<int> nums(n); // O(n)\n}\n
void algorithm(int n) {\n    int a = 0;                   // O(1)\n    int[] b = new int[10000];    // O(1)\n    if (n > 10)\n        int[] nums = new int[n]; // O(n)\n}\n
void Algorithm(int n) {\n    int a = 0;                   // O(1)\n    int[] b = new int[10000];    // O(1)\n    if (n > 10) {\n        int[] nums = new int[n]; // O(n)\n    }\n}\n
func algorithm(n int) {\n    a := 0                      // O(1)\n    b := make([]int, 10000)     // O(1)\n    var nums []int\n    if n > 10 {\n        nums := make([]int, n)  // O(n)\n    }\n    fmt.Println(a, b, nums)\n}\n
func algorithm(n: Int) {\n    let a = 0 // O(1)\n    let b = Array(repeating: 0, count: 10000) // O(1)\n    if n > 10 {\n        let nums = Array(repeating: 0, count: n) // O(n)\n    }\n}\n
function algorithm(n) {\n    const a = 0;                   // O(1)\n    const b = new Array(10000);    // O(1)\n    if (n > 10) {\n        const nums = new Array(n); // O(n)\n    }\n}\n
function algorithm(n: number): void {\n    const a = 0;                   // O(1)\n    const b = new Array(10000);    // O(1)\n    if (n > 10) {\n        const nums = new Array(n); // O(n)\n    }\n}\n
void algorithm(int n) {\n  int a = 0;                            // O(1)\n  List<int> b = List.filled(10000, 0);  // O(1)\n  if (n > 10) {\n    List<int> nums = List.filled(n, 0); // O(n)\n  }\n}\n
fn algorithm(n: i32) {\n    let a = 0;                              // O(1)\n    let b = [0; 10000];                     // O(1)\n    if n > 10 {\n        let nums = vec![0; n as usize];     // O(n)\n    }\n}\n
void algorithm(int n) {\n    int a = 0;               // O(1)\n    int b[10000];            // O(1)\n    if (n > 10)\n        int nums[n] = {0};   // O(n)\n}\n
\n

In recursive functions, stack frame space must be taken into count. Consider the following code:

PythonC++JavaC#GoSwiftJSTSDartRustCZig
def function() -> int:\n    # Perform certain operations\n    return 0\n\ndef loop(n: int):\n    \"\"\"Loop O(1)\"\"\"\"\"\n    for _ in range(n):\n        function()\n\ndef recur(n: int) -> int:\n    \"\"\"Recursion O(n)\"\"\"\"\"\n    if n == 1: return\n    return recur(n - 1)\n
int func() {\n    // Perform certain operations\n    return 0;\n}\n/* Cycle O(1) */\nvoid loop(int n) {\n    for (int i = 0; i < n; i++) {\n        func();\n    }\n}\n/* Recursion O(n) */\nvoid recur(int n) {\n    if (n == 1) return;\n    return recur(n - 1);\n}\n
int function() {\n    // Perform certain operations\n    return 0;\n}\n/* Cycle O(1) */\nvoid loop(int n) {\n    for (int i = 0; i < n; i++) {\n        function();\n    }\n}\n/* Recursion O(n) */\nvoid recur(int n) {\n    if (n == 1) return;\n    return recur(n - 1);\n}\n
int Function() {\n    // Perform certain operations\n    return 0;\n}\n/* Cycle O(1) */\nvoid Loop(int n) {\n    for (int i = 0; i < n; i++) {\n        Function();\n    }\n}\n/* Recursion O(n) */\nint Recur(int n) {\n    if (n == 1) return 1;\n    return Recur(n - 1);\n}\n
func function() int {\n    // Perform certain operations\n    return 0\n}\n\n/* Cycle O(1) */\nfunc loop(n int) {\n    for i := 0; i < n; i++ {\n        function()\n    }\n}\n\n/* Recursion O(n) */\nfunc recur(n int) {\n    if n == 1 {\n        return\n    }\n    recur(n - 1)\n}\n
@discardableResult\nfunc function() -> Int {\n    // Perform certain operations\n    return 0\n}\n\n/* Cycle O(1) */\nfunc loop(n: Int) {\n    for _ in 0 ..< n {\n        function()\n    }\n}\n\n/* Recursion O(n) */\nfunc recur(n: Int) {\n    if n == 1 {\n        return\n    }\n    recur(n: n - 1)\n}\n
function constFunc() {\n    // Perform certain operations\n    return 0;\n}\n/* Cycle O(1) */\nfunction loop(n) {\n    for (let i = 0; i < n; i++) {\n        constFunc();\n    }\n}\n/* Recursion O(n) */\nfunction recur(n) {\n    if (n === 1) return;\n    return recur(n - 1);\n}\n
function constFunc(): number {\n    // Perform certain operations\n    return 0;\n}\n/* Cycle O(1) */\nfunction loop(n: number): void {\n    for (let i = 0; i < n; i++) {\n        constFunc();\n    }\n}\n/* Recursion O(n) */\nfunction recur(n: number): void {\n    if (n === 1) return;\n    return recur(n - 1);\n}\n
int function() {\n  // Perform certain operations\n  return 0;\n}\n/* Cycle O(1) */\nvoid loop(int n) {\n  for (int i = 0; i < n; i++) {\n    function();\n  }\n}\n/* Recursion O(n) */\nvoid recur(int n) {\n  if (n == 1) return;\n  return recur(n - 1);\n}\n
fn function() -> i32 {\n    // Perform certain operations\n    return 0;\n}\n/* Cycle O(1) */\nfn loop(n: i32) {\n    for i in 0..n {\n        function();\n    }\n}\n/* Recursion O(n) */\nvoid recur(n: i32) {\n    if n == 1 {\n        return;\n    }\n    recur(n - 1);\n}\n
int func() {\n    // Perform certain operations\n    return 0;\n}\n/* Cycle O(1) */\nvoid loop(int n) {\n    for (int i = 0; i < n; i++) {\n        func();\n    }\n}\n/* Recursion O(n) */\nvoid recur(int n) {\n    if (n == 1) return;\n    return recur(n - 1);\n}\n
\n

The time complexity of both loop() and recur() functions is \\(O(n)\\), but their space complexities differ.

  • The loop() function calls function() \\(n\\) times in a loop, where each iteration's function() returns and releases its stack frame space, so the space complexity remains \\(O(1)\\).
  • The recursive function recur() will have \\(n\\) instances of unreturned recur() existing simultaneously during its execution, thus occupying \\(O(n)\\) stack frame space.
"},{"location":"chapter_computational_complexity/space_complexity/#243-common-types","title":"2.4.3 \u00a0 Common Types","text":"

Let the size of the input data be \\(n\\), the following chart displays common types of space complexities (arranged from low to high).

\\[ \\begin{aligned} O(1) < O(\\log n) < O(n) < O(n^2) < O(2^n) \\newline \\text{Constant Order} < \\text{Logarithmic Order} < \\text{Linear Order} < \\text{Quadratic Order} < \\text{Exponential Order} \\end{aligned} \\]

Figure 2-16 \u00a0 Common Types of Space Complexity

"},{"location":"chapter_computational_complexity/space_complexity/#1-constant-order-o1","title":"1. \u00a0 Constant Order \\(O(1)\\)","text":"

Constant order is common in constants, variables, objects that are independent of the size of input data \\(n\\).

Note that memory occupied by initializing variables or calling functions in a loop, which is released upon entering the next cycle, does not accumulate over space, thus the space complexity remains \\(O(1)\\):

PythonC++JavaC#GoSwiftJSTSDartRustCZig space_complexity.py
def function() -> int:\n    \"\"\"\u51fd\u6570\"\"\"\n    # \u6267\u884c\u67d0\u4e9b\u64cd\u4f5c\n    return 0\n\ndef constant(n: int):\n    \"\"\"\u5e38\u6570\u9636\"\"\"\n    # \u5e38\u91cf\u3001\u53d8\u91cf\u3001\u5bf9\u8c61\u5360\u7528 O(1) \u7a7a\u95f4\n    a = 0\n    nums = [0] * 10000\n    node = ListNode(0)\n    # \u5faa\u73af\u4e2d\u7684\u53d8\u91cf\u5360\u7528 O(1) \u7a7a\u95f4\n    for _ in range(n):\n        c = 0\n    # \u5faa\u73af\u4e2d\u7684\u51fd\u6570\u5360\u7528 O(1) \u7a7a\u95f4\n    for _ in range(n):\n        function()\n
space_complexity.cpp
/* \u51fd\u6570 */\nint func() {\n    // \u6267\u884c\u67d0\u4e9b\u64cd\u4f5c\n    return 0;\n}\n\n/* \u5e38\u6570\u9636 */\nvoid constant(int n) {\n    // \u5e38\u91cf\u3001\u53d8\u91cf\u3001\u5bf9\u8c61\u5360\u7528 O(1) \u7a7a\u95f4\n    const int a = 0;\n    int b = 0;\n    vector<int> nums(10000);\n    ListNode node(0);\n    // \u5faa\u73af\u4e2d\u7684\u53d8\u91cf\u5360\u7528 O(1) \u7a7a\u95f4\n    for (int i = 0; i < n; i++) {\n        int c = 0;\n    }\n    // \u5faa\u73af\u4e2d\u7684\u51fd\u6570\u5360\u7528 O(1) \u7a7a\u95f4\n    for (int i = 0; i < n; i++) {\n        func();\n    }\n}\n
space_complexity.java
/* \u51fd\u6570 */\nint function() {\n    // \u6267\u884c\u67d0\u4e9b\u64cd\u4f5c\n    return 0;\n}\n\n/* \u5e38\u6570\u9636 */\nvoid constant(int n) {\n    // \u5e38\u91cf\u3001\u53d8\u91cf\u3001\u5bf9\u8c61\u5360\u7528 O(1) \u7a7a\u95f4\n    final int a = 0;\n    int b = 0;\n    int[] nums = new int[10000];\n    ListNode node = new ListNode(0);\n    // \u5faa\u73af\u4e2d\u7684\u53d8\u91cf\u5360\u7528 O(1) \u7a7a\u95f4\n    for (int i = 0; i < n; i++) {\n        int c = 0;\n    }\n    // \u5faa\u73af\u4e2d\u7684\u51fd\u6570\u5360\u7528 O(1) \u7a7a\u95f4\n    for (int i = 0; i < n; i++) {\n        function();\n    }\n}\n
space_complexity.cs
/* \u51fd\u6570 */\nint Function() {\n    // \u6267\u884c\u67d0\u4e9b\u64cd\u4f5c\n    return 0;\n}\n\n/* \u5e38\u6570\u9636 */\nvoid Constant(int n) {\n    // \u5e38\u91cf\u3001\u53d8\u91cf\u3001\u5bf9\u8c61\u5360\u7528 O(1) \u7a7a\u95f4\n    int a = 0;\n    int b = 0;\n    int[] nums = new int[10000];\n    ListNode node = new(0);\n    // \u5faa\u73af\u4e2d\u7684\u53d8\u91cf\u5360\u7528 O(1) \u7a7a\u95f4\n    for (int i = 0; i < n; i++) {\n        int c = 0;\n    }\n    // \u5faa\u73af\u4e2d\u7684\u51fd\u6570\u5360\u7528 O(1) \u7a7a\u95f4\n    for (int i = 0; i < n; i++) {\n        Function();\n    }\n}\n
space_complexity.go
/* \u51fd\u6570 */\nfunc function() int {\n    // \u6267\u884c\u67d0\u4e9b\u64cd\u4f5c...\n    return 0\n}\n\n/* \u5e38\u6570\u9636 */\nfunc spaceConstant(n int) {\n    // \u5e38\u91cf\u3001\u53d8\u91cf\u3001\u5bf9\u8c61\u5360\u7528 O(1) \u7a7a\u95f4\n    const a = 0\n    b := 0\n    nums := make([]int, 10000)\n    node := newNode(0)\n    // \u5faa\u73af\u4e2d\u7684\u53d8\u91cf\u5360\u7528 O(1) \u7a7a\u95f4\n    var c int\n    for i := 0; i < n; i++ {\n        c = 0\n    }\n    // \u5faa\u73af\u4e2d\u7684\u51fd\u6570\u5360\u7528 O(1) \u7a7a\u95f4\n    for i := 0; i < n; i++ {\n        function()\n    }\n    b += 0\n    c += 0\n    nums[0] = 0\n    node.val = 0\n}\n
space_complexity.swift
/* \u51fd\u6570 */\n@discardableResult\nfunc function() -> Int {\n    // \u6267\u884c\u67d0\u4e9b\u64cd\u4f5c\n    return 0\n}\n\n/* \u5e38\u6570\u9636 */\nfunc constant(n: Int) {\n    // \u5e38\u91cf\u3001\u53d8\u91cf\u3001\u5bf9\u8c61\u5360\u7528 O(1) \u7a7a\u95f4\n    let a = 0\n    var b = 0\n    let nums = Array(repeating: 0, count: 10000)\n    let node = ListNode(x: 0)\n    // \u5faa\u73af\u4e2d\u7684\u53d8\u91cf\u5360\u7528 O(1) \u7a7a\u95f4\n    for _ in 0 ..< n {\n        let c = 0\n    }\n    // \u5faa\u73af\u4e2d\u7684\u51fd\u6570\u5360\u7528 O(1) \u7a7a\u95f4\n    for _ in 0 ..< n {\n        function()\n    }\n}\n
space_complexity.js
/* \u51fd\u6570 */\nfunction constFunc() {\n    // \u6267\u884c\u67d0\u4e9b\u64cd\u4f5c\n    return 0;\n}\n\n/* \u5e38\u6570\u9636 */\nfunction constant(n) {\n    // \u5e38\u91cf\u3001\u53d8\u91cf\u3001\u5bf9\u8c61\u5360\u7528 O(1) \u7a7a\u95f4\n    const a = 0;\n    const b = 0;\n    const nums = new Array(10000);\n    const node = new ListNode(0);\n    // \u5faa\u73af\u4e2d\u7684\u53d8\u91cf\u5360\u7528 O(1) \u7a7a\u95f4\n    for (let i = 0; i < n; i++) {\n        const c = 0;\n    }\n    // \u5faa\u73af\u4e2d\u7684\u51fd\u6570\u5360\u7528 O(1) \u7a7a\u95f4\n    for (let i = 0; i < n; i++) {\n        constFunc();\n    }\n}\n
space_complexity.ts
/* \u51fd\u6570 */\nfunction constFunc(): number {\n    // \u6267\u884c\u67d0\u4e9b\u64cd\u4f5c\n    return 0;\n}\n\n/* \u5e38\u6570\u9636 */\nfunction constant(n: number): void {\n    // \u5e38\u91cf\u3001\u53d8\u91cf\u3001\u5bf9\u8c61\u5360\u7528 O(1) \u7a7a\u95f4\n    const a = 0;\n    const b = 0;\n    const nums = new Array(10000);\n    const node = new ListNode(0);\n    // \u5faa\u73af\u4e2d\u7684\u53d8\u91cf\u5360\u7528 O(1) \u7a7a\u95f4\n    for (let i = 0; i < n; i++) {\n        const c = 0;\n    }\n    // \u5faa\u73af\u4e2d\u7684\u51fd\u6570\u5360\u7528 O(1) \u7a7a\u95f4\n    for (let i = 0; i < n; i++) {\n        constFunc();\n    }\n}\n
space_complexity.dart
/* \u51fd\u6570 */\nint function() {\n  // \u6267\u884c\u67d0\u4e9b\u64cd\u4f5c\n  return 0;\n}\n\n/* \u5e38\u6570\u9636 */\nvoid constant(int n) {\n  // \u5e38\u91cf\u3001\u53d8\u91cf\u3001\u5bf9\u8c61\u5360\u7528 O(1) \u7a7a\u95f4\n  final int a = 0;\n  int b = 0;\n  List<int> nums = List.filled(10000, 0);\n  ListNode node = ListNode(0);\n  // \u5faa\u73af\u4e2d\u7684\u53d8\u91cf\u5360\u7528 O(1) \u7a7a\u95f4\n  for (var i = 0; i < n; i++) {\n    int c = 0;\n  }\n  // \u5faa\u73af\u4e2d\u7684\u51fd\u6570\u5360\u7528 O(1) \u7a7a\u95f4\n  for (var i = 0; i < n; i++) {\n    function();\n  }\n}\n
space_complexity.rs
/* \u51fd\u6570 */\nfn function() -> i32 {\n    // \u6267\u884c\u67d0\u4e9b\u64cd\u4f5c\n    return 0;\n}\n\n/* \u5e38\u6570\u9636 */\n#[allow(unused)]\nfn constant(n: i32) {\n    // \u5e38\u91cf\u3001\u53d8\u91cf\u3001\u5bf9\u8c61\u5360\u7528 O(1) \u7a7a\u95f4\n    const A: i32 = 0;\n    let b = 0;\n    let nums = vec![0; 10000];\n    let node = ListNode::new(0);\n    // \u5faa\u73af\u4e2d\u7684\u53d8\u91cf\u5360\u7528 O(1) \u7a7a\u95f4\n    for i in 0..n {\n        let c = 0;\n    }\n    // \u5faa\u73af\u4e2d\u7684\u51fd\u6570\u5360\u7528 O(1) \u7a7a\u95f4\n    for i in 0..n {\n        function();\n    }\n}\n
space_complexity.c
/* \u51fd\u6570 */\nint func() {\n    // \u6267\u884c\u67d0\u4e9b\u64cd\u4f5c\n    return 0;\n}\n\n/* \u5e38\u6570\u9636 */\nvoid constant(int n) {\n    // \u5e38\u91cf\u3001\u53d8\u91cf\u3001\u5bf9\u8c61\u5360\u7528 O(1) \u7a7a\u95f4\n    const int a = 0;\n    int b = 0;\n    int nums[1000];\n    ListNode *node = newListNode(0);\n    free(node);\n    // \u5faa\u73af\u4e2d\u7684\u53d8\u91cf\u5360\u7528 O(1) \u7a7a\u95f4\n    for (int i = 0; i < n; i++) {\n        int c = 0;\n    }\n    // \u5faa\u73af\u4e2d\u7684\u51fd\u6570\u5360\u7528 O(1) \u7a7a\u95f4\n    for (int i = 0; i < n; i++) {\n        func();\n    }\n}\n
space_complexity.zig
// \u51fd\u6570\nfn function() i32 {\n    // \u6267\u884c\u67d0\u4e9b\u64cd\u4f5c\n    return 0;\n}\n\n// \u5e38\u6570\u9636\nfn constant(n: i32) void {\n    // \u5e38\u91cf\u3001\u53d8\u91cf\u3001\u5bf9\u8c61\u5360\u7528 O(1) \u7a7a\u95f4\n    const a: i32 = 0;\n    var b: i32 = 0;\n    var nums = [_]i32{0}**10000;\n    var node = inc.ListNode(i32){.val = 0};\n    var i: i32 = 0;\n    // \u5faa\u73af\u4e2d\u7684\u53d8\u91cf\u5360\u7528 O(1) \u7a7a\u95f4\n    while (i < n) : (i += 1) {\n        var c: i32 = 0;\n        _ = c;\n    }\n    // \u5faa\u73af\u4e2d\u7684\u51fd\u6570\u5360\u7528 O(1) \u7a7a\u95f4\n    i = 0;\n    while (i < n) : (i += 1) {\n        _ = function();\n    }\n    _ = a;\n    _ = b;\n    _ = nums;\n    _ = node;\n}\n
Code Visualization

Full Screen >

"},{"location":"chapter_computational_complexity/space_complexity/#2-linear-order-on","title":"2. \u00a0 Linear Order \\(O(n)\\)","text":"

Linear order is common in arrays, linked lists, stacks, queues, etc., where the number of elements is proportional to \\(n\\):

PythonC++JavaC#GoSwiftJSTSDartRustCZig space_complexity.py
def linear(n: int):\n    \"\"\"\u7ebf\u6027\u9636\"\"\"\n    # \u957f\u5ea6\u4e3a n \u7684\u5217\u8868\u5360\u7528 O(n) \u7a7a\u95f4\n    nums = [0] * n\n    # \u957f\u5ea6\u4e3a n \u7684\u54c8\u5e0c\u8868\u5360\u7528 O(n) \u7a7a\u95f4\n    hmap = dict[int, str]()\n    for i in range(n):\n        hmap[i] = str(i)\n
space_complexity.cpp
/* \u7ebf\u6027\u9636 */\nvoid linear(int n) {\n    // \u957f\u5ea6\u4e3a n \u7684\u6570\u7ec4\u5360\u7528 O(n) \u7a7a\u95f4\n    vector<int> nums(n);\n    // \u957f\u5ea6\u4e3a n \u7684\u5217\u8868\u5360\u7528 O(n) \u7a7a\u95f4\n    vector<ListNode> nodes;\n    for (int i = 0; i < n; i++) {\n        nodes.push_back(ListNode(i));\n    }\n    // \u957f\u5ea6\u4e3a n \u7684\u54c8\u5e0c\u8868\u5360\u7528 O(n) \u7a7a\u95f4\n    unordered_map<int, string> map;\n    for (int i = 0; i < n; i++) {\n        map[i] = to_string(i);\n    }\n}\n
space_complexity.java
/* \u7ebf\u6027\u9636 */\nvoid linear(int n) {\n    // \u957f\u5ea6\u4e3a n \u7684\u6570\u7ec4\u5360\u7528 O(n) \u7a7a\u95f4\n    int[] nums = new int[n];\n    // \u957f\u5ea6\u4e3a n \u7684\u5217\u8868\u5360\u7528 O(n) \u7a7a\u95f4\n    List<ListNode> nodes = new ArrayList<>();\n    for (int i = 0; i < n; i++) {\n        nodes.add(new ListNode(i));\n    }\n    // \u957f\u5ea6\u4e3a n \u7684\u54c8\u5e0c\u8868\u5360\u7528 O(n) \u7a7a\u95f4\n    Map<Integer, String> map = new HashMap<>();\n    for (int i = 0; i < n; i++) {\n        map.put(i, String.valueOf(i));\n    }\n}\n
space_complexity.cs
/* \u7ebf\u6027\u9636 */\nvoid Linear(int n) {\n    // \u957f\u5ea6\u4e3a n \u7684\u6570\u7ec4\u5360\u7528 O(n) \u7a7a\u95f4\n    int[] nums = new int[n];\n    // \u957f\u5ea6\u4e3a n \u7684\u5217\u8868\u5360\u7528 O(n) \u7a7a\u95f4\n    List<ListNode> nodes = [];\n    for (int i = 0; i < n; i++) {\n        nodes.Add(new ListNode(i));\n    }\n    // \u957f\u5ea6\u4e3a n \u7684\u54c8\u5e0c\u8868\u5360\u7528 O(n) \u7a7a\u95f4\n    Dictionary<int, string> map = [];\n    for (int i = 0; i < n; i++) {\n        map.Add(i, i.ToString());\n    }\n}\n
space_complexity.go
/* \u7ebf\u6027\u9636 */\nfunc spaceLinear(n int) {\n    // \u957f\u5ea6\u4e3a n \u7684\u6570\u7ec4\u5360\u7528 O(n) \u7a7a\u95f4\n    _ = make([]int, n)\n    // \u957f\u5ea6\u4e3a n \u7684\u5217\u8868\u5360\u7528 O(n) \u7a7a\u95f4\n    var nodes []*node\n    for i := 0; i < n; i++ {\n        nodes = append(nodes, newNode(i))\n    }\n    // \u957f\u5ea6\u4e3a n \u7684\u54c8\u5e0c\u8868\u5360\u7528 O(n) \u7a7a\u95f4\n    m := make(map[int]string, n)\n    for i := 0; i < n; i++ {\n        m[i] = strconv.Itoa(i)\n    }\n}\n
space_complexity.swift
/* \u7ebf\u6027\u9636 */\nfunc linear(n: Int) {\n    // \u957f\u5ea6\u4e3a n \u7684\u6570\u7ec4\u5360\u7528 O(n) \u7a7a\u95f4\n    let nums = Array(repeating: 0, count: n)\n    // \u957f\u5ea6\u4e3a n \u7684\u5217\u8868\u5360\u7528 O(n) \u7a7a\u95f4\n    let nodes = (0 ..< n).map { ListNode(x: $0) }\n    // \u957f\u5ea6\u4e3a n \u7684\u54c8\u5e0c\u8868\u5360\u7528 O(n) \u7a7a\u95f4\n    let map = Dictionary(uniqueKeysWithValues: (0 ..< n).map { ($0, \"\\($0)\") })\n}\n
space_complexity.js
/* \u7ebf\u6027\u9636 */\nfunction linear(n) {\n    // \u957f\u5ea6\u4e3a n \u7684\u6570\u7ec4\u5360\u7528 O(n) \u7a7a\u95f4\n    const nums = new Array(n);\n    // \u957f\u5ea6\u4e3a n \u7684\u5217\u8868\u5360\u7528 O(n) \u7a7a\u95f4\n    const nodes = [];\n    for (let i = 0; i < n; i++) {\n        nodes.push(new ListNode(i));\n    }\n    // \u957f\u5ea6\u4e3a n \u7684\u54c8\u5e0c\u8868\u5360\u7528 O(n) \u7a7a\u95f4\n    const map = new Map();\n    for (let i = 0; i < n; i++) {\n        map.set(i, i.toString());\n    }\n}\n
space_complexity.ts
/* \u7ebf\u6027\u9636 */\nfunction linear(n: number): void {\n    // \u957f\u5ea6\u4e3a n \u7684\u6570\u7ec4\u5360\u7528 O(n) \u7a7a\u95f4\n    const nums = new Array(n);\n    // \u957f\u5ea6\u4e3a n \u7684\u5217\u8868\u5360\u7528 O(n) \u7a7a\u95f4\n    const nodes: ListNode[] = [];\n    for (let i = 0; i < n; i++) {\n        nodes.push(new ListNode(i));\n    }\n    // \u957f\u5ea6\u4e3a n \u7684\u54c8\u5e0c\u8868\u5360\u7528 O(n) \u7a7a\u95f4\n    const map = new Map();\n    for (let i = 0; i < n; i++) {\n        map.set(i, i.toString());\n    }\n}\n
space_complexity.dart
/* \u7ebf\u6027\u9636 */\nvoid linear(int n) {\n  // \u957f\u5ea6\u4e3a n \u7684\u6570\u7ec4\u5360\u7528 O(n) \u7a7a\u95f4\n  List<int> nums = List.filled(n, 0);\n  // \u957f\u5ea6\u4e3a n \u7684\u5217\u8868\u5360\u7528 O(n) \u7a7a\u95f4\n  List<ListNode> nodes = [];\n  for (var i = 0; i < n; i++) {\n    nodes.add(ListNode(i));\n  }\n  // \u957f\u5ea6\u4e3a n \u7684\u54c8\u5e0c\u8868\u5360\u7528 O(n) \u7a7a\u95f4\n  Map<int, String> map = HashMap();\n  for (var i = 0; i < n; i++) {\n    map.putIfAbsent(i, () => i.toString());\n  }\n}\n
space_complexity.rs
/* \u7ebf\u6027\u9636 */\n#[allow(unused)]\nfn linear(n: i32) {\n    // \u957f\u5ea6\u4e3a n \u7684\u6570\u7ec4\u5360\u7528 O(n) \u7a7a\u95f4\n    let mut nums = vec![0; n as usize];\n    // \u957f\u5ea6\u4e3a n \u7684\u5217\u8868\u5360\u7528 O(n) \u7a7a\u95f4\n    let mut nodes = Vec::new();\n    for i in 0..n {\n        nodes.push(ListNode::new(i))\n    }\n    // \u957f\u5ea6\u4e3a n \u7684\u54c8\u5e0c\u8868\u5360\u7528 O(n) \u7a7a\u95f4\n    let mut map = HashMap::new();\n    for i in 0..n {\n        map.insert(i, i.to_string());\n    }\n}\n
space_complexity.c
/* \u54c8\u5e0c\u8868 */\ntypedef struct {\n    int key;\n    int val;\n    UT_hash_handle hh; // \u57fa\u4e8e uthash.h \u5b9e\u73b0\n} HashTable;\n\n/* \u7ebf\u6027\u9636 */\nvoid linear(int n) {\n    // \u957f\u5ea6\u4e3a n \u7684\u6570\u7ec4\u5360\u7528 O(n) \u7a7a\u95f4\n    int *nums = malloc(sizeof(int) * n);\n    free(nums);\n\n    // \u957f\u5ea6\u4e3a n \u7684\u5217\u8868\u5360\u7528 O(n) \u7a7a\u95f4\n    ListNode **nodes = malloc(sizeof(ListNode *) * n);\n    for (int i = 0; i < n; i++) {\n        nodes[i] = newListNode(i);\n    }\n    // \u5185\u5b58\u91ca\u653e\n    for (int i = 0; i < n; i++) {\n        free(nodes[i]);\n    }\n    free(nodes);\n\n    // \u957f\u5ea6\u4e3a n \u7684\u54c8\u5e0c\u8868\u5360\u7528 O(n) \u7a7a\u95f4\n    HashTable *h = NULL;\n    for (int i = 0; i < n; i++) {\n        HashTable *tmp = malloc(sizeof(HashTable));\n        tmp->key = i;\n        tmp->val = i;\n        HASH_ADD_INT(h, key, tmp);\n    }\n\n    // \u5185\u5b58\u91ca\u653e\n    HashTable *curr, *tmp;\n    HASH_ITER(hh, h, curr, tmp) {\n        HASH_DEL(h, curr);\n        free(curr);\n    }\n}\n
space_complexity.zig
// \u7ebf\u6027\u9636\nfn linear(comptime n: i32) !void {\n    // \u957f\u5ea6\u4e3a n \u7684\u6570\u7ec4\u5360\u7528 O(n) \u7a7a\u95f4\n    var nums = [_]i32{0}**n;\n    // \u957f\u5ea6\u4e3a n \u7684\u5217\u8868\u5360\u7528 O(n) \u7a7a\u95f4\n    var nodes = std.ArrayList(i32).init(std.heap.page_allocator);\n    defer nodes.deinit();\n    var i: i32 = 0;\n    while (i < n) : (i += 1) {\n        try nodes.append(i);\n    }\n    // \u957f\u5ea6\u4e3a n \u7684\u54c8\u5e0c\u8868\u5360\u7528 O(n) \u7a7a\u95f4\n    var map = std.AutoArrayHashMap(i32, []const u8).init(std.heap.page_allocator);\n    defer map.deinit();\n    var j: i32 = 0;\n    while (j < n) : (j += 1) {\n        const string = try std.fmt.allocPrint(std.heap.page_allocator, \"{d}\", .{j});\n        defer std.heap.page_allocator.free(string);\n        try map.put(i, string);\n    }\n    _ = nums;\n}\n
Code Visualization

Full Screen >

As shown below, this function's recursive depth is \\(n\\), meaning there are \\(n\\) instances of unreturned linear_recur() function, using \\(O(n)\\) size of stack frame space:

PythonC++JavaC#GoSwiftJSTSDartRustCZig space_complexity.py
def linear_recur(n: int):\n    \"\"\"\u7ebf\u6027\u9636\uff08\u9012\u5f52\u5b9e\u73b0\uff09\"\"\"\n    print(\"\u9012\u5f52 n =\", n)\n    if n == 1:\n        return\n    linear_recur(n - 1)\n
space_complexity.cpp
/* \u7ebf\u6027\u9636\uff08\u9012\u5f52\u5b9e\u73b0\uff09 */\nvoid linearRecur(int n) {\n    cout << \"\u9012\u5f52 n = \" << n << endl;\n    if (n == 1)\n        return;\n    linearRecur(n - 1);\n}\n
space_complexity.java
/* \u7ebf\u6027\u9636\uff08\u9012\u5f52\u5b9e\u73b0\uff09 */\nvoid linearRecur(int n) {\n    System.out.println(\"\u9012\u5f52 n = \" + n);\n    if (n == 1)\n        return;\n    linearRecur(n - 1);\n}\n
space_complexity.cs
/* \u7ebf\u6027\u9636\uff08\u9012\u5f52\u5b9e\u73b0\uff09 */\nvoid LinearRecur(int n) {\n    Console.WriteLine(\"\u9012\u5f52 n = \" + n);\n    if (n == 1) return;\n    LinearRecur(n - 1);\n}\n
space_complexity.go
/* \u7ebf\u6027\u9636\uff08\u9012\u5f52\u5b9e\u73b0\uff09 */\nfunc spaceLinearRecur(n int) {\n    fmt.Println(\"\u9012\u5f52 n =\", n)\n    if n == 1 {\n        return\n    }\n    spaceLinearRecur(n - 1)\n}\n
space_complexity.swift
/* \u7ebf\u6027\u9636\uff08\u9012\u5f52\u5b9e\u73b0\uff09 */\nfunc linearRecur(n: Int) {\n    print(\"\u9012\u5f52 n = \\(n)\")\n    if n == 1 {\n        return\n    }\n    linearRecur(n: n - 1)\n}\n
space_complexity.js
/* \u7ebf\u6027\u9636\uff08\u9012\u5f52\u5b9e\u73b0\uff09 */\nfunction linearRecur(n) {\n    console.log(`\u9012\u5f52 n = ${n}`);\n    if (n === 1) return;\n    linearRecur(n - 1);\n}\n
space_complexity.ts
/* \u7ebf\u6027\u9636\uff08\u9012\u5f52\u5b9e\u73b0\uff09 */\nfunction linearRecur(n: number): void {\n    console.log(`\u9012\u5f52 n = ${n}`);\n    if (n === 1) return;\n    linearRecur(n - 1);\n}\n
space_complexity.dart
/* \u7ebf\u6027\u9636\uff08\u9012\u5f52\u5b9e\u73b0\uff09 */\nvoid linearRecur(int n) {\n  print('\u9012\u5f52 n = $n');\n  if (n == 1) return;\n  linearRecur(n - 1);\n}\n
space_complexity.rs
/* \u7ebf\u6027\u9636\uff08\u9012\u5f52\u5b9e\u73b0\uff09 */\nfn linear_recur(n: i32) {\n    println!(\"\u9012\u5f52 n = {}\", n);\n    if n == 1 {\n        return;\n    };\n    linear_recur(n - 1);\n}\n
space_complexity.c
/* \u7ebf\u6027\u9636\uff08\u9012\u5f52\u5b9e\u73b0\uff09 */\nvoid linearRecur(int n) {\n    printf(\"\u9012\u5f52 n = %d\\r\\n\", n);\n    if (n == 1)\n        return;\n    linearRecur(n - 1);\n}\n
space_complexity.zig
// \u7ebf\u6027\u9636\uff08\u9012\u5f52\u5b9e\u73b0\uff09\nfn linearRecur(comptime n: i32) void {\n    std.debug.print(\"\u9012\u5f52 n = {}\\n\", .{n});\n    if (n == 1) return;\n    linearRecur(n - 1);\n}\n
Code Visualization

Full Screen >

Figure 2-17 \u00a0 Recursive Function Generating Linear Order Space Complexity

"},{"location":"chapter_computational_complexity/space_complexity/#3-quadratic-order-on2","title":"3. \u00a0 Quadratic Order \\(O(n^2)\\)","text":"

Quadratic order is common in matrices and graphs, where the number of elements is quadratic to \\(n\\):

PythonC++JavaC#GoSwiftJSTSDartRustCZig space_complexity.py
def quadratic(n: int):\n    \"\"\"\u5e73\u65b9\u9636\"\"\"\n    # \u4e8c\u7ef4\u5217\u8868\u5360\u7528 O(n^2) \u7a7a\u95f4\n    num_matrix = [[0] * n for _ in range(n)]\n
space_complexity.cpp
/* \u5e73\u65b9\u9636 */\nvoid quadratic(int n) {\n    // \u4e8c\u7ef4\u5217\u8868\u5360\u7528 O(n^2) \u7a7a\u95f4\n    vector<vector<int>> numMatrix;\n    for (int i = 0; i < n; i++) {\n        vector<int> tmp;\n        for (int j = 0; j < n; j++) {\n            tmp.push_back(0);\n        }\n        numMatrix.push_back(tmp);\n    }\n}\n
space_complexity.java
/* \u5e73\u65b9\u9636 */\nvoid quadratic(int n) {\n    // \u77e9\u9635\u5360\u7528 O(n^2) \u7a7a\u95f4\n    int[][] numMatrix = new int[n][n];\n    // \u4e8c\u7ef4\u5217\u8868\u5360\u7528 O(n^2) \u7a7a\u95f4\n    List<List<Integer>> numList = new ArrayList<>();\n    for (int i = 0; i < n; i++) {\n        List<Integer> tmp = new ArrayList<>();\n        for (int j = 0; j < n; j++) {\n            tmp.add(0);\n        }\n        numList.add(tmp);\n    }\n}\n
space_complexity.cs
/* \u5e73\u65b9\u9636 */\nvoid Quadratic(int n) {\n    // \u77e9\u9635\u5360\u7528 O(n^2) \u7a7a\u95f4\n    int[,] numMatrix = new int[n, n];\n    // \u4e8c\u7ef4\u5217\u8868\u5360\u7528 O(n^2) \u7a7a\u95f4\n    List<List<int>> numList = [];\n    for (int i = 0; i < n; i++) {\n        List<int> tmp = [];\n        for (int j = 0; j < n; j++) {\n            tmp.Add(0);\n        }\n        numList.Add(tmp);\n    }\n}\n
space_complexity.go
/* \u5e73\u65b9\u9636 */\nfunc spaceQuadratic(n int) {\n    // \u77e9\u9635\u5360\u7528 O(n^2) \u7a7a\u95f4\n    numMatrix := make([][]int, n)\n    for i := 0; i < n; i++ {\n        numMatrix[i] = make([]int, n)\n    }\n}\n
space_complexity.swift
/* \u5e73\u65b9\u9636 */\nfunc quadratic(n: Int) {\n    // \u4e8c\u7ef4\u5217\u8868\u5360\u7528 O(n^2) \u7a7a\u95f4\n    let numList = Array(repeating: Array(repeating: 0, count: n), count: n)\n}\n
space_complexity.js
/* \u5e73\u65b9\u9636 */\nfunction quadratic(n) {\n    // \u77e9\u9635\u5360\u7528 O(n^2) \u7a7a\u95f4\n    const numMatrix = Array(n)\n        .fill(null)\n        .map(() => Array(n).fill(null));\n    // \u4e8c\u7ef4\u5217\u8868\u5360\u7528 O(n^2) \u7a7a\u95f4\n    const numList = [];\n    for (let i = 0; i < n; i++) {\n        const tmp = [];\n        for (let j = 0; j < n; j++) {\n            tmp.push(0);\n        }\n        numList.push(tmp);\n    }\n}\n
space_complexity.ts
/* \u5e73\u65b9\u9636 */\nfunction quadratic(n: number): void {\n    // \u77e9\u9635\u5360\u7528 O(n^2) \u7a7a\u95f4\n    const numMatrix = Array(n)\n        .fill(null)\n        .map(() => Array(n).fill(null));\n    // \u4e8c\u7ef4\u5217\u8868\u5360\u7528 O(n^2) \u7a7a\u95f4\n    const numList = [];\n    for (let i = 0; i < n; i++) {\n        const tmp = [];\n        for (let j = 0; j < n; j++) {\n            tmp.push(0);\n        }\n        numList.push(tmp);\n    }\n}\n
space_complexity.dart
/* \u5e73\u65b9\u9636 */\nvoid quadratic(int n) {\n  // \u77e9\u9635\u5360\u7528 O(n^2) \u7a7a\u95f4\n  List<List<int>> numMatrix = List.generate(n, (_) => List.filled(n, 0));\n  // \u4e8c\u7ef4\u5217\u8868\u5360\u7528 O(n^2) \u7a7a\u95f4\n  List<List<int>> numList = [];\n  for (var i = 0; i < n; i++) {\n    List<int> tmp = [];\n    for (int j = 0; j < n; j++) {\n      tmp.add(0);\n    }\n    numList.add(tmp);\n  }\n}\n
space_complexity.rs
/* \u5e73\u65b9\u9636 */\n#[allow(unused)]\nfn quadratic(n: i32) {\n    // \u77e9\u9635\u5360\u7528 O(n^2) \u7a7a\u95f4\n    let num_matrix = vec![vec![0; n as usize]; n as usize];\n    // \u4e8c\u7ef4\u5217\u8868\u5360\u7528 O(n^2) \u7a7a\u95f4\n    let mut num_list = Vec::new();\n    for i in 0..n {\n        let mut tmp = Vec::new();\n        for j in 0..n {\n            tmp.push(0);\n        }\n        num_list.push(tmp);\n    }\n}\n
space_complexity.c
/* \u5e73\u65b9\u9636 */\nvoid quadratic(int n) {\n    // \u4e8c\u7ef4\u5217\u8868\u5360\u7528 O(n^2) \u7a7a\u95f4\n    int **numMatrix = malloc(sizeof(int *) * n);\n    for (int i = 0; i < n; i++) {\n        int *tmp = malloc(sizeof(int) * n);\n        for (int j = 0; j < n; j++) {\n            tmp[j] = 0;\n        }\n        numMatrix[i] = tmp;\n    }\n\n    // \u5185\u5b58\u91ca\u653e\n    for (int i = 0; i < n; i++) {\n        free(numMatrix[i]);\n    }\n    free(numMatrix);\n}\n
space_complexity.zig
// \u5e73\u65b9\u9636\nfn quadratic(n: i32) !void {\n    // \u4e8c\u7ef4\u5217\u8868\u5360\u7528 O(n^2) \u7a7a\u95f4\n    var nodes = std.ArrayList(std.ArrayList(i32)).init(std.heap.page_allocator);\n    defer nodes.deinit();\n    var i: i32 = 0;\n    while (i < n) : (i += 1) {\n        var tmp = std.ArrayList(i32).init(std.heap.page_allocator);\n        defer tmp.deinit();\n        var j: i32 = 0;\n        while (j < n) : (j += 1) {\n            try tmp.append(0);\n        }\n        try nodes.append(tmp);\n    }\n}\n
Code Visualization

Full Screen >

As shown below, the recursive depth of this function is \\(n\\), and in each recursive call, an array is initialized with lengths \\(n\\), \\(n-1\\), \\(\\dots\\), \\(2\\), \\(1\\), averaging \\(n/2\\), thus overall occupying \\(O(n^2)\\) space:

PythonC++JavaC#GoSwiftJSTSDartRustCZig space_complexity.py
def quadratic_recur(n: int) -> int:\n    \"\"\"\u5e73\u65b9\u9636\uff08\u9012\u5f52\u5b9e\u73b0\uff09\"\"\"\n    if n <= 0:\n        return 0\n    # \u6570\u7ec4 nums \u957f\u5ea6\u4e3a n, n-1, ..., 2, 1\n    nums = [0] * n\n    return quadratic_recur(n - 1)\n
space_complexity.cpp
/* \u5e73\u65b9\u9636\uff08\u9012\u5f52\u5b9e\u73b0\uff09 */\nint quadraticRecur(int n) {\n    if (n <= 0)\n        return 0;\n    vector<int> nums(n);\n    cout << \"\u9012\u5f52 n = \" << n << \" \u4e2d\u7684 nums \u957f\u5ea6 = \" << nums.size() << endl;\n    return quadraticRecur(n - 1);\n}\n
space_complexity.java
/* \u5e73\u65b9\u9636\uff08\u9012\u5f52\u5b9e\u73b0\uff09 */\nint quadraticRecur(int n) {\n    if (n <= 0)\n        return 0;\n    // \u6570\u7ec4 nums \u957f\u5ea6\u4e3a n, n-1, ..., 2, 1\n    int[] nums = new int[n];\n    System.out.println(\"\u9012\u5f52 n = \" + n + \" \u4e2d\u7684 nums \u957f\u5ea6 = \" + nums.length);\n    return quadraticRecur(n - 1);\n}\n
space_complexity.cs
/* \u5e73\u65b9\u9636\uff08\u9012\u5f52\u5b9e\u73b0\uff09 */\nint QuadraticRecur(int n) {\n    if (n <= 0) return 0;\n    int[] nums = new int[n];\n    Console.WriteLine(\"\u9012\u5f52 n = \" + n + \" \u4e2d\u7684 nums \u957f\u5ea6 = \" + nums.Length);\n    return QuadraticRecur(n - 1);\n}\n
space_complexity.go
/* \u5e73\u65b9\u9636\uff08\u9012\u5f52\u5b9e\u73b0\uff09 */\nfunc spaceQuadraticRecur(n int) int {\n    if n <= 0 {\n        return 0\n    }\n    nums := make([]int, n)\n    fmt.Printf(\"\u9012\u5f52 n = %d \u4e2d\u7684 nums \u957f\u5ea6 = %d \\n\", n, len(nums))\n    return spaceQuadraticRecur(n - 1)\n}\n
space_complexity.swift
/* \u5e73\u65b9\u9636\uff08\u9012\u5f52\u5b9e\u73b0\uff09 */\n@discardableResult\nfunc quadraticRecur(n: Int) -> Int {\n    if n <= 0 {\n        return 0\n    }\n    // \u6570\u7ec4 nums \u957f\u5ea6\u4e3a n, n-1, ..., 2, 1\n    let nums = Array(repeating: 0, count: n)\n    print(\"\u9012\u5f52 n = \\(n) \u4e2d\u7684 nums \u957f\u5ea6 = \\(nums.count)\")\n    return quadraticRecur(n: n - 1)\n}\n
space_complexity.js
/* \u5e73\u65b9\u9636\uff08\u9012\u5f52\u5b9e\u73b0\uff09 */\nfunction quadraticRecur(n) {\n    if (n <= 0) return 0;\n    const nums = new Array(n);\n    console.log(`\u9012\u5f52 n = ${n} \u4e2d\u7684 nums \u957f\u5ea6 = ${nums.length}`);\n    return quadraticRecur(n - 1);\n}\n
space_complexity.ts
/* \u5e73\u65b9\u9636\uff08\u9012\u5f52\u5b9e\u73b0\uff09 */\nfunction quadraticRecur(n: number): number {\n    if (n <= 0) return 0;\n    const nums = new Array(n);\n    console.log(`\u9012\u5f52 n = ${n} \u4e2d\u7684 nums \u957f\u5ea6 = ${nums.length}`);\n    return quadraticRecur(n - 1);\n}\n
space_complexity.dart
/* \u5e73\u65b9\u9636\uff08\u9012\u5f52\u5b9e\u73b0\uff09 */\nint quadraticRecur(int n) {\n  if (n <= 0) return 0;\n  List<int> nums = List.filled(n, 0);\n  print('\u9012\u5f52 n = $n \u4e2d\u7684 nums \u957f\u5ea6 = ${nums.length}');\n  return quadraticRecur(n - 1);\n}\n
space_complexity.rs
/* \u5e73\u65b9\u9636\uff08\u9012\u5f52\u5b9e\u73b0\uff09 */\nfn quadratic_recur(n: i32) -> i32 {\n    if n <= 0 {\n        return 0;\n    };\n    // \u6570\u7ec4 nums \u957f\u5ea6\u4e3a n, n-1, ..., 2, 1\n    let nums = vec![0; n as usize];\n    println!(\"\u9012\u5f52 n = {} \u4e2d\u7684 nums \u957f\u5ea6 = {}\", n, nums.len());\n    return quadratic_recur(n - 1);\n}\n
space_complexity.c
/* \u5e73\u65b9\u9636\uff08\u9012\u5f52\u5b9e\u73b0\uff09 */\nint quadraticRecur(int n) {\n    if (n <= 0)\n        return 0;\n    int *nums = malloc(sizeof(int) * n);\n    printf(\"\u9012\u5f52 n = %d \u4e2d\u7684 nums \u957f\u5ea6 = %d\\r\\n\", n, n);\n    int res = quadraticRecur(n - 1);\n    free(nums);\n    return res;\n}\n
space_complexity.zig
// \u5e73\u65b9\u9636\uff08\u9012\u5f52\u5b9e\u73b0\uff09\nfn quadraticRecur(comptime n: i32) i32 {\n    if (n <= 0) return 0;\n    var nums = [_]i32{0}**n;\n    std.debug.print(\"\u9012\u5f52 n = {} \u4e2d\u7684 nums \u957f\u5ea6 = {}\\n\", .{n, nums.len});\n    return quadraticRecur(n - 1);\n}\n
Code Visualization

Full Screen >

Figure 2-18 \u00a0 Recursive Function Generating Quadratic Order Space Complexity

"},{"location":"chapter_computational_complexity/space_complexity/#4-exponential-order-o2n","title":"4. \u00a0 Exponential Order \\(O(2^n)\\)","text":"

Exponential order is common in binary trees. Observe the below image, a \"full binary tree\" with \\(n\\) levels has \\(2^n - 1\\) nodes, occupying \\(O(2^n)\\) space:

PythonC++JavaC#GoSwiftJSTSDartRustCZig space_complexity.py
def build_tree(n: int) -> TreeNode | None:\n    \"\"\"\u6307\u6570\u9636\uff08\u5efa\u7acb\u6ee1\u4e8c\u53c9\u6811\uff09\"\"\"\n    if n == 0:\n        return None\n    root = TreeNode(0)\n    root.left = build_tree(n - 1)\n    root.right = build_tree(n - 1)\n    return root\n
space_complexity.cpp
/* \u6307\u6570\u9636\uff08\u5efa\u7acb\u6ee1\u4e8c\u53c9\u6811\uff09 */\nTreeNode *buildTree(int n) {\n    if (n == 0)\n        return nullptr;\n    TreeNode *root = new TreeNode(0);\n    root->left = buildTree(n - 1);\n    root->right = buildTree(n - 1);\n    return root;\n}\n
space_complexity.java
/* \u6307\u6570\u9636\uff08\u5efa\u7acb\u6ee1\u4e8c\u53c9\u6811\uff09 */\nTreeNode buildTree(int n) {\n    if (n == 0)\n        return null;\n    TreeNode root = new TreeNode(0);\n    root.left = buildTree(n - 1);\n    root.right = buildTree(n - 1);\n    return root;\n}\n
space_complexity.cs
/* \u6307\u6570\u9636\uff08\u5efa\u7acb\u6ee1\u4e8c\u53c9\u6811\uff09 */\nTreeNode? BuildTree(int n) {\n    if (n == 0) return null;\n    TreeNode root = new(0) {\n        left = BuildTree(n - 1),\n        right = BuildTree(n - 1)\n    };\n    return root;\n}\n
space_complexity.go
/* \u6307\u6570\u9636\uff08\u5efa\u7acb\u6ee1\u4e8c\u53c9\u6811\uff09 */\nfunc buildTree(n int) *TreeNode {\n    if n == 0 {\n        return nil\n    }\n    root := NewTreeNode(0)\n    root.Left = buildTree(n - 1)\n    root.Right = buildTree(n - 1)\n    return root\n}\n
space_complexity.swift
/* \u6307\u6570\u9636\uff08\u5efa\u7acb\u6ee1\u4e8c\u53c9\u6811\uff09 */\nfunc buildTree(n: Int) -> TreeNode? {\n    if n == 0 {\n        return nil\n    }\n    let root = TreeNode(x: 0)\n    root.left = buildTree(n: n - 1)\n    root.right = buildTree(n: n - 1)\n    return root\n}\n
space_complexity.js
/* \u6307\u6570\u9636\uff08\u5efa\u7acb\u6ee1\u4e8c\u53c9\u6811\uff09 */\nfunction buildTree(n) {\n    if (n === 0) return null;\n    const root = new TreeNode(0);\n    root.left = buildTree(n - 1);\n    root.right = buildTree(n - 1);\n    return root;\n}\n
space_complexity.ts
/* \u6307\u6570\u9636\uff08\u5efa\u7acb\u6ee1\u4e8c\u53c9\u6811\uff09 */\nfunction buildTree(n: number): TreeNode | null {\n    if (n === 0) return null;\n    const root = new TreeNode(0);\n    root.left = buildTree(n - 1);\n    root.right = buildTree(n - 1);\n    return root;\n}\n
space_complexity.dart
/* \u6307\u6570\u9636\uff08\u5efa\u7acb\u6ee1\u4e8c\u53c9\u6811\uff09 */\nTreeNode? buildTree(int n) {\n  if (n == 0) return null;\n  TreeNode root = TreeNode(0);\n  root.left = buildTree(n - 1);\n  root.right = buildTree(n - 1);\n  return root;\n}\n
space_complexity.rs
/* \u6307\u6570\u9636\uff08\u5efa\u7acb\u6ee1\u4e8c\u53c9\u6811\uff09 */\nfn build_tree(n: i32) -> Option<Rc<RefCell<TreeNode>>> {\n    if n == 0 {\n        return None;\n    };\n    let root = TreeNode::new(0);\n    root.borrow_mut().left = build_tree(n - 1);\n    root.borrow_mut().right = build_tree(n - 1);\n    return Some(root);\n}\n
space_complexity.c
/* \u6307\u6570\u9636\uff08\u5efa\u7acb\u6ee1\u4e8c\u53c9\u6811\uff09 */\nTreeNode *buildTree(int n) {\n    if (n == 0)\n        return NULL;\n    TreeNode *root = newTreeNode(0);\n    root->left = buildTree(n - 1);\n    root->right = buildTree(n - 1);\n    return root;\n}\n
space_complexity.zig
// \u6307\u6570\u9636\uff08\u5efa\u7acb\u6ee1\u4e8c\u53c9\u6811\uff09\nfn buildTree(mem_allocator: std.mem.Allocator, n: i32) !?*inc.TreeNode(i32) {\n    if (n == 0) return null;\n    const root = try mem_allocator.create(inc.TreeNode(i32));\n    root.init(0);\n    root.left = try buildTree(mem_allocator, n - 1);\n    root.right = try buildTree(mem_allocator, n - 1);\n    return root;\n}\n
Code Visualization

Full Screen >

Figure 2-19 \u00a0 Full Binary Tree Generating Exponential Order Space Complexity

"},{"location":"chapter_computational_complexity/space_complexity/#5-logarithmic-order-olog-n","title":"5. \u00a0 Logarithmic Order \\(O(\\log n)\\)","text":"

Logarithmic order is common in divide-and-conquer algorithms. For example, in merge sort, an array of length \\(n\\) is recursively divided in half each round, forming a recursion tree of height \\(\\log n\\), using \\(O(\\log n)\\) stack frame space.

Another example is converting a number to a string. Given a positive integer \\(n\\), its number of digits is \\(\\log_{10} n + 1\\), corresponding to the length of the string, thus the space complexity is \\(O(\\log_{10} n + 1) = O(\\log n)\\).

"},{"location":"chapter_computational_complexity/space_complexity/#244-balancing-time-and-space","title":"2.4.4 \u00a0 Balancing Time and Space","text":"

Ideally, we aim for both time complexity and space complexity to be optimal. However, in practice, optimizing both simultaneously is often difficult.

Lowering time complexity usually comes at the cost of increased space complexity, and vice versa. The approach of sacrificing memory space to improve algorithm speed is known as \"space-time tradeoff\"; the reverse is known as \"time-space tradeoff\".

The choice depends on which aspect we value more. In most cases, time is more precious than space, so \"space-time tradeoff\" is often the more common strategy. Of course, controlling space complexity is also very important when dealing with large volumes of data.

"},{"location":"chapter_computational_complexity/summary/","title":"2.5 \u00a0 Summary","text":""},{"location":"chapter_computational_complexity/summary/#1-key-review","title":"1. \u00a0 Key Review","text":"

Algorithm Efficiency Assessment

  • Time efficiency and space efficiency are the two main criteria for assessing the merits of an algorithm.
  • We can assess algorithm efficiency through actual testing, but it's challenging to eliminate the influence of the test environment, and it consumes substantial computational resources.
  • Complexity analysis can overcome the disadvantages of actual testing. Its results are applicable across all operating platforms and can reveal the efficiency of algorithms at different data scales.

Time Complexity

  • Time complexity measures the trend of an algorithm's running time with the increase in data volume, effectively assessing algorithm efficiency. However, it can fail in certain cases, such as with small input data volumes or when time complexities are the same, making it challenging to precisely compare the efficiency of algorithms.
  • Worst-case time complexity is denoted using big O notation, representing the asymptotic upper bound, reflecting the growth level of the number of operations \\(T(n)\\) as \\(n\\) approaches infinity.
  • Calculating time complexity involves two steps: first counting the number of operations, then determining the asymptotic upper bound.
  • Common time complexities, arranged from low to high, include \\(O(1)\\), \\(O(\\log n)\\), \\(O(n)\\), \\(O(n \\log n)\\), \\(O(n^2)\\), \\(O(2^n)\\), and \\(O(n!)\\), among others.
  • The time complexity of some algorithms is not fixed and depends on the distribution of input data. Time complexities are divided into worst, best, and average cases. The best case is rarely used because input data generally needs to meet strict conditions to achieve the best case.
  • Average time complexity reflects the efficiency of an algorithm under random data inputs, closely resembling the algorithm's performance in actual applications. Calculating average time complexity requires accounting for the distribution of input data and the subsequent mathematical expectation.

Space Complexity

  • Space complexity, similar to time complexity, measures the trend of memory space occupied by an algorithm with the increase in data volume.
  • The relevant memory space used during the algorithm's execution can be divided into input space, temporary space, and output space. Generally, input space is not included in space complexity calculations. Temporary space can be divided into temporary data, stack frame space, and instruction space, where stack frame space usually affects space complexity only in recursive functions.
  • We usually focus only on the worst-case space complexity, which means calculating the space complexity of the algorithm under the worst input data and at the worst moment of operation.
  • Common space complexities, arranged from low to high, include \\(O(1)\\), \\(O(\\log n)\\), \\(O(n)\\), \\(O(n^2)\\), and \\(O(2^n)\\), among others.
"},{"location":"chapter_computational_complexity/summary/#2-q-a","title":"2. \u00a0 Q & A","text":"

Q: Is the space complexity of tail recursion \\(O(1)\\)?

Theoretically, the space complexity of a tail-recursive function can be optimized to \\(O(1)\\). However, most programming languages (such as Java, Python, C++, Go, C#) do not support automatic optimization of tail recursion, so it's generally considered to have a space complexity of \\(O(n)\\).

Q: What is the difference between the terms \"function\" and \"method\"?

A \"function\" can be executed independently, with all parameters passed explicitly. A \"method\" is associated with an object and is implicitly passed to the object calling it, able to operate on the data contained within an instance of a class.

Here are some examples from common programming languages:

  • C is a procedural programming language without object-oriented concepts, so it only has functions. However, we can simulate object-oriented programming by creating structures (struct), and functions associated with these structures are equivalent to methods in other programming languages.
  • Java and C# are object-oriented programming languages where code blocks (methods) are typically part of a class. Static methods behave like functions because they are bound to the class and cannot access specific instance variables.
  • C++ and Python support both procedural programming (functions) and object-oriented programming (methods).

Q: Does the \"Common Types of Space Complexity\" figure reflect the absolute size of occupied space?

No, the figure shows space complexities, which reflect growth trends, not the absolute size of the occupied space.

If you take \\(n = 8\\), you might find that the values of each curve don't correspond to their functions. This is because each curve includes a constant term, intended to compress the value range into a visually comfortable range.

In practice, since we usually don't know the \"constant term\" complexity of each method, it's generally not possible to choose the best solution for \\(n = 8\\) based solely on complexity. However, for \\(n = 8^5\\), it's much easier to choose, as the growth trend becomes dominant.

"},{"location":"chapter_computational_complexity/time_complexity/","title":"2.3 \u00a0 Time Complexity","text":"

Time complexity is a concept used to measure how the run time of an algorithm increases with the size of the input data. Understanding time complexity is crucial for accurately assessing the efficiency of an algorithm.

  1. Determining the Running Platform: This includes hardware configuration, programming language, system environment, etc., all of which can affect the efficiency of code execution.
  2. Evaluating the Run Time for Various Computational Operations: For instance, an addition operation + might take 1 ns, a multiplication operation * might take 10 ns, a print operation print() might take 5 ns, etc.
  3. Counting All the Computational Operations in the Code: Summing the execution times of all these operations gives the total run time.

For example, consider the following code with an input size of \\(n\\):

PythonC++JavaC#GoSwiftJSTSDartRustCZig
# Under an operating platform\ndef algorithm(n: int):\n    a = 2      # 1 ns\n    a = a + 1  # 1 ns\n    a = a * 2  # 10 ns\n    # Cycle n times\n    for _ in range(n):  # 1 ns\n        print(0)        # 5 ns\n
// Under a particular operating platform\nvoid algorithm(int n) {\n    int a = 2;  // 1 ns\n    a = a + 1;  // 1 ns\n    a = a * 2;  // 10 ns\n    // Loop n times\n    for (int i = 0; i < n; i++) {  // 1 ns , every round i++ is executed\n        cout << 0 << endl;         // 5 ns\n    }\n}\n
// Under a particular operating platform\nvoid algorithm(int n) {\n    int a = 2;  // 1 ns\n    a = a + 1;  // 1 ns\n    a = a * 2;  // 10 ns\n    // Loop n times\n    for (int i = 0; i < n; i++) {  // 1 ns , every round i++ is executed\n        System.out.println(0);     // 5 ns\n    }\n}\n
// Under a particular operating platform\nvoid Algorithm(int n) {\n    int a = 2;  // 1 ns\n    a = a + 1;  // 1 ns\n    a = a * 2;  // 10 ns\n    // Loop n times\n    for (int i = 0; i < n; i++) {  // 1 ns , every round i++ is executed\n        Console.WriteLine(0);      // 5 ns\n    }\n}\n
// Under a particular operating platform\nfunc algorithm(n int) {\n    a := 2     // 1 ns\n    a = a + 1  // 1 ns\n    a = a * 2  // 10 ns\n    // Loop n times\n    for i := 0; i < n; i++ {  // 1 ns\n        fmt.Println(a)        // 5 ns\n    }\n}\n
// Under a particular operating platform\nfunc algorithm(n: Int) {\n    var a = 2 // 1 ns\n    a = a + 1 // 1 ns\n    a = a * 2 // 10 ns\n    // Loop n times\n    for _ in 0 ..< n { // 1 ns\n        print(0) // 5 ns\n    }\n}\n
// Under a particular operating platform\nfunction algorithm(n) {\n    var a = 2; // 1 ns\n    a = a + 1; // 1 ns\n    a = a * 2; // 10 ns\n    // Loop n times\n    for(let i = 0; i < n; i++) { // 1 ns , every round i++ is executed\n        console.log(0); // 5 ns\n    }\n}\n
// Under a particular operating platform\nfunction algorithm(n: number): void {\n    var a: number = 2; // 1 ns\n    a = a + 1; // 1 ns\n    a = a * 2; // 10 ns\n    // Loop n times\n    for(let i = 0; i < n; i++) { // 1 ns , every round i++ is executed\n        console.log(0); // 5 ns\n    }\n}\n
// Under a particular operating platform\nvoid algorithm(int n) {\n  int a = 2; // 1 ns\n  a = a + 1; // 1 ns\n  a = a * 2; // 10 ns\n  // Loop n times\n  for (int i = 0; i < n; i++) { // 1 ns , every round i++ is executed\n    print(0); // 5 ns\n  }\n}\n
// Under a particular operating platform\nfn algorithm(n: i32) {\n    let mut a = 2;      // 1 ns\n    a = a + 1;          // 1 ns\n    a = a * 2;          // 10 ns\n    // Loop n times\n    for _ in 0..n {     // 1 ns for each round i++\n        println!(\"{}\", 0);  // 5 ns\n    }\n}\n
// Under a particular operating platform\nvoid algorithm(int n) {\n    int a = 2;  // 1 ns\n    a = a + 1;  // 1 ns\n    a = a * 2;  // 10 ns\n    // Loop n times\n    for (int i = 0; i < n; i++) {   // 1 ns , every round i++ is executed\n        printf(\"%d\", 0);            // 5 ns\n    }\n}\n
// Under a particular operating platform\nfn algorithm(n: usize) void {\n    var a: i32 = 2; // 1 ns\n    a += 1; // 1 ns\n    a *= 2; // 10 ns\n    // Loop n times\n    for (0..n) |_| { // 1 ns\n        std.debug.print(\"{}\\n\", .{0}); // 5 ns\n    }\n}\n

Using the above method, the run time of the algorithm can be calculated as \\((6n + 12)\\) ns:

\\[ 1 + 1 + 10 + (1 + 5) \\times n = 6n + 12 \\]

However, in practice, counting the run time of an algorithm is neither practical nor reasonable. First, we don't want to tie the estimated time to the running platform, as algorithms need to run on various platforms. Second, it's challenging to know the run time for each type of operation, making the estimation process difficult.

"},{"location":"chapter_computational_complexity/time_complexity/#231-assessing-time-growth-trend","title":"2.3.1 \u00a0 Assessing Time Growth Trend","text":"

Time complexity analysis does not count the algorithm's run time, but rather the growth trend of the run time as the data volume increases.

Let's understand this concept of \"time growth trend\" with an example. Assume the input data size is \\(n\\), and consider three algorithms A, B, and C:

PythonC++JavaC#GoSwiftJSTSDartRustCZig
# Time complexity of algorithm A: constant order\ndef algorithm_A(n: int):\n    print(0)\n# Time complexity of algorithm B: linear order\ndef algorithm_B(n: int):\n    for _ in range(n):\n        print(0)\n# Time complexity of algorithm C: constant order\ndef algorithm_C(n: int):\n    for _ in range(1000000):\n        print(0)\n
// Time complexity of algorithm A: constant order\nvoid algorithm_A(int n) {\n    cout << 0 << endl;\n}\n// Time complexity of algorithm B: linear order\nvoid algorithm_B(int n) {\n    for (int i = 0; i < n; i++) {\n        cout << 0 << endl;\n    }\n}\n// Time complexity of algorithm C: constant order\nvoid algorithm_C(int n) {\n    for (int i = 0; i < 1000000; i++) {\n        cout << 0 << endl;\n    }\n}\n
// Time complexity of algorithm A: constant order\nvoid algorithm_A(int n) {\n    System.out.println(0);\n}\n// Time complexity of algorithm B: linear order\nvoid algorithm_B(int n) {\n    for (int i = 0; i < n; i++) {\n        System.out.println(0);\n    }\n}\n// Time complexity of algorithm C: constant order\nvoid algorithm_C(int n) {\n    for (int i = 0; i < 1000000; i++) {\n        System.out.println(0);\n    }\n}\n
// Time complexity of algorithm A: constant order\nvoid AlgorithmA(int n) {\n    Console.WriteLine(0);\n}\n// Time complexity of algorithm B: linear order\nvoid AlgorithmB(int n) {\n    for (int i = 0; i < n; i++) {\n        Console.WriteLine(0);\n    }\n}\n// Time complexity of algorithm C: constant order\nvoid AlgorithmC(int n) {\n    for (int i = 0; i < 1000000; i++) {\n        Console.WriteLine(0);\n    }\n}\n
// Time complexity of algorithm A: constant order\nfunc algorithm_A(n int) {\n    fmt.Println(0)\n}\n// Time complexity of algorithm B: linear order\nfunc algorithm_B(n int) {\n    for i := 0; i < n; i++ {\n        fmt.Println(0)\n    }\n}\n// Time complexity of algorithm C: constant order\nfunc algorithm_C(n int) {\n    for i := 0; i < 1000000; i++ {\n        fmt.Println(0)\n    }\n}\n
// Time complexity of algorithm A: constant order\nfunc algorithmA(n: Int) {\n    print(0)\n}\n\n// Time complexity of algorithm B: linear order\nfunc algorithmB(n: Int) {\n    for _ in 0 ..< n {\n        print(0)\n    }\n}\n\n// Time complexity of algorithm C: constant order\nfunc algorithmC(n: Int) {\n    for _ in 0 ..< 1_000_000 {\n        print(0)\n    }\n}\n
// Time complexity of algorithm A: constant order\nfunction algorithm_A(n) {\n    console.log(0);\n}\n// Time complexity of algorithm B: linear order\nfunction algorithm_B(n) {\n    for (let i = 0; i < n; i++) {\n        console.log(0);\n    }\n}\n// Time complexity of algorithm C: constant order\nfunction algorithm_C(n) {\n    for (let i = 0; i < 1000000; i++) {\n        console.log(0);\n    }\n}\n
// Time complexity of algorithm A: constant order\nfunction algorithm_A(n: number): void {\n    console.log(0);\n}\n// Time complexity of algorithm B: linear order\nfunction algorithm_B(n: number): void {\n    for (let i = 0; i < n; i++) {\n        console.log(0);\n    }\n}\n// Time complexity of algorithm C: constant order\nfunction algorithm_C(n: number): void {\n    for (let i = 0; i < 1000000; i++) {\n        console.log(0);\n    }\n}\n
// Time complexity of algorithm A: constant order\nvoid algorithmA(int n) {\n  print(0);\n}\n// Time complexity of algorithm B: linear order\nvoid algorithmB(int n) {\n  for (int i = 0; i < n; i++) {\n    print(0);\n  }\n}\n// Time complexity of algorithm C: constant order\nvoid algorithmC(int n) {\n  for (int i = 0; i < 1000000; i++) {\n    print(0);\n  }\n}\n
// Time complexity of algorithm A: constant order\nfn algorithm_A(n: i32) {\n    println!(\"{}\", 0);\n}\n// Time complexity of algorithm B: linear order\nfn algorithm_B(n: i32) {\n    for _ in 0..n {\n        println!(\"{}\", 0);\n    }\n}\n// Time complexity of algorithm C: constant order\nfn algorithm_C(n: i32) {\n    for _ in 0..1000000 {\n        println!(\"{}\", 0);\n    }\n}\n
// Time complexity of algorithm A: constant order\nvoid algorithm_A(int n) {\n    printf(\"%d\", 0);\n}\n// Time complexity of algorithm B: linear order\nvoid algorithm_B(int n) {\n    for (int i = 0; i < n; i++) {\n        printf(\"%d\", 0);\n    }\n}\n// Time complexity of algorithm C: constant order\nvoid algorithm_C(int n) {\n    for (int i = 0; i < 1000000; i++) {\n        printf(\"%d\", 0);\n    }\n}\n
// Time complexity of algorithm A: constant order\nfn algorithm_A(n: usize) void {\n    _ = n;\n    std.debug.print(\"{}\\n\", .{0});\n}\n// Time complexity of algorithm B: linear order\nfn algorithm_B(n: i32) void {\n    for (0..n) |_| {\n        std.debug.print(\"{}\\n\", .{0});\n    }\n}\n// Time complexity of algorithm C: constant order\nfn algorithm_C(n: i32) void {\n    _ = n;\n    for (0..1000000) |_| {\n        std.debug.print(\"{}\\n\", .{0});\n    }\n}\n

The following figure shows the time complexities of these three algorithms.

  • Algorithm A has just one print operation, and its run time does not grow with \\(n\\). Its time complexity is considered \"constant order.\"
  • Algorithm B involves a print operation looping \\(n\\) times, and its run time grows linearly with \\(n\\). Its time complexity is \"linear order.\"
  • Algorithm C has a print operation looping 1,000,000 times. Although it takes a long time, it is independent of the input data size \\(n\\). Therefore, the time complexity of C is the same as A, which is \"constant order.\"

Figure 2-7 \u00a0 Time Growth Trend of Algorithms A, B, and C

Compared to directly counting the run time of an algorithm, what are the characteristics of time complexity analysis?

  • Time complexity effectively assesses algorithm efficiency. For instance, algorithm B has linearly growing run time, which is slower than algorithm A when \\(n > 1\\) and slower than C when \\(n > 1,000,000\\). In fact, as long as the input data size \\(n\\) is sufficiently large, a \"constant order\" complexity algorithm will always be better than a \"linear order\" one, demonstrating the essence of time growth trend.
  • Time complexity analysis is more straightforward. Obviously, the running platform and the types of computational operations are irrelevant to the trend of run time growth. Therefore, in time complexity analysis, we can simply treat the execution time of all computational operations as the same \"unit time,\" simplifying the \"computational operation run time count\" to a \"computational operation count.\" This significantly reduces the complexity of estimation.
  • Time complexity has its limitations. For example, although algorithms A and C have the same time complexity, their actual run times can be quite different. Similarly, even though algorithm B has a higher time complexity than C, it is clearly superior when the input data size \\(n\\) is small. In these cases, it's difficult to judge the efficiency of algorithms based solely on time complexity. Nonetheless, despite these issues, complexity analysis remains the most effective and commonly used method for evaluating algorithm efficiency.
"},{"location":"chapter_computational_complexity/time_complexity/#232-asymptotic-upper-bound","title":"2.3.2 \u00a0 Asymptotic Upper Bound","text":"

Consider a function with an input size of \\(n\\):

PythonC++JavaC#GoSwiftJSTSDartRustCZig
def algorithm(n: int):\n    a = 1      # +1\n    a = a + 1  # +1\n    a = a * 2  # +1\n    # Cycle n times\n    for i in range(n):  # +1\n        print(0)        # +1\n
void algorithm(int n) {\n    int a = 1;  // +1\n    a = a + 1;  // +1\n    a = a * 2;  // +1\n    // Loop n times\n    for (int i = 0; i < n; i++) { // +1 (execute i ++ every round)\n        cout << 0 << endl;    // +1\n    }\n}\n
void algorithm(int n) {\n    int a = 1;  // +1\n    a = a + 1;  // +1\n    a = a * 2;  // +1\n    // Loop n times\n    for (int i = 0; i < n; i++) { // +1 (execute i ++ every round)\n        System.out.println(0);    // +1\n    }\n}\n
void Algorithm(int n) {\n    int a = 1;  // +1\n    a = a + 1;  // +1\n    a = a * 2;  // +1\n    // Loop n times\n    for (int i = 0; i < n; i++) {   // +1 (execute i ++ every round)\n        Console.WriteLine(0);   // +1\n    }\n}\n
func algorithm(n int) {\n    a := 1      // +1\n    a = a + 1   // +1\n    a = a * 2   // +1\n    // Loop n times\n    for i := 0; i < n; i++ {   // +1\n        fmt.Println(a)         // +1\n    }\n}\n
func algorithm(n: Int) {\n    var a = 1 // +1\n    a = a + 1 // +1\n    a = a * 2 // +1\n    // Loop n times\n    for _ in 0 ..< n { // +1\n        print(0) // +1\n    }\n}\n
function algorithm(n) {\n    var a = 1; // +1\n    a += 1; // +1\n    a *= 2; // +1\n    // Loop n times\n    for(let i = 0; i < n; i++){ // +1 (execute i ++ every round)\n        console.log(0); // +1\n    }\n}\n
function algorithm(n: number): void{\n    var a: number = 1; // +1\n    a += 1; // +1\n    a *= 2; // +1\n    // Loop n times\n    for(let i = 0; i < n; i++){ // +1 (execute i ++ every round)\n        console.log(0); // +1\n    }\n}\n
void algorithm(int n) {\n  int a = 1; // +1\n  a = a + 1; // +1\n  a = a * 2; // +1\n  // Loop n times\n  for (int i = 0; i < n; i++) { // +1 (execute i ++ every round)\n    print(0); // +1\n  }\n}\n
fn algorithm(n: i32) {\n    let mut a = 1;   // +1\n    a = a + 1;      // +1\n    a = a * 2;      // +1\n\n    // Loop n times\n    for _ in 0..n { // +1 (execute i ++ every round)\n        println!(\"{}\", 0); // +1\n    }\n}\n
void algorithm(int n) {\n    int a = 1;  // +1\n    a = a + 1;  // +1\n    a = a * 2;  // +1\n    // Loop n times\n    for (int i = 0; i < n; i++) {   // +1 (execute i ++ every round)\n        printf(\"%d\", 0);            // +1\n    }\n} \n
fn algorithm(n: usize) void {\n    var a: i32 = 1; // +1\n    a += 1; // +1\n    a *= 2; // +1\n    // Loop n times\n    for (0..n) |_| { // +1 (execute i ++ every round)\n        std.debug.print(\"{}\\n\", .{0}); // +1\n    }\n}\n

Given a function that represents the number of operations of an algorithm as a function of the input size \\(n\\), denoted as \\(T(n)\\), consider the following example:

\\[ T(n) = 3 + 2n \\]

Since \\(T(n)\\) is a linear function, its growth trend is linear, and therefore, its time complexity is of linear order, denoted as \\(O(n)\\). This mathematical notation, known as \"big-O notation,\" represents the \"asymptotic upper bound\" of the function \\(T(n)\\).

In essence, time complexity analysis is about finding the asymptotic upper bound of the \"number of operations \\(T(n)\\)\". It has a precise mathematical definition.

Asymptotic Upper Bound

If there exist positive real numbers \\(c\\) and \\(n_0\\) such that for all \\(n > n_0\\), \\(T(n) \\leq c \\cdot f(n)\\), then \\(f(n)\\) is considered an asymptotic upper bound of \\(T(n)\\), denoted as \\(T(n) = O(f(n))\\).

As illustrated below, calculating the asymptotic upper bound involves finding a function \\(f(n)\\) such that, as \\(n\\) approaches infinity, \\(T(n)\\) and \\(f(n)\\) have the same growth order, differing only by a constant factor \\(c\\).

Figure 2-8 \u00a0 Asymptotic Upper Bound of a Function

"},{"location":"chapter_computational_complexity/time_complexity/#233-calculation-method","title":"2.3.3 \u00a0 Calculation Method","text":"

While the concept of asymptotic upper bound might seem mathematically dense, you don't need to fully grasp it right away. Let's first understand the method of calculation, which can be practiced and comprehended over time.

Once \\(f(n)\\) is determined, we obtain the time complexity \\(O(f(n))\\). But how do we determine the asymptotic upper bound \\(f(n)\\)? This process generally involves two steps: counting the number of operations and determining the asymptotic upper bound.

"},{"location":"chapter_computational_complexity/time_complexity/#1-step-1-counting-the-number-of-operations","title":"1. \u00a0 Step 1: Counting the Number of Operations","text":"

This step involves going through the code line by line. However, due to the presence of the constant \\(c\\) in \\(c \\cdot f(n)\\), all coefficients and constant terms in \\(T(n)\\) can be ignored. This principle allows for simplification techniques in counting operations.

  1. Ignore constant terms in \\(T(n)\\), as they do not affect the time complexity being independent of \\(n\\).
  2. Omit all coefficients. For example, looping \\(2n\\), \\(5n + 1\\) times, etc., can be simplified to \\(n\\) times since the coefficient before \\(n\\) does not impact the time complexity.
  3. Use multiplication for nested loops. The total number of operations equals the product of the number of operations in each loop, applying the simplification techniques from points 1 and 2 for each loop level.

Given a function, we can use these techniques to count operations:

PythonC++JavaC#GoSwiftJSTSDartRustCZig
def algorithm(n: int):\n    a = 1      # +0 (trick 1)\n    a = a + n  # +0 (trick 1)\n    # +n (technique 2)\n    for i in range(5 * n + 1):\n        print(0)\n    # +n*n (technique 3)\n    for i in range(2 * n):\n        for j in range(n + 1):\n            print(0)\n
void algorithm(int n) {\n    int a = 1;  // +0 (trick 1)\n    a = a + n;  // +0 (trick 1)\n    // +n (technique 2)\n    for (int i = 0; i < 5 * n + 1; i++) {\n        cout << 0 << endl;\n    }\n    // +n*n (technique 3)\n    for (int i = 0; i < 2 * n; i++) {\n        for (int j = 0; j < n + 1; j++) {\n            cout << 0 << endl;\n        }\n    }\n}\n
void algorithm(int n) {\n    int a = 1;  // +0 (trick 1)\n    a = a + n;  // +0 (trick 1)\n    // +n (technique 2)\n    for (int i = 0; i < 5 * n + 1; i++) {\n        System.out.println(0);\n    }\n    // +n*n (technique 3)\n    for (int i = 0; i < 2 * n; i++) {\n        for (int j = 0; j < n + 1; j++) {\n            System.out.println(0);\n        }\n    }\n}\n
void Algorithm(int n) {\n    int a = 1;  // +0 (trick 1)\n    a = a + n;  // +0 (trick 1)\n    // +n (technique 2)\n    for (int i = 0; i < 5 * n + 1; i++) {\n        Console.WriteLine(0);\n    }\n    // +n*n (technique 3)\n    for (int i = 0; i < 2 * n; i++) {\n        for (int j = 0; j < n + 1; j++) {\n            Console.WriteLine(0);\n        }\n    }\n}\n
func algorithm(n int) {\n    a := 1     // +0 (trick 1)\n    a = a + n  // +0 (trick 1)\n    // +n (technique 2)\n    for i := 0; i < 5 * n + 1; i++ {\n        fmt.Println(0)\n    }\n    // +n*n (technique 3)\n    for i := 0; i < 2 * n; i++ {\n        for j := 0; j < n + 1; j++ {\n            fmt.Println(0)\n        }\n    }\n}\n
func algorithm(n: Int) {\n    var a = 1 // +0 (trick 1)\n    a = a + n // +0 (trick 1)\n    // +n (technique 2)\n    for _ in 0 ..< (5 * n + 1) {\n        print(0)\n    }\n    // +n*n (technique 3)\n    for _ in 0 ..< (2 * n) {\n        for _ in 0 ..< (n + 1) {\n            print(0)\n        }\n    }\n}\n
function algorithm(n) {\n    let a = 1;  // +0 (trick 1)\n    a = a + n;  // +0 (trick 1)\n    // +n (technique 2)\n    for (let i = 0; i < 5 * n + 1; i++) {\n        console.log(0);\n    }\n    // +n*n (technique 3)\n    for (let i = 0; i < 2 * n; i++) {\n        for (let j = 0; j < n + 1; j++) {\n            console.log(0);\n        }\n    }\n}\n
function algorithm(n: number): void {\n    let a = 1;  // +0 (trick 1)\n    a = a + n;  // +0 (trick 1)\n    // +n (technique 2)\n    for (let i = 0; i < 5 * n + 1; i++) {\n        console.log(0);\n    }\n    // +n*n (technique 3)\n    for (let i = 0; i < 2 * n; i++) {\n        for (let j = 0; j < n + 1; j++) {\n            console.log(0);\n        }\n    }\n}\n
void algorithm(int n) {\n  int a = 1; // +0 (trick 1)\n  a = a + n; // +0 (trick 1)\n  // +n (technique 2)\n  for (int i = 0; i < 5 * n + 1; i++) {\n    print(0);\n  }\n  // +n*n (technique 3)\n  for (int i = 0; i < 2 * n; i++) {\n    for (int j = 0; j < n + 1; j++) {\n      print(0);\n    }\n  }\n}\n
fn algorithm(n: i32) {\n    let mut a = 1;     // +0 (trick 1)\n    a = a + n;        // +0 (trick 1)\n\n    // +n (technique 2)\n    for i in 0..(5 * n + 1) {\n        println!(\"{}\", 0);\n    }\n\n    // +n*n (technique 3)\n    for i in 0..(2 * n) {\n        for j in 0..(n + 1) {\n            println!(\"{}\", 0);\n        }\n    }\n}\n
void algorithm(int n) {\n    int a = 1;  // +0 (trick 1)\n    a = a + n;  // +0 (trick 1)\n    // +n (technique 2)\n    for (int i = 0; i < 5 * n + 1; i++) {\n        printf(\"%d\", 0);\n    }\n    // +n*n (technique 3)\n    for (int i = 0; i < 2 * n; i++) {\n        for (int j = 0; j < n + 1; j++) {\n            printf(\"%d\", 0);\n        }\n    }\n}\n
fn algorithm(n: usize) void {\n    var a: i32 = 1;     // +0 (trick 1)\n    a = a + @as(i32, @intCast(n));        // +0 (trick 1)\n\n    // +n (technique 2)\n    for(0..(5 * n + 1)) |_| {\n        std.debug.print(\"{}\\n\", .{0});\n    }\n\n    // +n*n (technique 3)\n    for(0..(2 * n)) |_| {\n        for(0..(n + 1)) |_| {\n            std.debug.print(\"{}\\n\", .{0});\n        }\n    }\n}\n

The formula below shows the counting results before and after simplification, both leading to a time complexity of \\(O(n^2)\\):

\\[ \\begin{aligned} T(n) & = 2n(n + 1) + (5n + 1) + 2 & \\text{Complete Count (-.-|||)} \\newline & = 2n^2 + 7n + 3 \\newline T(n) & = n^2 + n & \\text{Simplified Count (o.O)} \\end{aligned} \\]"},{"location":"chapter_computational_complexity/time_complexity/#2-step-2-determining-the-asymptotic-upper-bound","title":"2. \u00a0 Step 2: Determining the Asymptotic Upper Bound","text":"

The time complexity is determined by the highest order term in \\(T(n)\\). This is because, as \\(n\\) approaches infinity, the highest order term dominates, rendering the influence of other terms negligible.

The following table illustrates examples of different operation counts and their corresponding time complexities. Some exaggerated values are used to emphasize that coefficients cannot alter the order of growth. When \\(n\\) becomes very large, these constants become insignificant.

Table: Time Complexity for Different Operation Counts

Operation Count \\(T(n)\\) Time Complexity \\(O(f(n))\\) \\(100000\\) \\(O(1)\\) \\(3n + 2\\) \\(O(n)\\) \\(2n^2 + 3n + 2\\) \\(O(n^2)\\) \\(n^3 + 10000n^2\\) \\(O(n^3)\\) \\(2^n + 10000n^{10000}\\) \\(O(2^n)\\)"},{"location":"chapter_computational_complexity/time_complexity/#234-common-types-of-time-complexity","title":"2.3.4 \u00a0 Common Types of Time Complexity","text":"

Let's consider the input data size as \\(n\\). The common types of time complexities are illustrated below, arranged from lowest to highest:

\\[ \\begin{aligned} O(1) < O(\\log n) < O(n) < O(n \\log n) < O(n^2) < O(2^n) < O(n!) \\newline \\text{Constant Order} < \\text{Logarithmic Order} < \\text{Linear Order} < \\text{Linear-Logarithmic Order} < \\text{Quadratic Order} < \\text{Exponential Order} < \\text{Factorial Order} \\end{aligned} \\]

Figure 2-9 \u00a0 Common Types of Time Complexity

"},{"location":"chapter_computational_complexity/time_complexity/#1-constant-order-o1","title":"1. \u00a0 Constant Order \\(O(1)\\)","text":"

Constant order means the number of operations is independent of the input data size \\(n\\). In the following function, although the number of operations size might be large, the time complexity remains \\(O(1)\\) as it's unrelated to \\(n\\):

PythonC++JavaC#GoSwiftJSTSDartRustCZig time_complexity.py
def constant(n: int) -> int:\n    \"\"\"\u5e38\u6570\u9636\"\"\"\n    count = 0\n    size = 100000\n    for _ in range(size):\n        count += 1\n    return count\n
time_complexity.cpp
/* \u5e38\u6570\u9636 */\nint constant(int n) {\n    int count = 0;\n    int size = 100000;\n    for (int i = 0; i < size; i++)\n        count++;\n    return count;\n}\n
time_complexity.java
/* \u5e38\u6570\u9636 */\nint constant(int n) {\n    int count = 0;\n    int size = 100000;\n    for (int i = 0; i < size; i++)\n        count++;\n    return count;\n}\n
time_complexity.cs
/* \u5e38\u6570\u9636 */\nint Constant(int n) {\n    int count = 0;\n    int size = 100000;\n    for (int i = 0; i < size; i++)\n        count++;\n    return count;\n}\n
time_complexity.go
/* \u5e38\u6570\u9636 */\nfunc constant(n int) int {\n    count := 0\n    size := 100000\n    for i := 0; i < size; i++ {\n        count++\n    }\n    return count\n}\n
time_complexity.swift
/* \u5e38\u6570\u9636 */\nfunc constant(n: Int) -> Int {\n    var count = 0\n    let size = 100_000\n    for _ in 0 ..< size {\n        count += 1\n    }\n    return count\n}\n
time_complexity.js
/* \u5e38\u6570\u9636 */\nfunction constant(n) {\n    let count = 0;\n    const size = 100000;\n    for (let i = 0; i < size; i++) count++;\n    return count;\n}\n
time_complexity.ts
/* \u5e38\u6570\u9636 */\nfunction constant(n: number): number {\n    let count = 0;\n    const size = 100000;\n    for (let i = 0; i < size; i++) count++;\n    return count;\n}\n
time_complexity.dart
/* \u5e38\u6570\u9636 */\nint constant(int n) {\n  int count = 0;\n  int size = 100000;\n  for (var i = 0; i < size; i++) {\n    count++;\n  }\n  return count;\n}\n
time_complexity.rs
/* \u5e38\u6570\u9636 */\nfn constant(n: i32) -> i32 {\n    _ = n;\n    let mut count = 0;\n    let size = 100_000;\n    for _ in 0..size {\n        count += 1;\n    }\n    count\n}\n
time_complexity.c
/* \u5e38\u6570\u9636 */\nint constant(int n) {\n    int count = 0;\n    int size = 100000;\n    int i = 0;\n    for (int i = 0; i < size; i++) {\n        count++;\n    }\n    return count;\n}\n
time_complexity.zig
// \u5e38\u6570\u9636\nfn constant(n: i32) i32 {\n    _ = n;\n    var count: i32 = 0;\n    const size: i32 = 100_000;\n    var i: i32 = 0;\n    while(i<size) : (i += 1) {\n        count += 1;\n    }\n    return count;\n}\n
Code Visualization

Full Screen >

"},{"location":"chapter_computational_complexity/time_complexity/#2-linear-order-on","title":"2. \u00a0 Linear Order \\(O(n)\\)","text":"

Linear order indicates the number of operations grows linearly with the input data size \\(n\\). Linear order commonly appears in single-loop structures:

PythonC++JavaC#GoSwiftJSTSDartRustCZig time_complexity.py
def linear(n: int) -> int:\n    \"\"\"\u7ebf\u6027\u9636\"\"\"\n    count = 0\n    for _ in range(n):\n        count += 1\n    return count\n
time_complexity.cpp
/* \u7ebf\u6027\u9636 */\nint linear(int n) {\n    int count = 0;\n    for (int i = 0; i < n; i++)\n        count++;\n    return count;\n}\n
time_complexity.java
/* \u7ebf\u6027\u9636 */\nint linear(int n) {\n    int count = 0;\n    for (int i = 0; i < n; i++)\n        count++;\n    return count;\n}\n
time_complexity.cs
/* \u7ebf\u6027\u9636 */\nint Linear(int n) {\n    int count = 0;\n    for (int i = 0; i < n; i++)\n        count++;\n    return count;\n}\n
time_complexity.go
/* \u7ebf\u6027\u9636 */\nfunc linear(n int) int {\n    count := 0\n    for i := 0; i < n; i++ {\n        count++\n    }\n    return count\n}\n
time_complexity.swift
/* \u7ebf\u6027\u9636 */\nfunc linear(n: Int) -> Int {\n    var count = 0\n    for _ in 0 ..< n {\n        count += 1\n    }\n    return count\n}\n
time_complexity.js
/* \u7ebf\u6027\u9636 */\nfunction linear(n) {\n    let count = 0;\n    for (let i = 0; i < n; i++) count++;\n    return count;\n}\n
time_complexity.ts
/* \u7ebf\u6027\u9636 */\nfunction linear(n: number): number {\n    let count = 0;\n    for (let i = 0; i < n; i++) count++;\n    return count;\n}\n
time_complexity.dart
/* \u7ebf\u6027\u9636 */\nint linear(int n) {\n  int count = 0;\n  for (var i = 0; i < n; i++) {\n    count++;\n  }\n  return count;\n}\n
time_complexity.rs
/* \u7ebf\u6027\u9636 */\nfn linear(n: i32) -> i32 {\n    let mut count = 0;\n    for _ in 0..n {\n        count += 1;\n    }\n    count\n}\n
time_complexity.c
/* \u7ebf\u6027\u9636 */\nint linear(int n) {\n    int count = 0;\n    for (int i = 0; i < n; i++) {\n        count++;\n    }\n    return count;\n}\n
time_complexity.zig
// \u7ebf\u6027\u9636\nfn linear(n: i32) i32 {\n    var count: i32 = 0;\n    var i: i32 = 0;\n    while (i < n) : (i += 1) {\n        count += 1;\n    }\n    return count;\n}\n
Code Visualization

Full Screen >

Operations like array traversal and linked list traversal have a time complexity of \\(O(n)\\), where \\(n\\) is the length of the array or list:

PythonC++JavaC#GoSwiftJSTSDartRustCZig time_complexity.py
def array_traversal(nums: list[int]) -> int:\n    \"\"\"\u7ebf\u6027\u9636\uff08\u904d\u5386\u6570\u7ec4\uff09\"\"\"\n    count = 0\n    # \u5faa\u73af\u6b21\u6570\u4e0e\u6570\u7ec4\u957f\u5ea6\u6210\u6b63\u6bd4\n    for num in nums:\n        count += 1\n    return count\n
time_complexity.cpp
/* \u7ebf\u6027\u9636\uff08\u904d\u5386\u6570\u7ec4\uff09 */\nint arrayTraversal(vector<int> &nums) {\n    int count = 0;\n    // \u5faa\u73af\u6b21\u6570\u4e0e\u6570\u7ec4\u957f\u5ea6\u6210\u6b63\u6bd4\n    for (int num : nums) {\n        count++;\n    }\n    return count;\n}\n
time_complexity.java
/* \u7ebf\u6027\u9636\uff08\u904d\u5386\u6570\u7ec4\uff09 */\nint arrayTraversal(int[] nums) {\n    int count = 0;\n    // \u5faa\u73af\u6b21\u6570\u4e0e\u6570\u7ec4\u957f\u5ea6\u6210\u6b63\u6bd4\n    for (int num : nums) {\n        count++;\n    }\n    return count;\n}\n
time_complexity.cs
/* \u7ebf\u6027\u9636\uff08\u904d\u5386\u6570\u7ec4\uff09 */\nint ArrayTraversal(int[] nums) {\n    int count = 0;\n    // \u5faa\u73af\u6b21\u6570\u4e0e\u6570\u7ec4\u957f\u5ea6\u6210\u6b63\u6bd4\n    foreach (int num in nums) {\n        count++;\n    }\n    return count;\n}\n
time_complexity.go
/* \u7ebf\u6027\u9636\uff08\u904d\u5386\u6570\u7ec4\uff09 */\nfunc arrayTraversal(nums []int) int {\n    count := 0\n    // \u5faa\u73af\u6b21\u6570\u4e0e\u6570\u7ec4\u957f\u5ea6\u6210\u6b63\u6bd4\n    for range nums {\n        count++\n    }\n    return count\n}\n
time_complexity.swift
/* \u7ebf\u6027\u9636\uff08\u904d\u5386\u6570\u7ec4\uff09 */\nfunc arrayTraversal(nums: [Int]) -> Int {\n    var count = 0\n    // \u5faa\u73af\u6b21\u6570\u4e0e\u6570\u7ec4\u957f\u5ea6\u6210\u6b63\u6bd4\n    for _ in nums {\n        count += 1\n    }\n    return count\n}\n
time_complexity.js
/* \u7ebf\u6027\u9636\uff08\u904d\u5386\u6570\u7ec4\uff09 */\nfunction arrayTraversal(nums) {\n    let count = 0;\n    // \u5faa\u73af\u6b21\u6570\u4e0e\u6570\u7ec4\u957f\u5ea6\u6210\u6b63\u6bd4\n    for (let i = 0; i < nums.length; i++) {\n        count++;\n    }\n    return count;\n}\n
time_complexity.ts
/* \u7ebf\u6027\u9636\uff08\u904d\u5386\u6570\u7ec4\uff09 */\nfunction arrayTraversal(nums: number[]): number {\n    let count = 0;\n    // \u5faa\u73af\u6b21\u6570\u4e0e\u6570\u7ec4\u957f\u5ea6\u6210\u6b63\u6bd4\n    for (let i = 0; i < nums.length; i++) {\n        count++;\n    }\n    return count;\n}\n
time_complexity.dart
/* \u7ebf\u6027\u9636\uff08\u904d\u5386\u6570\u7ec4\uff09 */\nint arrayTraversal(List<int> nums) {\n  int count = 0;\n  // \u5faa\u73af\u6b21\u6570\u4e0e\u6570\u7ec4\u957f\u5ea6\u6210\u6b63\u6bd4\n  for (var _num in nums) {\n    count++;\n  }\n  return count;\n}\n
time_complexity.rs
/* \u7ebf\u6027\u9636\uff08\u904d\u5386\u6570\u7ec4\uff09 */\nfn array_traversal(nums: &[i32]) -> i32 {\n    let mut count = 0;\n    // \u5faa\u73af\u6b21\u6570\u4e0e\u6570\u7ec4\u957f\u5ea6\u6210\u6b63\u6bd4\n    for _ in nums {\n        count += 1;\n    }\n    count\n}\n
time_complexity.c
/* \u7ebf\u6027\u9636\uff08\u904d\u5386\u6570\u7ec4\uff09 */\nint arrayTraversal(int *nums, int n) {\n    int count = 0;\n    // \u5faa\u73af\u6b21\u6570\u4e0e\u6570\u7ec4\u957f\u5ea6\u6210\u6b63\u6bd4\n    for (int i = 0; i < n; i++) {\n        count++;\n    }\n    return count;\n}\n
time_complexity.zig
// \u7ebf\u6027\u9636\uff08\u904d\u5386\u6570\u7ec4\uff09\nfn arrayTraversal(nums: []i32) i32 {\n    var count: i32 = 0;\n    // \u5faa\u73af\u6b21\u6570\u4e0e\u6570\u7ec4\u957f\u5ea6\u6210\u6b63\u6bd4\n    for (nums) |_| {\n        count += 1;\n    }\n    return count;\n}\n
Code Visualization

Full Screen >

It's important to note that the input data size \\(n\\) should be determined based on the type of input data. For example, in the first example, \\(n\\) represents the input data size, while in the second example, the length of the array \\(n\\) is the data size.

"},{"location":"chapter_computational_complexity/time_complexity/#3-quadratic-order-on2","title":"3. \u00a0 Quadratic Order \\(O(n^2)\\)","text":"

Quadratic order means the number of operations grows quadratically with the input data size \\(n\\). Quadratic order typically appears in nested loops, where both the outer and inner loops have a time complexity of \\(O(n)\\), resulting in an overall complexity of \\(O(n^2)\\):

PythonC++JavaC#GoSwiftJSTSDartRustCZig time_complexity.py
def quadratic(n: int) -> int:\n    \"\"\"\u5e73\u65b9\u9636\"\"\"\n    count = 0\n    # \u5faa\u73af\u6b21\u6570\u4e0e\u6570\u636e\u5927\u5c0f n \u6210\u5e73\u65b9\u5173\u7cfb\n    for i in range(n):\n        for j in range(n):\n            count += 1\n    return count\n
time_complexity.cpp
/* \u5e73\u65b9\u9636 */\nint quadratic(int n) {\n    int count = 0;\n    // \u5faa\u73af\u6b21\u6570\u4e0e\u6570\u636e\u5927\u5c0f n \u6210\u5e73\u65b9\u5173\u7cfb\n    for (int i = 0; i < n; i++) {\n        for (int j = 0; j < n; j++) {\n            count++;\n        }\n    }\n    return count;\n}\n
time_complexity.java
/* \u5e73\u65b9\u9636 */\nint quadratic(int n) {\n    int count = 0;\n    // \u5faa\u73af\u6b21\u6570\u4e0e\u6570\u636e\u5927\u5c0f n \u6210\u5e73\u65b9\u5173\u7cfb\n    for (int i = 0; i < n; i++) {\n        for (int j = 0; j < n; j++) {\n            count++;\n        }\n    }\n    return count;\n}\n
time_complexity.cs
/* \u5e73\u65b9\u9636 */\nint Quadratic(int n) {\n    int count = 0;\n    // \u5faa\u73af\u6b21\u6570\u4e0e\u6570\u636e\u5927\u5c0f n \u6210\u5e73\u65b9\u5173\u7cfb\n    for (int i = 0; i < n; i++) {\n        for (int j = 0; j < n; j++) {\n            count++;\n        }\n    }\n    return count;\n}\n
time_complexity.go
/* \u5e73\u65b9\u9636 */\nfunc quadratic(n int) int {\n    count := 0\n    // \u5faa\u73af\u6b21\u6570\u4e0e\u6570\u636e\u5927\u5c0f n \u6210\u5e73\u65b9\u5173\u7cfb\n    for i := 0; i < n; i++ {\n        for j := 0; j < n; j++ {\n            count++\n        }\n    }\n    return count\n}\n
time_complexity.swift
/* \u5e73\u65b9\u9636 */\nfunc quadratic(n: Int) -> Int {\n    var count = 0\n    // \u5faa\u73af\u6b21\u6570\u4e0e\u6570\u636e\u5927\u5c0f n \u6210\u5e73\u65b9\u5173\u7cfb\n    for _ in 0 ..< n {\n        for _ in 0 ..< n {\n            count += 1\n        }\n    }\n    return count\n}\n
time_complexity.js
/* \u5e73\u65b9\u9636 */\nfunction quadratic(n) {\n    let count = 0;\n    // \u5faa\u73af\u6b21\u6570\u4e0e\u6570\u636e\u5927\u5c0f n \u6210\u5e73\u65b9\u5173\u7cfb\n    for (let i = 0; i < n; i++) {\n        for (let j = 0; j < n; j++) {\n            count++;\n        }\n    }\n    return count;\n}\n
time_complexity.ts
/* \u5e73\u65b9\u9636 */\nfunction quadratic(n: number): number {\n    let count = 0;\n    // \u5faa\u73af\u6b21\u6570\u4e0e\u6570\u636e\u5927\u5c0f n \u6210\u5e73\u65b9\u5173\u7cfb\n    for (let i = 0; i < n; i++) {\n        for (let j = 0; j < n; j++) {\n            count++;\n        }\n    }\n    return count;\n}\n
time_complexity.dart
/* \u5e73\u65b9\u9636 */\nint quadratic(int n) {\n  int count = 0;\n  // \u5faa\u73af\u6b21\u6570\u4e0e\u6570\u636e\u5927\u5c0f n \u6210\u5e73\u65b9\u5173\u7cfb\n  for (int i = 0; i < n; i++) {\n    for (int j = 0; j < n; j++) {\n      count++;\n    }\n  }\n  return count;\n}\n
time_complexity.rs
/* \u5e73\u65b9\u9636 */\nfn quadratic(n: i32) -> i32 {\n    let mut count = 0;\n    // \u5faa\u73af\u6b21\u6570\u4e0e\u6570\u636e\u5927\u5c0f n \u6210\u5e73\u65b9\u5173\u7cfb\n    for _ in 0..n {\n        for _ in 0..n {\n            count += 1;\n        }\n    }\n    count\n}\n
time_complexity.c
/* \u5e73\u65b9\u9636 */\nint quadratic(int n) {\n    int count = 0;\n    // \u5faa\u73af\u6b21\u6570\u4e0e\u6570\u636e\u5927\u5c0f n \u6210\u5e73\u65b9\u5173\u7cfb\n    for (int i = 0; i < n; i++) {\n        for (int j = 0; j < n; j++) {\n            count++;\n        }\n    }\n    return count;\n}\n
time_complexity.zig
// \u5e73\u65b9\u9636\nfn quadratic(n: i32) i32 {\n    var count: i32 = 0;\n    var i: i32 = 0;\n    // \u5faa\u73af\u6b21\u6570\u4e0e\u6570\u636e\u5927\u5c0f n \u6210\u5e73\u65b9\u5173\u7cfb\n    while (i < n) : (i += 1) {\n        var j: i32 = 0;\n        while (j < n) : (j += 1) {\n            count += 1;\n        }\n    }\n    return count;\n}\n
Code Visualization

Full Screen >

The following image compares constant order, linear order, and quadratic order time complexities.

Figure 2-10 \u00a0 Constant, Linear, and Quadratic Order Time Complexities

For instance, in bubble sort, the outer loop runs \\(n - 1\\) times, and the inner loop runs \\(n-1\\), \\(n-2\\), ..., \\(2\\), \\(1\\) times, averaging \\(n / 2\\) times, resulting in a time complexity of \\(O((n - 1) n / 2) = O(n^2)\\):

PythonC++JavaC#GoSwiftJSTSDartRustCZig time_complexity.py
def bubble_sort(nums: list[int]) -> int:\n    \"\"\"\u5e73\u65b9\u9636\uff08\u5192\u6ce1\u6392\u5e8f\uff09\"\"\"\n    count = 0  # \u8ba1\u6570\u5668\n    # \u5916\u5faa\u73af\uff1a\u672a\u6392\u5e8f\u533a\u95f4\u4e3a [0, i]\n    for i in range(len(nums) - 1, 0, -1):\n        # \u5185\u5faa\u73af\uff1a\u5c06\u672a\u6392\u5e8f\u533a\u95f4 [0, i] \u4e2d\u7684\u6700\u5927\u5143\u7d20\u4ea4\u6362\u81f3\u8be5\u533a\u95f4\u7684\u6700\u53f3\u7aef\n        for j in range(i):\n            if nums[j] > nums[j + 1]:\n                # \u4ea4\u6362 nums[j] \u4e0e nums[j + 1]\n                tmp: int = nums[j]\n                nums[j] = nums[j + 1]\n                nums[j + 1] = tmp\n                count += 3  # \u5143\u7d20\u4ea4\u6362\u5305\u542b 3 \u4e2a\u5355\u5143\u64cd\u4f5c\n    return count\n
time_complexity.cpp
/* \u5e73\u65b9\u9636\uff08\u5192\u6ce1\u6392\u5e8f\uff09 */\nint bubbleSort(vector<int> &nums) {\n    int count = 0; // \u8ba1\u6570\u5668\n    // \u5916\u5faa\u73af\uff1a\u672a\u6392\u5e8f\u533a\u95f4\u4e3a [0, i]\n    for (int i = nums.size() - 1; i > 0; i--) {\n        // \u5185\u5faa\u73af\uff1a\u5c06\u672a\u6392\u5e8f\u533a\u95f4 [0, i] \u4e2d\u7684\u6700\u5927\u5143\u7d20\u4ea4\u6362\u81f3\u8be5\u533a\u95f4\u7684\u6700\u53f3\u7aef\n        for (int j = 0; j < i; j++) {\n            if (nums[j] > nums[j + 1]) {\n                // \u4ea4\u6362 nums[j] \u4e0e nums[j + 1]\n                int tmp = nums[j];\n                nums[j] = nums[j + 1];\n                nums[j + 1] = tmp;\n                count += 3; // \u5143\u7d20\u4ea4\u6362\u5305\u542b 3 \u4e2a\u5355\u5143\u64cd\u4f5c\n            }\n        }\n    }\n    return count;\n}\n
time_complexity.java
/* \u5e73\u65b9\u9636\uff08\u5192\u6ce1\u6392\u5e8f\uff09 */\nint bubbleSort(int[] nums) {\n    int count = 0; // \u8ba1\u6570\u5668\n    // \u5916\u5faa\u73af\uff1a\u672a\u6392\u5e8f\u533a\u95f4\u4e3a [0, i]\n    for (int i = nums.length - 1; i > 0; i--) {\n        // \u5185\u5faa\u73af\uff1a\u5c06\u672a\u6392\u5e8f\u533a\u95f4 [0, i] \u4e2d\u7684\u6700\u5927\u5143\u7d20\u4ea4\u6362\u81f3\u8be5\u533a\u95f4\u7684\u6700\u53f3\u7aef\n        for (int j = 0; j < i; j++) {\n            if (nums[j] > nums[j + 1]) {\n                // \u4ea4\u6362 nums[j] \u4e0e nums[j + 1]\n                int tmp = nums[j];\n                nums[j] = nums[j + 1];\n                nums[j + 1] = tmp;\n                count += 3; // \u5143\u7d20\u4ea4\u6362\u5305\u542b 3 \u4e2a\u5355\u5143\u64cd\u4f5c\n            }\n        }\n    }\n    return count;\n}\n
time_complexity.cs
/* \u5e73\u65b9\u9636\uff08\u5192\u6ce1\u6392\u5e8f\uff09 */\nint BubbleSort(int[] nums) {\n    int count = 0;  // \u8ba1\u6570\u5668\n    // \u5916\u5faa\u73af\uff1a\u672a\u6392\u5e8f\u533a\u95f4\u4e3a [0, i]\n    for (int i = nums.Length - 1; i > 0; i--) {\n        // \u5185\u5faa\u73af\uff1a\u5c06\u672a\u6392\u5e8f\u533a\u95f4 [0, i] \u4e2d\u7684\u6700\u5927\u5143\u7d20\u4ea4\u6362\u81f3\u8be5\u533a\u95f4\u7684\u6700\u53f3\u7aef\n        for (int j = 0; j < i; j++) {\n            if (nums[j] > nums[j + 1]) {\n                // \u4ea4\u6362 nums[j] \u4e0e nums[j + 1]\n                (nums[j + 1], nums[j]) = (nums[j], nums[j + 1]);\n                count += 3;  // \u5143\u7d20\u4ea4\u6362\u5305\u542b 3 \u4e2a\u5355\u5143\u64cd\u4f5c\n            }\n        }\n    }\n    return count;\n}\n
time_complexity.go
/* \u5e73\u65b9\u9636\uff08\u5192\u6ce1\u6392\u5e8f\uff09 */\nfunc bubbleSort(nums []int) int {\n    count := 0 // \u8ba1\u6570\u5668\n    // \u5916\u5faa\u73af\uff1a\u672a\u6392\u5e8f\u533a\u95f4\u4e3a [0, i]\n    for i := len(nums) - 1; i > 0; i-- {\n        // \u5185\u5faa\u73af\uff1a\u5c06\u672a\u6392\u5e8f\u533a\u95f4 [0, i] \u4e2d\u7684\u6700\u5927\u5143\u7d20\u4ea4\u6362\u81f3\u8be5\u533a\u95f4\u7684\u6700\u53f3\u7aef\n        for j := 0; j < i; j++ {\n            if nums[j] > nums[j+1] {\n                // \u4ea4\u6362 nums[j] \u4e0e nums[j + 1]\n                tmp := nums[j]\n                nums[j] = nums[j+1]\n                nums[j+1] = tmp\n                count += 3 // \u5143\u7d20\u4ea4\u6362\u5305\u542b 3 \u4e2a\u5355\u5143\u64cd\u4f5c\n            }\n        }\n    }\n    return count\n}\n
time_complexity.swift
/* \u5e73\u65b9\u9636\uff08\u5192\u6ce1\u6392\u5e8f\uff09 */\nfunc bubbleSort(nums: inout [Int]) -> Int {\n    var count = 0 // \u8ba1\u6570\u5668\n    // \u5916\u5faa\u73af\uff1a\u672a\u6392\u5e8f\u533a\u95f4\u4e3a [0, i]\n    for i in nums.indices.dropFirst().reversed() {\n        // \u5185\u5faa\u73af\uff1a\u5c06\u672a\u6392\u5e8f\u533a\u95f4 [0, i] \u4e2d\u7684\u6700\u5927\u5143\u7d20\u4ea4\u6362\u81f3\u8be5\u533a\u95f4\u7684\u6700\u53f3\u7aef\n        for j in 0 ..< i {\n            if nums[j] > nums[j + 1] {\n                // \u4ea4\u6362 nums[j] \u4e0e nums[j + 1]\n                let tmp = nums[j]\n                nums[j] = nums[j + 1]\n                nums[j + 1] = tmp\n                count += 3 // \u5143\u7d20\u4ea4\u6362\u5305\u542b 3 \u4e2a\u5355\u5143\u64cd\u4f5c\n            }\n        }\n    }\n    return count\n}\n
time_complexity.js
/* \u5e73\u65b9\u9636\uff08\u5192\u6ce1\u6392\u5e8f\uff09 */\nfunction bubbleSort(nums) {\n    let count = 0; // \u8ba1\u6570\u5668\n    // \u5916\u5faa\u73af\uff1a\u672a\u6392\u5e8f\u533a\u95f4\u4e3a [0, i]\n    for (let i = nums.length - 1; i > 0; i--) {\n        // \u5185\u5faa\u73af\uff1a\u5c06\u672a\u6392\u5e8f\u533a\u95f4 [0, i] \u4e2d\u7684\u6700\u5927\u5143\u7d20\u4ea4\u6362\u81f3\u8be5\u533a\u95f4\u7684\u6700\u53f3\u7aef\n        for (let j = 0; j < i; j++) {\n            if (nums[j] > nums[j + 1]) {\n                // \u4ea4\u6362 nums[j] \u4e0e nums[j + 1]\n                let tmp = nums[j];\n                nums[j] = nums[j + 1];\n                nums[j + 1] = tmp;\n                count += 3; // \u5143\u7d20\u4ea4\u6362\u5305\u542b 3 \u4e2a\u5355\u5143\u64cd\u4f5c\n            }\n        }\n    }\n    return count;\n}\n
time_complexity.ts
/* \u5e73\u65b9\u9636\uff08\u5192\u6ce1\u6392\u5e8f\uff09 */\nfunction bubbleSort(nums: number[]): number {\n    let count = 0; // \u8ba1\u6570\u5668\n    // \u5916\u5faa\u73af\uff1a\u672a\u6392\u5e8f\u533a\u95f4\u4e3a [0, i]\n    for (let i = nums.length - 1; i > 0; i--) {\n        // \u5185\u5faa\u73af\uff1a\u5c06\u672a\u6392\u5e8f\u533a\u95f4 [0, i] \u4e2d\u7684\u6700\u5927\u5143\u7d20\u4ea4\u6362\u81f3\u8be5\u533a\u95f4\u7684\u6700\u53f3\u7aef\n        for (let j = 0; j < i; j++) {\n            if (nums[j] > nums[j + 1]) {\n                // \u4ea4\u6362 nums[j] \u4e0e nums[j + 1]\n                let tmp = nums[j];\n                nums[j] = nums[j + 1];\n                nums[j + 1] = tmp;\n                count += 3; // \u5143\u7d20\u4ea4\u6362\u5305\u542b 3 \u4e2a\u5355\u5143\u64cd\u4f5c\n            }\n        }\n    }\n    return count;\n}\n
time_complexity.dart
/* \u5e73\u65b9\u9636\uff08\u5192\u6ce1\u6392\u5e8f\uff09 */\nint bubbleSort(List<int> nums) {\n  int count = 0; // \u8ba1\u6570\u5668\n  // \u5916\u5faa\u73af\uff1a\u672a\u6392\u5e8f\u533a\u95f4\u4e3a [0, i]\n  for (var i = nums.length - 1; i > 0; i--) {\n    // \u5185\u5faa\u73af\uff1a\u5c06\u672a\u6392\u5e8f\u533a\u95f4 [0, i] \u4e2d\u7684\u6700\u5927\u5143\u7d20\u4ea4\u6362\u81f3\u8be5\u533a\u95f4\u7684\u6700\u53f3\u7aef\n    for (var j = 0; j < i; j++) {\n      if (nums[j] > nums[j + 1]) {\n        // \u4ea4\u6362 nums[j] \u4e0e nums[j + 1]\n        int tmp = nums[j];\n        nums[j] = nums[j + 1];\n        nums[j + 1] = tmp;\n        count += 3; // \u5143\u7d20\u4ea4\u6362\u5305\u542b 3 \u4e2a\u5355\u5143\u64cd\u4f5c\n      }\n    }\n  }\n  return count;\n}\n
time_complexity.rs
/* \u5e73\u65b9\u9636\uff08\u5192\u6ce1\u6392\u5e8f\uff09 */\nfn bubble_sort(nums: &mut [i32]) -> i32 {\n    let mut count = 0; // \u8ba1\u6570\u5668\n\n    // \u5916\u5faa\u73af\uff1a\u672a\u6392\u5e8f\u533a\u95f4\u4e3a [0, i]\n    for i in (1..nums.len()).rev() {\n        // \u5185\u5faa\u73af\uff1a\u5c06\u672a\u6392\u5e8f\u533a\u95f4 [0, i] \u4e2d\u7684\u6700\u5927\u5143\u7d20\u4ea4\u6362\u81f3\u8be5\u533a\u95f4\u7684\u6700\u53f3\u7aef\n        for j in 0..i {\n            if nums[j] > nums[j + 1] {\n                // \u4ea4\u6362 nums[j] \u4e0e nums[j + 1]\n                let tmp = nums[j];\n                nums[j] = nums[j + 1];\n                nums[j + 1] = tmp;\n                count += 3; // \u5143\u7d20\u4ea4\u6362\u5305\u542b 3 \u4e2a\u5355\u5143\u64cd\u4f5c\n            }\n        }\n    }\n    count\n}\n
time_complexity.c
/* \u5e73\u65b9\u9636\uff08\u5192\u6ce1\u6392\u5e8f\uff09 */\nint bubbleSort(int *nums, int n) {\n    int count = 0; // \u8ba1\u6570\u5668\n    // \u5916\u5faa\u73af\uff1a\u672a\u6392\u5e8f\u533a\u95f4\u4e3a [0, i]\n    for (int i = n - 1; i > 0; i--) {\n        // \u5185\u5faa\u73af\uff1a\u5c06\u672a\u6392\u5e8f\u533a\u95f4 [0, i] \u4e2d\u7684\u6700\u5927\u5143\u7d20\u4ea4\u6362\u81f3\u8be5\u533a\u95f4\u7684\u6700\u53f3\u7aef\n        for (int j = 0; j < i; j++) {\n            if (nums[j] > nums[j + 1]) {\n                // \u4ea4\u6362 nums[j] \u4e0e nums[j + 1]\n                int tmp = nums[j];\n                nums[j] = nums[j + 1];\n                nums[j + 1] = tmp;\n                count += 3; // \u5143\u7d20\u4ea4\u6362\u5305\u542b 3 \u4e2a\u5355\u5143\u64cd\u4f5c\n            }\n        }\n    }\n    return count;\n}\n
time_complexity.zig
// \u5e73\u65b9\u9636\uff08\u5192\u6ce1\u6392\u5e8f\uff09\nfn bubbleSort(nums: []i32) i32 {\n    var count: i32 = 0;  // \u8ba1\u6570\u5668 \n    // \u5916\u5faa\u73af\uff1a\u672a\u6392\u5e8f\u533a\u95f4\u4e3a [0, i]\n    var i: i32 = @as(i32, @intCast(nums.len)) - 1;\n    while (i > 0) : (i -= 1) {\n        var j: usize = 0;\n        // \u5185\u5faa\u73af\uff1a\u5c06\u672a\u6392\u5e8f\u533a\u95f4 [0, i] \u4e2d\u7684\u6700\u5927\u5143\u7d20\u4ea4\u6362\u81f3\u8be5\u533a\u95f4\u7684\u6700\u53f3\u7aef\n        while (j < i) : (j += 1) {\n            if (nums[j] > nums[j + 1]) {\n                // \u4ea4\u6362 nums[j] \u4e0e nums[j + 1]\n                var tmp = nums[j];\n                nums[j] = nums[j + 1];\n                nums[j + 1] = tmp;\n                count += 3;  // \u5143\u7d20\u4ea4\u6362\u5305\u542b 3 \u4e2a\u5355\u5143\u64cd\u4f5c\n            }\n        }\n    }\n    return count;\n}\n
Code Visualization

Full Screen >

"},{"location":"chapter_computational_complexity/time_complexity/#4-exponential-order-o2n","title":"4. \u00a0 Exponential Order \\(O(2^n)\\)","text":"

Biological \"cell division\" is a classic example of exponential order growth: starting with one cell, it becomes two after one division, four after two divisions, and so on, resulting in \\(2^n\\) cells after \\(n\\) divisions.

The following image and code simulate the cell division process, with a time complexity of \\(O(2^n)\\):

PythonC++JavaC#GoSwiftJSTSDartRustCZig time_complexity.py
def exponential(n: int) -> int:\n    \"\"\"\u6307\u6570\u9636\uff08\u5faa\u73af\u5b9e\u73b0\uff09\"\"\"\n    count = 0\n    base = 1\n    # \u7ec6\u80de\u6bcf\u8f6e\u4e00\u5206\u4e3a\u4e8c\uff0c\u5f62\u6210\u6570\u5217 1, 2, 4, 8, ..., 2^(n-1)\n    for _ in range(n):\n        for _ in range(base):\n            count += 1\n        base *= 2\n    # count = 1 + 2 + 4 + 8 + .. + 2^(n-1) = 2^n - 1\n    return count\n
time_complexity.cpp
/* \u6307\u6570\u9636\uff08\u5faa\u73af\u5b9e\u73b0\uff09 */\nint exponential(int n) {\n    int count = 0, base = 1;\n    // \u7ec6\u80de\u6bcf\u8f6e\u4e00\u5206\u4e3a\u4e8c\uff0c\u5f62\u6210\u6570\u5217 1, 2, 4, 8, ..., 2^(n-1)\n    for (int i = 0; i < n; i++) {\n        for (int j = 0; j < base; j++) {\n            count++;\n        }\n        base *= 2;\n    }\n    // count = 1 + 2 + 4 + 8 + .. + 2^(n-1) = 2^n - 1\n    return count;\n}\n
time_complexity.java
/* \u6307\u6570\u9636\uff08\u5faa\u73af\u5b9e\u73b0\uff09 */\nint exponential(int n) {\n    int count = 0, base = 1;\n    // \u7ec6\u80de\u6bcf\u8f6e\u4e00\u5206\u4e3a\u4e8c\uff0c\u5f62\u6210\u6570\u5217 1, 2, 4, 8, ..., 2^(n-1)\n    for (int i = 0; i < n; i++) {\n        for (int j = 0; j < base; j++) {\n            count++;\n        }\n        base *= 2;\n    }\n    // count = 1 + 2 + 4 + 8 + .. + 2^(n-1) = 2^n - 1\n    return count;\n}\n
time_complexity.cs
/* \u6307\u6570\u9636\uff08\u5faa\u73af\u5b9e\u73b0\uff09 */\nint Exponential(int n) {\n    int count = 0, bas = 1;\n    // \u7ec6\u80de\u6bcf\u8f6e\u4e00\u5206\u4e3a\u4e8c\uff0c\u5f62\u6210\u6570\u5217 1, 2, 4, 8, ..., 2^(n-1)\n    for (int i = 0; i < n; i++) {\n        for (int j = 0; j < bas; j++) {\n            count++;\n        }\n        bas *= 2;\n    }\n    // count = 1 + 2 + 4 + 8 + .. + 2^(n-1) = 2^n - 1\n    return count;\n}\n
time_complexity.go
/* \u6307\u6570\u9636\uff08\u5faa\u73af\u5b9e\u73b0\uff09*/\nfunc exponential(n int) int {\n    count, base := 0, 1\n    // \u7ec6\u80de\u6bcf\u8f6e\u4e00\u5206\u4e3a\u4e8c\uff0c\u5f62\u6210\u6570\u5217 1, 2, 4, 8, ..., 2^(n-1)\n    for i := 0; i < n; i++ {\n        for j := 0; j < base; j++ {\n            count++\n        }\n        base *= 2\n    }\n    // count = 1 + 2 + 4 + 8 + .. + 2^(n-1) = 2^n - 1\n    return count\n}\n
time_complexity.swift
/* \u6307\u6570\u9636\uff08\u5faa\u73af\u5b9e\u73b0\uff09 */\nfunc exponential(n: Int) -> Int {\n    var count = 0\n    var base = 1\n    // \u7ec6\u80de\u6bcf\u8f6e\u4e00\u5206\u4e3a\u4e8c\uff0c\u5f62\u6210\u6570\u5217 1, 2, 4, 8, ..., 2^(n-1)\n    for _ in 0 ..< n {\n        for _ in 0 ..< base {\n            count += 1\n        }\n        base *= 2\n    }\n    // count = 1 + 2 + 4 + 8 + .. + 2^(n-1) = 2^n - 1\n    return count\n}\n
time_complexity.js
/* \u6307\u6570\u9636\uff08\u5faa\u73af\u5b9e\u73b0\uff09 */\nfunction exponential(n) {\n    let count = 0,\n        base = 1;\n    // \u7ec6\u80de\u6bcf\u8f6e\u4e00\u5206\u4e3a\u4e8c\uff0c\u5f62\u6210\u6570\u5217 1, 2, 4, 8, ..., 2^(n-1)\n    for (let i = 0; i < n; i++) {\n        for (let j = 0; j < base; j++) {\n            count++;\n        }\n        base *= 2;\n    }\n    // count = 1 + 2 + 4 + 8 + .. + 2^(n-1) = 2^n - 1\n    return count;\n}\n
time_complexity.ts
/* \u6307\u6570\u9636\uff08\u5faa\u73af\u5b9e\u73b0\uff09 */\nfunction exponential(n: number): number {\n    let count = 0,\n        base = 1;\n    // \u7ec6\u80de\u6bcf\u8f6e\u4e00\u5206\u4e3a\u4e8c\uff0c\u5f62\u6210\u6570\u5217 1, 2, 4, 8, ..., 2^(n-1)\n    for (let i = 0; i < n; i++) {\n        for (let j = 0; j < base; j++) {\n            count++;\n        }\n        base *= 2;\n    }\n    // count = 1 + 2 + 4 + 8 + .. + 2^(n-1) = 2^n - 1\n    return count;\n}\n
time_complexity.dart
/* \u6307\u6570\u9636\uff08\u5faa\u73af\u5b9e\u73b0\uff09 */\nint exponential(int n) {\n  int count = 0, base = 1;\n  // \u7ec6\u80de\u6bcf\u8f6e\u4e00\u5206\u4e3a\u4e8c\uff0c\u5f62\u6210\u6570\u5217 1, 2, 4, 8, ..., 2^(n-1)\n  for (var i = 0; i < n; i++) {\n    for (var j = 0; j < base; j++) {\n      count++;\n    }\n    base *= 2;\n  }\n  // count = 1 + 2 + 4 + 8 + .. + 2^(n-1) = 2^n - 1\n  return count;\n}\n
time_complexity.rs
/* \u6307\u6570\u9636\uff08\u5faa\u73af\u5b9e\u73b0\uff09 */\nfn exponential(n: i32) -> i32 {\n    let mut count = 0;\n    let mut base = 1;\n    // \u7ec6\u80de\u6bcf\u8f6e\u4e00\u5206\u4e3a\u4e8c\uff0c\u5f62\u6210\u6570\u5217 1, 2, 4, 8, ..., 2^(n-1)\n    for _ in 0..n {\n        for _ in 0..base {\n            count += 1\n        }\n        base *= 2;\n    }\n    // count = 1 + 2 + 4 + 8 + .. + 2^(n-1) = 2^n - 1\n    count\n}\n
time_complexity.c
/* \u6307\u6570\u9636\uff08\u5faa\u73af\u5b9e\u73b0\uff09 */\nint exponential(int n) {\n    int count = 0;\n    int bas = 1;\n    // \u7ec6\u80de\u6bcf\u8f6e\u4e00\u5206\u4e3a\u4e8c\uff0c\u5f62\u6210\u6570\u5217 1, 2, 4, 8, ..., 2^(n-1)\n    for (int i = 0; i < n; i++) {\n        for (int j = 0; j < bas; j++) {\n            count++;\n        }\n        bas *= 2;\n    }\n    // count = 1 + 2 + 4 + 8 + .. + 2^(n-1) = 2^n - 1\n    return count;\n}\n
time_complexity.zig
// \u6307\u6570\u9636\uff08\u5faa\u73af\u5b9e\u73b0\uff09\nfn exponential(n: i32) i32 {\n    var count: i32 = 0;\n    var bas: i32 = 1;\n    var i: i32 = 0;\n    // \u7ec6\u80de\u6bcf\u8f6e\u4e00\u5206\u4e3a\u4e8c\uff0c\u5f62\u6210\u6570\u5217 1, 2, 4, 8, ..., 2^(n-1)\n    while (i < n) : (i += 1) {\n        var j: i32 = 0;\n        while (j < bas) : (j += 1) {\n            count += 1;\n        }\n        bas *= 2;\n    }\n    // count = 1 + 2 + 4 + 8 + .. + 2^(n-1) = 2^n - 1\n    return count;\n}\n
Code Visualization

Full Screen >

Figure 2-11 \u00a0 Exponential Order Time Complexity

In practice, exponential order often appears in recursive functions. For example, in the code below, it recursively splits into two halves, stopping after \\(n\\) divisions:

PythonC++JavaC#GoSwiftJSTSDartRustCZig time_complexity.py
def exp_recur(n: int) -> int:\n    \"\"\"\u6307\u6570\u9636\uff08\u9012\u5f52\u5b9e\u73b0\uff09\"\"\"\n    if n == 1:\n        return 1\n    return exp_recur(n - 1) + exp_recur(n - 1) + 1\n
time_complexity.cpp
/* \u6307\u6570\u9636\uff08\u9012\u5f52\u5b9e\u73b0\uff09 */\nint expRecur(int n) {\n    if (n == 1)\n        return 1;\n    return expRecur(n - 1) + expRecur(n - 1) + 1;\n}\n
time_complexity.java
/* \u6307\u6570\u9636\uff08\u9012\u5f52\u5b9e\u73b0\uff09 */\nint expRecur(int n) {\n    if (n == 1)\n        return 1;\n    return expRecur(n - 1) + expRecur(n - 1) + 1;\n}\n
time_complexity.cs
/* \u6307\u6570\u9636\uff08\u9012\u5f52\u5b9e\u73b0\uff09 */\nint ExpRecur(int n) {\n    if (n == 1) return 1;\n    return ExpRecur(n - 1) + ExpRecur(n - 1) + 1;\n}\n
time_complexity.go
/* \u6307\u6570\u9636\uff08\u9012\u5f52\u5b9e\u73b0\uff09*/\nfunc expRecur(n int) int {\n    if n == 1 {\n        return 1\n    }\n    return expRecur(n-1) + expRecur(n-1) + 1\n}\n
time_complexity.swift
/* \u6307\u6570\u9636\uff08\u9012\u5f52\u5b9e\u73b0\uff09 */\nfunc expRecur(n: Int) -> Int {\n    if n == 1 {\n        return 1\n    }\n    return expRecur(n: n - 1) + expRecur(n: n - 1) + 1\n}\n
time_complexity.js
/* \u6307\u6570\u9636\uff08\u9012\u5f52\u5b9e\u73b0\uff09 */\nfunction expRecur(n) {\n    if (n === 1) return 1;\n    return expRecur(n - 1) + expRecur(n - 1) + 1;\n}\n
time_complexity.ts
/* \u6307\u6570\u9636\uff08\u9012\u5f52\u5b9e\u73b0\uff09 */\nfunction expRecur(n: number): number {\n    if (n === 1) return 1;\n    return expRecur(n - 1) + expRecur(n - 1) + 1;\n}\n
time_complexity.dart
/* \u6307\u6570\u9636\uff08\u9012\u5f52\u5b9e\u73b0\uff09 */\nint expRecur(int n) {\n  if (n == 1) return 1;\n  return expRecur(n - 1) + expRecur(n - 1) + 1;\n}\n
time_complexity.rs
/* \u6307\u6570\u9636\uff08\u9012\u5f52\u5b9e\u73b0\uff09 */\nfn exp_recur(n: i32) -> i32 {\n    if n == 1 {\n        return 1;\n    }\n    exp_recur(n - 1) + exp_recur(n - 1) + 1\n}\n
time_complexity.c
/* \u6307\u6570\u9636\uff08\u9012\u5f52\u5b9e\u73b0\uff09 */\nint expRecur(int n) {\n    if (n == 1)\n        return 1;\n    return expRecur(n - 1) + expRecur(n - 1) + 1;\n}\n
time_complexity.zig
// \u6307\u6570\u9636\uff08\u9012\u5f52\u5b9e\u73b0\uff09\nfn expRecur(n: i32) i32 {\n    if (n == 1) return 1;\n    return expRecur(n - 1) + expRecur(n - 1) + 1;\n}\n
Code Visualization

Full Screen >

Exponential order growth is extremely rapid and is commonly seen in exhaustive search methods (brute force, backtracking, etc.). For large-scale problems, exponential order is unacceptable, often requiring dynamic programming or greedy algorithms as solutions.

"},{"location":"chapter_computational_complexity/time_complexity/#5-logarithmic-order-olog-n","title":"5. \u00a0 Logarithmic Order \\(O(\\log n)\\)","text":"

In contrast to exponential order, logarithmic order reflects situations where \"the size is halved each round.\" Given an input data size \\(n\\), since the size is halved each round, the number of iterations is \\(\\log_2 n\\), the inverse function of \\(2^n\\).

The following image and code simulate the \"halving each round\" process, with a time complexity of \\(O(\\log_2 n)\\), commonly abbreviated as \\(O(\\log n)\\):

PythonC++JavaC#GoSwiftJSTSDartRustCZig time_complexity.py
def logarithmic(n: int) -> int:\n    \"\"\"\u5bf9\u6570\u9636\uff08\u5faa\u73af\u5b9e\u73b0\uff09\"\"\"\n    count = 0\n    while n > 1:\n        n = n / 2\n        count += 1\n    return count\n
time_complexity.cpp
/* \u5bf9\u6570\u9636\uff08\u5faa\u73af\u5b9e\u73b0\uff09 */\nint logarithmic(int n) {\n    int count = 0;\n    while (n > 1) {\n        n = n / 2;\n        count++;\n    }\n    return count;\n}\n
time_complexity.java
/* \u5bf9\u6570\u9636\uff08\u5faa\u73af\u5b9e\u73b0\uff09 */\nint logarithmic(int n) {\n    int count = 0;\n    while (n > 1) {\n        n = n / 2;\n        count++;\n    }\n    return count;\n}\n
time_complexity.cs
/* \u5bf9\u6570\u9636\uff08\u5faa\u73af\u5b9e\u73b0\uff09 */\nint Logarithmic(int n) {\n    int count = 0;\n    while (n > 1) {\n        n /= 2;\n        count++;\n    }\n    return count;\n}\n
time_complexity.go
/* \u5bf9\u6570\u9636\uff08\u5faa\u73af\u5b9e\u73b0\uff09*/\nfunc logarithmic(n int) int {\n    count := 0\n    for n > 1 {\n        n = n / 2\n        count++\n    }\n    return count\n}\n
time_complexity.swift
/* \u5bf9\u6570\u9636\uff08\u5faa\u73af\u5b9e\u73b0\uff09 */\nfunc logarithmic(n: Int) -> Int {\n    var count = 0\n    var n = n\n    while n > 1 {\n        n = n / 2\n        count += 1\n    }\n    return count\n}\n
time_complexity.js
/* \u5bf9\u6570\u9636\uff08\u5faa\u73af\u5b9e\u73b0\uff09 */\nfunction logarithmic(n) {\n    let count = 0;\n    while (n > 1) {\n        n = n / 2;\n        count++;\n    }\n    return count;\n}\n
time_complexity.ts
/* \u5bf9\u6570\u9636\uff08\u5faa\u73af\u5b9e\u73b0\uff09 */\nfunction logarithmic(n: number): number {\n    let count = 0;\n    while (n > 1) {\n        n = n / 2;\n        count++;\n    }\n    return count;\n}\n
time_complexity.dart
/* \u5bf9\u6570\u9636\uff08\u5faa\u73af\u5b9e\u73b0\uff09 */\nint logarithmic(int n) {\n  int count = 0;\n  while (n > 1) {\n    n = n ~/ 2;\n    count++;\n  }\n  return count;\n}\n
time_complexity.rs
/* \u5bf9\u6570\u9636\uff08\u5faa\u73af\u5b9e\u73b0\uff09 */\nfn logarithmic(mut n: i32) -> i32 {\n    let mut count = 0;\n    while n > 1 {\n        n = n / 2;\n        count += 1;\n    }\n    count\n}\n
time_complexity.c
/* \u5bf9\u6570\u9636\uff08\u5faa\u73af\u5b9e\u73b0\uff09 */\nint logarithmic(int n) {\n    int count = 0;\n    while (n > 1) {\n        n = n / 2;\n        count++;\n    }\n    return count;\n}\n
time_complexity.zig
// \u5bf9\u6570\u9636\uff08\u5faa\u73af\u5b9e\u73b0\uff09\nfn logarithmic(n: i32) i32 {\n    var count: i32 = 0;\n    var n_var = n;\n    while (n_var > 1)\n    {\n        n_var = n_var / 2;\n        count +=1;\n    }\n    return count;\n}\n
Code Visualization

Full Screen >

Figure 2-12 \u00a0 Logarithmic Order Time Complexity

Like exponential order, logarithmic order also frequently appears in recursive functions. The code below forms a recursive tree of height \\(\\log_2 n\\):

PythonC++JavaC#GoSwiftJSTSDartRustCZig time_complexity.py
def log_recur(n: int) -> int:\n    \"\"\"\u5bf9\u6570\u9636\uff08\u9012\u5f52\u5b9e\u73b0\uff09\"\"\"\n    if n <= 1:\n        return 0\n    return log_recur(n / 2) + 1\n
time_complexity.cpp
/* \u5bf9\u6570\u9636\uff08\u9012\u5f52\u5b9e\u73b0\uff09 */\nint logRecur(int n) {\n    if (n <= 1)\n        return 0;\n    return logRecur(n / 2) + 1;\n}\n
time_complexity.java
/* \u5bf9\u6570\u9636\uff08\u9012\u5f52\u5b9e\u73b0\uff09 */\nint logRecur(int n) {\n    if (n <= 1)\n        return 0;\n    return logRecur(n / 2) + 1;\n}\n
time_complexity.cs
/* \u5bf9\u6570\u9636\uff08\u9012\u5f52\u5b9e\u73b0\uff09 */\nint LogRecur(int n) {\n    if (n <= 1) return 0;\n    return LogRecur(n / 2) + 1;\n}\n
time_complexity.go
/* \u5bf9\u6570\u9636\uff08\u9012\u5f52\u5b9e\u73b0\uff09*/\nfunc logRecur(n int) int {\n    if n <= 1 {\n        return 0\n    }\n    return logRecur(n/2) + 1\n}\n
time_complexity.swift
/* \u5bf9\u6570\u9636\uff08\u9012\u5f52\u5b9e\u73b0\uff09 */\nfunc logRecur(n: Int) -> Int {\n    if n <= 1 {\n        return 0\n    }\n    return logRecur(n: n / 2) + 1\n}\n
time_complexity.js
/* \u5bf9\u6570\u9636\uff08\u9012\u5f52\u5b9e\u73b0\uff09 */\nfunction logRecur(n) {\n    if (n <= 1) return 0;\n    return logRecur(n / 2) + 1;\n}\n
time_complexity.ts
/* \u5bf9\u6570\u9636\uff08\u9012\u5f52\u5b9e\u73b0\uff09 */\nfunction logRecur(n: number): number {\n    if (n <= 1) return 0;\n    return logRecur(n / 2) + 1;\n}\n
time_complexity.dart
/* \u5bf9\u6570\u9636\uff08\u9012\u5f52\u5b9e\u73b0\uff09 */\nint logRecur(int n) {\n  if (n <= 1) return 0;\n  return logRecur(n ~/ 2) + 1;\n}\n
time_complexity.rs
/* \u5bf9\u6570\u9636\uff08\u9012\u5f52\u5b9e\u73b0\uff09 */\nfn log_recur(n: i32) -> i32 {\n    if n <= 1 {\n        return 0;\n    }\n    log_recur(n / 2) + 1\n}\n
time_complexity.c
/* \u5bf9\u6570\u9636\uff08\u9012\u5f52\u5b9e\u73b0\uff09 */\nint logRecur(int n) {\n    if (n <= 1)\n        return 0;\n    return logRecur(n / 2) + 1;\n}\n
time_complexity.zig
// \u5bf9\u6570\u9636\uff08\u9012\u5f52\u5b9e\u73b0\uff09\nfn logRecur(n: i32) i32 {\n    if (n <= 1) return 0;\n    return logRecur(n / 2) + 1;\n}\n
Code Visualization

Full Screen >

Logarithmic order is typical in algorithms based on the divide-and-conquer strategy, embodying the \"split into many\" and \"simplify complex problems\" approach. It's slow-growing and is the most ideal time complexity after constant order.

What is the base of \\(O(\\log n)\\)?

Technically, \"splitting into \\(m\\)\" corresponds to a time complexity of \\(O(\\log_m n)\\). Using the logarithm base change formula, we can equate different logarithmic complexities:

\\[ O(\\log_m n) = O(\\log_k n / \\log_k m) = O(\\log_k n) \\]

This means the base \\(m\\) can be changed without affecting the complexity. Therefore, we often omit the base \\(m\\) and simply denote logarithmic order as \\(O(\\log n)\\).

"},{"location":"chapter_computational_complexity/time_complexity/#6-linear-logarithmic-order-on-log-n","title":"6. \u00a0 Linear-Logarithmic Order \\(O(n \\log n)\\)","text":"

Linear-logarithmic order often appears in nested loops, with the complexities of the two loops being \\(O(\\log n)\\) and \\(O(n)\\) respectively. The related code is as follows:

PythonC++JavaC#GoSwiftJSTSDartRustCZig time_complexity.py
def linear_log_recur(n: int) -> int:\n    \"\"\"\u7ebf\u6027\u5bf9\u6570\u9636\"\"\"\n    if n <= 1:\n        return 1\n    count: int = linear_log_recur(n // 2) + linear_log_recur(n // 2)\n    for _ in range(n):\n        count += 1\n    return count\n
time_complexity.cpp
/* \u7ebf\u6027\u5bf9\u6570\u9636 */\nint linearLogRecur(int n) {\n    if (n <= 1)\n        return 1;\n    int count = linearLogRecur(n / 2) + linearLogRecur(n / 2);\n    for (int i = 0; i < n; i++) {\n        count++;\n    }\n    return count;\n}\n
time_complexity.java
/* \u7ebf\u6027\u5bf9\u6570\u9636 */\nint linearLogRecur(int n) {\n    if (n <= 1)\n        return 1;\n    int count = linearLogRecur(n / 2) + linearLogRecur(n / 2);\n    for (int i = 0; i < n; i++) {\n        count++;\n    }\n    return count;\n}\n
time_complexity.cs
/* \u7ebf\u6027\u5bf9\u6570\u9636 */\nint LinearLogRecur(int n) {\n    if (n <= 1) return 1;\n    int count = LinearLogRecur(n / 2) + LinearLogRecur(n / 2);\n    for (int i = 0; i < n; i++) {\n        count++;\n    }\n    return count;\n}\n
time_complexity.go
/* \u7ebf\u6027\u5bf9\u6570\u9636 */\nfunc linearLogRecur(n int) int {\n    if n <= 1 {\n        return 1\n    }\n    count := linearLogRecur(n/2) + linearLogRecur(n/2)\n    for i := 0; i < n; i++ {\n        count++\n    }\n    return count\n}\n
time_complexity.swift
/* \u7ebf\u6027\u5bf9\u6570\u9636 */\nfunc linearLogRecur(n: Int) -> Int {\n    if n <= 1 {\n        return 1\n    }\n    var count = linearLogRecur(n: n / 2) + linearLogRecur(n: n / 2)\n    for _ in stride(from: 0, to: n, by: 1) {\n        count += 1\n    }\n    return count\n}\n
time_complexity.js
/* \u7ebf\u6027\u5bf9\u6570\u9636 */\nfunction linearLogRecur(n) {\n    if (n <= 1) return 1;\n    let count = linearLogRecur(n / 2) + linearLogRecur(n / 2);\n    for (let i = 0; i < n; i++) {\n        count++;\n    }\n    return count;\n}\n
time_complexity.ts
/* \u7ebf\u6027\u5bf9\u6570\u9636 */\nfunction linearLogRecur(n: number): number {\n    if (n <= 1) return 1;\n    let count = linearLogRecur(n / 2) + linearLogRecur(n / 2);\n    for (let i = 0; i < n; i++) {\n        count++;\n    }\n    return count;\n}\n
time_complexity.dart
/* \u7ebf\u6027\u5bf9\u6570\u9636 */\nint linearLogRecur(int n) {\n  if (n <= 1) return 1;\n  int count = linearLogRecur(n ~/ 2) + linearLogRecur(n ~/ 2);\n  for (var i = 0; i < n; i++) {\n    count++;\n  }\n  return count;\n}\n
time_complexity.rs
/* \u7ebf\u6027\u5bf9\u6570\u9636 */\nfn linear_log_recur(n: i32) -> i32 {\n    if n <= 1 {\n        return 1;\n    }\n    let mut count = linear_log_recur(n / 2) + linear_log_recur(n / 2);\n    for _ in 0..n as i32 {\n        count += 1;\n    }\n    return count;\n}\n
time_complexity.c
/* \u7ebf\u6027\u5bf9\u6570\u9636 */\nint linearLogRecur(int n) {\n    if (n <= 1)\n        return 1;\n    int count = linearLogRecur(n / 2) + linearLogRecur(n / 2);\n    for (int i = 0; i < n; i++) {\n        count++;\n    }\n    return count;\n}\n
time_complexity.zig
// \u7ebf\u6027\u5bf9\u6570\u9636\nfn linearLogRecur(n: i32) i32 {\n    if (n <= 1) return 1;\n    var count: i32 = linearLogRecur(n / 2) + linearLogRecur(n / 2);\n    var i: i32 = 0;\n    while (i < n) : (i += 1) {\n        count += 1;\n    }\n    return count;\n}\n
Code Visualization

Full Screen >

The image below demonstrates how linear-logarithmic order is generated. Each level of a binary tree has \\(n\\) operations, and the tree has \\(\\log_2 n + 1\\) levels, resulting in a time complexity of \\(O(n \\log n)\\).

Figure 2-13 \u00a0 Linear-Logarithmic Order Time Complexity

Mainstream sorting algorithms typically have a time complexity of \\(O(n \\log n)\\), such as quicksort, mergesort, and heapsort.

"},{"location":"chapter_computational_complexity/time_complexity/#7-factorial-order-on","title":"7. \u00a0 Factorial Order \\(O(n!)\\)","text":"

Factorial order corresponds to the mathematical problem of \"full permutation.\" Given \\(n\\) distinct elements, the total number of possible permutations is:

\\[ n! = n \\times (n - 1) \\times (n - 2) \\times \\dots \\times 2 \\times 1 \\]

Factorials are typically implemented using recursion. As shown in the image and code below, the first level splits into \\(n\\) branches, the second level into \\(n - 1\\) branches, and so on, stopping after the \\(n\\)th level:

PythonC++JavaC#GoSwiftJSTSDartRustCZig time_complexity.py
def factorial_recur(n: int) -> int:\n    \"\"\"\u9636\u4e58\u9636\uff08\u9012\u5f52\u5b9e\u73b0\uff09\"\"\"\n    if n == 0:\n        return 1\n    count = 0\n    # \u4ece 1 \u4e2a\u5206\u88c2\u51fa n \u4e2a\n    for _ in range(n):\n        count += factorial_recur(n - 1)\n    return count\n
time_complexity.cpp
/* \u9636\u4e58\u9636\uff08\u9012\u5f52\u5b9e\u73b0\uff09 */\nint factorialRecur(int n) {\n    if (n == 0)\n        return 1;\n    int count = 0;\n    // \u4ece 1 \u4e2a\u5206\u88c2\u51fa n \u4e2a\n    for (int i = 0; i < n; i++) {\n        count += factorialRecur(n - 1);\n    }\n    return count;\n}\n
time_complexity.java
/* \u9636\u4e58\u9636\uff08\u9012\u5f52\u5b9e\u73b0\uff09 */\nint factorialRecur(int n) {\n    if (n == 0)\n        return 1;\n    int count = 0;\n    // \u4ece 1 \u4e2a\u5206\u88c2\u51fa n \u4e2a\n    for (int i = 0; i < n; i++) {\n        count += factorialRecur(n - 1);\n    }\n    return count;\n}\n
time_complexity.cs
/* \u9636\u4e58\u9636\uff08\u9012\u5f52\u5b9e\u73b0\uff09 */\nint FactorialRecur(int n) {\n    if (n == 0) return 1;\n    int count = 0;\n    // \u4ece 1 \u4e2a\u5206\u88c2\u51fa n \u4e2a\n    for (int i = 0; i < n; i++) {\n        count += FactorialRecur(n - 1);\n    }\n    return count;\n}\n
time_complexity.go
/* \u9636\u4e58\u9636\uff08\u9012\u5f52\u5b9e\u73b0\uff09 */\nfunc factorialRecur(n int) int {\n    if n == 0 {\n        return 1\n    }\n    count := 0\n    // \u4ece 1 \u4e2a\u5206\u88c2\u51fa n \u4e2a\n    for i := 0; i < n; i++ {\n        count += factorialRecur(n - 1)\n    }\n    return count\n}\n
time_complexity.swift
/* \u9636\u4e58\u9636\uff08\u9012\u5f52\u5b9e\u73b0\uff09 */\nfunc factorialRecur(n: Int) -> Int {\n    if n == 0 {\n        return 1\n    }\n    var count = 0\n    // \u4ece 1 \u4e2a\u5206\u88c2\u51fa n \u4e2a\n    for _ in 0 ..< n {\n        count += factorialRecur(n: n - 1)\n    }\n    return count\n}\n
time_complexity.js
/* \u9636\u4e58\u9636\uff08\u9012\u5f52\u5b9e\u73b0\uff09 */\nfunction factorialRecur(n) {\n    if (n === 0) return 1;\n    let count = 0;\n    // \u4ece 1 \u4e2a\u5206\u88c2\u51fa n \u4e2a\n    for (let i = 0; i < n; i++) {\n        count += factorialRecur(n - 1);\n    }\n    return count;\n}\n
time_complexity.ts
/* \u9636\u4e58\u9636\uff08\u9012\u5f52\u5b9e\u73b0\uff09 */\nfunction factorialRecur(n: number): number {\n    if (n === 0) return 1;\n    let count = 0;\n    // \u4ece 1 \u4e2a\u5206\u88c2\u51fa n \u4e2a\n    for (let i = 0; i < n; i++) {\n        count += factorialRecur(n - 1);\n    }\n    return count;\n}\n
time_complexity.dart
/* \u9636\u4e58\u9636\uff08\u9012\u5f52\u5b9e\u73b0\uff09 */\nint factorialRecur(int n) {\n  if (n == 0) return 1;\n  int count = 0;\n  // \u4ece 1 \u4e2a\u5206\u88c2\u51fa n \u4e2a\n  for (var i = 0; i < n; i++) {\n    count += factorialRecur(n - 1);\n  }\n  return count;\n}\n
time_complexity.rs
/* \u9636\u4e58\u9636\uff08\u9012\u5f52\u5b9e\u73b0\uff09 */\nfn factorial_recur(n: i32) -> i32 {\n    if n == 0 {\n        return 1;\n    }\n    let mut count = 0;\n    // \u4ece 1 \u4e2a\u5206\u88c2\u51fa n \u4e2a\n    for _ in 0..n {\n        count += factorial_recur(n - 1);\n    }\n    count\n}\n
time_complexity.c
/* \u9636\u4e58\u9636\uff08\u9012\u5f52\u5b9e\u73b0\uff09 */\nint factorialRecur(int n) {\n    if (n == 0)\n        return 1;\n    int count = 0;\n    for (int i = 0; i < n; i++) {\n        count += factorialRecur(n - 1);\n    }\n    return count;\n}\n
time_complexity.zig
// \u9636\u4e58\u9636\uff08\u9012\u5f52\u5b9e\u73b0\uff09\nfn factorialRecur(n: i32) i32 {\n    if (n == 0) return 1;\n    var count: i32 = 0;\n    var i: i32 = 0;\n    // \u4ece 1 \u4e2a\u5206\u88c2\u51fa n \u4e2a\n    while (i < n) : (i += 1) {\n        count += factorialRecur(n - 1);\n    }\n    return count;\n}\n
Code Visualization

Full Screen >

Figure 2-14 \u00a0 Factorial Order Time Complexity

Note that factorial order grows even faster than exponential order; it's unacceptable for larger \\(n\\) values.

"},{"location":"chapter_computational_complexity/time_complexity/#235-worst-best-and-average-time-complexities","title":"2.3.5 \u00a0 Worst, Best, and Average Time Complexities","text":"

The time efficiency of an algorithm is often not fixed but depends on the distribution of the input data. Assume we have an array nums of length \\(n\\), consisting of numbers from \\(1\\) to \\(n\\), each appearing only once, but in a randomly shuffled order. The task is to return the index of the element \\(1\\). We can draw the following conclusions:

  • When nums = [?, ?, ..., 1], that is, when the last element is \\(1\\), it requires a complete traversal of the array, achieving the worst-case time complexity of \\(O(n)\\).
  • When nums = [1, ?, ?, ...], that is, when the first element is \\(1\\), no matter the length of the array, no further traversal is needed, achieving the best-case time complexity of \\(\\Omega(1)\\).

The \"worst-case time complexity\" corresponds to the asymptotic upper bound, denoted by the big \\(O\\) notation. Correspondingly, the \"best-case time complexity\" corresponds to the asymptotic lower bound, denoted by \\(\\Omega\\):

PythonC++JavaC#GoSwiftJSTSDartRustCZig worst_best_time_complexity.py
def random_numbers(n: int) -> list[int]:\n    \"\"\"\u751f\u6210\u4e00\u4e2a\u6570\u7ec4\uff0c\u5143\u7d20\u4e3a: 1, 2, ..., n \uff0c\u987a\u5e8f\u88ab\u6253\u4e71\"\"\"\n    # \u751f\u6210\u6570\u7ec4 nums =: 1, 2, 3, ..., n\n    nums = [i for i in range(1, n + 1)]\n    # \u968f\u673a\u6253\u4e71\u6570\u7ec4\u5143\u7d20\n    random.shuffle(nums)\n    return nums\n\ndef find_one(nums: list[int]) -> int:\n    \"\"\"\u67e5\u627e\u6570\u7ec4 nums \u4e2d\u6570\u5b57 1 \u6240\u5728\u7d22\u5f15\"\"\"\n    for i in range(len(nums)):\n        # \u5f53\u5143\u7d20 1 \u5728\u6570\u7ec4\u5934\u90e8\u65f6\uff0c\u8fbe\u5230\u6700\u4f73\u65f6\u95f4\u590d\u6742\u5ea6 O(1)\n        # \u5f53\u5143\u7d20 1 \u5728\u6570\u7ec4\u5c3e\u90e8\u65f6\uff0c\u8fbe\u5230\u6700\u5dee\u65f6\u95f4\u590d\u6742\u5ea6 O(n)\n        if nums[i] == 1:\n            return i\n    return -1\n
worst_best_time_complexity.cpp
/* \u751f\u6210\u4e00\u4e2a\u6570\u7ec4\uff0c\u5143\u7d20\u4e3a { 1, 2, ..., n }\uff0c\u987a\u5e8f\u88ab\u6253\u4e71 */\nvector<int> randomNumbers(int n) {\n    vector<int> nums(n);\n    // \u751f\u6210\u6570\u7ec4 nums = { 1, 2, 3, ..., n }\n    for (int i = 0; i < n; i++) {\n        nums[i] = i + 1;\n    }\n    // \u4f7f\u7528\u7cfb\u7edf\u65f6\u95f4\u751f\u6210\u968f\u673a\u79cd\u5b50\n    unsigned seed = chrono::system_clock::now().time_since_epoch().count();\n    // \u968f\u673a\u6253\u4e71\u6570\u7ec4\u5143\u7d20\n    shuffle(nums.begin(), nums.end(), default_random_engine(seed));\n    return nums;\n}\n\n/* \u67e5\u627e\u6570\u7ec4 nums \u4e2d\u6570\u5b57 1 \u6240\u5728\u7d22\u5f15 */\nint findOne(vector<int> &nums) {\n    for (int i = 0; i < nums.size(); i++) {\n        // \u5f53\u5143\u7d20 1 \u5728\u6570\u7ec4\u5934\u90e8\u65f6\uff0c\u8fbe\u5230\u6700\u4f73\u65f6\u95f4\u590d\u6742\u5ea6 O(1)\n        // \u5f53\u5143\u7d20 1 \u5728\u6570\u7ec4\u5c3e\u90e8\u65f6\uff0c\u8fbe\u5230\u6700\u5dee\u65f6\u95f4\u590d\u6742\u5ea6 O(n)\n        if (nums[i] == 1)\n            return i;\n    }\n    return -1;\n}\n
worst_best_time_complexity.java
/* \u751f\u6210\u4e00\u4e2a\u6570\u7ec4\uff0c\u5143\u7d20\u4e3a { 1, 2, ..., n }\uff0c\u987a\u5e8f\u88ab\u6253\u4e71 */\nint[] randomNumbers(int n) {\n    Integer[] nums = new Integer[n];\n    // \u751f\u6210\u6570\u7ec4 nums = { 1, 2, 3, ..., n }\n    for (int i = 0; i < n; i++) {\n        nums[i] = i + 1;\n    }\n    // \u968f\u673a\u6253\u4e71\u6570\u7ec4\u5143\u7d20\n    Collections.shuffle(Arrays.asList(nums));\n    // Integer[] -> int[]\n    int[] res = new int[n];\n    for (int i = 0; i < n; i++) {\n        res[i] = nums[i];\n    }\n    return res;\n}\n\n/* \u67e5\u627e\u6570\u7ec4 nums \u4e2d\u6570\u5b57 1 \u6240\u5728\u7d22\u5f15 */\nint findOne(int[] nums) {\n    for (int i = 0; i < nums.length; i++) {\n        // \u5f53\u5143\u7d20 1 \u5728\u6570\u7ec4\u5934\u90e8\u65f6\uff0c\u8fbe\u5230\u6700\u4f73\u65f6\u95f4\u590d\u6742\u5ea6 O(1)\n        // \u5f53\u5143\u7d20 1 \u5728\u6570\u7ec4\u5c3e\u90e8\u65f6\uff0c\u8fbe\u5230\u6700\u5dee\u65f6\u95f4\u590d\u6742\u5ea6 O(n)\n        if (nums[i] == 1)\n            return i;\n    }\n    return -1;\n}\n
worst_best_time_complexity.cs
/* \u751f\u6210\u4e00\u4e2a\u6570\u7ec4\uff0c\u5143\u7d20\u4e3a { 1, 2, ..., n }\uff0c\u987a\u5e8f\u88ab\u6253\u4e71 */\nint[] RandomNumbers(int n) {\n    int[] nums = new int[n];\n    // \u751f\u6210\u6570\u7ec4 nums = { 1, 2, 3, ..., n }\n    for (int i = 0; i < n; i++) {\n        nums[i] = i + 1;\n    }\n\n    // \u968f\u673a\u6253\u4e71\u6570\u7ec4\u5143\u7d20\n    for (int i = 0; i < nums.Length; i++) {\n        int index = new Random().Next(i, nums.Length);\n        (nums[i], nums[index]) = (nums[index], nums[i]);\n    }\n    return nums;\n}\n\n/* \u67e5\u627e\u6570\u7ec4 nums \u4e2d\u6570\u5b57 1 \u6240\u5728\u7d22\u5f15 */\nint FindOne(int[] nums) {\n    for (int i = 0; i < nums.Length; i++) {\n        // \u5f53\u5143\u7d20 1 \u5728\u6570\u7ec4\u5934\u90e8\u65f6\uff0c\u8fbe\u5230\u6700\u4f73\u65f6\u95f4\u590d\u6742\u5ea6 O(1)\n        // \u5f53\u5143\u7d20 1 \u5728\u6570\u7ec4\u5c3e\u90e8\u65f6\uff0c\u8fbe\u5230\u6700\u5dee\u65f6\u95f4\u590d\u6742\u5ea6 O(n)\n        if (nums[i] == 1)\n            return i;\n    }\n    return -1;\n}\n
worst_best_time_complexity.go
/* \u751f\u6210\u4e00\u4e2a\u6570\u7ec4\uff0c\u5143\u7d20\u4e3a { 1, 2, ..., n }\uff0c\u987a\u5e8f\u88ab\u6253\u4e71 */\nfunc randomNumbers(n int) []int {\n    nums := make([]int, n)\n    // \u751f\u6210\u6570\u7ec4 nums = { 1, 2, 3, ..., n }\n    for i := 0; i < n; i++ {\n        nums[i] = i + 1\n    }\n    // \u968f\u673a\u6253\u4e71\u6570\u7ec4\u5143\u7d20\n    rand.Shuffle(len(nums), func(i, j int) {\n        nums[i], nums[j] = nums[j], nums[i]\n    })\n    return nums\n}\n\n/* \u67e5\u627e\u6570\u7ec4 nums \u4e2d\u6570\u5b57 1 \u6240\u5728\u7d22\u5f15 */\nfunc findOne(nums []int) int {\n    for i := 0; i < len(nums); i++ {\n        // \u5f53\u5143\u7d20 1 \u5728\u6570\u7ec4\u5934\u90e8\u65f6\uff0c\u8fbe\u5230\u6700\u4f73\u65f6\u95f4\u590d\u6742\u5ea6 O(1)\n        // \u5f53\u5143\u7d20 1 \u5728\u6570\u7ec4\u5c3e\u90e8\u65f6\uff0c\u8fbe\u5230\u6700\u5dee\u65f6\u95f4\u590d\u6742\u5ea6 O(n)\n        if nums[i] == 1 {\n            return i\n        }\n    }\n    return -1\n}\n
worst_best_time_complexity.swift
/* \u751f\u6210\u4e00\u4e2a\u6570\u7ec4\uff0c\u5143\u7d20\u4e3a { 1, 2, ..., n }\uff0c\u987a\u5e8f\u88ab\u6253\u4e71 */\nfunc randomNumbers(n: Int) -> [Int] {\n    // \u751f\u6210\u6570\u7ec4 nums = { 1, 2, 3, ..., n }\n    var nums = Array(1 ... n)\n    // \u968f\u673a\u6253\u4e71\u6570\u7ec4\u5143\u7d20\n    nums.shuffle()\n    return nums\n}\n\n/* \u67e5\u627e\u6570\u7ec4 nums \u4e2d\u6570\u5b57 1 \u6240\u5728\u7d22\u5f15 */\nfunc findOne(nums: [Int]) -> Int {\n    for i in nums.indices {\n        // \u5f53\u5143\u7d20 1 \u5728\u6570\u7ec4\u5934\u90e8\u65f6\uff0c\u8fbe\u5230\u6700\u4f73\u65f6\u95f4\u590d\u6742\u5ea6 O(1)\n        // \u5f53\u5143\u7d20 1 \u5728\u6570\u7ec4\u5c3e\u90e8\u65f6\uff0c\u8fbe\u5230\u6700\u5dee\u65f6\u95f4\u590d\u6742\u5ea6 O(n)\n        if nums[i] == 1 {\n            return i\n        }\n    }\n    return -1\n}\n
worst_best_time_complexity.js
/* \u751f\u6210\u4e00\u4e2a\u6570\u7ec4\uff0c\u5143\u7d20\u4e3a { 1, 2, ..., n }\uff0c\u987a\u5e8f\u88ab\u6253\u4e71 */\nfunction randomNumbers(n) {\n    const nums = Array(n);\n    // \u751f\u6210\u6570\u7ec4 nums = { 1, 2, 3, ..., n }\n    for (let i = 0; i < n; i++) {\n        nums[i] = i + 1;\n    }\n    // \u968f\u673a\u6253\u4e71\u6570\u7ec4\u5143\u7d20\n    for (let i = 0; i < n; i++) {\n        const r = Math.floor(Math.random() * (i + 1));\n        const temp = nums[i];\n        nums[i] = nums[r];\n        nums[r] = temp;\n    }\n    return nums;\n}\n\n/* \u67e5\u627e\u6570\u7ec4 nums \u4e2d\u6570\u5b57 1 \u6240\u5728\u7d22\u5f15 */\nfunction findOne(nums) {\n    for (let i = 0; i < nums.length; i++) {\n        // \u5f53\u5143\u7d20 1 \u5728\u6570\u7ec4\u5934\u90e8\u65f6\uff0c\u8fbe\u5230\u6700\u4f73\u65f6\u95f4\u590d\u6742\u5ea6 O(1)\n        // \u5f53\u5143\u7d20 1 \u5728\u6570\u7ec4\u5c3e\u90e8\u65f6\uff0c\u8fbe\u5230\u6700\u5dee\u65f6\u95f4\u590d\u6742\u5ea6 O(n)\n        if (nums[i] === 1) {\n            return i;\n        }\n    }\n    return -1;\n}\n
worst_best_time_complexity.ts
/* \u751f\u6210\u4e00\u4e2a\u6570\u7ec4\uff0c\u5143\u7d20\u4e3a { 1, 2, ..., n }\uff0c\u987a\u5e8f\u88ab\u6253\u4e71 */\nfunction randomNumbers(n: number): number[] {\n    const nums = Array(n);\n    // \u751f\u6210\u6570\u7ec4 nums = { 1, 2, 3, ..., n }\n    for (let i = 0; i < n; i++) {\n        nums[i] = i + 1;\n    }\n    // \u968f\u673a\u6253\u4e71\u6570\u7ec4\u5143\u7d20\n    for (let i = 0; i < n; i++) {\n        const r = Math.floor(Math.random() * (i + 1));\n        const temp = nums[i];\n        nums[i] = nums[r];\n        nums[r] = temp;\n    }\n    return nums;\n}\n\n/* \u67e5\u627e\u6570\u7ec4 nums \u4e2d\u6570\u5b57 1 \u6240\u5728\u7d22\u5f15 */\nfunction findOne(nums: number[]): number {\n    for (let i = 0; i < nums.length; i++) {\n        // \u5f53\u5143\u7d20 1 \u5728\u6570\u7ec4\u5934\u90e8\u65f6\uff0c\u8fbe\u5230\u6700\u4f73\u65f6\u95f4\u590d\u6742\u5ea6 O(1)\n        // \u5f53\u5143\u7d20 1 \u5728\u6570\u7ec4\u5c3e\u90e8\u65f6\uff0c\u8fbe\u5230\u6700\u5dee\u65f6\u95f4\u590d\u6742\u5ea6 O(n)\n        if (nums[i] === 1) {\n            return i;\n        }\n    }\n    return -1;\n}\n
worst_best_time_complexity.dart
/* \u751f\u6210\u4e00\u4e2a\u6570\u7ec4\uff0c\u5143\u7d20\u4e3a { 1, 2, ..., n }\uff0c\u987a\u5e8f\u88ab\u6253\u4e71 */\nList<int> randomNumbers(int n) {\n  final nums = List.filled(n, 0);\n  // \u751f\u6210\u6570\u7ec4 nums = { 1, 2, 3, ..., n }\n  for (var i = 0; i < n; i++) {\n    nums[i] = i + 1;\n  }\n  // \u968f\u673a\u6253\u4e71\u6570\u7ec4\u5143\u7d20\n  nums.shuffle();\n\n  return nums;\n}\n\n/* \u67e5\u627e\u6570\u7ec4 nums \u4e2d\u6570\u5b57 1 \u6240\u5728\u7d22\u5f15 */\nint findOne(List<int> nums) {\n  for (var i = 0; i < nums.length; i++) {\n    // \u5f53\u5143\u7d20 1 \u5728\u6570\u7ec4\u5934\u90e8\u65f6\uff0c\u8fbe\u5230\u6700\u4f73\u65f6\u95f4\u590d\u6742\u5ea6 O(1)\n    // \u5f53\u5143\u7d20 1 \u5728\u6570\u7ec4\u5c3e\u90e8\u65f6\uff0c\u8fbe\u5230\u6700\u5dee\u65f6\u95f4\u590d\u6742\u5ea6 O(n)\n    if (nums[i] == 1) return i;\n  }\n\n  return -1;\n}\n
worst_best_time_complexity.rs
/* \u751f\u6210\u4e00\u4e2a\u6570\u7ec4\uff0c\u5143\u7d20\u4e3a { 1, 2, ..., n }\uff0c\u987a\u5e8f\u88ab\u6253\u4e71 */\nfn random_numbers(n: i32) -> Vec<i32> {\n    // \u751f\u6210\u6570\u7ec4 nums = { 1, 2, 3, ..., n }\n    let mut nums = (1..=n).collect::<Vec<i32>>();\n    // \u968f\u673a\u6253\u4e71\u6570\u7ec4\u5143\u7d20\n    nums.shuffle(&mut thread_rng());\n    nums\n}\n\n/* \u67e5\u627e\u6570\u7ec4 nums \u4e2d\u6570\u5b57 1 \u6240\u5728\u7d22\u5f15 */\nfn find_one(nums: &[i32]) -> Option<usize> {\n    for i in 0..nums.len() {\n        // \u5f53\u5143\u7d20 1 \u5728\u6570\u7ec4\u5934\u90e8\u65f6\uff0c\u8fbe\u5230\u6700\u4f73\u65f6\u95f4\u590d\u6742\u5ea6 O(1)\n        // \u5f53\u5143\u7d20 1 \u5728\u6570\u7ec4\u5c3e\u90e8\u65f6\uff0c\u8fbe\u5230\u6700\u5dee\u65f6\u95f4\u590d\u6742\u5ea6 O(n)\n        if nums[i] == 1 {\n            return Some(i);\n        }\n    }\n    None\n}\n
worst_best_time_complexity.c
/* \u751f\u6210\u4e00\u4e2a\u6570\u7ec4\uff0c\u5143\u7d20\u4e3a { 1, 2, ..., n }\uff0c\u987a\u5e8f\u88ab\u6253\u4e71 */\nint *randomNumbers(int n) {\n    // \u5206\u914d\u5806\u533a\u5185\u5b58\uff08\u521b\u5efa\u4e00\u7ef4\u53ef\u53d8\u957f\u6570\u7ec4\uff1a\u6570\u7ec4\u4e2d\u5143\u7d20\u6570\u91cf\u4e3a n \uff0c\u5143\u7d20\u7c7b\u578b\u4e3a int \uff09\n    int *nums = (int *)malloc(n * sizeof(int));\n    // \u751f\u6210\u6570\u7ec4 nums = { 1, 2, 3, ..., n }\n    for (int i = 0; i < n; i++) {\n        nums[i] = i + 1;\n    }\n    // \u968f\u673a\u6253\u4e71\u6570\u7ec4\u5143\u7d20\n    for (int i = n - 1; i > 0; i--) {\n        int j = rand() % (i + 1);\n        int temp = nums[i];\n        nums[i] = nums[j];\n        nums[j] = temp;\n    }\n    return nums;\n}\n\n/* \u67e5\u627e\u6570\u7ec4 nums \u4e2d\u6570\u5b57 1 \u6240\u5728\u7d22\u5f15 */\nint findOne(int *nums, int n) {\n    for (int i = 0; i < n; i++) {\n        // \u5f53\u5143\u7d20 1 \u5728\u6570\u7ec4\u5934\u90e8\u65f6\uff0c\u8fbe\u5230\u6700\u4f73\u65f6\u95f4\u590d\u6742\u5ea6 O(1)\n        // \u5f53\u5143\u7d20 1 \u5728\u6570\u7ec4\u5c3e\u90e8\u65f6\uff0c\u8fbe\u5230\u6700\u5dee\u65f6\u95f4\u590d\u6742\u5ea6 O(n)\n        if (nums[i] == 1)\n            return i;\n    }\n    return -1;\n}\n
worst_best_time_complexity.zig
// \u751f\u6210\u4e00\u4e2a\u6570\u7ec4\uff0c\u5143\u7d20\u4e3a { 1, 2, ..., n }\uff0c\u987a\u5e8f\u88ab\u6253\u4e71\nfn randomNumbers(comptime n: usize) [n]i32 {\n    var nums: [n]i32 = undefined;\n    // \u751f\u6210\u6570\u7ec4 nums = { 1, 2, 3, ..., n }\n    for (&nums, 0..) |*num, i| {\n        num.* = @as(i32, @intCast(i)) + 1;\n    }\n    // \u968f\u673a\u6253\u4e71\u6570\u7ec4\u5143\u7d20\n    const rand = std.crypto.random;\n    rand.shuffle(i32, &nums);\n    return nums;\n}\n\n// \u67e5\u627e\u6570\u7ec4 nums \u4e2d\u6570\u5b57 1 \u6240\u5728\u7d22\u5f15\nfn findOne(nums: []i32) i32 {\n    for (nums, 0..) |num, i| {\n        // \u5f53\u5143\u7d20 1 \u5728\u6570\u7ec4\u5934\u90e8\u65f6\uff0c\u8fbe\u5230\u6700\u4f73\u65f6\u95f4\u590d\u6742\u5ea6 O(1)\n        // \u5f53\u5143\u7d20 1 \u5728\u6570\u7ec4\u5c3e\u90e8\u65f6\uff0c\u8fbe\u5230\u6700\u5dee\u65f6\u95f4\u590d\u6742\u5ea6 O(n)\n        if (num == 1) return @intCast(i);\n    }\n    return -1;\n}\n
Code Visualization

Full Screen >

It's important to note that the best-case time complexity is rarely used in practice, as it is usually only achievable under very low probabilities and might be misleading. The worst-case time complexity is more practical as it provides a safety value for efficiency, allowing us to confidently use the algorithm.

From the above example, it's clear that both the worst-case and best-case time complexities only occur under \"special data distributions,\" which may have a small probability of occurrence and may not accurately reflect the algorithm's run efficiency. In contrast, the average time complexity can reflect the algorithm's efficiency under random input data, denoted by the \\(\\Theta\\) notation.

For some algorithms, we can simply estimate the average case under a random data distribution. For example, in the aforementioned example, since the input array is shuffled, the probability of element \\(1\\) appearing at any index is equal. Therefore, the average number of loops for the algorithm is half the length of the array \\(n / 2\\), giving an average time complexity of \\(\\Theta(n / 2) = \\Theta(n)\\).

However, calculating the average time complexity for more complex algorithms can be quite difficult, as it's challenging to analyze the overall mathematical expectation under the data distribution. In such cases, we usually use the worst-case time complexity as the standard for judging the efficiency of the algorithm.

Why is the \\(\\Theta\\) symbol rarely seen?

Possibly because the \\(O\\) notation is more commonly spoken, it is often used to represent the average time complexity. However, strictly speaking, this practice is not accurate. In this book and other materials, if you encounter statements like \"average time complexity \\(O(n)\\)\", please understand it directly as \\(\\Theta(n)\\).

"},{"location":"chapter_data_structure/","title":"Chapter 3. \u00a0 Data Structures","text":"

Abstract

Data structures serve as a robust and diverse framework.

They offer a blueprint for the orderly organization of data, upon which algorithms come to life.

"},{"location":"chapter_data_structure/#chapter-contents","title":"Chapter Contents","text":"
  • 3.1 \u00a0 Classification of Data Structures
  • 3.2 \u00a0 Fundamental Data Types
  • 3.3 \u00a0 Number Encoding *
  • 3.4 \u00a0 Character Encoding *
  • 3.5 \u00a0 Summary
"},{"location":"chapter_data_structure/basic_data_types/","title":"3.2 \u00a0 Basic Data Types","text":"

When discussing data in computers, various forms like text, images, videos, voice and 3D models comes to mind. Despite their different organizational forms, they are all composed of various basic data types.

Basic data types are those that the CPU can directly operate on and are directly used in algorithms, mainly including the following.

  • Integer types: byte, short, int, long.
  • Floating-point types: float, double, used to represent decimals.
  • Character type: char, used to represent letters, punctuation, and even emojis in various languages.
  • Boolean type: bool, used to represent \"yes\" or \"no\" decisions.

Basic data types are stored in computers in binary form. One binary digit is 1 bit. In most modern operating systems, 1 byte consists of 8 bits.

The range of values for basic data types depends on the size of the space they occupy. Below, we take Java as an example.

  • The integer type byte occupies 1 byte = 8 bits and can represent \\(2^8\\) numbers.
  • The integer type int occupies 4 bytes = 32 bits and can represent \\(2^{32}\\) numbers.

The following table lists the space occupied, value range, and default values of various basic data types in Java. While memorizing this table isn't necessary, having a general understanding of it and referencing it when required is recommended.

Table 3-1 \u00a0 Space Occupied and Value Range of Basic Data Types

Type Symbol Space Occupied Minimum Value Maximum Value Default Value Integer byte 1 byte \\(-2^7\\) (\\(-128\\)) \\(2^7 - 1\\) (\\(127\\)) 0 short 2 bytes \\(-2^{15}\\) \\(2^{15} - 1\\) 0 int 4 bytes \\(-2^{31}\\) \\(2^{31} - 1\\) 0 long 8 bytes \\(-2^{63}\\) \\(2^{63} - 1\\) 0 Float float 4 bytes \\(1.175 \\times 10^{-38}\\) \\(3.403 \\times 10^{38}\\) \\(0.0\\text{f}\\) double 8 bytes \\(2.225 \\times 10^{-308}\\) \\(1.798 \\times 10^{308}\\) 0.0 Char char 2 bytes 0 \\(2^{16} - 1\\) 0 Boolean bool 1 byte \\(\\text{false}\\) \\(\\text{true}\\) \\(\\text{false}\\)

Please note that the above table is specific to Java's basic data types. Every programming language has its own data type definitions, which might differ in space occupied, value ranges, and default values.

  • In Python, the integer type int can be of any size, limited only by available memory; the floating-point float is double precision 64-bit; there is no char type, as a single character is actually a string str of length 1.
  • C and C++ do not specify the size of basic data types, it varies with implementation and platform. The above table follows the LP64 data model, used for Unix 64-bit operating systems including Linux and macOS.
  • The size of char in C and C++ is 1 byte, while in most programming languages, it depends on the specific character encoding method, as detailed in the \"Character Encoding\" chapter.
  • Even though representing a boolean only requires 1 bit (0 or 1), it is usually stored in memory as 1 byte. This is because modern computer CPUs typically use 1 byte as the smallest addressable memory unit.

So, what is the connection between basic data types and data structures? We know that data structures are ways to organize and store data in computers. The focus here is on \"structure\" rather than \"data\".

If we want to represent \"a row of numbers\", we naturally think of using an array. This is because the linear structure of an array can represent the adjacency and the ordering of the numbers, but whether the stored content is an integer int, a decimal float, or a character char, is irrelevant to the \"data structure\".

In other words, basic data types provide the \"content type\" of data, while data structures provide the \"way of organizing\" data. For example, in the following code, we use the same data structure (array) to store and represent different basic data types, including int, float, char, bool, etc.

PythonC++JavaC#GoSwiftJSTSDartRustCZig
# Using various basic data types to initialize arrays\nnumbers: list[int] = [0] * 5\ndecimals: list[float] = [0.0] * 5\n# Python's characters are actually strings of length 1\ncharacters: list[str] = ['0'] * 5\nbools: list[bool] = [False] * 5\n# Python's lists can freely store various basic data types and object references\ndata = [0, 0.0, 'a', False, ListNode(0)]\n
// Using various basic data types to initialize arrays\nint numbers[5];\nfloat decimals[5];\nchar characters[5];\nbool bools[5];\n
// Using various basic data types to initialize arrays\nint[] numbers = new int[5];\nfloat[] decimals = new float[5];\nchar[] characters = new char[5];\nboolean[] bools = new boolean[5];\n
// Using various basic data types to initialize arrays\nint[] numbers = new int[5];\nfloat[] decimals = new float[5];\nchar[] characters = new char[5];\nbool[] bools = new bool[5];\n
// Using various basic data types to initialize arrays\nvar numbers = [5]int{}\nvar decimals = [5]float64{}\nvar characters = [5]byte{}\nvar bools = [5]bool{}\n
// Using various basic data types to initialize arrays\nlet numbers = Array(repeating: 0, count: 5)\nlet decimals = Array(repeating: 0.0, count: 5)\nlet characters: [Character] = Array(repeating: \"a\", count: 5)\nlet bools = Array(repeating: false, count: 5)\n
// JavaScript's arrays can freely store various basic data types and objects\nconst array = [0, 0.0, 'a', false];\n
// Using various basic data types to initialize arrays\nconst numbers: number[] = [];\nconst characters: string[] = [];\nconst bools: boolean[] = [];\n
// Using various basic data types to initialize arrays\nList<int> numbers = List.filled(5, 0);\nList<double> decimals = List.filled(5, 0.0);\nList<String> characters = List.filled(5, 'a');\nList<bool> bools = List.filled(5, false);\n
// Using various basic data types to initialize arrays\nlet numbers: Vec<i32> = vec![0; 5];\nlet decimals: Vec<f32> = vec![0.0, 5];\nlet characters: Vec<char> = vec!['0'; 5];\nlet bools: Vec<bool> = vec![false; 5];\n
// Using various basic data types to initialize arrays\nint numbers[10];\nfloat decimals[10];\nchar characters[10];\nbool bools[10];\n
// Using various basic data types to initialize arrays\nvar numbers: [5]i32 = undefined;\nvar decimals: [5]f32 = undefined;\nvar characters: [5]u8 = undefined;\nvar bools: [5]bool = undefined;\n
"},{"location":"chapter_data_structure/character_encoding/","title":"3.4 \u00a0 Character Encoding *","text":"

In the computer system, all data is stored in binary form, and characters (represented by char) are no exception. To represent characters, we need to develop a \"character set\" that defines a one-to-one mapping between each character and binary numbers. With the character set, computers can convert binary numbers to characters by looking up the table.

"},{"location":"chapter_data_structure/character_encoding/#341-ascii-character-set","title":"3.4.1 \u00a0 ASCII Character Set","text":"

The \"ASCII code\" is one of the earliest character sets, officially known as the American Standard Code for Information Interchange. It uses 7 binary digits (the lower 7 bits of a byte) to represent a character, allowing for a maximum of 128 different characters. As shown in the Figure 3-6 , ASCII includes uppercase and lowercase English letters, numbers 0 ~ 9, various punctuation marks, and certain control characters (such as newline and tab).

Figure 3-6 \u00a0 ASCII Code

However, ASCII can only represent English characters. With the globalization of computers, a character set called \"EASCII\" was developed to represent more languages. It expands from the 7-bit structure of ASCII to 8 bits, enabling the representation of 256 characters.

Globally, various region-specific EASCII character sets have been introduced. The first 128 characters of these sets are consistent with the ASCII, while the remaining 128 characters are defined differently to accommodate the requirements of different languages.

"},{"location":"chapter_data_structure/character_encoding/#342-gbk-character-set","title":"3.4.2 \u00a0 GBK Character Set","text":"

Later, it was found that EASCII still could not meet the character requirements of many languages. For instance, there are nearly a hundred thousand Chinese characters, with several thousand used regularly. In 1980, the Standardization Administration of China released the \"GB2312\" character set, which included 6763 Chinese characters, essentially fulfilling the computer processing needs for the Chinese language.

However, GB2312 could not handle some rare and traditional characters. The \"GBK\" character set expands GB2312 and includes 21886 Chinese characters. In the GBK encoding scheme, ASCII characters are represented with one byte, while Chinese characters use two bytes.

"},{"location":"chapter_data_structure/character_encoding/#343-unicode-character-set","title":"3.4.3 \u00a0 Unicode Character Set","text":"

With the rapid evolution of computer technology and a plethora of character sets and encoding standards, numerous problems arose. On the one hand, these character sets generally only defined characters for specific languages and could not function properly in multilingual environments. On the other hand, the existence of multiple character set standards for the same language caused garbled text when information was exchanged between computers using different encoding standards.

Researchers of that era thought: What if a comprehensive character set encompassing all global languages and symbols was developed? Wouldn't this resolve the issues associated with cross-linguistic environments and garbled text? Inspired by this idea, the extensive character set, Unicode, was born.

\"Unicode\" is referred to as \"\u7edf\u4e00\u7801\" (Unified Code) in Chinese, theoretically capable of accommodating over a million characters. It aims to incorporate characters from all over the world into a single set, providing a universal character set for processing and displaying various languages and reducing the issues of garbled text due to different encoding standards.

Since its release in 1991, Unicode has continually expanded to include new languages and characters. As of September 2022, Unicode contains 149,186 characters, including characters, symbols, and even emojis from various languages. In the vast Unicode character set, commonly used characters occupy 2 bytes, while some rare characters may occupy 3 or even 4 bytes.

Unicode is a universal character set that assigns a number (called a \"code point\") to each character, but it does not specify how these character code points should be stored in a computer system. One might ask: How does a system interpret Unicode code points of varying lengths within a text? For example, given a 2-byte code, how does the system determine if it represents a single 2-byte character or two 1-byte characters?

A straightforward solution to this problem is to store all characters as equal-length encodings. As shown in the Figure 3-7 , each character in \"Hello\" occupies 1 byte, while each character in \"\u7b97\u6cd5\" (algorithm) occupies 2 bytes. We could encode all characters in \"Hello \u7b97\u6cd5\" as 2 bytes by padding the higher bits with zeros. This method would enable the system to interpret a character every 2 bytes, recovering the content of the phrase.

Figure 3-7 \u00a0 Unicode Encoding Example

However, as ASCII has shown us, encoding English only requires 1 byte. Using the above approach would double the space occupied by English text compared to ASCII encoding, which is a waste of memory space. Therefore, a more efficient Unicode encoding method is needed.

"},{"location":"chapter_data_structure/character_encoding/#344-utf-8-encoding","title":"3.4.4 \u00a0 UTF-8 Encoding","text":"

Currently, UTF-8 has become the most widely used Unicode encoding method internationally. It is a variable-length encoding, using 1 to 4 bytes to represent a character, depending on the complexity of the character. ASCII characters need only 1 byte, Latin and Greek letters require 2 bytes, commonly used Chinese characters need 3 bytes, and some other rare characters need 4 bytes.

The encoding rules for UTF-8 are not complex and can be divided into two cases:

  • For 1-byte characters, set the highest bit to \\(0\\), and the remaining 7 bits to the Unicode code point. Notably, ASCII characters occupy the first 128 code points in the Unicode set. This means that UTF-8 encoding is backward compatible with ASCII. This implies that UTF-8 can be used to parse ancient ASCII text.
  • For characters of length \\(n\\) bytes (where \\(n > 1\\)), set the highest \\(n\\) bits of the first byte to \\(1\\), and the \\((n + 1)^{\\text{th}}\\) bit to \\(0\\); starting from the second byte, set the highest 2 bits of each byte to \\(10\\); the rest of the bits are used to fill the Unicode code point.

The Figure 3-8 shows the UTF-8 encoding for \"Hello\u7b97\u6cd5\". It can be observed that since the highest \\(n\\) bits are set to \\(1\\), the system can determine the length of the character as \\(n\\) by counting the number of highest bits set to \\(1\\).

But why set the highest 2 bits of the remaining bytes to \\(10\\)? Actually, this \\(10\\) serves as a kind of checksum. If the system starts parsing text from an incorrect byte, the \\(10\\) at the beginning of the byte can help the system quickly detect anomalies.

The reason for using \\(10\\) as a checksum is that, under UTF-8 encoding rules, it's impossible for the highest two bits of a character to be \\(10\\). This can be proven by contradiction: If the highest two bits of a character are \\(10\\), it indicates that the character's length is \\(1\\), corresponding to ASCII. However, the highest bit of an ASCII character should be \\(0\\), which contradicts the assumption.

Figure 3-8 \u00a0 UTF-8 Encoding Example

Apart from UTF-8, other common encoding methods include:

  • UTF-16 Encoding: Uses 2 or 4 bytes to represent a character. All ASCII characters and commonly used non-English characters are represented with 2 bytes; a few characters require 4 bytes. For 2-byte characters, the UTF-16 encoding equals the Unicode code point.
  • UTF-32 Encoding: Every character uses 4 bytes. This means UTF-32 occupies more space than UTF-8 and UTF-16, especially for texts with a high proportion of ASCII characters.

From the perspective of storage space, using UTF-8 to represent English characters is very efficient because it only requires 1 byte; using UTF-16 to encode some non-English characters (such as Chinese) can be more efficient because it only requires 2 bytes, while UTF-8 might need 3 bytes.

From a compatibility perspective, UTF-8 is the most versatile, with many tools and libraries supporting UTF-8 as a priority.

"},{"location":"chapter_data_structure/character_encoding/#345-character-encoding-in-programming-languages","title":"3.4.5 \u00a0 Character Encoding in Programming Languages","text":"

Historically, many programming languages utilized fixed-length encodings such as UTF-16 or UTF-32 for processing strings during program execution. This allows strings to be handled as arrays, offering several advantages:

  • Random Access: Strings encoded in UTF-16 can be accessed randomly with ease. For UTF-8, which is a variable-length encoding, locating the \\(i^{th}\\) character requires traversing the string from the start to the \\(i^{th}\\) position, taking \\(O(n)\\) time.
  • Character Counting: Similar to random access, counting the number of characters in a UTF-16 encoded string is an \\(O(1)\\) operation. However, counting characters in a UTF-8 encoded string requires traversing the entire string.
  • String Operations: Many string operations like splitting, concatenating, inserting, and deleting are easier on UTF-16 encoded strings. These operations generally require additional computation on UTF-8 encoded strings to ensure the validity of the UTF-8 encoding.

The design of character encoding schemes in programming languages is an interesting topic involving various factors:

  • Java\u2019s String type uses UTF-16 encoding, with each character occupying 2 bytes. This was based on the initial belief that 16 bits were sufficient to represent all possible characters and proven incorrect later. As the Unicode standard expanded beyond 16 bits, characters in Java may now be represented by a pair of 16-bit values, known as \u201csurrogate pairs.\u201d
  • JavaScript and TypeScript use UTF-16 encoding for similar reasons as Java. When JavaScript was first introduced by Netscape in 1995, Unicode was still in its early stages, and 16-bit encoding was sufficient to represent all Unicode characters.
  • C# uses UTF-16 encoding, largely because the .NET platform, designed by Microsoft, and many Microsoft technologies, including the Windows operating system, extensively use UTF-16 encoding.

Due to the underestimation of character counts, these languages had to use \"surrogate pairs\" to represent Unicode characters exceeding 16 bits. This approach has its drawbacks: strings containing surrogate pairs may have characters occupying 2 or 4 bytes, losing the advantage of fixed-length encoding. Additionally, handling surrogate pairs adds complexity and debugging difficulty to programming.

Addressing these challenges, some languages have adopted alternative encoding strategies:

  • Python\u2019s str type uses Unicode encoding with a flexible representation where the storage length of characters depends on the largest Unicode code point in the string. If all characters are ASCII, each character occupies 1 byte, 2 bytes for characters within the Basic Multilingual Plane (BMP), and 4 bytes for characters beyond the BMP.
  • Go\u2019s string type internally uses UTF-8 encoding. Go also provides the rune type for representing individual Unicode code points.
  • Rust\u2019s str and String types use UTF-8 encoding internally. Rust also offers the char type for individual Unicode code points.

It\u2019s important to note that the above discussion pertains to how strings are stored in programming languages, which is different from how strings are stored in files or transmitted over networks. For file storage or network transmission, strings are usually encoded in UTF-8 format for optimal compatibility and space efficiency.

"},{"location":"chapter_data_structure/classification_of_data_structure/","title":"3.1 \u00a0 Classification of Data Structures","text":"

Common data structures include arrays, linked lists, stacks, queues, hash tables, trees, heaps, and graphs. They can be classified into \"logical structure\" and \"physical structure\".

"},{"location":"chapter_data_structure/classification_of_data_structure/#311-logical-structure-linear-and-non-linear","title":"3.1.1 \u00a0 Logical Structure: Linear and Non-Linear","text":"

The logical structures reveal the logical relationships between data elements. In arrays and linked lists, data are arranged in a specific sequence, demonstrating the linear relationship between data; while in trees, data are arranged hierarchically from the top down, showing the derived relationship between \"ancestors\" and \"descendants\"; and graphs are composed of nodes and edges, reflecting the intricate network relationship.

As shown in the Figure 3-1 , logical structures can be divided into two major categories: \"linear\" and \"non-linear\". Linear structures are more intuitive, indicating data is arranged linearly in logical relationships; non-linear structures, conversely, are arranged non-linearly.

  • Linear Data Structures: Arrays, Linked Lists, Stacks, Queues, Hash Tables.
  • Non-Linear Data Structures: Trees, Heaps, Graphs, Hash Tables.

Figure 3-1 \u00a0 Linear and Non-Linear Data Structures

Non-linear data structures can be further divided into tree structures and network structures.

  • Linear Structures: Arrays, linked lists, queues, stacks, and hash tables, where elements have a one-to-one sequential relationship.
  • Tree Structures: Trees, Heaps, Hash Tables, where elements have a one-to-many relationship.
  • Network Structures: Graphs, where elements have a many-to-many relationships.
"},{"location":"chapter_data_structure/classification_of_data_structure/#312-physical-structure-contiguous-and-dispersed","title":"3.1.2 \u00a0 Physical Structure: Contiguous and Dispersed","text":"

During the execution of an algorithm, the data being processed is stored in memory. The Figure 3-2 shows a computer memory stick where each black square is a physical memory space. We can think of memory as a vast Excel spreadsheet, with each cell capable of storing a certain amount of data.

The system accesses the data at the target location by means of a memory address. As shown in the Figure 3-2 , the computer assigns a unique identifier to each cell in the table according to specific rules, ensuring that each memory space has a unique memory address. With these addresses, the program can access the data stored in memory.

Figure 3-2 \u00a0 Memory Stick, Memory Spaces, Memory Addresses

Tip

It's worth noting that comparing memory to an Excel spreadsheet is a simplified analogy. The actual working mechanism of memory is more complex, involving concepts like address space, memory management, cache mechanisms, virtual memory, and physical memory.

Memory is a shared resource for all programs. When a block of memory is occupied by one program, it cannot be simultaneously used by other programs. Therefore, considering memory resources is crucial in designing data structures and algorithms. For instance, the algorithm's peak memory usage should not exceed the remaining free memory of the system; if there is a lack of contiguous memory blocks, then the data structure chosen must be able to be stored in non-contiguous memory blocks.

As illustrated in the Figure 3-3 , the physical structure reflects the way data is stored in computer memory and it can be divided into contiguous space storage (arrays) and non-contiguous space storage (linked lists). The two types of physical structures exhibit complementary characteristics in terms of time efficiency and space efficiency.

Figure 3-3 \u00a0 Contiguous Space Storage and Dispersed Space Storage

It is worth noting that all data structures are implemented based on arrays, linked lists, or a combination of both. For example, stacks and queues can be implemented using either arrays or linked lists; while implementations of hash tables may involve both arrays and linked lists. - Array-based implementations: Stacks, Queues, Hash Tables, Trees, Heaps, Graphs, Matrices, Tensors (arrays with dimensions \\(\\geq 3\\)). - Linked-list-based implementations: Stacks, Queues, Hash Tables, Trees, Heaps, Graphs, etc.

Data structures implemented based on arrays are also called \u201cStatic Data Structures,\u201d meaning their length cannot be changed after initialization. Conversely, those based on linked lists are called \u201cDynamic Data Structures,\u201d which can still adjust their size during program execution.

Tip

If you find it challenging to comprehend the physical structure, it is recommended that you read the next chapter, \"Arrays and Linked Lists,\" and revisit this section later.

"},{"location":"chapter_data_structure/number_encoding/","title":"3.3 \u00a0 Number Encoding *","text":"

Note

In this book, chapters marked with an asterisk '*' are optional readings. If you are short on time or find them challenging, you may skip these initially and return to them after completing the essential chapters.

"},{"location":"chapter_data_structure/number_encoding/#331-integer-encoding","title":"3.3.1 \u00a0 Integer Encoding","text":"

In the table from the previous section, we observed that all integer types can represent one more negative number than positive numbers, such as the byte range of \\([-128, 127]\\). This phenomenon seems counterintuitive, and its underlying reason involves knowledge of sign-magnitude, one's complement, and two's complement encoding.

Firstly, it's important to note that numbers are stored in computers using the two's complement form. Before analyzing why this is the case, let's define these three encoding methods:

  • Sign-magnitude: The highest bit of a binary representation of a number is considered the sign bit, where \\(0\\) represents a positive number and \\(1\\) represents a negative number. The remaining bits represent the value of the number.
  • One's complement: The one's complement of a positive number is the same as its sign-magnitude. For negative numbers, it's obtained by inverting all bits except the sign bit.
  • Two's complement: The two's complement of a positive number is the same as its sign-magnitude. For negative numbers, it's obtained by adding \\(1\\) to their one's complement.

The following diagram illustrates the conversions among sign-magnitude, one's complement, and two's complement:

Figure 3-4 \u00a0 Conversions between Sign-Magnitude, One's Complement, and Two's Complement

Although sign-magnitude is the most intuitive, it has limitations. For one, negative numbers in sign-magnitude cannot be directly used in calculations. For example, in sign-magnitude, calculating \\(1 + (-2)\\) results in \\(-3\\), which is incorrect.

\\[ \\begin{aligned} & 1 + (-2) \\newline & \\rightarrow 0000 \\; 0001 + 1000 \\; 0010 \\newline & = 1000 \\; 0011 \\newline & \\rightarrow -3 \\end{aligned} \\]

To address this, computers introduced the one's complement. If we convert to one's complement and calculate \\(1 + (-2)\\), then convert the result back to sign-magnitude, we get the correct result of \\(-1\\).

\\[ \\begin{aligned} & 1 + (-2) \\newline & \\rightarrow 0000 \\; 0001 \\; \\text{(Sign-magnitude)} + 1000 \\; 0010 \\; \\text{(Sign-magnitude)} \\newline & = 0000 \\; 0001 \\; \\text{(One's complement)} + 1111 \\; 1101 \\; \\text{(One's complement)} \\newline & = 1111 \\; 1110 \\; \\text{(One's complement)} \\newline & = 1000 \\; 0001 \\; \\text{(Sign-magnitude)} \\newline & \\rightarrow -1 \\end{aligned} \\]

Additionally, there are two representations of zero in sign-magnitude: \\(+0\\) and \\(-0\\). This means two different binary encodings for zero, which could lead to ambiguity. For example, in conditional checks, not differentiating between positive and negative zero might result in incorrect outcomes. Addressing this ambiguity would require additional checks, potentially reducing computational efficiency.

\\[ \\begin{aligned} +0 & \\rightarrow 0000 \\; 0000 \\newline -0 & \\rightarrow 1000 \\; 0000 \\end{aligned} \\]

Like sign-magnitude, one's complement also suffers from the positive and negative zero ambiguity. Therefore, computers further introduced the two's complement. Let's observe the conversion process for negative zero in sign-magnitude, one's complement, and two's complement:

\\[ \\begin{aligned} -0 \\rightarrow \\; & 1000 \\; 0000 \\; \\text{(Sign-magnitude)} \\newline = \\; & 1111 \\; 1111 \\; \\text{(One's complement)} \\newline = 1 \\; & 0000 \\; 0000 \\; \\text{(Two's complement)} \\newline \\end{aligned} \\]

Adding \\(1\\) to the one's complement of negative zero produces a carry, but with byte length being only 8 bits, the carried-over \\(1\\) to the 9th bit is discarded. Therefore, the two's complement of negative zero is \\(0000 \\; 0000\\), the same as positive zero, thus resolving the ambiguity.

One last puzzle is the \\([-128, 127]\\) range for byte, with an additional negative number, \\(-128\\). We observe that for the interval \\([-127, +127]\\), all integers have corresponding sign-magnitude, one's complement, and two's complement, allowing for mutual conversion between them.

However, the two's complement \\(1000 \\; 0000\\) is an exception without a corresponding sign-magnitude. According to the conversion method, its sign-magnitude would be \\(0000 \\; 0000\\), indicating zero. This presents a contradiction because its two's complement should represent itself. Computers designate this special two's complement \\(1000 \\; 0000\\) as representing \\(-128\\). In fact, the calculation of \\((-1) + (-127)\\) in two's complement results in \\(-128\\).

\\[ \\begin{aligned} & (-127) + (-1) \\newline & \\rightarrow 1111 \\; 1111 \\; \\text{(Sign-magnitude)} + 1000 \\; 0001 \\; \\text{(Sign-magnitude)} \\newline & = 1000 \\; 0000 \\; \\text{(One's complement)} + 1111 \\; 1110 \\; \\text{(One's complement)} \\newline & = 1000 \\; 0001 \\; \\text{(Two's complement)} + 1111 \\; 1111 \\; \\text{(Two's complement)} \\newline & = 1000 \\; 0000 \\; \\text{(Two's complement)} \\newline & \\rightarrow -128 \\end{aligned} \\]

As you might have noticed, all these calculations are additions, hinting at an important fact: computers' internal hardware circuits are primarily designed around addition operations. This is because addition is simpler to implement in hardware compared to other operations like multiplication, division, and subtraction, allowing for easier parallelization and faster computation.

It's important to note that this doesn't mean computers can only perform addition. By combining addition with basic logical operations, computers can execute a variety of other mathematical operations. For example, the subtraction \\(a - b\\) can be translated into \\(a + (-b)\\); multiplication and division can be translated into multiple additions or subtractions.

We can now summarize the reason for using two's complement in computers: with two's complement representation, computers can use the same circuits and operations to handle both positive and negative number addition, eliminating the need for special hardware circuits for subtraction and avoiding the ambiguity of positive and negative zero. This greatly simplifies hardware design and enhances computational efficiency.

The design of two's complement is quite ingenious, and due to space constraints, we'll stop here. Interested readers are encouraged to explore further.

"},{"location":"chapter_data_structure/number_encoding/#332-floating-point-number-encoding","title":"3.3.2 \u00a0 Floating-Point Number Encoding","text":"

You might have noticed something intriguing: despite having the same length of 4 bytes, why does a float have a much larger range of values compared to an int? This seems counterintuitive, as one would expect the range to shrink for float since it needs to represent fractions.

In fact, this is due to the different representation method used by floating-point numbers (float). Let's consider a 32-bit binary number as:

\\[ b_{31} b_{30} b_{29} \\ldots b_2 b_1 b_0 \\]

According to the IEEE 754 standard, a 32-bit float consists of the following three parts:

  • Sign bit \\(\\mathrm{S}\\): Occupies 1 bit, corresponding to \\(b_{31}\\).
  • Exponent bit \\(\\mathrm{E}\\): Occupies 8 bits, corresponding to \\(b_{30} b_{29} \\ldots b_{23}\\).
  • Fraction bit \\(\\mathrm{N}\\): Occupies 23 bits, corresponding to \\(b_{22} b_{21} \\ldots b_0\\).

The value of a binary float number is calculated as:

\\[ \\text{val} = (-1)^{b_{31}} \\times 2^{\\left(b_{30} b_{29} \\ldots b_{23}\\right)_2 - 127} \\times \\left(1 . b_{22} b_{21} \\ldots b_0\\right)_2 \\]

Converted to a decimal formula, this becomes:

\\[ \\text{val} = (-1)^{\\mathrm{S}} \\times 2^{\\mathrm{E} - 127} \\times (1 + \\mathrm{N}) \\]

The range of each component is:

\\[ \\begin{aligned} \\mathrm{S} \\in & \\{ 0, 1\\}, \\quad \\mathrm{E} \\in \\{ 1, 2, \\dots, 254 \\} \\newline (1 + \\mathrm{N}) = & (1 + \\sum_{i=1}^{23} b_{23-i} \\times 2^{-i}) \\subset [1, 2 - 2^{-23}] \\end{aligned} \\]

Figure 3-5 \u00a0 Example Calculation of a float in IEEE 754 Standard

Observing the diagram, given an example data \\(\\mathrm{S} = 0\\), \\(\\mathrm{E} = 124\\), \\(\\mathrm{N} = 2^{-2} + 2^{-3} = 0.375\\), we have:

\\[ \\text{val} = (-1)^0 \\times 2^{124 - 127} \\times (1 + 0.375) = 0.171875 \\]

Now we can answer the initial question: The representation of float includes an exponent bit, leading to a much larger range than int. Based on the above calculation, the maximum positive number representable by float is approximately \\(2^{254 - 127} \\times (2 - 2^{-23}) \\approx 3.4 \\times 10^{38}\\), and the minimum negative number is obtained by switching the sign bit.

However, the trade-off for float's expanded range is a sacrifice in precision. The integer type int uses all 32 bits to represent the number, with values evenly distributed; but due to the exponent bit, the larger the value of a float, the greater the difference between adjacent numbers.

As shown in the Table 3-2 , exponent bits \\(E = 0\\) and \\(E = 255\\) have special meanings, used to represent zero, infinity, \\(\\mathrm{NaN}\\), etc.

Table 3-2 \u00a0 Meaning of Exponent Bits

Exponent Bit E Fraction Bit \\(\\mathrm{N} = 0\\) Fraction Bit \\(\\mathrm{N} \\ne 0\\) Calculation Formula \\(0\\) \\(\\pm 0\\) Subnormal Numbers \\((-1)^{\\mathrm{S}} \\times 2^{-126} \\times (0.\\mathrm{N})\\) \\(1, 2, \\dots, 254\\) Normal Numbers Normal Numbers \\((-1)^{\\mathrm{S}} \\times 2^{(\\mathrm{E} -127)} \\times (1.\\mathrm{N})\\) \\(255\\) \\(\\pm \\infty\\) \\(\\mathrm{NaN}\\)

It's worth noting that subnormal numbers significantly improve the precision of floating-point numbers. The smallest positive normal number is \\(2^{-126}\\), and the smallest positive subnormal number is \\(2^{-126} \\times 2^{-23}\\).

Double-precision double also uses a similar representation method to float, which is not elaborated here for brevity.

"},{"location":"chapter_data_structure/summary/","title":"3.5 \u00a0 Summary","text":""},{"location":"chapter_data_structure/summary/#1-key-review","title":"1. \u00a0 Key Review","text":"
  • Data structures can be categorized from two perspectives: logical structure and physical structure. Logical structure describes the logical relationships between data elements, while physical structure describes how data is stored in computer memory.
  • Common logical structures include linear, tree-like, and network structures. We generally classify data structures into linear (arrays, linked lists, stacks, queues) and non-linear (trees, graphs, heaps) based on their logical structure. The implementation of hash tables may involve both linear and non-linear data structures.
  • When a program runs, data is stored in computer memory. Each memory space has a corresponding memory address, and the program accesses data through these addresses.
  • Physical structures are primarily divided into contiguous space storage (arrays) and dispersed space storage (linked lists). All data structures are implemented using arrays, linked lists, or a combination of both.
  • Basic data types in computers include integers (byte, short, int, long), floating-point numbers (float, double), characters (char), and booleans (boolean). Their range depends on the size of the space occupied and the representation method.
  • Original code, complement code, and two's complement code are three methods of encoding numbers in computers, and they can be converted into each other. The highest bit of the original code of an integer is the sign bit, and the remaining bits represent the value of the number.
  • Integers are stored in computers in the form of two's complement. In this representation, the computer can treat the addition of positive and negative numbers uniformly, without the need for special hardware circuits for subtraction, and there is no ambiguity of positive and negative zero.
  • The encoding of floating-point numbers consists of 1 sign bit, 8 exponent bits, and 23 fraction bits. Due to the presence of the exponent bit, the range of floating-point numbers is much greater than that of integers, but at the cost of sacrificing precision.
  • ASCII is the earliest English character set, 1 byte in length, and includes 127 characters. The GBK character set is a commonly used Chinese character set, including more than 20,000 Chinese characters. Unicode strives to provide a complete character set standard, including characters from various languages worldwide, thus solving the problem of garbled characters caused by inconsistent character encoding methods.
  • UTF-8 is the most popular Unicode encoding method, with excellent universality. It is a variable-length encoding method with good scalability and effectively improves the efficiency of space usage. UTF-16 and UTF-32 are fixed-length encoding methods. When encoding Chinese characters, UTF-16 occupies less space than UTF-8. Programming languages like Java and C# use UTF-16 encoding by default.
"},{"location":"chapter_data_structure/summary/#2-q-a","title":"2. \u00a0 Q & A","text":"

Q: Why does a hash table contain both linear and non-linear data structures?

The underlying structure of a hash table is an array. To resolve hash collisions, we may use \"chaining\": each bucket in the array points to a linked list, which, when exceeding a certain threshold, might be transformed into a tree (usually a red-black tree). From a storage perspective, the foundation of a hash table is an array, where each bucket slot might contain a value, a linked list, or a tree. Therefore, hash tables may contain both linear data structures (arrays, linked lists) and non-linear data structures (trees).

Q: Is the length of the char type 1 byte?

The length of the char type is determined by the encoding method used by the programming language. For example, Java, JavaScript, TypeScript, and C# all use UTF-16 encoding (to save Unicode code points), so the length of the char type is 2 bytes.

Q: Is there ambiguity in calling data structures based on arrays \"static data structures\"? Because operations like push and pop on stacks are \"dynamic\".

While stacks indeed allow for dynamic data operations, the data structure itself remains \"static\" (with unchangeable length). Even though data structures based on arrays can dynamically add or remove elements, their capacity is fixed. If the data volume exceeds the pre-allocated size, a new, larger array needs to be created, and the contents of the old array copied into it.

Q: When building stacks (queues) without specifying their size, why are they considered \"static data structures\"?

In high-level programming languages, we don't need to manually specify the initial capacity of stacks (queues); this task is automatically handled internally by the class. For example, the initial capacity of Java's ArrayList is usually 10. Furthermore, the expansion operation is also implemented automatically. See the subsequent \"List\" chapter for details.

"},{"location":"chapter_hashing/","title":"Chapter 6. \u00a0 Hash Table","text":"

Abstract

In the world of computing, a hash table is akin to an intelligent librarian.

It understands how to compute index numbers, enabling swift retrieval of the desired book.

"},{"location":"chapter_hashing/#chapter-contents","title":"Chapter Contents","text":"
  • 6.1 \u00a0 Hash Table
  • 6.2 \u00a0 Hash Collision
  • 6.3 \u00a0 Hash Algorithm
  • 6.4 \u00a0 Summary
"},{"location":"chapter_hashing/hash_algorithm/","title":"6.3 \u00a0 Hash Algorithms","text":"

The previous two sections introduced the working principle of hash tables and the methods to handle hash collisions. However, both open addressing and chaining can only ensure that the hash table functions normally when collisions occur, but cannot reduce the frequency of hash collisions.

If hash collisions occur too frequently, the performance of the hash table will deteriorate drastically. As shown in the Figure 6-8 , for a chaining hash table, in the ideal case, the key-value pairs are evenly distributed across the buckets, achieving optimal query efficiency; in the worst case, all key-value pairs are stored in the same bucket, degrading the time complexity to \\(O(n)\\).

Figure 6-8 \u00a0 Ideal and Worst Cases of Hash Collisions

The distribution of key-value pairs is determined by the hash function. Recalling the steps of calculating a hash function, first compute the hash value, then modulo it by the array length:

index = hash(key) % capacity\n

Observing the above formula, when the hash table capacity capacity is fixed, the hash algorithm hash() determines the output value, thereby determining the distribution of key-value pairs in the hash table.

This means that, to reduce the probability of hash collisions, we should focus on the design of the hash algorithm hash().

"},{"location":"chapter_hashing/hash_algorithm/#631-goals-of-hash-algorithms","title":"6.3.1 \u00a0 Goals of Hash Algorithms","text":"

To achieve a \"fast and stable\" hash table data structure, hash algorithms should have the following characteristics:

  • Determinism: For the same input, the hash algorithm should always produce the same output. Only then can the hash table be reliable.
  • High Efficiency: The process of computing the hash value should be fast enough. The smaller the computational overhead, the more practical the hash table.
  • Uniform Distribution: The hash algorithm should ensure that key-value pairs are evenly distributed in the hash table. The more uniform the distribution, the lower the probability of hash collisions.

In fact, hash algorithms are not only used to implement hash tables but are also widely applied in other fields.

  • Password Storage: To protect the security of user passwords, systems usually do not store the plaintext passwords but rather the hash values of the passwords. When a user enters a password, the system calculates the hash value of the input and compares it with the stored hash value. If they match, the password is considered correct.
  • Data Integrity Check: The data sender can calculate the hash value of the data and send it along; the receiver can recalculate the hash value of the received data and compare it with the received hash value. If they match, the data is considered intact.

For cryptographic applications, to prevent reverse engineering such as deducing the original password from the hash value, hash algorithms need higher-level security features.

  • Unidirectionality: It should be impossible to deduce any information about the input data from the hash value.
  • Collision Resistance: It should be extremely difficult to find two different inputs that produce the same hash value.
  • Avalanche Effect: Minor changes in the input should lead to significant and unpredictable changes in the output.

Note that \"Uniform Distribution\" and \"Collision Resistance\" are two separate concepts. Satisfying uniform distribution does not necessarily mean collision resistance. For example, under random input key, the hash function key % 100 can produce a uniformly distributed output. However, this hash algorithm is too simple, and all key with the same last two digits will have the same output, making it easy to deduce a usable key from the hash value, thereby cracking the password.

"},{"location":"chapter_hashing/hash_algorithm/#632-design-of-hash-algorithms","title":"6.3.2 \u00a0 Design of Hash Algorithms","text":"

The design of hash algorithms is a complex issue that requires consideration of many factors. However, for some less demanding scenarios, we can also design some simple hash algorithms.

  • Additive Hash: Add up the ASCII codes of each character in the input and use the total sum as the hash value.
  • Multiplicative Hash: Utilize the non-correlation of multiplication, multiplying each round by a constant, accumulating the ASCII codes of each character into the hash value.
  • XOR Hash: Accumulate the hash value by XORing each element of the input data.
  • Rotating Hash: Accumulate the ASCII code of each character into a hash value, performing a rotation operation on the hash value before each accumulation.
PythonC++JavaC#GoSwiftJSTSDartRustCZig simple_hash.py
def add_hash(key: str) -> int:\n    \"\"\"\u52a0\u6cd5\u54c8\u5e0c\"\"\"\n    hash = 0\n    modulus = 1000000007\n    for c in key:\n        hash += ord(c)\n    return hash % modulus\n\ndef mul_hash(key: str) -> int:\n    \"\"\"\u4e58\u6cd5\u54c8\u5e0c\"\"\"\n    hash = 0\n    modulus = 1000000007\n    for c in key:\n        hash = 31 * hash + ord(c)\n    return hash % modulus\n\ndef xor_hash(key: str) -> int:\n    \"\"\"\u5f02\u6216\u54c8\u5e0c\"\"\"\n    hash = 0\n    modulus = 1000000007\n    for c in key:\n        hash ^= ord(c)\n    return hash % modulus\n\ndef rot_hash(key: str) -> int:\n    \"\"\"\u65cb\u8f6c\u54c8\u5e0c\"\"\"\n    hash = 0\n    modulus = 1000000007\n    for c in key:\n        hash = (hash << 4) ^ (hash >> 28) ^ ord(c)\n    return hash % modulus\n
simple_hash.cpp
/* \u52a0\u6cd5\u54c8\u5e0c */\nint addHash(string key) {\n    long long hash = 0;\n    const int MODULUS = 1000000007;\n    for (unsigned char c : key) {\n        hash = (hash + (int)c) % MODULUS;\n    }\n    return (int)hash;\n}\n\n/* \u4e58\u6cd5\u54c8\u5e0c */\nint mulHash(string key) {\n    long long hash = 0;\n    const int MODULUS = 1000000007;\n    for (unsigned char c : key) {\n        hash = (31 * hash + (int)c) % MODULUS;\n    }\n    return (int)hash;\n}\n\n/* \u5f02\u6216\u54c8\u5e0c */\nint xorHash(string key) {\n    int hash = 0;\n    const int MODULUS = 1000000007;\n    for (unsigned char c : key) {\n        hash ^= (int)c;\n    }\n    return hash & MODULUS;\n}\n\n/* \u65cb\u8f6c\u54c8\u5e0c */\nint rotHash(string key) {\n    long long hash = 0;\n    const int MODULUS = 1000000007;\n    for (unsigned char c : key) {\n        hash = ((hash << 4) ^ (hash >> 28) ^ (int)c) % MODULUS;\n    }\n    return (int)hash;\n}\n
simple_hash.java
/* \u52a0\u6cd5\u54c8\u5e0c */\nint addHash(String key) {\n    long hash = 0;\n    final int MODULUS = 1000000007;\n    for (char c : key.toCharArray()) {\n        hash = (hash + (int) c) % MODULUS;\n    }\n    return (int) hash;\n}\n\n/* \u4e58\u6cd5\u54c8\u5e0c */\nint mulHash(String key) {\n    long hash = 0;\n    final int MODULUS = 1000000007;\n    for (char c : key.toCharArray()) {\n        hash = (31 * hash + (int) c) % MODULUS;\n    }\n    return (int) hash;\n}\n\n/* \u5f02\u6216\u54c8\u5e0c */\nint xorHash(String key) {\n    int hash = 0;\n    final int MODULUS = 1000000007;\n    for (char c : key.toCharArray()) {\n        hash ^= (int) c;\n    }\n    return hash & MODULUS;\n}\n\n/* \u65cb\u8f6c\u54c8\u5e0c */\nint rotHash(String key) {\n    long hash = 0;\n    final int MODULUS = 1000000007;\n    for (char c : key.toCharArray()) {\n        hash = ((hash << 4) ^ (hash >> 28) ^ (int) c) % MODULUS;\n    }\n    return (int) hash;\n}\n
simple_hash.cs
/* \u52a0\u6cd5\u54c8\u5e0c */\nint AddHash(string key) {\n    long hash = 0;\n    const int MODULUS = 1000000007;\n    foreach (char c in key) {\n        hash = (hash + c) % MODULUS;\n    }\n    return (int)hash;\n}\n\n/* \u4e58\u6cd5\u54c8\u5e0c */\nint MulHash(string key) {\n    long hash = 0;\n    const int MODULUS = 1000000007;\n    foreach (char c in key) {\n        hash = (31 * hash + c) % MODULUS;\n    }\n    return (int)hash;\n}\n\n/* \u5f02\u6216\u54c8\u5e0c */\nint XorHash(string key) {\n    int hash = 0;\n    const int MODULUS = 1000000007;\n    foreach (char c in key) {\n        hash ^= c;\n    }\n    return hash & MODULUS;\n}\n\n/* \u65cb\u8f6c\u54c8\u5e0c */\nint RotHash(string key) {\n    long hash = 0;\n    const int MODULUS = 1000000007;\n    foreach (char c in key) {\n        hash = ((hash << 4) ^ (hash >> 28) ^ c) % MODULUS;\n    }\n    return (int)hash;\n}\n
simple_hash.go
/* \u52a0\u6cd5\u54c8\u5e0c */\nfunc addHash(key string) int {\n    var hash int64\n    var modulus int64\n\n    modulus = 1000000007\n    for _, b := range []byte(key) {\n        hash = (hash + int64(b)) % modulus\n    }\n    return int(hash)\n}\n\n/* \u4e58\u6cd5\u54c8\u5e0c */\nfunc mulHash(key string) int {\n    var hash int64\n    var modulus int64\n\n    modulus = 1000000007\n    for _, b := range []byte(key) {\n        hash = (31*hash + int64(b)) % modulus\n    }\n    return int(hash)\n}\n\n/* \u5f02\u6216\u54c8\u5e0c */\nfunc xorHash(key string) int {\n    hash := 0\n    modulus := 1000000007\n    for _, b := range []byte(key) {\n        fmt.Println(int(b))\n        hash ^= int(b)\n        hash = (31*hash + int(b)) % modulus\n    }\n    return hash & modulus\n}\n\n/* \u65cb\u8f6c\u54c8\u5e0c */\nfunc rotHash(key string) int {\n    var hash int64\n    var modulus int64\n\n    modulus = 1000000007\n    for _, b := range []byte(key) {\n        hash = ((hash << 4) ^ (hash >> 28) ^ int64(b)) % modulus\n    }\n    return int(hash)\n}\n
simple_hash.swift
/* \u52a0\u6cd5\u54c8\u5e0c */\nfunc addHash(key: String) -> Int {\n    var hash = 0\n    let MODULUS = 1_000_000_007\n    for c in key {\n        for scalar in c.unicodeScalars {\n            hash = (hash + Int(scalar.value)) % MODULUS\n        }\n    }\n    return hash\n}\n\n/* \u4e58\u6cd5\u54c8\u5e0c */\nfunc mulHash(key: String) -> Int {\n    var hash = 0\n    let MODULUS = 1_000_000_007\n    for c in key {\n        for scalar in c.unicodeScalars {\n            hash = (31 * hash + Int(scalar.value)) % MODULUS\n        }\n    }\n    return hash\n}\n\n/* \u5f02\u6216\u54c8\u5e0c */\nfunc xorHash(key: String) -> Int {\n    var hash = 0\n    let MODULUS = 1_000_000_007\n    for c in key {\n        for scalar in c.unicodeScalars {\n            hash ^= Int(scalar.value)\n        }\n    }\n    return hash & MODULUS\n}\n\n/* \u65cb\u8f6c\u54c8\u5e0c */\nfunc rotHash(key: String) -> Int {\n    var hash = 0\n    let MODULUS = 1_000_000_007\n    for c in key {\n        for scalar in c.unicodeScalars {\n            hash = ((hash << 4) ^ (hash >> 28) ^ Int(scalar.value)) % MODULUS\n        }\n    }\n    return hash\n}\n
simple_hash.js
/* \u52a0\u6cd5\u54c8\u5e0c */\nfunction addHash(key) {\n    let hash = 0;\n    const MODULUS = 1000000007;\n    for (const c of key) {\n        hash = (hash + c.charCodeAt(0)) % MODULUS;\n    }\n    return hash;\n}\n\n/* \u4e58\u6cd5\u54c8\u5e0c */\nfunction mulHash(key) {\n    let hash = 0;\n    const MODULUS = 1000000007;\n    for (const c of key) {\n        hash = (31 * hash + c.charCodeAt(0)) % MODULUS;\n    }\n    return hash;\n}\n\n/* \u5f02\u6216\u54c8\u5e0c */\nfunction xorHash(key) {\n    let hash = 0;\n    const MODULUS = 1000000007;\n    for (const c of key) {\n        hash ^= c.charCodeAt(0);\n    }\n    return hash & MODULUS;\n}\n\n/* \u65cb\u8f6c\u54c8\u5e0c */\nfunction rotHash(key) {\n    let hash = 0;\n    const MODULUS = 1000000007;\n    for (const c of key) {\n        hash = ((hash << 4) ^ (hash >> 28) ^ c.charCodeAt(0)) % MODULUS;\n    }\n    return hash;\n}\n
simple_hash.ts
/* \u52a0\u6cd5\u54c8\u5e0c */\nfunction addHash(key: string): number {\n    let hash = 0;\n    const MODULUS = 1000000007;\n    for (const c of key) {\n        hash = (hash + c.charCodeAt(0)) % MODULUS;\n    }\n    return hash;\n}\n\n/* \u4e58\u6cd5\u54c8\u5e0c */\nfunction mulHash(key: string): number {\n    let hash = 0;\n    const MODULUS = 1000000007;\n    for (const c of key) {\n        hash = (31 * hash + c.charCodeAt(0)) % MODULUS;\n    }\n    return hash;\n}\n\n/* \u5f02\u6216\u54c8\u5e0c */\nfunction xorHash(key: string): number {\n    let hash = 0;\n    const MODULUS = 1000000007;\n    for (const c of key) {\n        hash ^= c.charCodeAt(0);\n    }\n    return hash & MODULUS;\n}\n\n/* \u65cb\u8f6c\u54c8\u5e0c */\nfunction rotHash(key: string): number {\n    let hash = 0;\n    const MODULUS = 1000000007;\n    for (const c of key) {\n        hash = ((hash << 4) ^ (hash >> 28) ^ c.charCodeAt(0)) % MODULUS;\n    }\n    return hash;\n}\n
simple_hash.dart
/* \u52a0\u6cd5\u54c8\u5e0c */\nint addHash(String key) {\n  int hash = 0;\n  final int MODULUS = 1000000007;\n  for (int i = 0; i < key.length; i++) {\n    hash = (hash + key.codeUnitAt(i)) % MODULUS;\n  }\n  return hash;\n}\n\n/* \u4e58\u6cd5\u54c8\u5e0c */\nint mulHash(String key) {\n  int hash = 0;\n  final int MODULUS = 1000000007;\n  for (int i = 0; i < key.length; i++) {\n    hash = (31 * hash + key.codeUnitAt(i)) % MODULUS;\n  }\n  return hash;\n}\n\n/* \u5f02\u6216\u54c8\u5e0c */\nint xorHash(String key) {\n  int hash = 0;\n  final int MODULUS = 1000000007;\n  for (int i = 0; i < key.length; i++) {\n    hash ^= key.codeUnitAt(i);\n  }\n  return hash & MODULUS;\n}\n\n/* \u65cb\u8f6c\u54c8\u5e0c */\nint rotHash(String key) {\n  int hash = 0;\n  final int MODULUS = 1000000007;\n  for (int i = 0; i < key.length; i++) {\n    hash = ((hash << 4) ^ (hash >> 28) ^ key.codeUnitAt(i)) % MODULUS;\n  }\n  return hash;\n}\n
simple_hash.rs
/* \u52a0\u6cd5\u54c8\u5e0c */\nfn add_hash(key: &str) -> i32 {\n    let mut hash = 0_i64;\n    const MODULUS: i64 = 1000000007;\n\n    for c in key.chars() {\n        hash = (hash + c as i64) % MODULUS;\n    }\n\n    hash as i32\n}\n\n/* \u4e58\u6cd5\u54c8\u5e0c */\nfn mul_hash(key: &str) -> i32 {\n    let mut hash = 0_i64;\n    const MODULUS: i64 = 1000000007;\n\n    for c in key.chars() {\n        hash = (31 * hash + c as i64) % MODULUS;\n    }\n\n    hash as i32\n}\n\n/* \u5f02\u6216\u54c8\u5e0c */\nfn xor_hash(key: &str) -> i32 {\n    let mut hash = 0_i64;\n    const MODULUS: i64 = 1000000007;\n\n    for c in key.chars() {\n        hash ^= c as i64;\n    }\n\n    (hash & MODULUS) as i32\n}\n\n/* \u65cb\u8f6c\u54c8\u5e0c */\nfn rot_hash(key: &str) -> i32 {\n    let mut hash = 0_i64;\n    const MODULUS: i64 = 1000000007;\n\n    for c in key.chars() {\n        hash = ((hash << 4) ^ (hash >> 28) ^ c as i64) % MODULUS;\n    }\n\n    hash as i32\n}\n
simple_hash.c
/* \u52a0\u6cd5\u54c8\u5e0c */\nint addHash(char *key) {\n    long long hash = 0;\n    const int MODULUS = 1000000007;\n    for (int i = 0; i < strlen(key); i++) {\n        hash = (hash + (unsigned char)key[i]) % MODULUS;\n    }\n    return (int)hash;\n}\n\n/* \u4e58\u6cd5\u54c8\u5e0c */\nint mulHash(char *key) {\n    long long hash = 0;\n    const int MODULUS = 1000000007;\n    for (int i = 0; i < strlen(key); i++) {\n        hash = (31 * hash + (unsigned char)key[i]) % MODULUS;\n    }\n    return (int)hash;\n}\n\n/* \u5f02\u6216\u54c8\u5e0c */\nint xorHash(char *key) {\n    int hash = 0;\n    const int MODULUS = 1000000007;\n\n    for (int i = 0; i < strlen(key); i++) {\n        hash ^= (unsigned char)key[i];\n    }\n    return hash & MODULUS;\n}\n\n/* \u65cb\u8f6c\u54c8\u5e0c */\nint rotHash(char *key) {\n    long long hash = 0;\n    const int MODULUS = 1000000007;\n    for (int i = 0; i < strlen(key); i++) {\n        hash = ((hash << 4) ^ (hash >> 28) ^ (unsigned char)key[i]) % MODULUS;\n    }\n\n    return (int)hash;\n}\n
simple_hash.zig
[class]{}-[func]{addHash}\n\n[class]{}-[func]{mulHash}\n\n[class]{}-[func]{xorHash}\n\n[class]{}-[func]{rotHash}\n
Code Visualization

Full Screen >

It is observed that the last step of each hash algorithm is to take the modulus of the large prime number \\(1000000007\\) to ensure that the hash value is within an appropriate range. It is worth pondering why emphasis is placed on modulo a prime number, or what are the disadvantages of modulo a composite number? This is an interesting question.

To conclude: Using a large prime number as the modulus can maximize the uniform distribution of hash values. Since a prime number does not share common factors with other numbers, it can reduce the periodic patterns caused by the modulo operation, thus avoiding hash collisions.

For example, suppose we choose the composite number \\(9\\) as the modulus, which can be divided by \\(3\\), then all key divisible by \\(3\\) will be mapped to hash values \\(0\\), \\(3\\), \\(6\\).

\\[ \\begin{aligned} \\text{modulus} & = 9 \\newline \\text{key} & = \\{ 0, 3, 6, 9, 12, 15, 18, 21, 24, 27, 30, 33, \\dots \\} \\newline \\text{hash} & = \\{ 0, 3, 6, 0, 3, 6, 0, 3, 6, 0, 3, 6,\\dots \\} \\end{aligned} \\]

If the input key happens to have this kind of arithmetic sequence distribution, then the hash values will cluster, thereby exacerbating hash collisions. Now, suppose we replace modulus with the prime number \\(13\\), since there are no common factors between key and modulus, the uniformity of the output hash values will be significantly improved.

\\[ \\begin{aligned} \\text{modulus} & = 13 \\newline \\text{key} & = \\{ 0, 3, 6, 9, 12, 15, 18, 21, 24, 27, 30, 33, \\dots \\} \\newline \\text{hash} & = \\{ 0, 3, 6, 9, 12, 2, 5, 8, 11, 1, 4, 7, \\dots \\} \\end{aligned} \\]

It is worth noting that if the key is guaranteed to be randomly and uniformly distributed, then choosing a prime number or a composite number as the modulus can both produce uniformly distributed hash values. However, when the distribution of key has some periodicity, modulo a composite number is more likely to result in clustering.

In summary, we usually choose a prime number as the modulus, and this prime number should be large enough to eliminate periodic patterns as much as possible, enhancing the robustness of the hash algorithm.

"},{"location":"chapter_hashing/hash_algorithm/#633-common-hash-algorithms","title":"6.3.3 \u00a0 Common Hash Algorithms","text":"

It is not hard to see that the simple hash algorithms mentioned above are quite \"fragile\" and far from reaching the design goals of hash algorithms. For example, since addition and XOR obey the commutative law, additive hash and XOR hash cannot distinguish strings with the same content but in different order, which may exacerbate hash collisions and cause security issues.

In practice, we usually use some standard hash algorithms, such as MD5, SHA-1, SHA-2, and SHA-3. They can map input data of any length to a fixed-length hash value.

Over the past century, hash algorithms have been in a continuous process of upgrading and optimization. Some researchers strive to improve the performance of hash algorithms, while others, including hackers, are dedicated to finding security issues in hash algorithms. The Table 6-2 shows hash algorithms commonly used in practical applications.

  • MD5 and SHA-1 have been successfully attacked multiple times and are thus abandoned in various security applications.
  • SHA-2 series, especially SHA-256, is one of the most secure hash algorithms to date, with no successful attacks reported, hence commonly used in various security applications and protocols.
  • SHA-3 has lower implementation costs and higher computational efficiency compared to SHA-2, but its current usage coverage is not as extensive as the SHA-2 series.

Table 6-2 \u00a0 Common Hash Algorithms

MD5 SHA-1 SHA-2 SHA-3 Release Year 1992 1995 2002 2008 Output Length 128 bit 160 bit 256/512 bit 224/256/384/512 bit Hash Collisions Frequent Frequent Rare Rare Security Level Low, has been successfully attacked Low, has been successfully attacked High High Applications Abandoned, still used for data integrity checks Abandoned Cryptocurrency transaction verification, digital signatures, etc. Can be used to replace SHA-2"},{"location":"chapter_hashing/hash_algorithm/#hash-values-in-data-structures","title":"Hash Values in Data Structures","text":"

We know that the keys in a hash table can be of various data types such as integers, decimals, or strings. Programming languages usually provide built-in hash algorithms for these data types to calculate the bucket indices in the hash table. Taking Python as an example, we can use the hash() function to compute the hash values for various data types.

  • The hash values of integers and booleans are their own values.
  • The calculation of hash values for floating-point numbers and strings is more complex, and interested readers are encouraged to study this on their own.
  • The hash value of a tuple is a combination of the hash values of each of its elements, resulting in a single hash value.
  • The hash value of an object is generated based on its memory address. By overriding the hash method of an object, hash values can be generated based on content.

Tip

Be aware that the definition and methods of the built-in hash value calculation functions in different programming languages vary.

PythonC++JavaC#GoSwiftJSTSDartRustCZig built_in_hash.py
num = 3\nhash_num = hash(num)\n# Hash value of integer 3 is 3\n\nbol = True\nhash_bol = hash(bol)\n# Hash value of boolean True is 1\n\ndec = 3.14159\nhash_dec = hash(dec)\n# Hash value of decimal 3.14159 is 326484311674566659\n\nstr = \"Hello \u7b97\u6cd5\"\nhash_str = hash(str)\n# Hash value of string \"Hello \u7b97\u6cd5\" is 4617003410720528961\n\ntup = (12836, \"\u5c0f\u54c8\")\nhash_tup = hash(tup)\n# Hash value of tuple (12836, '\u5c0f\u54c8') is 1029005403108185979\n\nobj = ListNode(0)\nhash_obj = hash(obj)\n# Hash value of ListNode object at 0x1058fd810 is 274267521\n
built_in_hash.cpp
int num = 3;\nsize_t hashNum = hash<int>()(num);\n// Hash value of integer 3 is 3\n\nbool bol = true;\nsize_t hashBol = hash<bool>()(bol);\n// Hash value of boolean 1 is 1\n\ndouble dec = 3.14159;\nsize_t hashDec = hash<double>()(dec);\n// Hash value of decimal 3.14159 is 4614256650576692846\n\nstring str = \"Hello \u7b97\u6cd5\";\nsize_t hashStr = hash<string>()(str);\n// Hash value of string \"Hello \u7b97\u6cd5\" is 15466937326284535026\n\n// In C++, built-in std::hash() only provides hash values for basic data types\n// Hash values for arrays and objects need to be implemented separately\n
built_in_hash.java
int num = 3;\nint hashNum = Integer.hashCode(num);\n// Hash value of integer 3 is 3\n\nboolean bol = true;\nint hashBol = Boolean.hashCode(bol);\n// Hash value of boolean true is 1231\n\ndouble dec = 3.14159;\nint hashDec = Double.hashCode(dec);\n// Hash value of decimal 3.14159 is -1340954729\n\nString str = \"Hello \u7b97\u6cd5\";\nint hashStr = str.hashCode();\n// Hash value of string \"Hello \u7b97\u6cd5\" is -727081396\n\nObject[] arr = { 12836, \"\u5c0f\u54c8\" };\nint hashTup = Arrays.hashCode(arr);\n// Hash value of array [12836, \u5c0f\u54c8] is 1151158\n\nListNode obj = new ListNode(0);\nint hashObj = obj.hashCode();\n// Hash value of ListNode object utils.ListNode@7dc5e7b4 is 2110121908\n
built_in_hash.cs
int num = 3;\nint hashNum = num.GetHashCode();\n// Hash value of integer 3 is 3;\n\nbool bol = true;\nint hashBol = bol.GetHashCode();\n// Hash value of boolean true is 1;\n\ndouble dec = 3.14159;\nint hashDec = dec.GetHashCode();\n// Hash value of decimal 3.14159 is -1340954729;\n\nstring str = \"Hello \u7b97\u6cd5\";\nint hashStr = str.GetHashCode();\n// Hash value of string \"Hello \u7b97\u6cd5\" is -586107568;\n\nobject[] arr = [12836, \"\u5c0f\u54c8\"];\nint hashTup = arr.GetHashCode();\n// Hash value of array [12836, \u5c0f\u54c8] is 42931033;\n\nListNode obj = new(0);\nint hashObj = obj.GetHashCode();\n// Hash value of ListNode object 0 is 39053774;\n
built_in_hash.go
// Go does not provide built-in hash code functions\n
built_in_hash.swift
let num = 3\nlet hashNum = num.hashValue\n// Hash value of integer 3 is 9047044699613009734\n\nlet bol = true\nlet hashBol = bol.hashValue\n// Hash value of boolean true is -4431640247352757451\n\nlet dec = 3.14159\nlet hashDec = dec.hashValue\n// Hash value of decimal 3.14159 is -2465384235396674631\n\nlet str = \"Hello \u7b97\u6cd5\"\nlet hashStr = str.hashValue\n// Hash value of string \"Hello \u7b97\u6cd5\" is -7850626797806988787\n\nlet arr = [AnyHashable(12836), AnyHashable(\"\u5c0f\u54c8\")]\nlet hashTup = arr.hashValue\n// Hash value of array [AnyHashable(12836), AnyHashable(\"\u5c0f\u54c8\")] is -2308633508154532996\n\nlet obj = ListNode(x: 0)\nlet hashObj = obj.hashValue\n// Hash value of ListNode object utils.ListNode is -2434780518035996159\n
built_in_hash.js
// JavaScript does not provide built-in hash code functions\n
built_in_hash.ts
// TypeScript does not provide built-in hash code functions\n
built_in_hash.dart
int num = 3;\nint hashNum = num.hashCode;\n// Hash value of integer 3 is 34803\n\nbool bol = true;\nint hashBol = bol.hashCode;\n// Hash value of boolean true is 1231\n\ndouble dec = 3.14159;\nint hashDec = dec.hashCode;\n// Hash value of decimal 3.14159 is 2570631074981783\n\nString str = \"Hello \u7b97\u6cd5\";\nint hashStr = str.hashCode;\n// Hash value of string \"Hello \u7b97\u6cd5\" is 468167534\n\nList arr = [12836, \"\u5c0f\u54c8\"];\nint hashArr = arr.hashCode;\n// Hash value of array [12836, \u5c0f\u54c8] is 976512528\n\nListNode obj = new ListNode(0);\nint hashObj = obj.hashCode;\n// Hash value of ListNode object Instance of 'ListNode' is 1033450432\n
built_in_hash.rs
use std::collections::hash_map::DefaultHasher;\nuse std::hash::{Hash, Hasher};\n\nlet num = 3;\nlet mut num_hasher = DefaultHasher::new();\nnum.hash(&mut num_hasher);\nlet hash_num = num_hasher.finish();\n// Hash value of integer 3 is 568126464209439262\n\nlet bol = true;\nlet mut bol_hasher = DefaultHasher::new();\nbol.hash(&mut bol_hasher);\nlet hash_bol = bol_hasher.finish();\n// Hash value of boolean true is 4952851536318644461\n\nlet dec: f32 = 3.14159;\nlet mut dec_hasher = DefaultHasher::new();\ndec.to_bits().hash(&mut dec_hasher);\nlet hash_dec = dec_hasher.finish();\n// Hash value of decimal 3.14159 is 2566941990314602357\n\nlet str = \"Hello \u7b97\u6cd5\";\nlet mut str_hasher = DefaultHasher::new();\nstr.hash(&mut str_hasher);\nlet hash_str = str_hasher.finish();\n// Hash value of string \"Hello \u7b97\u6cd5\" is 16092673739211250988\n\nlet arr = (&12836, &\"\u5c0f\u54c8\");\nlet mut tup_hasher = DefaultHasher::new();\narr.hash(&mut tup_hasher);\nlet hash_tup = tup_hasher.finish();\n// Hash value of tuple (12836, \"\u5c0f\u54c8\") is 1885128010422702749\n\nlet node = ListNode::new(42);\nlet mut hasher = DefaultHasher::new();\nnode.borrow().val.hash(&mut hasher);\nlet hash = hasher.finish();\n// Hash value of ListNode object RefCell { value: ListNode { val: 42, next: None } } is 15387811073369036852\n
built_in_hash.c
// C does not provide built-in hash code functions\n
built_in_hash.zig
\n
Code Visualization

Full Screen >

In many programming languages, only immutable objects can serve as the key in a hash table. If we use a list (dynamic array) as a key, when the contents of the list change, its hash value also changes, and we would no longer be able to find the original value in the hash table.

Although the member variables of a custom object (such as a linked list node) are mutable, it is hashable. This is because the hash value of an object is usually generated based on its memory address, and even if the contents of the object change, the memory address remains the same, so the hash value remains unchanged.

You might have noticed that the hash values output in different consoles are different. This is because the Python interpreter adds a random salt to the string hash function each time it starts up. This approach effectively prevents HashDoS attacks and enhances the security of the hash algorithm.

"},{"location":"chapter_hashing/hash_collision/","title":"6.2 \u00a0 Hash Collision","text":"

As mentioned in the previous section, usually the input space of a hash function is much larger than its output space, making hash collisions theoretically inevitable. For example, if the input space consists of all integers and the output space is the size of the array capacity, multiple integers will inevitably map to the same bucket index.

Hash collisions can lead to incorrect query results, severely affecting the usability of hash tables. To solve this problem, we expand the hash table whenever a hash collision occurs, until the collision is resolved. This method is simple and effective but inefficient due to the extensive data transfer and hash value computation involved in resizing the hash table. To improve efficiency, we can adopt the following strategies:

  1. Improve the data structure of the hash table, allowing it to function normally in the event of a hash collision.
  2. Only perform resizing when necessary, i.e., when hash collisions are severe.

There are mainly two methods for improving the structure of hash tables: \"Separate Chaining\" and \"Open Addressing\".

"},{"location":"chapter_hashing/hash_collision/#621-separate-chaining","title":"6.2.1 \u00a0 Separate Chaining","text":"

In the original hash table, each bucket can store only one key-value pair. \"Separate chaining\" transforms individual elements into a linked list, with key-value pairs as list nodes, storing all colliding key-value pairs in the same list. The Figure 6-5 shows an example of a hash table with separate chaining.

Figure 6-5 \u00a0 Separate Chaining Hash Table

The operations of a hash table implemented with separate chaining have changed as follows:

  • Querying Elements: Input key, pass through the hash function to obtain the bucket index, access the head node of the list, then traverse the list and compare key to find the target key-value pair.
  • Adding Elements: First access the list head node via the hash function, then add the node (key-value pair) to the list.
  • Deleting Elements: Access the list head based on the hash function's result, then traverse the list to find and remove the target node.

Separate chaining has the following limitations:

  • Increased Space Usage: The linked list contains node pointers, which consume more memory space than arrays.
  • Reduced Query Efficiency: Due to the need for linear traversal of the list to find the corresponding element.

The code below provides a simple implementation of a separate chaining hash table, with two things to note:

  • Lists (dynamic arrays) are used instead of linked lists for simplicity. In this setup, the hash table (array) contains multiple buckets, each of which is a list.
  • This implementation includes a method for resizing the hash table. When the load factor exceeds \\(\\frac{2}{3}\\), we resize the hash table to twice its original size.
PythonC++JavaC#GoSwiftJSTSDartRustCZig hash_map_chaining.py
class HashMapChaining:\n    \"\"\"\u94fe\u5f0f\u5730\u5740\u54c8\u5e0c\u8868\"\"\"\n\n    def __init__(self):\n        \"\"\"\u6784\u9020\u65b9\u6cd5\"\"\"\n        self.size = 0  # \u952e\u503c\u5bf9\u6570\u91cf\n        self.capacity = 4  # \u54c8\u5e0c\u8868\u5bb9\u91cf\n        self.load_thres = 2.0 / 3.0  # \u89e6\u53d1\u6269\u5bb9\u7684\u8d1f\u8f7d\u56e0\u5b50\u9608\u503c\n        self.extend_ratio = 2  # \u6269\u5bb9\u500d\u6570\n        self.buckets = [[] for _ in range(self.capacity)]  # \u6876\u6570\u7ec4\n\n    def hash_func(self, key: int) -> int:\n        \"\"\"\u54c8\u5e0c\u51fd\u6570\"\"\"\n        return key % self.capacity\n\n    def load_factor(self) -> float:\n        \"\"\"\u8d1f\u8f7d\u56e0\u5b50\"\"\"\n        return self.size / self.capacity\n\n    def get(self, key: int) -> str | None:\n        \"\"\"\u67e5\u8be2\u64cd\u4f5c\"\"\"\n        index = self.hash_func(key)\n        bucket = self.buckets[index]\n        # \u904d\u5386\u6876\uff0c\u82e5\u627e\u5230 key \uff0c\u5219\u8fd4\u56de\u5bf9\u5e94 val\n        for pair in bucket:\n            if pair.key == key:\n                return pair.val\n        # \u82e5\u672a\u627e\u5230 key \uff0c\u5219\u8fd4\u56de None\n        return None\n\n    def put(self, key: int, val: str):\n        \"\"\"\u6dfb\u52a0\u64cd\u4f5c\"\"\"\n        # \u5f53\u8d1f\u8f7d\u56e0\u5b50\u8d85\u8fc7\u9608\u503c\u65f6\uff0c\u6267\u884c\u6269\u5bb9\n        if self.load_factor() > self.load_thres:\n            self.extend()\n        index = self.hash_func(key)\n        bucket = self.buckets[index]\n        # \u904d\u5386\u6876\uff0c\u82e5\u9047\u5230\u6307\u5b9a key \uff0c\u5219\u66f4\u65b0\u5bf9\u5e94 val \u5e76\u8fd4\u56de\n        for pair in bucket:\n            if pair.key == key:\n                pair.val = val\n                return\n        # \u82e5\u65e0\u8be5 key \uff0c\u5219\u5c06\u952e\u503c\u5bf9\u6dfb\u52a0\u81f3\u5c3e\u90e8\n        pair = Pair(key, val)\n        bucket.append(pair)\n        self.size += 1\n\n    def remove(self, key: int):\n        \"\"\"\u5220\u9664\u64cd\u4f5c\"\"\"\n        index = self.hash_func(key)\n        bucket = self.buckets[index]\n        # \u904d\u5386\u6876\uff0c\u4ece\u4e2d\u5220\u9664\u952e\u503c\u5bf9\n        for pair in bucket:\n            if pair.key == key:\n                bucket.remove(pair)\n                self.size -= 1\n                break\n\n    def extend(self):\n        \"\"\"\u6269\u5bb9\u54c8\u5e0c\u8868\"\"\"\n        # \u6682\u5b58\u539f\u54c8\u5e0c\u8868\n        buckets = self.buckets\n        # \u521d\u59cb\u5316\u6269\u5bb9\u540e\u7684\u65b0\u54c8\u5e0c\u8868\n        self.capacity *= self.extend_ratio\n        self.buckets = [[] for _ in range(self.capacity)]\n        self.size = 0\n        # \u5c06\u952e\u503c\u5bf9\u4ece\u539f\u54c8\u5e0c\u8868\u642c\u8fd0\u81f3\u65b0\u54c8\u5e0c\u8868\n        for bucket in buckets:\n            for pair in bucket:\n                self.put(pair.key, pair.val)\n\n    def print(self):\n        \"\"\"\u6253\u5370\u54c8\u5e0c\u8868\"\"\"\n        for bucket in self.buckets:\n            res = []\n            for pair in bucket:\n                res.append(str(pair.key) + \" -> \" + pair.val)\n            print(res)\n
hash_map_chaining.cpp
/* \u94fe\u5f0f\u5730\u5740\u54c8\u5e0c\u8868 */\nclass HashMapChaining {\n  private:\n    int size;                       // \u952e\u503c\u5bf9\u6570\u91cf\n    int capacity;                   // \u54c8\u5e0c\u8868\u5bb9\u91cf\n    double loadThres;               // \u89e6\u53d1\u6269\u5bb9\u7684\u8d1f\u8f7d\u56e0\u5b50\u9608\u503c\n    int extendRatio;                // \u6269\u5bb9\u500d\u6570\n    vector<vector<Pair *>> buckets; // \u6876\u6570\u7ec4\n\n  public:\n    /* \u6784\u9020\u65b9\u6cd5 */\n    HashMapChaining() : size(0), capacity(4), loadThres(2.0 / 3.0), extendRatio(2) {\n        buckets.resize(capacity);\n    }\n\n    /* \u6790\u6784\u65b9\u6cd5 */\n    ~HashMapChaining() {\n        for (auto &bucket : buckets) {\n            for (Pair *pair : bucket) {\n                // \u91ca\u653e\u5185\u5b58\n                delete pair;\n            }\n        }\n    }\n\n    /* \u54c8\u5e0c\u51fd\u6570 */\n    int hashFunc(int key) {\n        return key % capacity;\n    }\n\n    /* \u8d1f\u8f7d\u56e0\u5b50 */\n    double loadFactor() {\n        return (double)size / (double)capacity;\n    }\n\n    /* \u67e5\u8be2\u64cd\u4f5c */\n    string get(int key) {\n        int index = hashFunc(key);\n        // \u904d\u5386\u6876\uff0c\u82e5\u627e\u5230 key \uff0c\u5219\u8fd4\u56de\u5bf9\u5e94 val\n        for (Pair *pair : buckets[index]) {\n            if (pair->key == key) {\n                return pair->val;\n            }\n        }\n        // \u82e5\u672a\u627e\u5230 key \uff0c\u5219\u8fd4\u56de\u7a7a\u5b57\u7b26\u4e32\n        return \"\";\n    }\n\n    /* \u6dfb\u52a0\u64cd\u4f5c */\n    void put(int key, string val) {\n        // \u5f53\u8d1f\u8f7d\u56e0\u5b50\u8d85\u8fc7\u9608\u503c\u65f6\uff0c\u6267\u884c\u6269\u5bb9\n        if (loadFactor() > loadThres) {\n            extend();\n        }\n        int index = hashFunc(key);\n        // \u904d\u5386\u6876\uff0c\u82e5\u9047\u5230\u6307\u5b9a key \uff0c\u5219\u66f4\u65b0\u5bf9\u5e94 val \u5e76\u8fd4\u56de\n        for (Pair *pair : buckets[index]) {\n            if (pair->key == key) {\n                pair->val = val;\n                return;\n            }\n        }\n        // \u82e5\u65e0\u8be5 key \uff0c\u5219\u5c06\u952e\u503c\u5bf9\u6dfb\u52a0\u81f3\u5c3e\u90e8\n        buckets[index].push_back(new Pair(key, val));\n        size++;\n    }\n\n    /* \u5220\u9664\u64cd\u4f5c */\n    void remove(int key) {\n        int index = hashFunc(key);\n        auto &bucket = buckets[index];\n        // \u904d\u5386\u6876\uff0c\u4ece\u4e2d\u5220\u9664\u952e\u503c\u5bf9\n        for (int i = 0; i < bucket.size(); i++) {\n            if (bucket[i]->key == key) {\n                Pair *tmp = bucket[i];\n                bucket.erase(bucket.begin() + i); // \u4ece\u4e2d\u5220\u9664\u952e\u503c\u5bf9\n                delete tmp;                       // \u91ca\u653e\u5185\u5b58\n                size--;\n                return;\n            }\n        }\n    }\n\n    /* \u6269\u5bb9\u54c8\u5e0c\u8868 */\n    void extend() {\n        // \u6682\u5b58\u539f\u54c8\u5e0c\u8868\n        vector<vector<Pair *>> bucketsTmp = buckets;\n        // \u521d\u59cb\u5316\u6269\u5bb9\u540e\u7684\u65b0\u54c8\u5e0c\u8868\n        capacity *= extendRatio;\n        buckets.clear();\n        buckets.resize(capacity);\n        size = 0;\n        // \u5c06\u952e\u503c\u5bf9\u4ece\u539f\u54c8\u5e0c\u8868\u642c\u8fd0\u81f3\u65b0\u54c8\u5e0c\u8868\n        for (auto &bucket : bucketsTmp) {\n            for (Pair *pair : bucket) {\n                put(pair->key, pair->val);\n                // \u91ca\u653e\u5185\u5b58\n                delete pair;\n            }\n        }\n    }\n\n    /* \u6253\u5370\u54c8\u5e0c\u8868 */\n    void print() {\n        for (auto &bucket : buckets) {\n            cout << \"[\";\n            for (Pair *pair : bucket) {\n                cout << pair->key << \" -> \" << pair->val << \", \";\n            }\n            cout << \"]\\n\";\n        }\n    }\n};\n
hash_map_chaining.java
/* \u94fe\u5f0f\u5730\u5740\u54c8\u5e0c\u8868 */\nclass HashMapChaining {\n    int size; // \u952e\u503c\u5bf9\u6570\u91cf\n    int capacity; // \u54c8\u5e0c\u8868\u5bb9\u91cf\n    double loadThres; // \u89e6\u53d1\u6269\u5bb9\u7684\u8d1f\u8f7d\u56e0\u5b50\u9608\u503c\n    int extendRatio; // \u6269\u5bb9\u500d\u6570\n    List<List<Pair>> buckets; // \u6876\u6570\u7ec4\n\n    /* \u6784\u9020\u65b9\u6cd5 */\n    public HashMapChaining() {\n        size = 0;\n        capacity = 4;\n        loadThres = 2.0 / 3.0;\n        extendRatio = 2;\n        buckets = new ArrayList<>(capacity);\n        for (int i = 0; i < capacity; i++) {\n            buckets.add(new ArrayList<>());\n        }\n    }\n\n    /* \u54c8\u5e0c\u51fd\u6570 */\n    int hashFunc(int key) {\n        return key % capacity;\n    }\n\n    /* \u8d1f\u8f7d\u56e0\u5b50 */\n    double loadFactor() {\n        return (double) size / capacity;\n    }\n\n    /* \u67e5\u8be2\u64cd\u4f5c */\n    String get(int key) {\n        int index = hashFunc(key);\n        List<Pair> bucket = buckets.get(index);\n        // \u904d\u5386\u6876\uff0c\u82e5\u627e\u5230 key \uff0c\u5219\u8fd4\u56de\u5bf9\u5e94 val\n        for (Pair pair : bucket) {\n            if (pair.key == key) {\n                return pair.val;\n            }\n        }\n        // \u82e5\u672a\u627e\u5230 key \uff0c\u5219\u8fd4\u56de null\n        return null;\n    }\n\n    /* \u6dfb\u52a0\u64cd\u4f5c */\n    void put(int key, String val) {\n        // \u5f53\u8d1f\u8f7d\u56e0\u5b50\u8d85\u8fc7\u9608\u503c\u65f6\uff0c\u6267\u884c\u6269\u5bb9\n        if (loadFactor() > loadThres) {\n            extend();\n        }\n        int index = hashFunc(key);\n        List<Pair> bucket = buckets.get(index);\n        // \u904d\u5386\u6876\uff0c\u82e5\u9047\u5230\u6307\u5b9a key \uff0c\u5219\u66f4\u65b0\u5bf9\u5e94 val \u5e76\u8fd4\u56de\n        for (Pair pair : bucket) {\n            if (pair.key == key) {\n                pair.val = val;\n                return;\n            }\n        }\n        // \u82e5\u65e0\u8be5 key \uff0c\u5219\u5c06\u952e\u503c\u5bf9\u6dfb\u52a0\u81f3\u5c3e\u90e8\n        Pair pair = new Pair(key, val);\n        bucket.add(pair);\n        size++;\n    }\n\n    /* \u5220\u9664\u64cd\u4f5c */\n    void remove(int key) {\n        int index = hashFunc(key);\n        List<Pair> bucket = buckets.get(index);\n        // \u904d\u5386\u6876\uff0c\u4ece\u4e2d\u5220\u9664\u952e\u503c\u5bf9\n        for (Pair pair : bucket) {\n            if (pair.key == key) {\n                bucket.remove(pair);\n                size--;\n                break;\n            }\n        }\n    }\n\n    /* \u6269\u5bb9\u54c8\u5e0c\u8868 */\n    void extend() {\n        // \u6682\u5b58\u539f\u54c8\u5e0c\u8868\n        List<List<Pair>> bucketsTmp = buckets;\n        // \u521d\u59cb\u5316\u6269\u5bb9\u540e\u7684\u65b0\u54c8\u5e0c\u8868\n        capacity *= extendRatio;\n        buckets = new ArrayList<>(capacity);\n        for (int i = 0; i < capacity; i++) {\n            buckets.add(new ArrayList<>());\n        }\n        size = 0;\n        // \u5c06\u952e\u503c\u5bf9\u4ece\u539f\u54c8\u5e0c\u8868\u642c\u8fd0\u81f3\u65b0\u54c8\u5e0c\u8868\n        for (List<Pair> bucket : bucketsTmp) {\n            for (Pair pair : bucket) {\n                put(pair.key, pair.val);\n            }\n        }\n    }\n\n    /* \u6253\u5370\u54c8\u5e0c\u8868 */\n    void print() {\n        for (List<Pair> bucket : buckets) {\n            List<String> res = new ArrayList<>();\n            for (Pair pair : bucket) {\n                res.add(pair.key + \" -> \" + pair.val);\n            }\n            System.out.println(res);\n        }\n    }\n}\n
hash_map_chaining.cs
/* \u94fe\u5f0f\u5730\u5740\u54c8\u5e0c\u8868 */\nclass HashMapChaining {\n    int size; // \u952e\u503c\u5bf9\u6570\u91cf\n    int capacity; // \u54c8\u5e0c\u8868\u5bb9\u91cf\n    double loadThres; // \u89e6\u53d1\u6269\u5bb9\u7684\u8d1f\u8f7d\u56e0\u5b50\u9608\u503c\n    int extendRatio; // \u6269\u5bb9\u500d\u6570\n    List<List<Pair>> buckets; // \u6876\u6570\u7ec4\n\n    /* \u6784\u9020\u65b9\u6cd5 */\n    public HashMapChaining() {\n        size = 0;\n        capacity = 4;\n        loadThres = 2.0 / 3.0;\n        extendRatio = 2;\n        buckets = new List<List<Pair>>(capacity);\n        for (int i = 0; i < capacity; i++) {\n            buckets.Add([]);\n        }\n    }\n\n    /* \u54c8\u5e0c\u51fd\u6570 */\n    int HashFunc(int key) {\n        return key % capacity;\n    }\n\n    /* \u8d1f\u8f7d\u56e0\u5b50 */\n    double LoadFactor() {\n        return (double)size / capacity;\n    }\n\n    /* \u67e5\u8be2\u64cd\u4f5c */\n    public string? Get(int key) {\n        int index = HashFunc(key);\n        // \u904d\u5386\u6876\uff0c\u82e5\u627e\u5230 key \uff0c\u5219\u8fd4\u56de\u5bf9\u5e94 val\n        foreach (Pair pair in buckets[index]) {\n            if (pair.key == key) {\n                return pair.val;\n            }\n        }\n        // \u82e5\u672a\u627e\u5230 key \uff0c\u5219\u8fd4\u56de null\n        return null;\n    }\n\n    /* \u6dfb\u52a0\u64cd\u4f5c */\n    public void Put(int key, string val) {\n        // \u5f53\u8d1f\u8f7d\u56e0\u5b50\u8d85\u8fc7\u9608\u503c\u65f6\uff0c\u6267\u884c\u6269\u5bb9\n        if (LoadFactor() > loadThres) {\n            Extend();\n        }\n        int index = HashFunc(key);\n        // \u904d\u5386\u6876\uff0c\u82e5\u9047\u5230\u6307\u5b9a key \uff0c\u5219\u66f4\u65b0\u5bf9\u5e94 val \u5e76\u8fd4\u56de\n        foreach (Pair pair in buckets[index]) {\n            if (pair.key == key) {\n                pair.val = val;\n                return;\n            }\n        }\n        // \u82e5\u65e0\u8be5 key \uff0c\u5219\u5c06\u952e\u503c\u5bf9\u6dfb\u52a0\u81f3\u5c3e\u90e8\n        buckets[index].Add(new Pair(key, val));\n        size++;\n    }\n\n    /* \u5220\u9664\u64cd\u4f5c */\n    public void Remove(int key) {\n        int index = HashFunc(key);\n        // \u904d\u5386\u6876\uff0c\u4ece\u4e2d\u5220\u9664\u952e\u503c\u5bf9\n        foreach (Pair pair in buckets[index].ToList()) {\n            if (pair.key == key) {\n                buckets[index].Remove(pair);\n                size--;\n                break;\n            }\n        }\n    }\n\n    /* \u6269\u5bb9\u54c8\u5e0c\u8868 */\n    void Extend() {\n        // \u6682\u5b58\u539f\u54c8\u5e0c\u8868\n        List<List<Pair>> bucketsTmp = buckets;\n        // \u521d\u59cb\u5316\u6269\u5bb9\u540e\u7684\u65b0\u54c8\u5e0c\u8868\n        capacity *= extendRatio;\n        buckets = new List<List<Pair>>(capacity);\n        for (int i = 0; i < capacity; i++) {\n            buckets.Add([]);\n        }\n        size = 0;\n        // \u5c06\u952e\u503c\u5bf9\u4ece\u539f\u54c8\u5e0c\u8868\u642c\u8fd0\u81f3\u65b0\u54c8\u5e0c\u8868\n        foreach (List<Pair> bucket in bucketsTmp) {\n            foreach (Pair pair in bucket) {\n                Put(pair.key, pair.val);\n            }\n        }\n    }\n\n    /* \u6253\u5370\u54c8\u5e0c\u8868 */\n    public void Print() {\n        foreach (List<Pair> bucket in buckets) {\n            List<string> res = [];\n            foreach (Pair pair in bucket) {\n                res.Add(pair.key + \" -> \" + pair.val);\n            }\n            foreach (string kv in res) {\n                Console.WriteLine(kv);\n            }\n        }\n    }\n}\n
hash_map_chaining.go
/* \u94fe\u5f0f\u5730\u5740\u54c8\u5e0c\u8868 */\ntype hashMapChaining struct {\n    size        int      // \u952e\u503c\u5bf9\u6570\u91cf\n    capacity    int      // \u54c8\u5e0c\u8868\u5bb9\u91cf\n    loadThres   float64  // \u89e6\u53d1\u6269\u5bb9\u7684\u8d1f\u8f7d\u56e0\u5b50\u9608\u503c\n    extendRatio int      // \u6269\u5bb9\u500d\u6570\n    buckets     [][]pair // \u6876\u6570\u7ec4\n}\n\n/* \u6784\u9020\u65b9\u6cd5 */\nfunc newHashMapChaining() *hashMapChaining {\n    buckets := make([][]pair, 4)\n    for i := 0; i < 4; i++ {\n        buckets[i] = make([]pair, 0)\n    }\n    return &hashMapChaining{\n        size:        0,\n        capacity:    4,\n        loadThres:   2.0 / 3.0,\n        extendRatio: 2,\n        buckets:     buckets,\n    }\n}\n\n/* \u54c8\u5e0c\u51fd\u6570 */\nfunc (m *hashMapChaining) hashFunc(key int) int {\n    return key % m.capacity\n}\n\n/* \u8d1f\u8f7d\u56e0\u5b50 */\nfunc (m *hashMapChaining) loadFactor() float64 {\n    return float64(m.size) / float64(m.capacity)\n}\n\n/* \u67e5\u8be2\u64cd\u4f5c */\nfunc (m *hashMapChaining) get(key int) string {\n    idx := m.hashFunc(key)\n    bucket := m.buckets[idx]\n    // \u904d\u5386\u6876\uff0c\u82e5\u627e\u5230 key \uff0c\u5219\u8fd4\u56de\u5bf9\u5e94 val\n    for _, p := range bucket {\n        if p.key == key {\n            return p.val\n        }\n    }\n    // \u82e5\u672a\u627e\u5230 key \uff0c\u5219\u8fd4\u56de\u7a7a\u5b57\u7b26\u4e32\n    return \"\"\n}\n\n/* \u6dfb\u52a0\u64cd\u4f5c */\nfunc (m *hashMapChaining) put(key int, val string) {\n    // \u5f53\u8d1f\u8f7d\u56e0\u5b50\u8d85\u8fc7\u9608\u503c\u65f6\uff0c\u6267\u884c\u6269\u5bb9\n    if m.loadFactor() > m.loadThres {\n        m.extend()\n    }\n    idx := m.hashFunc(key)\n    // \u904d\u5386\u6876\uff0c\u82e5\u9047\u5230\u6307\u5b9a key \uff0c\u5219\u66f4\u65b0\u5bf9\u5e94 val \u5e76\u8fd4\u56de\n    for i := range m.buckets[idx] {\n        if m.buckets[idx][i].key == key {\n            m.buckets[idx][i].val = val\n            return\n        }\n    }\n    // \u82e5\u65e0\u8be5 key \uff0c\u5219\u5c06\u952e\u503c\u5bf9\u6dfb\u52a0\u81f3\u5c3e\u90e8\n    p := pair{\n        key: key,\n        val: val,\n    }\n    m.buckets[idx] = append(m.buckets[idx], p)\n    m.size += 1\n}\n\n/* \u5220\u9664\u64cd\u4f5c */\nfunc (m *hashMapChaining) remove(key int) {\n    idx := m.hashFunc(key)\n    // \u904d\u5386\u6876\uff0c\u4ece\u4e2d\u5220\u9664\u952e\u503c\u5bf9\n    for i, p := range m.buckets[idx] {\n        if p.key == key {\n            // \u5207\u7247\u5220\u9664\n            m.buckets[idx] = append(m.buckets[idx][:i], m.buckets[idx][i+1:]...)\n            m.size -= 1\n            break\n        }\n    }\n}\n\n/* \u6269\u5bb9\u54c8\u5e0c\u8868 */\nfunc (m *hashMapChaining) extend() {\n    // \u6682\u5b58\u539f\u54c8\u5e0c\u8868\n    tmpBuckets := make([][]pair, len(m.buckets))\n    for i := 0; i < len(m.buckets); i++ {\n        tmpBuckets[i] = make([]pair, len(m.buckets[i]))\n        copy(tmpBuckets[i], m.buckets[i])\n    }\n    // \u521d\u59cb\u5316\u6269\u5bb9\u540e\u7684\u65b0\u54c8\u5e0c\u8868\n    m.capacity *= m.extendRatio\n    m.buckets = make([][]pair, m.capacity)\n    for i := 0; i < m.capacity; i++ {\n        m.buckets[i] = make([]pair, 0)\n    }\n    m.size = 0\n    // \u5c06\u952e\u503c\u5bf9\u4ece\u539f\u54c8\u5e0c\u8868\u642c\u8fd0\u81f3\u65b0\u54c8\u5e0c\u8868\n    for _, bucket := range tmpBuckets {\n        for _, p := range bucket {\n            m.put(p.key, p.val)\n        }\n    }\n}\n\n/* \u6253\u5370\u54c8\u5e0c\u8868 */\nfunc (m *hashMapChaining) print() {\n    var builder strings.Builder\n\n    for _, bucket := range m.buckets {\n        builder.WriteString(\"[\")\n        for _, p := range bucket {\n            builder.WriteString(strconv.Itoa(p.key) + \" -> \" + p.val + \" \")\n        }\n        builder.WriteString(\"]\")\n        fmt.Println(builder.String())\n        builder.Reset()\n    }\n}\n
hash_map_chaining.swift
/* \u94fe\u5f0f\u5730\u5740\u54c8\u5e0c\u8868 */\nclass HashMapChaining {\n    var size: Int // \u952e\u503c\u5bf9\u6570\u91cf\n    var capacity: Int // \u54c8\u5e0c\u8868\u5bb9\u91cf\n    var loadThres: Double // \u89e6\u53d1\u6269\u5bb9\u7684\u8d1f\u8f7d\u56e0\u5b50\u9608\u503c\n    var extendRatio: Int // \u6269\u5bb9\u500d\u6570\n    var buckets: [[Pair]] // \u6876\u6570\u7ec4\n\n    /* \u6784\u9020\u65b9\u6cd5 */\n    init() {\n        size = 0\n        capacity = 4\n        loadThres = 2.0 / 3.0\n        extendRatio = 2\n        buckets = Array(repeating: [], count: capacity)\n    }\n\n    /* \u54c8\u5e0c\u51fd\u6570 */\n    func hashFunc(key: Int) -> Int {\n        key % capacity\n    }\n\n    /* \u8d1f\u8f7d\u56e0\u5b50 */\n    func loadFactor() -> Double {\n        Double(size) / Double(capacity)\n    }\n\n    /* \u67e5\u8be2\u64cd\u4f5c */\n    func get(key: Int) -> String? {\n        let index = hashFunc(key: key)\n        let bucket = buckets[index]\n        // \u904d\u5386\u6876\uff0c\u82e5\u627e\u5230 key \uff0c\u5219\u8fd4\u56de\u5bf9\u5e94 val\n        for pair in bucket {\n            if pair.key == key {\n                return pair.val\n            }\n        }\n        // \u82e5\u672a\u627e\u5230 key \uff0c\u5219\u8fd4\u56de nil\n        return nil\n    }\n\n    /* \u6dfb\u52a0\u64cd\u4f5c */\n    func put(key: Int, val: String) {\n        // \u5f53\u8d1f\u8f7d\u56e0\u5b50\u8d85\u8fc7\u9608\u503c\u65f6\uff0c\u6267\u884c\u6269\u5bb9\n        if loadFactor() > loadThres {\n            extend()\n        }\n        let index = hashFunc(key: key)\n        let bucket = buckets[index]\n        // \u904d\u5386\u6876\uff0c\u82e5\u9047\u5230\u6307\u5b9a key \uff0c\u5219\u66f4\u65b0\u5bf9\u5e94 val \u5e76\u8fd4\u56de\n        for pair in bucket {\n            if pair.key == key {\n                pair.val = val\n                return\n            }\n        }\n        // \u82e5\u65e0\u8be5 key \uff0c\u5219\u5c06\u952e\u503c\u5bf9\u6dfb\u52a0\u81f3\u5c3e\u90e8\n        let pair = Pair(key: key, val: val)\n        buckets[index].append(pair)\n        size += 1\n    }\n\n    /* \u5220\u9664\u64cd\u4f5c */\n    func remove(key: Int) {\n        let index = hashFunc(key: key)\n        let bucket = buckets[index]\n        // \u904d\u5386\u6876\uff0c\u4ece\u4e2d\u5220\u9664\u952e\u503c\u5bf9\n        for (pairIndex, pair) in bucket.enumerated() {\n            if pair.key == key {\n                buckets[index].remove(at: pairIndex)\n                size -= 1\n                break\n            }\n        }\n    }\n\n    /* \u6269\u5bb9\u54c8\u5e0c\u8868 */\n    func extend() {\n        // \u6682\u5b58\u539f\u54c8\u5e0c\u8868\n        let bucketsTmp = buckets\n        // \u521d\u59cb\u5316\u6269\u5bb9\u540e\u7684\u65b0\u54c8\u5e0c\u8868\n        capacity *= extendRatio\n        buckets = Array(repeating: [], count: capacity)\n        size = 0\n        // \u5c06\u952e\u503c\u5bf9\u4ece\u539f\u54c8\u5e0c\u8868\u642c\u8fd0\u81f3\u65b0\u54c8\u5e0c\u8868\n        for bucket in bucketsTmp {\n            for pair in bucket {\n                put(key: pair.key, val: pair.val)\n            }\n        }\n    }\n\n    /* \u6253\u5370\u54c8\u5e0c\u8868 */\n    func print() {\n        for bucket in buckets {\n            let res = bucket.map { \"\\($0.key) -> \\($0.val)\" }\n            Swift.print(res)\n        }\n    }\n}\n
hash_map_chaining.js
/* \u94fe\u5f0f\u5730\u5740\u54c8\u5e0c\u8868 */\nclass HashMapChaining {\n    #size; // \u952e\u503c\u5bf9\u6570\u91cf\n    #capacity; // \u54c8\u5e0c\u8868\u5bb9\u91cf\n    #loadThres; // \u89e6\u53d1\u6269\u5bb9\u7684\u8d1f\u8f7d\u56e0\u5b50\u9608\u503c\n    #extendRatio; // \u6269\u5bb9\u500d\u6570\n    #buckets; // \u6876\u6570\u7ec4\n\n    /* \u6784\u9020\u65b9\u6cd5 */\n    constructor() {\n        this.#size = 0;\n        this.#capacity = 4;\n        this.#loadThres = 2.0 / 3.0;\n        this.#extendRatio = 2;\n        this.#buckets = new Array(this.#capacity).fill(null).map((x) => []);\n    }\n\n    /* \u54c8\u5e0c\u51fd\u6570 */\n    #hashFunc(key) {\n        return key % this.#capacity;\n    }\n\n    /* \u8d1f\u8f7d\u56e0\u5b50 */\n    #loadFactor() {\n        return this.#size / this.#capacity;\n    }\n\n    /* \u67e5\u8be2\u64cd\u4f5c */\n    get(key) {\n        const index = this.#hashFunc(key);\n        const bucket = this.#buckets[index];\n        // \u904d\u5386\u6876\uff0c\u82e5\u627e\u5230 key \uff0c\u5219\u8fd4\u56de\u5bf9\u5e94 val\n        for (const pair of bucket) {\n            if (pair.key === key) {\n                return pair.val;\n            }\n        }\n        // \u82e5\u672a\u627e\u5230 key \uff0c\u5219\u8fd4\u56de null\n        return null;\n    }\n\n    /* \u6dfb\u52a0\u64cd\u4f5c */\n    put(key, val) {\n        // \u5f53\u8d1f\u8f7d\u56e0\u5b50\u8d85\u8fc7\u9608\u503c\u65f6\uff0c\u6267\u884c\u6269\u5bb9\n        if (this.#loadFactor() > this.#loadThres) {\n            this.#extend();\n        }\n        const index = this.#hashFunc(key);\n        const bucket = this.#buckets[index];\n        // \u904d\u5386\u6876\uff0c\u82e5\u9047\u5230\u6307\u5b9a key \uff0c\u5219\u66f4\u65b0\u5bf9\u5e94 val \u5e76\u8fd4\u56de\n        for (const pair of bucket) {\n            if (pair.key === key) {\n                pair.val = val;\n                return;\n            }\n        }\n        // \u82e5\u65e0\u8be5 key \uff0c\u5219\u5c06\u952e\u503c\u5bf9\u6dfb\u52a0\u81f3\u5c3e\u90e8\n        const pair = new Pair(key, val);\n        bucket.push(pair);\n        this.#size++;\n    }\n\n    /* \u5220\u9664\u64cd\u4f5c */\n    remove(key) {\n        const index = this.#hashFunc(key);\n        let bucket = this.#buckets[index];\n        // \u904d\u5386\u6876\uff0c\u4ece\u4e2d\u5220\u9664\u952e\u503c\u5bf9\n        for (let i = 0; i < bucket.length; i++) {\n            if (bucket[i].key === key) {\n                bucket.splice(i, 1);\n                this.#size--;\n                break;\n            }\n        }\n    }\n\n    /* \u6269\u5bb9\u54c8\u5e0c\u8868 */\n    #extend() {\n        // \u6682\u5b58\u539f\u54c8\u5e0c\u8868\n        const bucketsTmp = this.#buckets;\n        // \u521d\u59cb\u5316\u6269\u5bb9\u540e\u7684\u65b0\u54c8\u5e0c\u8868\n        this.#capacity *= this.#extendRatio;\n        this.#buckets = new Array(this.#capacity).fill(null).map((x) => []);\n        this.#size = 0;\n        // \u5c06\u952e\u503c\u5bf9\u4ece\u539f\u54c8\u5e0c\u8868\u642c\u8fd0\u81f3\u65b0\u54c8\u5e0c\u8868\n        for (const bucket of bucketsTmp) {\n            for (const pair of bucket) {\n                this.put(pair.key, pair.val);\n            }\n        }\n    }\n\n    /* \u6253\u5370\u54c8\u5e0c\u8868 */\n    print() {\n        for (const bucket of this.#buckets) {\n            let res = [];\n            for (const pair of bucket) {\n                res.push(pair.key + ' -> ' + pair.val);\n            }\n            console.log(res);\n        }\n    }\n}\n
hash_map_chaining.ts
/* \u94fe\u5f0f\u5730\u5740\u54c8\u5e0c\u8868 */\nclass HashMapChaining {\n    #size: number; // \u952e\u503c\u5bf9\u6570\u91cf\n    #capacity: number; // \u54c8\u5e0c\u8868\u5bb9\u91cf\n    #loadThres: number; // \u89e6\u53d1\u6269\u5bb9\u7684\u8d1f\u8f7d\u56e0\u5b50\u9608\u503c\n    #extendRatio: number; // \u6269\u5bb9\u500d\u6570\n    #buckets: Pair[][]; // \u6876\u6570\u7ec4\n\n    /* \u6784\u9020\u65b9\u6cd5 */\n    constructor() {\n        this.#size = 0;\n        this.#capacity = 4;\n        this.#loadThres = 2.0 / 3.0;\n        this.#extendRatio = 2;\n        this.#buckets = new Array(this.#capacity).fill(null).map((x) => []);\n    }\n\n    /* \u54c8\u5e0c\u51fd\u6570 */\n    #hashFunc(key: number): number {\n        return key % this.#capacity;\n    }\n\n    /* \u8d1f\u8f7d\u56e0\u5b50 */\n    #loadFactor(): number {\n        return this.#size / this.#capacity;\n    }\n\n    /* \u67e5\u8be2\u64cd\u4f5c */\n    get(key: number): string | null {\n        const index = this.#hashFunc(key);\n        const bucket = this.#buckets[index];\n        // \u904d\u5386\u6876\uff0c\u82e5\u627e\u5230 key \uff0c\u5219\u8fd4\u56de\u5bf9\u5e94 val\n        for (const pair of bucket) {\n            if (pair.key === key) {\n                return pair.val;\n            }\n        }\n        // \u82e5\u672a\u627e\u5230 key \uff0c\u5219\u8fd4\u56de null\n        return null;\n    }\n\n    /* \u6dfb\u52a0\u64cd\u4f5c */\n    put(key: number, val: string): void {\n        // \u5f53\u8d1f\u8f7d\u56e0\u5b50\u8d85\u8fc7\u9608\u503c\u65f6\uff0c\u6267\u884c\u6269\u5bb9\n        if (this.#loadFactor() > this.#loadThres) {\n            this.#extend();\n        }\n        const index = this.#hashFunc(key);\n        const bucket = this.#buckets[index];\n        // \u904d\u5386\u6876\uff0c\u82e5\u9047\u5230\u6307\u5b9a key \uff0c\u5219\u66f4\u65b0\u5bf9\u5e94 val \u5e76\u8fd4\u56de\n        for (const pair of bucket) {\n            if (pair.key === key) {\n                pair.val = val;\n                return;\n            }\n        }\n        // \u82e5\u65e0\u8be5 key \uff0c\u5219\u5c06\u952e\u503c\u5bf9\u6dfb\u52a0\u81f3\u5c3e\u90e8\n        const pair = new Pair(key, val);\n        bucket.push(pair);\n        this.#size++;\n    }\n\n    /* \u5220\u9664\u64cd\u4f5c */\n    remove(key: number): void {\n        const index = this.#hashFunc(key);\n        let bucket = this.#buckets[index];\n        // \u904d\u5386\u6876\uff0c\u4ece\u4e2d\u5220\u9664\u952e\u503c\u5bf9\n        for (let i = 0; i < bucket.length; i++) {\n            if (bucket[i].key === key) {\n                bucket.splice(i, 1);\n                this.#size--;\n                break;\n            }\n        }\n    }\n\n    /* \u6269\u5bb9\u54c8\u5e0c\u8868 */\n    #extend(): void {\n        // \u6682\u5b58\u539f\u54c8\u5e0c\u8868\n        const bucketsTmp = this.#buckets;\n        // \u521d\u59cb\u5316\u6269\u5bb9\u540e\u7684\u65b0\u54c8\u5e0c\u8868\n        this.#capacity *= this.#extendRatio;\n        this.#buckets = new Array(this.#capacity).fill(null).map((x) => []);\n        this.#size = 0;\n        // \u5c06\u952e\u503c\u5bf9\u4ece\u539f\u54c8\u5e0c\u8868\u642c\u8fd0\u81f3\u65b0\u54c8\u5e0c\u8868\n        for (const bucket of bucketsTmp) {\n            for (const pair of bucket) {\n                this.put(pair.key, pair.val);\n            }\n        }\n    }\n\n    /* \u6253\u5370\u54c8\u5e0c\u8868 */\n    print(): void {\n        for (const bucket of this.#buckets) {\n            let res = [];\n            for (const pair of bucket) {\n                res.push(pair.key + ' -> ' + pair.val);\n            }\n            console.log(res);\n        }\n    }\n}\n
hash_map_chaining.dart
/* \u94fe\u5f0f\u5730\u5740\u54c8\u5e0c\u8868 */\nclass HashMapChaining {\n  late int size; // \u952e\u503c\u5bf9\u6570\u91cf\n  late int capacity; // \u54c8\u5e0c\u8868\u5bb9\u91cf\n  late double loadThres; // \u89e6\u53d1\u6269\u5bb9\u7684\u8d1f\u8f7d\u56e0\u5b50\u9608\u503c\n  late int extendRatio; // \u6269\u5bb9\u500d\u6570\n  late List<List<Pair>> buckets; // \u6876\u6570\u7ec4\n\n  /* \u6784\u9020\u65b9\u6cd5 */\n  HashMapChaining() {\n    size = 0;\n    capacity = 4;\n    loadThres = 2.0 / 3.0;\n    extendRatio = 2;\n    buckets = List.generate(capacity, (_) => []);\n  }\n\n  /* \u54c8\u5e0c\u51fd\u6570 */\n  int hashFunc(int key) {\n    return key % capacity;\n  }\n\n  /* \u8d1f\u8f7d\u56e0\u5b50 */\n  double loadFactor() {\n    return size / capacity;\n  }\n\n  /* \u67e5\u8be2\u64cd\u4f5c */\n  String? get(int key) {\n    int index = hashFunc(key);\n    List<Pair> bucket = buckets[index];\n    // \u904d\u5386\u6876\uff0c\u82e5\u627e\u5230 key \uff0c\u5219\u8fd4\u56de\u5bf9\u5e94 val\n    for (Pair pair in bucket) {\n      if (pair.key == key) {\n        return pair.val;\n      }\n    }\n    // \u82e5\u672a\u627e\u5230 key \uff0c\u5219\u8fd4\u56de null\n    return null;\n  }\n\n  /* \u6dfb\u52a0\u64cd\u4f5c */\n  void put(int key, String val) {\n    // \u5f53\u8d1f\u8f7d\u56e0\u5b50\u8d85\u8fc7\u9608\u503c\u65f6\uff0c\u6267\u884c\u6269\u5bb9\n    if (loadFactor() > loadThres) {\n      extend();\n    }\n    int index = hashFunc(key);\n    List<Pair> bucket = buckets[index];\n    // \u904d\u5386\u6876\uff0c\u82e5\u9047\u5230\u6307\u5b9a key \uff0c\u5219\u66f4\u65b0\u5bf9\u5e94 val \u5e76\u8fd4\u56de\n    for (Pair pair in bucket) {\n      if (pair.key == key) {\n        pair.val = val;\n        return;\n      }\n    }\n    // \u82e5\u65e0\u8be5 key \uff0c\u5219\u5c06\u952e\u503c\u5bf9\u6dfb\u52a0\u81f3\u5c3e\u90e8\n    Pair pair = Pair(key, val);\n    bucket.add(pair);\n    size++;\n  }\n\n  /* \u5220\u9664\u64cd\u4f5c */\n  void remove(int key) {\n    int index = hashFunc(key);\n    List<Pair> bucket = buckets[index];\n    // \u904d\u5386\u6876\uff0c\u4ece\u4e2d\u5220\u9664\u952e\u503c\u5bf9\n    for (Pair pair in bucket) {\n      if (pair.key == key) {\n        bucket.remove(pair);\n        size--;\n        break;\n      }\n    }\n  }\n\n  /* \u6269\u5bb9\u54c8\u5e0c\u8868 */\n  void extend() {\n    // \u6682\u5b58\u539f\u54c8\u5e0c\u8868\n    List<List<Pair>> bucketsTmp = buckets;\n    // \u521d\u59cb\u5316\u6269\u5bb9\u540e\u7684\u65b0\u54c8\u5e0c\u8868\n    capacity *= extendRatio;\n    buckets = List.generate(capacity, (_) => []);\n    size = 0;\n    // \u5c06\u952e\u503c\u5bf9\u4ece\u539f\u54c8\u5e0c\u8868\u642c\u8fd0\u81f3\u65b0\u54c8\u5e0c\u8868\n    for (List<Pair> bucket in bucketsTmp) {\n      for (Pair pair in bucket) {\n        put(pair.key, pair.val);\n      }\n    }\n  }\n\n  /* \u6253\u5370\u54c8\u5e0c\u8868 */\n  void printHashMap() {\n    for (List<Pair> bucket in buckets) {\n      List<String> res = [];\n      for (Pair pair in bucket) {\n        res.add(\"${pair.key} -> ${pair.val}\");\n      }\n      print(res);\n    }\n  }\n}\n
hash_map_chaining.rs
/* \u94fe\u5f0f\u5730\u5740\u54c8\u5e0c\u8868 */\nstruct HashMapChaining {\n    size: i32,\n    capacity: i32,\n    load_thres: f32,\n    extend_ratio: i32,\n    buckets: Vec<Vec<Pair>>,\n}\n\nimpl HashMapChaining {\n    /* \u6784\u9020\u65b9\u6cd5 */\n    fn new() -> Self {\n        Self {\n            size: 0,\n            capacity: 4,\n            load_thres: 2.0 / 3.0,\n            extend_ratio: 2,\n            buckets: vec![vec![]; 4],\n        }\n    }\n\n    /* \u54c8\u5e0c\u51fd\u6570 */\n    fn hash_func(&self, key: i32) -> usize {\n        key as usize % self.capacity as usize\n    }\n\n    /* \u8d1f\u8f7d\u56e0\u5b50 */\n    fn load_factor(&self) -> f32 {\n        self.size as f32 / self.capacity as f32\n    }\n\n    /* \u5220\u9664\u64cd\u4f5c */\n    fn remove(&mut self, key: i32) -> Option<String> {\n        let index = self.hash_func(key);\n        let bucket = &mut self.buckets[index];\n\n        // \u904d\u5386\u6876\uff0c\u4ece\u4e2d\u5220\u9664\u952e\u503c\u5bf9\n        for i in 0..bucket.len() {\n            if bucket[i].key == key {\n                let pair = bucket.remove(i);\n                self.size -= 1;\n                return Some(pair.val);\n            }\n        }\n\n        // \u82e5\u672a\u627e\u5230 key \uff0c\u5219\u8fd4\u56de None\n        None\n    }\n\n    /* \u6269\u5bb9\u54c8\u5e0c\u8868 */\n    fn extend(&mut self) {\n        // \u6682\u5b58\u539f\u54c8\u5e0c\u8868\n        let buckets_tmp = std::mem::replace(&mut self.buckets, vec![]);\n\n        // \u521d\u59cb\u5316\u6269\u5bb9\u540e\u7684\u65b0\u54c8\u5e0c\u8868\n        self.capacity *= self.extend_ratio;\n        self.buckets = vec![Vec::new(); self.capacity as usize];\n        self.size = 0;\n\n        // \u5c06\u952e\u503c\u5bf9\u4ece\u539f\u54c8\u5e0c\u8868\u642c\u8fd0\u81f3\u65b0\u54c8\u5e0c\u8868\n        for bucket in buckets_tmp {\n            for pair in bucket {\n                self.put(pair.key, pair.val);\n            }\n        }\n    }\n\n    /* \u6253\u5370\u54c8\u5e0c\u8868 */\n    fn print(&self) {\n        for bucket in &self.buckets {\n            let mut res = Vec::new();\n            for pair in bucket {\n                res.push(format!(\"{} -> {}\", pair.key, pair.val));\n            }\n            println!(\"{:?}\", res);\n        }\n    }\n\n    /* \u6dfb\u52a0\u64cd\u4f5c */\n    fn put(&mut self, key: i32, val: String) {\n        // \u5f53\u8d1f\u8f7d\u56e0\u5b50\u8d85\u8fc7\u9608\u503c\u65f6\uff0c\u6267\u884c\u6269\u5bb9\n        if self.load_factor() > self.load_thres {\n            self.extend();\n        }\n\n        let index = self.hash_func(key);\n        let bucket = &mut self.buckets[index];\n\n        // \u904d\u5386\u6876\uff0c\u82e5\u9047\u5230\u6307\u5b9a key \uff0c\u5219\u66f4\u65b0\u5bf9\u5e94 val \u5e76\u8fd4\u56de\n        for pair in bucket {\n            if pair.key == key {\n                pair.val = val.clone();\n                return;\n            }\n        }\n        let bucket = &mut self.buckets[index];\n\n        // \u82e5\u65e0\u8be5 key \uff0c\u5219\u5c06\u952e\u503c\u5bf9\u6dfb\u52a0\u81f3\u5c3e\u90e8\n        let pair = Pair {\n            key,\n            val: val.clone(),\n        };\n        bucket.push(pair);\n        self.size += 1;\n    }\n\n    /* \u67e5\u8be2\u64cd\u4f5c */\n    fn get(&self, key: i32) -> Option<&str> {\n        let index = self.hash_func(key);\n        let bucket = &self.buckets[index];\n\n        // \u904d\u5386\u6876\uff0c\u82e5\u627e\u5230 key \uff0c\u5219\u8fd4\u56de\u5bf9\u5e94 val\n        for pair in bucket {\n            if pair.key == key {\n                return Some(&pair.val);\n            }\n        }\n\n        // \u82e5\u672a\u627e\u5230 key \uff0c\u5219\u8fd4\u56de None\n        None\n    }\n}\n
hash_map_chaining.c
/* \u94fe\u8868\u8282\u70b9 */\ntypedef struct Node {\n    Pair *pair;\n    struct Node *next;\n} Node;\n\n/* \u94fe\u5f0f\u5730\u5740\u54c8\u5e0c\u8868 */\ntypedef struct {\n    int size;         // \u952e\u503c\u5bf9\u6570\u91cf\n    int capacity;     // \u54c8\u5e0c\u8868\u5bb9\u91cf\n    double loadThres; // \u89e6\u53d1\u6269\u5bb9\u7684\u8d1f\u8f7d\u56e0\u5b50\u9608\u503c\n    int extendRatio;  // \u6269\u5bb9\u500d\u6570\n    Node **buckets;   // \u6876\u6570\u7ec4\n} HashMapChaining;\n\n/* \u6784\u9020\u51fd\u6570 */\nHashMapChaining *newHashMapChaining() {\n    HashMapChaining *hashMap = (HashMapChaining *)malloc(sizeof(HashMapChaining));\n    hashMap->size = 0;\n    hashMap->capacity = 4;\n    hashMap->loadThres = 2.0 / 3.0;\n    hashMap->extendRatio = 2;\n    hashMap->buckets = (Node **)malloc(hashMap->capacity * sizeof(Node *));\n    for (int i = 0; i < hashMap->capacity; i++) {\n        hashMap->buckets[i] = NULL;\n    }\n    return hashMap;\n}\n\n/* \u6790\u6784\u51fd\u6570 */\nvoid delHashMapChaining(HashMapChaining *hashMap) {\n    for (int i = 0; i < hashMap->capacity; i++) {\n        Node *cur = hashMap->buckets[i];\n        while (cur) {\n            Node *tmp = cur;\n            cur = cur->next;\n            free(tmp->pair);\n            free(tmp);\n        }\n    }\n    free(hashMap->buckets);\n    free(hashMap);\n}\n\n/* \u54c8\u5e0c\u51fd\u6570 */\nint hashFunc(HashMapChaining *hashMap, int key) {\n    return key % hashMap->capacity;\n}\n\n/* \u8d1f\u8f7d\u56e0\u5b50 */\ndouble loadFactor(HashMapChaining *hashMap) {\n    return (double)hashMap->size / (double)hashMap->capacity;\n}\n\n/* \u67e5\u8be2\u64cd\u4f5c */\nchar *get(HashMapChaining *hashMap, int key) {\n    int index = hashFunc(hashMap, key);\n    // \u904d\u5386\u6876\uff0c\u82e5\u627e\u5230 key \uff0c\u5219\u8fd4\u56de\u5bf9\u5e94 val\n    Node *cur = hashMap->buckets[index];\n    while (cur) {\n        if (cur->pair->key == key) {\n            return cur->pair->val;\n        }\n        cur = cur->next;\n    }\n    return \"\"; // \u82e5\u672a\u627e\u5230 key \uff0c\u5219\u8fd4\u56de\u7a7a\u5b57\u7b26\u4e32\n}\n\n/* \u6dfb\u52a0\u64cd\u4f5c */\nvoid put(HashMapChaining *hashMap, int key, const char *val) {\n    // \u5f53\u8d1f\u8f7d\u56e0\u5b50\u8d85\u8fc7\u9608\u503c\u65f6\uff0c\u6267\u884c\u6269\u5bb9\n    if (loadFactor(hashMap) > hashMap->loadThres) {\n        extend(hashMap);\n    }\n    int index = hashFunc(hashMap, key);\n    // \u904d\u5386\u6876\uff0c\u82e5\u9047\u5230\u6307\u5b9a key \uff0c\u5219\u66f4\u65b0\u5bf9\u5e94 val \u5e76\u8fd4\u56de\n    Node *cur = hashMap->buckets[index];\n    while (cur) {\n        if (cur->pair->key == key) {\n            strcpy(cur->pair->val, val); // \u82e5\u9047\u5230\u6307\u5b9a key \uff0c\u5219\u66f4\u65b0\u5bf9\u5e94 val \u5e76\u8fd4\u56de\n            return;\n        }\n        cur = cur->next;\n    }\n    // \u82e5\u65e0\u8be5 key \uff0c\u5219\u5c06\u952e\u503c\u5bf9\u6dfb\u52a0\u81f3\u94fe\u8868\u5934\u90e8\n    Pair *newPair = (Pair *)malloc(sizeof(Pair));\n    newPair->key = key;\n    strcpy(newPair->val, val);\n    Node *newNode = (Node *)malloc(sizeof(Node));\n    newNode->pair = newPair;\n    newNode->next = hashMap->buckets[index];\n    hashMap->buckets[index] = newNode;\n    hashMap->size++;\n}\n\n/* \u6269\u5bb9\u54c8\u5e0c\u8868 */\nvoid extend(HashMapChaining *hashMap) {\n    // \u6682\u5b58\u539f\u54c8\u5e0c\u8868\n    int oldCapacity = hashMap->capacity;\n    Node **oldBuckets = hashMap->buckets;\n    // \u521d\u59cb\u5316\u6269\u5bb9\u540e\u7684\u65b0\u54c8\u5e0c\u8868\n    hashMap->capacity *= hashMap->extendRatio;\n    hashMap->buckets = (Node **)malloc(hashMap->capacity * sizeof(Node *));\n    for (int i = 0; i < hashMap->capacity; i++) {\n        hashMap->buckets[i] = NULL;\n    }\n    hashMap->size = 0;\n    // \u5c06\u952e\u503c\u5bf9\u4ece\u539f\u54c8\u5e0c\u8868\u642c\u8fd0\u81f3\u65b0\u54c8\u5e0c\u8868\n    for (int i = 0; i < oldCapacity; i++) {\n        Node *cur = oldBuckets[i];\n        while (cur) {\n            put(hashMap, cur->pair->key, cur->pair->val);\n            Node *temp = cur;\n            cur = cur->next;\n            // \u91ca\u653e\u5185\u5b58\n            free(temp->pair);\n            free(temp);\n        }\n    }\n\n    free(oldBuckets);\n}\n\n/* \u5220\u9664\u64cd\u4f5c */\nvoid removeItem(HashMapChaining *hashMap, int key) {\n    int index = hashFunc(hashMap, key);\n    Node *cur = hashMap->buckets[index];\n    Node *pre = NULL;\n    while (cur) {\n        if (cur->pair->key == key) {\n            // \u4ece\u4e2d\u5220\u9664\u952e\u503c\u5bf9\n            if (pre) {\n                pre->next = cur->next;\n            } else {\n                hashMap->buckets[index] = cur->next;\n            }\n            // \u91ca\u653e\u5185\u5b58\n            free(cur->pair);\n            free(cur);\n            hashMap->size--;\n            return;\n        }\n        pre = cur;\n        cur = cur->next;\n    }\n}\n\n/* \u6253\u5370\u54c8\u5e0c\u8868 */\nvoid print(HashMapChaining *hashMap) {\n    for (int i = 0; i < hashMap->capacity; i++) {\n        Node *cur = hashMap->buckets[i];\n        printf(\"[\");\n        while (cur) {\n            printf(\"%d -> %s, \", cur->pair->key, cur->pair->val);\n            cur = cur->next;\n        }\n        printf(\"]\\n\");\n    }\n}\n
hash_map_chaining.zig
[class]{HashMapChaining}-[func]{}\n
Code Visualization

Full Screen >

It's worth noting that when the list is very long, the query efficiency \\(O(n)\\) is poor. At this point, the list can be converted to an \"AVL tree\" or \"Red-Black tree\" to optimize the time complexity of the query operation to \\(O(\\log n)\\).

"},{"location":"chapter_hashing/hash_collision/#622-open-addressing","title":"6.2.2 \u00a0 Open Addressing","text":"

\"Open addressing\" does not introduce additional data structures but uses \"multiple probes\" to handle hash collisions. The probing methods mainly include linear probing, quadratic probing, and double hashing.

Let's use linear probing as an example to introduce the mechanism of open addressing hash tables.

"},{"location":"chapter_hashing/hash_collision/#1-linear-probing","title":"1. \u00a0 Linear Probing","text":"

Linear probing uses a fixed-step linear search for probing, differing from ordinary hash tables.

  • Inserting Elements: Calculate the bucket index using the hash function. If the bucket already contains an element, linearly traverse forward from the conflict position (usually with a step size of \\(1\\)) until an empty bucket is found, then insert the element.
  • Searching for Elements: If a hash collision is found, use the same step size to linearly traverse forward until the corresponding element is found and return value; if an empty bucket is encountered, it means the target element is not in the hash table, so return None.

The Figure 6-6 shows the distribution of key-value pairs in an open addressing (linear probing) hash table. According to this hash function, keys with the same last two digits will be mapped to the same bucket. Through linear probing, they are stored consecutively in that bucket and the buckets below it.

Figure 6-6 \u00a0 Distribution of Key-Value Pairs in Open Addressing (Linear Probing) Hash Table

However, linear probing tends to create \"clustering\". Specifically, the longer a continuous position in the array is occupied, the more likely these positions are to encounter hash collisions, further promoting the growth of these clusters and eventually leading to deterioration in the efficiency of operations.

It's important to note that we cannot directly delete elements in an open addressing hash table. Deleting an element creates an empty bucket None in the array. When searching for elements, if linear probing encounters this empty bucket, it will return, making the elements below this bucket inaccessible. The program may incorrectly assume these elements do not exist, as shown in the Figure 6-7 .

Figure 6-7 \u00a0 Query Issues Caused by Deletion in Open Addressing

To solve this problem, we can use a \"lazy deletion\" mechanism: instead of directly removing elements from the hash table, use a constant TOMBSTONE to mark the bucket. In this mechanism, both None and TOMBSTONE represent empty buckets and can hold key-value pairs. However, when linear probing encounters TOMBSTONE, it should continue traversing since there may still be key-value pairs below it.

However, lazy deletion may accelerate the degradation of hash table performance. Every deletion operation produces a delete mark, and as TOMBSTONE increases, so does the search time, as linear probing may have to skip multiple TOMBSTONE to find the target element.

Therefore, consider recording the index of the first TOMBSTONE encountered during linear probing and swapping the target element found with this TOMBSTONE. The advantage of this is that each time a query or addition is performed, the element is moved to a bucket closer to the ideal position (starting point of probing), thereby optimizing the query efficiency.

The code below implements an open addressing (linear probing) hash table with lazy deletion. To make fuller use of the hash table space, we treat the hash table as a \"circular array,\" continuing to traverse from the beginning when the end of the array is passed.

PythonC++JavaC#GoSwiftJSTSDartRustCZig hash_map_open_addressing.py
class HashMapOpenAddressing:\n    \"\"\"\u5f00\u653e\u5bfb\u5740\u54c8\u5e0c\u8868\"\"\"\n\n    def __init__(self):\n        \"\"\"\u6784\u9020\u65b9\u6cd5\"\"\"\n        self.size = 0  # \u952e\u503c\u5bf9\u6570\u91cf\n        self.capacity = 4  # \u54c8\u5e0c\u8868\u5bb9\u91cf\n        self.load_thres = 2.0 / 3.0  # \u89e6\u53d1\u6269\u5bb9\u7684\u8d1f\u8f7d\u56e0\u5b50\u9608\u503c\n        self.extend_ratio = 2  # \u6269\u5bb9\u500d\u6570\n        self.buckets: list[Pair | None] = [None] * self.capacity  # \u6876\u6570\u7ec4\n        self.TOMBSTONE = Pair(-1, \"-1\")  # \u5220\u9664\u6807\u8bb0\n\n    def hash_func(self, key: int) -> int:\n        \"\"\"\u54c8\u5e0c\u51fd\u6570\"\"\"\n        return key % self.capacity\n\n    def load_factor(self) -> float:\n        \"\"\"\u8d1f\u8f7d\u56e0\u5b50\"\"\"\n        return self.size / self.capacity\n\n    def find_bucket(self, key: int) -> int:\n        \"\"\"\u641c\u7d22 key \u5bf9\u5e94\u7684\u6876\u7d22\u5f15\"\"\"\n        index = self.hash_func(key)\n        first_tombstone = -1\n        # \u7ebf\u6027\u63a2\u6d4b\uff0c\u5f53\u9047\u5230\u7a7a\u6876\u65f6\u8df3\u51fa\n        while self.buckets[index] is not None:\n            # \u82e5\u9047\u5230 key \uff0c\u8fd4\u56de\u5bf9\u5e94\u7684\u6876\u7d22\u5f15\n            if self.buckets[index].key == key:\n                # \u82e5\u4e4b\u524d\u9047\u5230\u4e86\u5220\u9664\u6807\u8bb0\uff0c\u5219\u5c06\u952e\u503c\u5bf9\u79fb\u52a8\u81f3\u8be5\u7d22\u5f15\u5904\n                if first_tombstone != -1:\n                    self.buckets[first_tombstone] = self.buckets[index]\n                    self.buckets[index] = self.TOMBSTONE\n                    return first_tombstone  # \u8fd4\u56de\u79fb\u52a8\u540e\u7684\u6876\u7d22\u5f15\n                return index  # \u8fd4\u56de\u6876\u7d22\u5f15\n            # \u8bb0\u5f55\u9047\u5230\u7684\u9996\u4e2a\u5220\u9664\u6807\u8bb0\n            if first_tombstone == -1 and self.buckets[index] is self.TOMBSTONE:\n                first_tombstone = index\n            # \u8ba1\u7b97\u6876\u7d22\u5f15\uff0c\u8d8a\u8fc7\u5c3e\u90e8\u5219\u8fd4\u56de\u5934\u90e8\n            index = (index + 1) % self.capacity\n        # \u82e5 key \u4e0d\u5b58\u5728\uff0c\u5219\u8fd4\u56de\u6dfb\u52a0\u70b9\u7684\u7d22\u5f15\n        return index if first_tombstone == -1 else first_tombstone\n\n    def get(self, key: int) -> str:\n        \"\"\"\u67e5\u8be2\u64cd\u4f5c\"\"\"\n        # \u641c\u7d22 key \u5bf9\u5e94\u7684\u6876\u7d22\u5f15\n        index = self.find_bucket(key)\n        # \u82e5\u627e\u5230\u952e\u503c\u5bf9\uff0c\u5219\u8fd4\u56de\u5bf9\u5e94 val\n        if self.buckets[index] not in [None, self.TOMBSTONE]:\n            return self.buckets[index].val\n        # \u82e5\u952e\u503c\u5bf9\u4e0d\u5b58\u5728\uff0c\u5219\u8fd4\u56de None\n        return None\n\n    def put(self, key: int, val: str):\n        \"\"\"\u6dfb\u52a0\u64cd\u4f5c\"\"\"\n        # \u5f53\u8d1f\u8f7d\u56e0\u5b50\u8d85\u8fc7\u9608\u503c\u65f6\uff0c\u6267\u884c\u6269\u5bb9\n        if self.load_factor() > self.load_thres:\n            self.extend()\n        # \u641c\u7d22 key \u5bf9\u5e94\u7684\u6876\u7d22\u5f15\n        index = self.find_bucket(key)\n        # \u82e5\u627e\u5230\u952e\u503c\u5bf9\uff0c\u5219\u8986\u76d6 val \u5e76\u8fd4\u56de\n        if self.buckets[index] not in [None, self.TOMBSTONE]:\n            self.buckets[index].val = val\n            return\n        # \u82e5\u952e\u503c\u5bf9\u4e0d\u5b58\u5728\uff0c\u5219\u6dfb\u52a0\u8be5\u952e\u503c\u5bf9\n        self.buckets[index] = Pair(key, val)\n        self.size += 1\n\n    def remove(self, key: int):\n        \"\"\"\u5220\u9664\u64cd\u4f5c\"\"\"\n        # \u641c\u7d22 key \u5bf9\u5e94\u7684\u6876\u7d22\u5f15\n        index = self.find_bucket(key)\n        # \u82e5\u627e\u5230\u952e\u503c\u5bf9\uff0c\u5219\u7528\u5220\u9664\u6807\u8bb0\u8986\u76d6\u5b83\n        if self.buckets[index] not in [None, self.TOMBSTONE]:\n            self.buckets[index] = self.TOMBSTONE\n            self.size -= 1\n\n    def extend(self):\n        \"\"\"\u6269\u5bb9\u54c8\u5e0c\u8868\"\"\"\n        # \u6682\u5b58\u539f\u54c8\u5e0c\u8868\n        buckets_tmp = self.buckets\n        # \u521d\u59cb\u5316\u6269\u5bb9\u540e\u7684\u65b0\u54c8\u5e0c\u8868\n        self.capacity *= self.extend_ratio\n        self.buckets = [None] * self.capacity\n        self.size = 0\n        # \u5c06\u952e\u503c\u5bf9\u4ece\u539f\u54c8\u5e0c\u8868\u642c\u8fd0\u81f3\u65b0\u54c8\u5e0c\u8868\n        for pair in buckets_tmp:\n            if pair not in [None, self.TOMBSTONE]:\n                self.put(pair.key, pair.val)\n\n    def print(self):\n        \"\"\"\u6253\u5370\u54c8\u5e0c\u8868\"\"\"\n        for pair in self.buckets:\n            if pair is None:\n                print(\"None\")\n            elif pair is self.TOMBSTONE:\n                print(\"TOMBSTONE\")\n            else:\n                print(pair.key, \"->\", pair.val)\n
hash_map_open_addressing.cpp
/* \u5f00\u653e\u5bfb\u5740\u54c8\u5e0c\u8868 */\nclass HashMapOpenAddressing {\n  private:\n    int size;                             // \u952e\u503c\u5bf9\u6570\u91cf\n    int capacity = 4;                     // \u54c8\u5e0c\u8868\u5bb9\u91cf\n    const double loadThres = 2.0 / 3.0;     // \u89e6\u53d1\u6269\u5bb9\u7684\u8d1f\u8f7d\u56e0\u5b50\u9608\u503c\n    const int extendRatio = 2;            // \u6269\u5bb9\u500d\u6570\n    vector<Pair *> buckets;               // \u6876\u6570\u7ec4\n    Pair *TOMBSTONE = new Pair(-1, \"-1\"); // \u5220\u9664\u6807\u8bb0\n\n  public:\n    /* \u6784\u9020\u65b9\u6cd5 */\n    HashMapOpenAddressing() : size(0), buckets(capacity, nullptr) {\n    }\n\n    /* \u6790\u6784\u65b9\u6cd5 */\n    ~HashMapOpenAddressing() {\n        for (Pair *pair : buckets) {\n            if (pair != nullptr && pair != TOMBSTONE) {\n                delete pair;\n            }\n        }\n        delete TOMBSTONE;\n    }\n\n    /* \u54c8\u5e0c\u51fd\u6570 */\n    int hashFunc(int key) {\n        return key % capacity;\n    }\n\n    /* \u8d1f\u8f7d\u56e0\u5b50 */\n    double loadFactor() {\n        return (double)size / capacity;\n    }\n\n    /* \u641c\u7d22 key \u5bf9\u5e94\u7684\u6876\u7d22\u5f15 */\n    int findBucket(int key) {\n        int index = hashFunc(key);\n        int firstTombstone = -1;\n        // \u7ebf\u6027\u63a2\u6d4b\uff0c\u5f53\u9047\u5230\u7a7a\u6876\u65f6\u8df3\u51fa\n        while (buckets[index] != nullptr) {\n            // \u82e5\u9047\u5230 key \uff0c\u8fd4\u56de\u5bf9\u5e94\u7684\u6876\u7d22\u5f15\n            if (buckets[index]->key == key) {\n                // \u82e5\u4e4b\u524d\u9047\u5230\u4e86\u5220\u9664\u6807\u8bb0\uff0c\u5219\u5c06\u952e\u503c\u5bf9\u79fb\u52a8\u81f3\u8be5\u7d22\u5f15\u5904\n                if (firstTombstone != -1) {\n                    buckets[firstTombstone] = buckets[index];\n                    buckets[index] = TOMBSTONE;\n                    return firstTombstone; // \u8fd4\u56de\u79fb\u52a8\u540e\u7684\u6876\u7d22\u5f15\n                }\n                return index; // \u8fd4\u56de\u6876\u7d22\u5f15\n            }\n            // \u8bb0\u5f55\u9047\u5230\u7684\u9996\u4e2a\u5220\u9664\u6807\u8bb0\n            if (firstTombstone == -1 && buckets[index] == TOMBSTONE) {\n                firstTombstone = index;\n            }\n            // \u8ba1\u7b97\u6876\u7d22\u5f15\uff0c\u8d8a\u8fc7\u5c3e\u90e8\u5219\u8fd4\u56de\u5934\u90e8\n            index = (index + 1) % capacity;\n        }\n        // \u82e5 key \u4e0d\u5b58\u5728\uff0c\u5219\u8fd4\u56de\u6dfb\u52a0\u70b9\u7684\u7d22\u5f15\n        return firstTombstone == -1 ? index : firstTombstone;\n    }\n\n    /* \u67e5\u8be2\u64cd\u4f5c */\n    string get(int key) {\n        // \u641c\u7d22 key \u5bf9\u5e94\u7684\u6876\u7d22\u5f15\n        int index = findBucket(key);\n        // \u82e5\u627e\u5230\u952e\u503c\u5bf9\uff0c\u5219\u8fd4\u56de\u5bf9\u5e94 val\n        if (buckets[index] != nullptr && buckets[index] != TOMBSTONE) {\n            return buckets[index]->val;\n        }\n        // \u82e5\u952e\u503c\u5bf9\u4e0d\u5b58\u5728\uff0c\u5219\u8fd4\u56de\u7a7a\u5b57\u7b26\u4e32\n        return \"\";\n    }\n\n    /* \u6dfb\u52a0\u64cd\u4f5c */\n    void put(int key, string val) {\n        // \u5f53\u8d1f\u8f7d\u56e0\u5b50\u8d85\u8fc7\u9608\u503c\u65f6\uff0c\u6267\u884c\u6269\u5bb9\n        if (loadFactor() > loadThres) {\n            extend();\n        }\n        // \u641c\u7d22 key \u5bf9\u5e94\u7684\u6876\u7d22\u5f15\n        int index = findBucket(key);\n        // \u82e5\u627e\u5230\u952e\u503c\u5bf9\uff0c\u5219\u8986\u76d6 val \u5e76\u8fd4\u56de\n        if (buckets[index] != nullptr && buckets[index] != TOMBSTONE) {\n            buckets[index]->val = val;\n            return;\n        }\n        // \u82e5\u952e\u503c\u5bf9\u4e0d\u5b58\u5728\uff0c\u5219\u6dfb\u52a0\u8be5\u952e\u503c\u5bf9\n        buckets[index] = new Pair(key, val);\n        size++;\n    }\n\n    /* \u5220\u9664\u64cd\u4f5c */\n    void remove(int key) {\n        // \u641c\u7d22 key \u5bf9\u5e94\u7684\u6876\u7d22\u5f15\n        int index = findBucket(key);\n        // \u82e5\u627e\u5230\u952e\u503c\u5bf9\uff0c\u5219\u7528\u5220\u9664\u6807\u8bb0\u8986\u76d6\u5b83\n        if (buckets[index] != nullptr && buckets[index] != TOMBSTONE) {\n            delete buckets[index];\n            buckets[index] = TOMBSTONE;\n            size--;\n        }\n    }\n\n    /* \u6269\u5bb9\u54c8\u5e0c\u8868 */\n    void extend() {\n        // \u6682\u5b58\u539f\u54c8\u5e0c\u8868\n        vector<Pair *> bucketsTmp = buckets;\n        // \u521d\u59cb\u5316\u6269\u5bb9\u540e\u7684\u65b0\u54c8\u5e0c\u8868\n        capacity *= extendRatio;\n        buckets = vector<Pair *>(capacity, nullptr);\n        size = 0;\n        // \u5c06\u952e\u503c\u5bf9\u4ece\u539f\u54c8\u5e0c\u8868\u642c\u8fd0\u81f3\u65b0\u54c8\u5e0c\u8868\n        for (Pair *pair : bucketsTmp) {\n            if (pair != nullptr && pair != TOMBSTONE) {\n                put(pair->key, pair->val);\n                delete pair;\n            }\n        }\n    }\n\n    /* \u6253\u5370\u54c8\u5e0c\u8868 */\n    void print() {\n        for (Pair *pair : buckets) {\n            if (pair == nullptr) {\n                cout << \"nullptr\" << endl;\n            } else if (pair == TOMBSTONE) {\n                cout << \"TOMBSTONE\" << endl;\n            } else {\n                cout << pair->key << \" -> \" << pair->val << endl;\n            }\n        }\n    }\n};\n
hash_map_open_addressing.java
/* \u5f00\u653e\u5bfb\u5740\u54c8\u5e0c\u8868 */\nclass HashMapOpenAddressing {\n    private int size; // \u952e\u503c\u5bf9\u6570\u91cf\n    private int capacity = 4; // \u54c8\u5e0c\u8868\u5bb9\u91cf\n    private final double loadThres = 2.0 / 3.0; // \u89e6\u53d1\u6269\u5bb9\u7684\u8d1f\u8f7d\u56e0\u5b50\u9608\u503c\n    private final int extendRatio = 2; // \u6269\u5bb9\u500d\u6570\n    private Pair[] buckets; // \u6876\u6570\u7ec4\n    private final Pair TOMBSTONE = new Pair(-1, \"-1\"); // \u5220\u9664\u6807\u8bb0\n\n    /* \u6784\u9020\u65b9\u6cd5 */\n    public HashMapOpenAddressing() {\n        size = 0;\n        buckets = new Pair[capacity];\n    }\n\n    /* \u54c8\u5e0c\u51fd\u6570 */\n    private int hashFunc(int key) {\n        return key % capacity;\n    }\n\n    /* \u8d1f\u8f7d\u56e0\u5b50 */\n    private double loadFactor() {\n        return (double) size / capacity;\n    }\n\n    /* \u641c\u7d22 key \u5bf9\u5e94\u7684\u6876\u7d22\u5f15 */\n    private int findBucket(int key) {\n        int index = hashFunc(key);\n        int firstTombstone = -1;\n        // \u7ebf\u6027\u63a2\u6d4b\uff0c\u5f53\u9047\u5230\u7a7a\u6876\u65f6\u8df3\u51fa\n        while (buckets[index] != null) {\n            // \u82e5\u9047\u5230 key \uff0c\u8fd4\u56de\u5bf9\u5e94\u7684\u6876\u7d22\u5f15\n            if (buckets[index].key == key) {\n                // \u82e5\u4e4b\u524d\u9047\u5230\u4e86\u5220\u9664\u6807\u8bb0\uff0c\u5219\u5c06\u952e\u503c\u5bf9\u79fb\u52a8\u81f3\u8be5\u7d22\u5f15\u5904\n                if (firstTombstone != -1) {\n                    buckets[firstTombstone] = buckets[index];\n                    buckets[index] = TOMBSTONE;\n                    return firstTombstone; // \u8fd4\u56de\u79fb\u52a8\u540e\u7684\u6876\u7d22\u5f15\n                }\n                return index; // \u8fd4\u56de\u6876\u7d22\u5f15\n            }\n            // \u8bb0\u5f55\u9047\u5230\u7684\u9996\u4e2a\u5220\u9664\u6807\u8bb0\n            if (firstTombstone == -1 && buckets[index] == TOMBSTONE) {\n                firstTombstone = index;\n            }\n            // \u8ba1\u7b97\u6876\u7d22\u5f15\uff0c\u8d8a\u8fc7\u5c3e\u90e8\u5219\u8fd4\u56de\u5934\u90e8\n            index = (index + 1) % capacity;\n        }\n        // \u82e5 key \u4e0d\u5b58\u5728\uff0c\u5219\u8fd4\u56de\u6dfb\u52a0\u70b9\u7684\u7d22\u5f15\n        return firstTombstone == -1 ? index : firstTombstone;\n    }\n\n    /* \u67e5\u8be2\u64cd\u4f5c */\n    public String get(int key) {\n        // \u641c\u7d22 key \u5bf9\u5e94\u7684\u6876\u7d22\u5f15\n        int index = findBucket(key);\n        // \u82e5\u627e\u5230\u952e\u503c\u5bf9\uff0c\u5219\u8fd4\u56de\u5bf9\u5e94 val\n        if (buckets[index] != null && buckets[index] != TOMBSTONE) {\n            return buckets[index].val;\n        }\n        // \u82e5\u952e\u503c\u5bf9\u4e0d\u5b58\u5728\uff0c\u5219\u8fd4\u56de null\n        return null;\n    }\n\n    /* \u6dfb\u52a0\u64cd\u4f5c */\n    public void put(int key, String val) {\n        // \u5f53\u8d1f\u8f7d\u56e0\u5b50\u8d85\u8fc7\u9608\u503c\u65f6\uff0c\u6267\u884c\u6269\u5bb9\n        if (loadFactor() > loadThres) {\n            extend();\n        }\n        // \u641c\u7d22 key \u5bf9\u5e94\u7684\u6876\u7d22\u5f15\n        int index = findBucket(key);\n        // \u82e5\u627e\u5230\u952e\u503c\u5bf9\uff0c\u5219\u8986\u76d6 val \u5e76\u8fd4\u56de\n        if (buckets[index] != null && buckets[index] != TOMBSTONE) {\n            buckets[index].val = val;\n            return;\n        }\n        // \u82e5\u952e\u503c\u5bf9\u4e0d\u5b58\u5728\uff0c\u5219\u6dfb\u52a0\u8be5\u952e\u503c\u5bf9\n        buckets[index] = new Pair(key, val);\n        size++;\n    }\n\n    /* \u5220\u9664\u64cd\u4f5c */\n    public void remove(int key) {\n        // \u641c\u7d22 key \u5bf9\u5e94\u7684\u6876\u7d22\u5f15\n        int index = findBucket(key);\n        // \u82e5\u627e\u5230\u952e\u503c\u5bf9\uff0c\u5219\u7528\u5220\u9664\u6807\u8bb0\u8986\u76d6\u5b83\n        if (buckets[index] != null && buckets[index] != TOMBSTONE) {\n            buckets[index] = TOMBSTONE;\n            size--;\n        }\n    }\n\n    /* \u6269\u5bb9\u54c8\u5e0c\u8868 */\n    private void extend() {\n        // \u6682\u5b58\u539f\u54c8\u5e0c\u8868\n        Pair[] bucketsTmp = buckets;\n        // \u521d\u59cb\u5316\u6269\u5bb9\u540e\u7684\u65b0\u54c8\u5e0c\u8868\n        capacity *= extendRatio;\n        buckets = new Pair[capacity];\n        size = 0;\n        // \u5c06\u952e\u503c\u5bf9\u4ece\u539f\u54c8\u5e0c\u8868\u642c\u8fd0\u81f3\u65b0\u54c8\u5e0c\u8868\n        for (Pair pair : bucketsTmp) {\n            if (pair != null && pair != TOMBSTONE) {\n                put(pair.key, pair.val);\n            }\n        }\n    }\n\n    /* \u6253\u5370\u54c8\u5e0c\u8868 */\n    public void print() {\n        for (Pair pair : buckets) {\n            if (pair == null) {\n                System.out.println(\"null\");\n            } else if (pair == TOMBSTONE) {\n                System.out.println(\"TOMBSTONE\");\n            } else {\n                System.out.println(pair.key + \" -> \" + pair.val);\n            }\n        }\n    }\n}\n
hash_map_open_addressing.cs
/* \u5f00\u653e\u5bfb\u5740\u54c8\u5e0c\u8868 */\nclass HashMapOpenAddressing {\n    int size; // \u952e\u503c\u5bf9\u6570\u91cf\n    int capacity = 4; // \u54c8\u5e0c\u8868\u5bb9\u91cf\n    double loadThres = 2.0 / 3.0; // \u89e6\u53d1\u6269\u5bb9\u7684\u8d1f\u8f7d\u56e0\u5b50\u9608\u503c\n    int extendRatio = 2; // \u6269\u5bb9\u500d\u6570\n    Pair[] buckets; // \u6876\u6570\u7ec4\n    Pair TOMBSTONE = new(-1, \"-1\"); // \u5220\u9664\u6807\u8bb0\n\n    /* \u6784\u9020\u65b9\u6cd5 */\n    public HashMapOpenAddressing() {\n        size = 0;\n        buckets = new Pair[capacity];\n    }\n\n    /* \u54c8\u5e0c\u51fd\u6570 */\n    int HashFunc(int key) {\n        return key % capacity;\n    }\n\n    /* \u8d1f\u8f7d\u56e0\u5b50 */\n    double LoadFactor() {\n        return (double)size / capacity;\n    }\n\n    /* \u641c\u7d22 key \u5bf9\u5e94\u7684\u6876\u7d22\u5f15 */\n    int FindBucket(int key) {\n        int index = HashFunc(key);\n        int firstTombstone = -1;\n        // \u7ebf\u6027\u63a2\u6d4b\uff0c\u5f53\u9047\u5230\u7a7a\u6876\u65f6\u8df3\u51fa\n        while (buckets[index] != null) {\n            // \u82e5\u9047\u5230 key \uff0c\u8fd4\u56de\u5bf9\u5e94\u7684\u6876\u7d22\u5f15\n            if (buckets[index].key == key) {\n                // \u82e5\u4e4b\u524d\u9047\u5230\u4e86\u5220\u9664\u6807\u8bb0\uff0c\u5219\u5c06\u952e\u503c\u5bf9\u79fb\u52a8\u81f3\u8be5\u7d22\u5f15\u5904\n                if (firstTombstone != -1) {\n                    buckets[firstTombstone] = buckets[index];\n                    buckets[index] = TOMBSTONE;\n                    return firstTombstone; // \u8fd4\u56de\u79fb\u52a8\u540e\u7684\u6876\u7d22\u5f15\n                }\n                return index; // \u8fd4\u56de\u6876\u7d22\u5f15\n            }\n            // \u8bb0\u5f55\u9047\u5230\u7684\u9996\u4e2a\u5220\u9664\u6807\u8bb0\n            if (firstTombstone == -1 && buckets[index] == TOMBSTONE) {\n                firstTombstone = index;\n            }\n            // \u8ba1\u7b97\u6876\u7d22\u5f15\uff0c\u8d8a\u8fc7\u5c3e\u90e8\u5219\u8fd4\u56de\u5934\u90e8\n            index = (index + 1) % capacity;\n        }\n        // \u82e5 key \u4e0d\u5b58\u5728\uff0c\u5219\u8fd4\u56de\u6dfb\u52a0\u70b9\u7684\u7d22\u5f15\n        return firstTombstone == -1 ? index : firstTombstone;\n    }\n\n    /* \u67e5\u8be2\u64cd\u4f5c */\n    public string? Get(int key) {\n        // \u641c\u7d22 key \u5bf9\u5e94\u7684\u6876\u7d22\u5f15\n        int index = FindBucket(key);\n        // \u82e5\u627e\u5230\u952e\u503c\u5bf9\uff0c\u5219\u8fd4\u56de\u5bf9\u5e94 val\n        if (buckets[index] != null && buckets[index] != TOMBSTONE) {\n            return buckets[index].val;\n        }\n        // \u82e5\u952e\u503c\u5bf9\u4e0d\u5b58\u5728\uff0c\u5219\u8fd4\u56de null\n        return null;\n    }\n\n    /* \u6dfb\u52a0\u64cd\u4f5c */\n    public void Put(int key, string val) {\n        // \u5f53\u8d1f\u8f7d\u56e0\u5b50\u8d85\u8fc7\u9608\u503c\u65f6\uff0c\u6267\u884c\u6269\u5bb9\n        if (LoadFactor() > loadThres) {\n            Extend();\n        }\n        // \u641c\u7d22 key \u5bf9\u5e94\u7684\u6876\u7d22\u5f15\n        int index = FindBucket(key);\n        // \u82e5\u627e\u5230\u952e\u503c\u5bf9\uff0c\u5219\u8986\u76d6 val \u5e76\u8fd4\u56de\n        if (buckets[index] != null && buckets[index] != TOMBSTONE) {\n            buckets[index].val = val;\n            return;\n        }\n        // \u82e5\u952e\u503c\u5bf9\u4e0d\u5b58\u5728\uff0c\u5219\u6dfb\u52a0\u8be5\u952e\u503c\u5bf9\n        buckets[index] = new Pair(key, val);\n        size++;\n    }\n\n    /* \u5220\u9664\u64cd\u4f5c */\n    public void Remove(int key) {\n        // \u641c\u7d22 key \u5bf9\u5e94\u7684\u6876\u7d22\u5f15\n        int index = FindBucket(key);\n        // \u82e5\u627e\u5230\u952e\u503c\u5bf9\uff0c\u5219\u7528\u5220\u9664\u6807\u8bb0\u8986\u76d6\u5b83\n        if (buckets[index] != null && buckets[index] != TOMBSTONE) {\n            buckets[index] = TOMBSTONE;\n            size--;\n        }\n    }\n\n    /* \u6269\u5bb9\u54c8\u5e0c\u8868 */\n    void Extend() {\n        // \u6682\u5b58\u539f\u54c8\u5e0c\u8868\n        Pair[] bucketsTmp = buckets;\n        // \u521d\u59cb\u5316\u6269\u5bb9\u540e\u7684\u65b0\u54c8\u5e0c\u8868\n        capacity *= extendRatio;\n        buckets = new Pair[capacity];\n        size = 0;\n        // \u5c06\u952e\u503c\u5bf9\u4ece\u539f\u54c8\u5e0c\u8868\u642c\u8fd0\u81f3\u65b0\u54c8\u5e0c\u8868\n        foreach (Pair pair in bucketsTmp) {\n            if (pair != null && pair != TOMBSTONE) {\n                Put(pair.key, pair.val);\n            }\n        }\n    }\n\n    /* \u6253\u5370\u54c8\u5e0c\u8868 */\n    public void Print() {\n        foreach (Pair pair in buckets) {\n            if (pair == null) {\n                Console.WriteLine(\"null\");\n            } else if (pair == TOMBSTONE) {\n                Console.WriteLine(\"TOMBSTONE\");\n            } else {\n                Console.WriteLine(pair.key + \" -> \" + pair.val);\n            }\n        }\n    }\n}\n
hash_map_open_addressing.go
/* \u5f00\u653e\u5bfb\u5740\u54c8\u5e0c\u8868 */\ntype hashMapOpenAddressing struct {\n    size        int     // \u952e\u503c\u5bf9\u6570\u91cf\n    capacity    int     // \u54c8\u5e0c\u8868\u5bb9\u91cf\n    loadThres   float64 // \u89e6\u53d1\u6269\u5bb9\u7684\u8d1f\u8f7d\u56e0\u5b50\u9608\u503c\n    extendRatio int     // \u6269\u5bb9\u500d\u6570\n    buckets     []*pair // \u6876\u6570\u7ec4\n    TOMBSTONE   *pair   // \u5220\u9664\u6807\u8bb0\n}\n\n/* \u6784\u9020\u65b9\u6cd5 */\nfunc newHashMapOpenAddressing() *hashMapOpenAddressing {\n    return &hashMapOpenAddressing{\n        size:        0,\n        capacity:    4,\n        loadThres:   2.0 / 3.0,\n        extendRatio: 2,\n        buckets:     make([]*pair, 4),\n        TOMBSTONE:   &pair{-1, \"-1\"},\n    }\n}\n\n/* \u54c8\u5e0c\u51fd\u6570 */\nfunc (h *hashMapOpenAddressing) hashFunc(key int) int {\n    return key % h.capacity // \u6839\u636e\u952e\u8ba1\u7b97\u54c8\u5e0c\u503c\n}\n\n/* \u8d1f\u8f7d\u56e0\u5b50 */\nfunc (h *hashMapOpenAddressing) loadFactor() float64 {\n    return float64(h.size) / float64(h.capacity) // \u8ba1\u7b97\u5f53\u524d\u8d1f\u8f7d\u56e0\u5b50\n}\n\n/* \u641c\u7d22 key \u5bf9\u5e94\u7684\u6876\u7d22\u5f15 */\nfunc (h *hashMapOpenAddressing) findBucket(key int) int {\n    index := h.hashFunc(key) // \u83b7\u53d6\u521d\u59cb\u7d22\u5f15\n    firstTombstone := -1     // \u8bb0\u5f55\u9047\u5230\u7684\u7b2c\u4e00\u4e2aTOMBSTONE\u7684\u4f4d\u7f6e\n    for h.buckets[index] != nil {\n        if h.buckets[index].key == key {\n            if firstTombstone != -1 {\n                // \u82e5\u4e4b\u524d\u9047\u5230\u4e86\u5220\u9664\u6807\u8bb0\uff0c\u5219\u5c06\u952e\u503c\u5bf9\u79fb\u52a8\u81f3\u8be5\u7d22\u5f15\u5904\n                h.buckets[firstTombstone] = h.buckets[index]\n                h.buckets[index] = h.TOMBSTONE\n                return firstTombstone // \u8fd4\u56de\u79fb\u52a8\u540e\u7684\u6876\u7d22\u5f15\n            }\n            return index // \u8fd4\u56de\u627e\u5230\u7684\u7d22\u5f15\n        }\n        if firstTombstone == -1 && h.buckets[index] == h.TOMBSTONE {\n            firstTombstone = index // \u8bb0\u5f55\u9047\u5230\u7684\u9996\u4e2a\u5220\u9664\u6807\u8bb0\u7684\u4f4d\u7f6e\n        }\n        index = (index + 1) % h.capacity // \u7ebf\u6027\u63a2\u6d4b\uff0c\u8d8a\u8fc7\u5c3e\u90e8\u5219\u8fd4\u56de\u5934\u90e8\n    }\n    // \u82e5 key \u4e0d\u5b58\u5728\uff0c\u5219\u8fd4\u56de\u6dfb\u52a0\u70b9\u7684\u7d22\u5f15\n    if firstTombstone != -1 {\n        return firstTombstone\n    }\n    return index\n}\n\n/* \u67e5\u8be2\u64cd\u4f5c */\nfunc (h *hashMapOpenAddressing) get(key int) string {\n    index := h.findBucket(key) // \u641c\u7d22 key \u5bf9\u5e94\u7684\u6876\u7d22\u5f15\n    if h.buckets[index] != nil && h.buckets[index] != h.TOMBSTONE {\n        return h.buckets[index].val // \u82e5\u627e\u5230\u952e\u503c\u5bf9\uff0c\u5219\u8fd4\u56de\u5bf9\u5e94 val\n    }\n    return \"\" // \u82e5\u952e\u503c\u5bf9\u4e0d\u5b58\u5728\uff0c\u5219\u8fd4\u56de \"\"\n}\n\n/* \u6dfb\u52a0\u64cd\u4f5c */\nfunc (h *hashMapOpenAddressing) put(key int, val string) {\n    if h.loadFactor() > h.loadThres {\n        h.extend() // \u5f53\u8d1f\u8f7d\u56e0\u5b50\u8d85\u8fc7\u9608\u503c\u65f6\uff0c\u6267\u884c\u6269\u5bb9\n    }\n    index := h.findBucket(key) // \u641c\u7d22 key \u5bf9\u5e94\u7684\u6876\u7d22\u5f15\n    if h.buckets[index] == nil || h.buckets[index] == h.TOMBSTONE {\n        h.buckets[index] = &pair{key, val} // \u82e5\u952e\u503c\u5bf9\u4e0d\u5b58\u5728\uff0c\u5219\u6dfb\u52a0\u8be5\u952e\u503c\u5bf9\n        h.size++\n    } else {\n        h.buckets[index].val = val // \u82e5\u627e\u5230\u952e\u503c\u5bf9\uff0c\u5219\u8986\u76d6 val\n    }\n}\n\n/* \u5220\u9664\u64cd\u4f5c */\nfunc (h *hashMapOpenAddressing) remove(key int) {\n    index := h.findBucket(key) // \u641c\u7d22 key \u5bf9\u5e94\u7684\u6876\u7d22\u5f15\n    if h.buckets[index] != nil && h.buckets[index] != h.TOMBSTONE {\n        h.buckets[index] = h.TOMBSTONE // \u82e5\u627e\u5230\u952e\u503c\u5bf9\uff0c\u5219\u7528\u5220\u9664\u6807\u8bb0\u8986\u76d6\u5b83\n        h.size--\n    }\n}\n\n/* \u6269\u5bb9\u54c8\u5e0c\u8868 */\nfunc (h *hashMapOpenAddressing) extend() {\n    oldBuckets := h.buckets               // \u6682\u5b58\u539f\u54c8\u5e0c\u8868\n    h.capacity *= h.extendRatio           // \u66f4\u65b0\u5bb9\u91cf\n    h.buckets = make([]*pair, h.capacity) // \u521d\u59cb\u5316\u6269\u5bb9\u540e\u7684\u65b0\u54c8\u5e0c\u8868\n    h.size = 0                            // \u91cd\u7f6e\u5927\u5c0f\n    // \u5c06\u952e\u503c\u5bf9\u4ece\u539f\u54c8\u5e0c\u8868\u642c\u8fd0\u81f3\u65b0\u54c8\u5e0c\u8868\n    for _, pair := range oldBuckets {\n        if pair != nil && pair != h.TOMBSTONE {\n            h.put(pair.key, pair.val)\n        }\n    }\n}\n\n/* \u6253\u5370\u54c8\u5e0c\u8868 */\nfunc (h *hashMapOpenAddressing) print() {\n    for _, pair := range h.buckets {\n        if pair == nil {\n            fmt.Println(\"nil\")\n        } else if pair == h.TOMBSTONE {\n            fmt.Println(\"TOMBSTONE\")\n        } else {\n            fmt.Printf(\"%d -> %s\\n\", pair.key, pair.val)\n        }\n    }\n}\n
hash_map_open_addressing.swift
/* \u5f00\u653e\u5bfb\u5740\u54c8\u5e0c\u8868 */\nclass HashMapOpenAddressing {\n    var size: Int // \u952e\u503c\u5bf9\u6570\u91cf\n    var capacity: Int // \u54c8\u5e0c\u8868\u5bb9\u91cf\n    var loadThres: Double // \u89e6\u53d1\u6269\u5bb9\u7684\u8d1f\u8f7d\u56e0\u5b50\u9608\u503c\n    var extendRatio: Int // \u6269\u5bb9\u500d\u6570\n    var buckets: [Pair?] // \u6876\u6570\u7ec4\n    var TOMBSTONE: Pair // \u5220\u9664\u6807\u8bb0\n\n    /* \u6784\u9020\u65b9\u6cd5 */\n    init() {\n        size = 0\n        capacity = 4\n        loadThres = 2.0 / 3.0\n        extendRatio = 2\n        buckets = Array(repeating: nil, count: capacity)\n        TOMBSTONE = Pair(key: -1, val: \"-1\")\n    }\n\n    /* \u54c8\u5e0c\u51fd\u6570 */\n    func hashFunc(key: Int) -> Int {\n        key % capacity\n    }\n\n    /* \u8d1f\u8f7d\u56e0\u5b50 */\n    func loadFactor() -> Double {\n        Double(size) / Double(capacity)\n    }\n\n    /* \u641c\u7d22 key \u5bf9\u5e94\u7684\u6876\u7d22\u5f15 */\n    func findBucket(key: Int) -> Int {\n        var index = hashFunc(key: key)\n        var firstTombstone = -1\n        // \u7ebf\u6027\u63a2\u6d4b\uff0c\u5f53\u9047\u5230\u7a7a\u6876\u65f6\u8df3\u51fa\n        while buckets[index] != nil {\n            // \u82e5\u9047\u5230 key \uff0c\u8fd4\u56de\u5bf9\u5e94\u7684\u6876\u7d22\u5f15\n            if buckets[index]!.key == key {\n                // \u82e5\u4e4b\u524d\u9047\u5230\u4e86\u5220\u9664\u6807\u8bb0\uff0c\u5219\u5c06\u952e\u503c\u5bf9\u79fb\u52a8\u81f3\u8be5\u7d22\u5f15\u5904\n                if firstTombstone != -1 {\n                    buckets[firstTombstone] = buckets[index]\n                    buckets[index] = TOMBSTONE\n                    return firstTombstone // \u8fd4\u56de\u79fb\u52a8\u540e\u7684\u6876\u7d22\u5f15\n                }\n                return index // \u8fd4\u56de\u6876\u7d22\u5f15\n            }\n            // \u8bb0\u5f55\u9047\u5230\u7684\u9996\u4e2a\u5220\u9664\u6807\u8bb0\n            if firstTombstone == -1 && buckets[index] == TOMBSTONE {\n                firstTombstone = index\n            }\n            // \u8ba1\u7b97\u6876\u7d22\u5f15\uff0c\u8d8a\u8fc7\u5c3e\u90e8\u5219\u8fd4\u56de\u5934\u90e8\n            index = (index + 1) % capacity\n        }\n        // \u82e5 key \u4e0d\u5b58\u5728\uff0c\u5219\u8fd4\u56de\u6dfb\u52a0\u70b9\u7684\u7d22\u5f15\n        return firstTombstone == -1 ? index : firstTombstone\n    }\n\n    /* \u67e5\u8be2\u64cd\u4f5c */\n    func get(key: Int) -> String? {\n        // \u641c\u7d22 key \u5bf9\u5e94\u7684\u6876\u7d22\u5f15\n        let index = findBucket(key: key)\n        // \u82e5\u627e\u5230\u952e\u503c\u5bf9\uff0c\u5219\u8fd4\u56de\u5bf9\u5e94 val\n        if buckets[index] != nil, buckets[index] != TOMBSTONE {\n            return buckets[index]!.val\n        }\n        // \u82e5\u952e\u503c\u5bf9\u4e0d\u5b58\u5728\uff0c\u5219\u8fd4\u56de null\n        return nil\n    }\n\n    /* \u6dfb\u52a0\u64cd\u4f5c */\n    func put(key: Int, val: String) {\n        // \u5f53\u8d1f\u8f7d\u56e0\u5b50\u8d85\u8fc7\u9608\u503c\u65f6\uff0c\u6267\u884c\u6269\u5bb9\n        if loadFactor() > loadThres {\n            extend()\n        }\n        // \u641c\u7d22 key \u5bf9\u5e94\u7684\u6876\u7d22\u5f15\n        let index = findBucket(key: key)\n        // \u82e5\u627e\u5230\u952e\u503c\u5bf9\uff0c\u5219\u8986\u76d6 val \u5e76\u8fd4\u56de\n        if buckets[index] != nil, buckets[index] != TOMBSTONE {\n            buckets[index]!.val = val\n            return\n        }\n        // \u82e5\u952e\u503c\u5bf9\u4e0d\u5b58\u5728\uff0c\u5219\u6dfb\u52a0\u8be5\u952e\u503c\u5bf9\n        buckets[index] = Pair(key: key, val: val)\n        size += 1\n    }\n\n    /* \u5220\u9664\u64cd\u4f5c */\n    func remove(key: Int) {\n        // \u641c\u7d22 key \u5bf9\u5e94\u7684\u6876\u7d22\u5f15\n        let index = findBucket(key: key)\n        // \u82e5\u627e\u5230\u952e\u503c\u5bf9\uff0c\u5219\u7528\u5220\u9664\u6807\u8bb0\u8986\u76d6\u5b83\n        if buckets[index] != nil, buckets[index] != TOMBSTONE {\n            buckets[index] = TOMBSTONE\n            size -= 1\n        }\n    }\n\n    /* \u6269\u5bb9\u54c8\u5e0c\u8868 */\n    func extend() {\n        // \u6682\u5b58\u539f\u54c8\u5e0c\u8868\n        let bucketsTmp = buckets\n        // \u521d\u59cb\u5316\u6269\u5bb9\u540e\u7684\u65b0\u54c8\u5e0c\u8868\n        capacity *= extendRatio\n        buckets = Array(repeating: nil, count: capacity)\n        size = 0\n        // \u5c06\u952e\u503c\u5bf9\u4ece\u539f\u54c8\u5e0c\u8868\u642c\u8fd0\u81f3\u65b0\u54c8\u5e0c\u8868\n        for pair in bucketsTmp {\n            if let pair, pair != TOMBSTONE {\n                put(key: pair.key, val: pair.val)\n            }\n        }\n    }\n\n    /* \u6253\u5370\u54c8\u5e0c\u8868 */\n    func print() {\n        for pair in buckets {\n            if pair == nil {\n                Swift.print(\"null\")\n            } else if pair == TOMBSTONE {\n                Swift.print(\"TOMBSTONE\")\n            } else {\n                Swift.print(\"\\(pair!.key) -> \\(pair!.val)\")\n            }\n        }\n    }\n}\n
hash_map_open_addressing.js
/* \u5f00\u653e\u5bfb\u5740\u54c8\u5e0c\u8868 */\nclass HashMapOpenAddressing {\n    #size; // \u952e\u503c\u5bf9\u6570\u91cf\n    #capacity; // \u54c8\u5e0c\u8868\u5bb9\u91cf\n    #loadThres; // \u89e6\u53d1\u6269\u5bb9\u7684\u8d1f\u8f7d\u56e0\u5b50\u9608\u503c\n    #extendRatio; // \u6269\u5bb9\u500d\u6570\n    #buckets; // \u6876\u6570\u7ec4\n    #TOMBSTONE; // \u5220\u9664\u6807\u8bb0\n\n    /* \u6784\u9020\u65b9\u6cd5 */\n    constructor() {\n        this.#size = 0; // \u952e\u503c\u5bf9\u6570\u91cf\n        this.#capacity = 4; // \u54c8\u5e0c\u8868\u5bb9\u91cf\n        this.#loadThres = 2.0 / 3.0; // \u89e6\u53d1\u6269\u5bb9\u7684\u8d1f\u8f7d\u56e0\u5b50\u9608\u503c\n        this.#extendRatio = 2; // \u6269\u5bb9\u500d\u6570\n        this.#buckets = Array(this.#capacity).fill(null); // \u6876\u6570\u7ec4\n        this.#TOMBSTONE = new Pair(-1, '-1'); // \u5220\u9664\u6807\u8bb0\n    }\n\n    /* \u54c8\u5e0c\u51fd\u6570 */\n    #hashFunc(key) {\n        return key % this.#capacity;\n    }\n\n    /* \u8d1f\u8f7d\u56e0\u5b50 */\n    #loadFactor() {\n        return this.#size / this.#capacity;\n    }\n\n    /* \u641c\u7d22 key \u5bf9\u5e94\u7684\u6876\u7d22\u5f15 */\n    #findBucket(key) {\n        let index = this.#hashFunc(key);\n        let firstTombstone = -1;\n        // \u7ebf\u6027\u63a2\u6d4b\uff0c\u5f53\u9047\u5230\u7a7a\u6876\u65f6\u8df3\u51fa\n        while (this.#buckets[index] !== null) {\n            // \u82e5\u9047\u5230 key \uff0c\u8fd4\u56de\u5bf9\u5e94\u7684\u6876\u7d22\u5f15\n            if (this.#buckets[index].key === key) {\n                // \u82e5\u4e4b\u524d\u9047\u5230\u4e86\u5220\u9664\u6807\u8bb0\uff0c\u5219\u5c06\u952e\u503c\u5bf9\u79fb\u52a8\u81f3\u8be5\u7d22\u5f15\u5904\n                if (firstTombstone !== -1) {\n                    this.#buckets[firstTombstone] = this.#buckets[index];\n                    this.#buckets[index] = this.#TOMBSTONE;\n                    return firstTombstone; // \u8fd4\u56de\u79fb\u52a8\u540e\u7684\u6876\u7d22\u5f15\n                }\n                return index; // \u8fd4\u56de\u6876\u7d22\u5f15\n            }\n            // \u8bb0\u5f55\u9047\u5230\u7684\u9996\u4e2a\u5220\u9664\u6807\u8bb0\n            if (\n                firstTombstone === -1 &&\n                this.#buckets[index] === this.#TOMBSTONE\n            ) {\n                firstTombstone = index;\n            }\n            // \u8ba1\u7b97\u6876\u7d22\u5f15\uff0c\u8d8a\u8fc7\u5c3e\u90e8\u5219\u8fd4\u56de\u5934\u90e8\n            index = (index + 1) % this.#capacity;\n        }\n        // \u82e5 key \u4e0d\u5b58\u5728\uff0c\u5219\u8fd4\u56de\u6dfb\u52a0\u70b9\u7684\u7d22\u5f15\n        return firstTombstone === -1 ? index : firstTombstone;\n    }\n\n    /* \u67e5\u8be2\u64cd\u4f5c */\n    get(key) {\n        // \u641c\u7d22 key \u5bf9\u5e94\u7684\u6876\u7d22\u5f15\n        const index = this.#findBucket(key);\n        // \u82e5\u627e\u5230\u952e\u503c\u5bf9\uff0c\u5219\u8fd4\u56de\u5bf9\u5e94 val\n        if (\n            this.#buckets[index] !== null &&\n            this.#buckets[index] !== this.#TOMBSTONE\n        ) {\n            return this.#buckets[index].val;\n        }\n        // \u82e5\u952e\u503c\u5bf9\u4e0d\u5b58\u5728\uff0c\u5219\u8fd4\u56de null\n        return null;\n    }\n\n    /* \u6dfb\u52a0\u64cd\u4f5c */\n    put(key, val) {\n        // \u5f53\u8d1f\u8f7d\u56e0\u5b50\u8d85\u8fc7\u9608\u503c\u65f6\uff0c\u6267\u884c\u6269\u5bb9\n        if (this.#loadFactor() > this.#loadThres) {\n            this.#extend();\n        }\n        // \u641c\u7d22 key \u5bf9\u5e94\u7684\u6876\u7d22\u5f15\n        const index = this.#findBucket(key);\n        // \u82e5\u627e\u5230\u952e\u503c\u5bf9\uff0c\u5219\u8986\u76d6 val \u5e76\u8fd4\u56de\n        if (\n            this.#buckets[index] !== null &&\n            this.#buckets[index] !== this.#TOMBSTONE\n        ) {\n            this.#buckets[index].val = val;\n            return;\n        }\n        // \u82e5\u952e\u503c\u5bf9\u4e0d\u5b58\u5728\uff0c\u5219\u6dfb\u52a0\u8be5\u952e\u503c\u5bf9\n        this.#buckets[index] = new Pair(key, val);\n        this.#size++;\n    }\n\n    /* \u5220\u9664\u64cd\u4f5c */\n    remove(key) {\n        // \u641c\u7d22 key \u5bf9\u5e94\u7684\u6876\u7d22\u5f15\n        const index = this.#findBucket(key);\n        // \u82e5\u627e\u5230\u952e\u503c\u5bf9\uff0c\u5219\u7528\u5220\u9664\u6807\u8bb0\u8986\u76d6\u5b83\n        if (\n            this.#buckets[index] !== null &&\n            this.#buckets[index] !== this.#TOMBSTONE\n        ) {\n            this.#buckets[index] = this.#TOMBSTONE;\n            this.#size--;\n        }\n    }\n\n    /* \u6269\u5bb9\u54c8\u5e0c\u8868 */\n    #extend() {\n        // \u6682\u5b58\u539f\u54c8\u5e0c\u8868\n        const bucketsTmp = this.#buckets;\n        // \u521d\u59cb\u5316\u6269\u5bb9\u540e\u7684\u65b0\u54c8\u5e0c\u8868\n        this.#capacity *= this.#extendRatio;\n        this.#buckets = Array(this.#capacity).fill(null);\n        this.#size = 0;\n        // \u5c06\u952e\u503c\u5bf9\u4ece\u539f\u54c8\u5e0c\u8868\u642c\u8fd0\u81f3\u65b0\u54c8\u5e0c\u8868\n        for (const pair of bucketsTmp) {\n            if (pair !== null && pair !== this.#TOMBSTONE) {\n                this.put(pair.key, pair.val);\n            }\n        }\n    }\n\n    /* \u6253\u5370\u54c8\u5e0c\u8868 */\n    print() {\n        for (const pair of this.#buckets) {\n            if (pair === null) {\n                console.log('null');\n            } else if (pair === this.#TOMBSTONE) {\n                console.log('TOMBSTONE');\n            } else {\n                console.log(pair.key + ' -> ' + pair.val);\n            }\n        }\n    }\n}\n
hash_map_open_addressing.ts
/* \u5f00\u653e\u5bfb\u5740\u54c8\u5e0c\u8868 */\nclass HashMapOpenAddressing {\n    private size: number; // \u952e\u503c\u5bf9\u6570\u91cf\n    private capacity: number; // \u54c8\u5e0c\u8868\u5bb9\u91cf\n    private loadThres: number; // \u89e6\u53d1\u6269\u5bb9\u7684\u8d1f\u8f7d\u56e0\u5b50\u9608\u503c\n    private extendRatio: number; // \u6269\u5bb9\u500d\u6570\n    private buckets: Array<Pair | null>; // \u6876\u6570\u7ec4\n    private TOMBSTONE: Pair; // \u5220\u9664\u6807\u8bb0\n\n    /* \u6784\u9020\u65b9\u6cd5 */\n    constructor() {\n        this.size = 0; // \u952e\u503c\u5bf9\u6570\u91cf\n        this.capacity = 4; // \u54c8\u5e0c\u8868\u5bb9\u91cf\n        this.loadThres = 2.0 / 3.0; // \u89e6\u53d1\u6269\u5bb9\u7684\u8d1f\u8f7d\u56e0\u5b50\u9608\u503c\n        this.extendRatio = 2; // \u6269\u5bb9\u500d\u6570\n        this.buckets = Array(this.capacity).fill(null); // \u6876\u6570\u7ec4\n        this.TOMBSTONE = new Pair(-1, '-1'); // \u5220\u9664\u6807\u8bb0\n    }\n\n    /* \u54c8\u5e0c\u51fd\u6570 */\n    private hashFunc(key: number): number {\n        return key % this.capacity;\n    }\n\n    /* \u8d1f\u8f7d\u56e0\u5b50 */\n    private loadFactor(): number {\n        return this.size / this.capacity;\n    }\n\n    /* \u641c\u7d22 key \u5bf9\u5e94\u7684\u6876\u7d22\u5f15 */\n    private findBucket(key: number): number {\n        let index = this.hashFunc(key);\n        let firstTombstone = -1;\n        // \u7ebf\u6027\u63a2\u6d4b\uff0c\u5f53\u9047\u5230\u7a7a\u6876\u65f6\u8df3\u51fa\n        while (this.buckets[index] !== null) {\n            // \u82e5\u9047\u5230 key \uff0c\u8fd4\u56de\u5bf9\u5e94\u7684\u6876\u7d22\u5f15\n            if (this.buckets[index]!.key === key) {\n                // \u82e5\u4e4b\u524d\u9047\u5230\u4e86\u5220\u9664\u6807\u8bb0\uff0c\u5219\u5c06\u952e\u503c\u5bf9\u79fb\u52a8\u81f3\u8be5\u7d22\u5f15\u5904\n                if (firstTombstone !== -1) {\n                    this.buckets[firstTombstone] = this.buckets[index];\n                    this.buckets[index] = this.TOMBSTONE;\n                    return firstTombstone; // \u8fd4\u56de\u79fb\u52a8\u540e\u7684\u6876\u7d22\u5f15\n                }\n                return index; // \u8fd4\u56de\u6876\u7d22\u5f15\n            }\n            // \u8bb0\u5f55\u9047\u5230\u7684\u9996\u4e2a\u5220\u9664\u6807\u8bb0\n            if (\n                firstTombstone === -1 &&\n                this.buckets[index] === this.TOMBSTONE\n            ) {\n                firstTombstone = index;\n            }\n            // \u8ba1\u7b97\u6876\u7d22\u5f15\uff0c\u8d8a\u8fc7\u5c3e\u90e8\u5219\u8fd4\u56de\u5934\u90e8\n            index = (index + 1) % this.capacity;\n        }\n        // \u82e5 key \u4e0d\u5b58\u5728\uff0c\u5219\u8fd4\u56de\u6dfb\u52a0\u70b9\u7684\u7d22\u5f15\n        return firstTombstone === -1 ? index : firstTombstone;\n    }\n\n    /* \u67e5\u8be2\u64cd\u4f5c */\n    get(key: number): string | null {\n        // \u641c\u7d22 key \u5bf9\u5e94\u7684\u6876\u7d22\u5f15\n        const index = this.findBucket(key);\n        // \u82e5\u627e\u5230\u952e\u503c\u5bf9\uff0c\u5219\u8fd4\u56de\u5bf9\u5e94 val\n        if (\n            this.buckets[index] !== null &&\n            this.buckets[index] !== this.TOMBSTONE\n        ) {\n            return this.buckets[index]!.val;\n        }\n        // \u82e5\u952e\u503c\u5bf9\u4e0d\u5b58\u5728\uff0c\u5219\u8fd4\u56de null\n        return null;\n    }\n\n    /* \u6dfb\u52a0\u64cd\u4f5c */\n    put(key: number, val: string): void {\n        // \u5f53\u8d1f\u8f7d\u56e0\u5b50\u8d85\u8fc7\u9608\u503c\u65f6\uff0c\u6267\u884c\u6269\u5bb9\n        if (this.loadFactor() > this.loadThres) {\n            this.extend();\n        }\n        // \u641c\u7d22 key \u5bf9\u5e94\u7684\u6876\u7d22\u5f15\n        const index = this.findBucket(key);\n        // \u82e5\u627e\u5230\u952e\u503c\u5bf9\uff0c\u5219\u8986\u76d6 val \u5e76\u8fd4\u56de\n        if (\n            this.buckets[index] !== null &&\n            this.buckets[index] !== this.TOMBSTONE\n        ) {\n            this.buckets[index]!.val = val;\n            return;\n        }\n        // \u82e5\u952e\u503c\u5bf9\u4e0d\u5b58\u5728\uff0c\u5219\u6dfb\u52a0\u8be5\u952e\u503c\u5bf9\n        this.buckets[index] = new Pair(key, val);\n        this.size++;\n    }\n\n    /* \u5220\u9664\u64cd\u4f5c */\n    remove(key: number): void {\n        // \u641c\u7d22 key \u5bf9\u5e94\u7684\u6876\u7d22\u5f15\n        const index = this.findBucket(key);\n        // \u82e5\u627e\u5230\u952e\u503c\u5bf9\uff0c\u5219\u7528\u5220\u9664\u6807\u8bb0\u8986\u76d6\u5b83\n        if (\n            this.buckets[index] !== null &&\n            this.buckets[index] !== this.TOMBSTONE\n        ) {\n            this.buckets[index] = this.TOMBSTONE;\n            this.size--;\n        }\n    }\n\n    /* \u6269\u5bb9\u54c8\u5e0c\u8868 */\n    private extend(): void {\n        // \u6682\u5b58\u539f\u54c8\u5e0c\u8868\n        const bucketsTmp = this.buckets;\n        // \u521d\u59cb\u5316\u6269\u5bb9\u540e\u7684\u65b0\u54c8\u5e0c\u8868\n        this.capacity *= this.extendRatio;\n        this.buckets = Array(this.capacity).fill(null);\n        this.size = 0;\n        // \u5c06\u952e\u503c\u5bf9\u4ece\u539f\u54c8\u5e0c\u8868\u642c\u8fd0\u81f3\u65b0\u54c8\u5e0c\u8868\n        for (const pair of bucketsTmp) {\n            if (pair !== null && pair !== this.TOMBSTONE) {\n                this.put(pair.key, pair.val);\n            }\n        }\n    }\n\n    /* \u6253\u5370\u54c8\u5e0c\u8868 */\n    print(): void {\n        for (const pair of this.buckets) {\n            if (pair === null) {\n                console.log('null');\n            } else if (pair === this.TOMBSTONE) {\n                console.log('TOMBSTONE');\n            } else {\n                console.log(pair.key + ' -> ' + pair.val);\n            }\n        }\n    }\n}\n
hash_map_open_addressing.dart
/* \u5f00\u653e\u5bfb\u5740\u54c8\u5e0c\u8868 */\nclass HashMapOpenAddressing {\n  late int _size; // \u952e\u503c\u5bf9\u6570\u91cf\n  int _capacity = 4; // \u54c8\u5e0c\u8868\u5bb9\u91cf\n  double _loadThres = 2.0 / 3.0; // \u89e6\u53d1\u6269\u5bb9\u7684\u8d1f\u8f7d\u56e0\u5b50\u9608\u503c\n  int _extendRatio = 2; // \u6269\u5bb9\u500d\u6570\n  late List<Pair?> _buckets; // \u6876\u6570\u7ec4\n  Pair _TOMBSTONE = Pair(-1, \"-1\"); // \u5220\u9664\u6807\u8bb0\n\n  /* \u6784\u9020\u65b9\u6cd5 */\n  HashMapOpenAddressing() {\n    _size = 0;\n    _buckets = List.generate(_capacity, (index) => null);\n  }\n\n  /* \u54c8\u5e0c\u51fd\u6570 */\n  int hashFunc(int key) {\n    return key % _capacity;\n  }\n\n  /* \u8d1f\u8f7d\u56e0\u5b50 */\n  double loadFactor() {\n    return _size / _capacity;\n  }\n\n  /* \u641c\u7d22 key \u5bf9\u5e94\u7684\u6876\u7d22\u5f15 */\n  int findBucket(int key) {\n    int index = hashFunc(key);\n    int firstTombstone = -1;\n    // \u7ebf\u6027\u63a2\u6d4b\uff0c\u5f53\u9047\u5230\u7a7a\u6876\u65f6\u8df3\u51fa\n    while (_buckets[index] != null) {\n      // \u82e5\u9047\u5230 key \uff0c\u8fd4\u56de\u5bf9\u5e94\u7684\u6876\u7d22\u5f15\n      if (_buckets[index]!.key == key) {\n        // \u82e5\u4e4b\u524d\u9047\u5230\u4e86\u5220\u9664\u6807\u8bb0\uff0c\u5219\u5c06\u952e\u503c\u5bf9\u79fb\u52a8\u81f3\u8be5\u7d22\u5f15\u5904\n        if (firstTombstone != -1) {\n          _buckets[firstTombstone] = _buckets[index];\n          _buckets[index] = _TOMBSTONE;\n          return firstTombstone; // \u8fd4\u56de\u79fb\u52a8\u540e\u7684\u6876\u7d22\u5f15\n        }\n        return index; // \u8fd4\u56de\u6876\u7d22\u5f15\n      }\n      // \u8bb0\u5f55\u9047\u5230\u7684\u9996\u4e2a\u5220\u9664\u6807\u8bb0\n      if (firstTombstone == -1 && _buckets[index] == _TOMBSTONE) {\n        firstTombstone = index;\n      }\n      // \u8ba1\u7b97\u6876\u7d22\u5f15\uff0c\u8d8a\u8fc7\u5c3e\u90e8\u5219\u8fd4\u56de\u5934\u90e8\n      index = (index + 1) % _capacity;\n    }\n    // \u82e5 key \u4e0d\u5b58\u5728\uff0c\u5219\u8fd4\u56de\u6dfb\u52a0\u70b9\u7684\u7d22\u5f15\n    return firstTombstone == -1 ? index : firstTombstone;\n  }\n\n  /* \u67e5\u8be2\u64cd\u4f5c */\n  String? get(int key) {\n    // \u641c\u7d22 key \u5bf9\u5e94\u7684\u6876\u7d22\u5f15\n    int index = findBucket(key);\n    // \u82e5\u627e\u5230\u952e\u503c\u5bf9\uff0c\u5219\u8fd4\u56de\u5bf9\u5e94 val\n    if (_buckets[index] != null && _buckets[index] != _TOMBSTONE) {\n      return _buckets[index]!.val;\n    }\n    // \u82e5\u952e\u503c\u5bf9\u4e0d\u5b58\u5728\uff0c\u5219\u8fd4\u56de null\n    return null;\n  }\n\n  /* \u6dfb\u52a0\u64cd\u4f5c */\n  void put(int key, String val) {\n    // \u5f53\u8d1f\u8f7d\u56e0\u5b50\u8d85\u8fc7\u9608\u503c\u65f6\uff0c\u6267\u884c\u6269\u5bb9\n    if (loadFactor() > _loadThres) {\n      extend();\n    }\n    // \u641c\u7d22 key \u5bf9\u5e94\u7684\u6876\u7d22\u5f15\n    int index = findBucket(key);\n    // \u82e5\u627e\u5230\u952e\u503c\u5bf9\uff0c\u5219\u8986\u76d6 val \u5e76\u8fd4\u56de\n    if (_buckets[index] != null && _buckets[index] != _TOMBSTONE) {\n      _buckets[index]!.val = val;\n      return;\n    }\n    // \u82e5\u952e\u503c\u5bf9\u4e0d\u5b58\u5728\uff0c\u5219\u6dfb\u52a0\u8be5\u952e\u503c\u5bf9\n    _buckets[index] = new Pair(key, val);\n    _size++;\n  }\n\n  /* \u5220\u9664\u64cd\u4f5c */\n  void remove(int key) {\n    // \u641c\u7d22 key \u5bf9\u5e94\u7684\u6876\u7d22\u5f15\n    int index = findBucket(key);\n    // \u82e5\u627e\u5230\u952e\u503c\u5bf9\uff0c\u5219\u7528\u5220\u9664\u6807\u8bb0\u8986\u76d6\u5b83\n    if (_buckets[index] != null && _buckets[index] != _TOMBSTONE) {\n      _buckets[index] = _TOMBSTONE;\n      _size--;\n    }\n  }\n\n  /* \u6269\u5bb9\u54c8\u5e0c\u8868 */\n  void extend() {\n    // \u6682\u5b58\u539f\u54c8\u5e0c\u8868\n    List<Pair?> bucketsTmp = _buckets;\n    // \u521d\u59cb\u5316\u6269\u5bb9\u540e\u7684\u65b0\u54c8\u5e0c\u8868\n    _capacity *= _extendRatio;\n    _buckets = List.generate(_capacity, (index) => null);\n    _size = 0;\n    // \u5c06\u952e\u503c\u5bf9\u4ece\u539f\u54c8\u5e0c\u8868\u642c\u8fd0\u81f3\u65b0\u54c8\u5e0c\u8868\n    for (Pair? pair in bucketsTmp) {\n      if (pair != null && pair != _TOMBSTONE) {\n        put(pair.key, pair.val);\n      }\n    }\n  }\n\n  /* \u6253\u5370\u54c8\u5e0c\u8868 */\n  void printHashMap() {\n    for (Pair? pair in _buckets) {\n      if (pair == null) {\n        print(\"null\");\n      } else if (pair == _TOMBSTONE) {\n        print(\"TOMBSTONE\");\n      } else {\n        print(\"${pair.key} -> ${pair.val}\");\n      }\n    }\n  }\n}\n
hash_map_open_addressing.rs
/* \u5f00\u653e\u5bfb\u5740\u54c8\u5e0c\u8868 */\nstruct HashMapOpenAddressing {\n    size: usize,                // \u952e\u503c\u5bf9\u6570\u91cf\n    capacity: usize,            // \u54c8\u5e0c\u8868\u5bb9\u91cf\n    load_thres: f64,            // \u89e6\u53d1\u6269\u5bb9\u7684\u8d1f\u8f7d\u56e0\u5b50\u9608\u503c\n    extend_ratio: usize,        // \u6269\u5bb9\u500d\u6570\n    buckets: Vec<Option<Pair>>, // \u6876\u6570\u7ec4\n    TOMBSTONE: Option<Pair>,    // \u5220\u9664\u6807\u8bb0\n}\n\nimpl HashMapOpenAddressing {\n    /* \u6784\u9020\u65b9\u6cd5 */\n    fn new() -> Self {\n        Self {\n            size: 0,\n            capacity: 4,\n            load_thres: 2.0 / 3.0,\n            extend_ratio: 2,\n            buckets: vec![None; 4],\n            TOMBSTONE: Some(Pair {\n                key: -1,\n                val: \"-1\".to_string(),\n            }),\n        }\n    }\n\n    /* \u54c8\u5e0c\u51fd\u6570 */\n    fn hash_func(&self, key: i32) -> usize {\n        (key % self.capacity as i32) as usize\n    }\n\n    /* \u8d1f\u8f7d\u56e0\u5b50 */\n    fn load_factor(&self) -> f64 {\n        self.size as f64 / self.capacity as f64\n    }\n\n    /* \u641c\u7d22 key \u5bf9\u5e94\u7684\u6876\u7d22\u5f15 */\n    fn find_bucket(&mut self, key: i32) -> usize {\n        let mut index = self.hash_func(key);\n        let mut first_tombstone = -1;\n        // \u7ebf\u6027\u63a2\u6d4b\uff0c\u5f53\u9047\u5230\u7a7a\u6876\u65f6\u8df3\u51fa\n        while self.buckets[index].is_some() {\n            // \u82e5\u9047\u5230 key\uff0c\u8fd4\u56de\u5bf9\u5e94\u7684\u6876\u7d22\u5f15\n            if self.buckets[index].as_ref().unwrap().key == key {\n                // \u82e5\u4e4b\u524d\u9047\u5230\u4e86\u5220\u9664\u6807\u8bb0\uff0c\u5219\u5c06\u5efa\u503c\u5bf9\u79fb\u52a8\u81f3\u8be5\u7d22\u5f15\n                if first_tombstone != -1 {\n                    self.buckets[first_tombstone as usize] = self.buckets[index].take();\n                    self.buckets[index] = self.TOMBSTONE.clone();\n                    return first_tombstone as usize; // \u8fd4\u56de\u79fb\u52a8\u540e\u7684\u6876\u7d22\u5f15\n                }\n                return index; // \u8fd4\u56de\u6876\u7d22\u5f15\n            }\n            // \u8bb0\u5f55\u9047\u5230\u7684\u9996\u4e2a\u5220\u9664\u6807\u8bb0\n            if first_tombstone == -1 && self.buckets[index] == self.TOMBSTONE {\n                first_tombstone = index as i32;\n            }\n            // \u8ba1\u7b97\u6876\u7d22\u5f15\uff0c\u8d8a\u8fc7\u5c3e\u90e8\u5219\u8fd4\u56de\u5934\u90e8\n            index = (index + 1) % self.capacity;\n        }\n        // \u82e5 key \u4e0d\u5b58\u5728\uff0c\u5219\u8fd4\u56de\u6dfb\u52a0\u70b9\u7684\u7d22\u5f15\n        if first_tombstone == -1 {\n            index\n        } else {\n            first_tombstone as usize\n        }\n    }\n\n    /* \u67e5\u8be2\u64cd\u4f5c */\n    fn get(&mut self, key: i32) -> Option<&str> {\n        // \u641c\u7d22 key \u5bf9\u5e94\u7684\u6876\u7d22\u5f15\n        let index = self.find_bucket(key);\n        // \u82e5\u627e\u5230\u952e\u503c\u5bf9\uff0c\u5219\u8fd4\u56de\u5bf9\u5e94 val\n        if self.buckets[index].is_some() && self.buckets[index] != self.TOMBSTONE {\n            return self.buckets[index].as_ref().map(|pair| &pair.val as &str);\n        }\n        // \u82e5\u952e\u503c\u5bf9\u4e0d\u5b58\u5728\uff0c\u5219\u8fd4\u56de null\n        None\n    }\n\n    /* \u6dfb\u52a0\u64cd\u4f5c */\n    fn put(&mut self, key: i32, val: String) {\n        // \u5f53\u8d1f\u8f7d\u56e0\u5b50\u8d85\u8fc7\u9608\u503c\u65f6\uff0c\u6267\u884c\u6269\u5bb9\n        if self.load_factor() > self.load_thres {\n            self.extend();\n        }\n        // \u641c\u7d22 key \u5bf9\u5e94\u7684\u6876\u7d22\u5f15\n        let index = self.find_bucket(key);\n        // \u82e5\u627e\u5230\u952e\u503c\u5bf9\uff0c\u5219\u8986\u76d6 val \u5e76\u8fd4\u56de\n        if self.buckets[index].is_some() && self.buckets[index] != self.TOMBSTONE {\n            self.buckets[index].as_mut().unwrap().val = val;\n            return;\n        }\n        // \u82e5\u952e\u503c\u5bf9\u4e0d\u5b58\u5728\uff0c\u5219\u6dfb\u52a0\u8be5\u952e\u503c\u5bf9\n        self.buckets[index] = Some(Pair { key, val });\n        self.size += 1;\n    }\n\n    /* \u5220\u9664\u64cd\u4f5c */\n    fn remove(&mut self, key: i32) {\n        // \u641c\u7d22 key \u5bf9\u5e94\u7684\u6876\u7d22\u5f15\n        let index = self.find_bucket(key);\n        // \u82e5\u627e\u5230\u952e\u503c\u5bf9\uff0c\u5219\u7528\u5220\u9664\u6807\u8bb0\u8986\u76d6\u5b83\n        if self.buckets[index].is_some() && self.buckets[index] != self.TOMBSTONE {\n            self.buckets[index] = self.TOMBSTONE.clone();\n            self.size -= 1;\n        }\n    }\n\n    /* \u6269\u5bb9\u54c8\u5e0c\u8868 */\n    fn extend(&mut self) {\n        // \u6682\u5b58\u539f\u54c8\u5e0c\u8868\n        let buckets_tmp = self.buckets.clone();\n        // \u521d\u59cb\u5316\u6269\u5bb9\u540e\u7684\u65b0\u54c8\u5e0c\u8868\n        self.capacity *= self.extend_ratio;\n        self.buckets = vec![None; self.capacity];\n        self.size = 0;\n\n        // \u5c06\u952e\u503c\u5bf9\u4ece\u539f\u54c8\u5e0c\u8868\u642c\u8fd0\u81f3\u65b0\u54c8\u5e0c\u8868\n        for pair in buckets_tmp {\n            if pair.is_none() || pair == self.TOMBSTONE {\n                continue;\n            }\n            let pair = pair.unwrap();\n\n            self.put(pair.key, pair.val);\n        }\n    }\n    /* \u6253\u5370\u54c8\u5e0c\u8868 */\n    fn print(&self) {\n        for pair in &self.buckets {\n            if pair.is_none() {\n                println!(\"null\");\n            } else if pair == &self.TOMBSTONE {\n                println!(\"TOMBSTONE\");\n            } else {\n                let pair = pair.as_ref().unwrap();\n                println!(\"{} -> {}\", pair.key, pair.val);\n            }\n        }\n    }\n}\n
hash_map_open_addressing.c
/* \u5f00\u653e\u5bfb\u5740\u54c8\u5e0c\u8868 */\ntypedef struct {\n    int size;         // \u952e\u503c\u5bf9\u6570\u91cf\n    int capacity;     // \u54c8\u5e0c\u8868\u5bb9\u91cf\n    double loadThres; // \u89e6\u53d1\u6269\u5bb9\u7684\u8d1f\u8f7d\u56e0\u5b50\u9608\u503c\n    int extendRatio;  // \u6269\u5bb9\u500d\u6570\n    Pair **buckets;   // \u6876\u6570\u7ec4\n    Pair *TOMBSTONE;  // \u5220\u9664\u6807\u8bb0\n} HashMapOpenAddressing;\n\n/* \u6784\u9020\u51fd\u6570 */\nHashMapOpenAddressing *newHashMapOpenAddressing() {\n    HashMapOpenAddressing *hashMap = (HashMapOpenAddressing *)malloc(sizeof(HashMapOpenAddressing));\n    hashMap->size = 0;\n    hashMap->capacity = 4;\n    hashMap->loadThres = 2.0 / 3.0;\n    hashMap->extendRatio = 2;\n    hashMap->buckets = (Pair **)malloc(sizeof(Pair *) * hashMap->capacity);\n    hashMap->TOMBSTONE = (Pair *)malloc(sizeof(Pair));\n    hashMap->TOMBSTONE->key = -1;\n    hashMap->TOMBSTONE->val = \"-1\";\n\n    return hashMap;\n}\n\n/* \u6790\u6784\u51fd\u6570 */\nvoid delHashMapOpenAddressing(HashMapOpenAddressing *hashMap) {\n    for (int i = 0; i < hashMap->capacity; i++) {\n        Pair *pair = hashMap->buckets[i];\n        if (pair != NULL && pair != hashMap->TOMBSTONE) {\n            free(pair->val);\n            free(pair);\n        }\n    }\n}\n\n/* \u54c8\u5e0c\u51fd\u6570 */\nint hashFunc(HashMapOpenAddressing *hashMap, int key) {\n    return key % hashMap->capacity;\n}\n\n/* \u8d1f\u8f7d\u56e0\u5b50 */\ndouble loadFactor(HashMapOpenAddressing *hashMap) {\n    return (double)hashMap->size / (double)hashMap->capacity;\n}\n\n/* \u641c\u7d22 key \u5bf9\u5e94\u7684\u6876\u7d22\u5f15 */\nint findBucket(HashMapOpenAddressing *hashMap, int key) {\n    int index = hashFunc(hashMap, key);\n    int firstTombstone = -1;\n    // \u7ebf\u6027\u63a2\u6d4b\uff0c\u5f53\u9047\u5230\u7a7a\u6876\u65f6\u8df3\u51fa\n    while (hashMap->buckets[index] != NULL) {\n        // \u82e5\u9047\u5230 key \uff0c\u8fd4\u56de\u5bf9\u5e94\u7684\u6876\u7d22\u5f15\n        if (hashMap->buckets[index]->key == key) {\n            // \u82e5\u4e4b\u524d\u9047\u5230\u4e86\u5220\u9664\u6807\u8bb0\uff0c\u5219\u5c06\u952e\u503c\u5bf9\u79fb\u52a8\u81f3\u8be5\u7d22\u5f15\u5904\n            if (firstTombstone != -1) {\n                hashMap->buckets[firstTombstone] = hashMap->buckets[index];\n                hashMap->buckets[index] = hashMap->TOMBSTONE;\n                return firstTombstone; // \u8fd4\u56de\u79fb\u52a8\u540e\u7684\u6876\u7d22\u5f15\n            }\n            return index; // \u8fd4\u56de\u6876\u7d22\u5f15\n        }\n        // \u8bb0\u5f55\u9047\u5230\u7684\u9996\u4e2a\u5220\u9664\u6807\u8bb0\n        if (firstTombstone == -1 && hashMap->buckets[index] == hashMap->TOMBSTONE) {\n            firstTombstone = index;\n        }\n        // \u8ba1\u7b97\u6876\u7d22\u5f15\uff0c\u8d8a\u8fc7\u5c3e\u90e8\u5219\u8fd4\u56de\u5934\u90e8\n        index = (index + 1) % hashMap->capacity;\n    }\n    // \u82e5 key \u4e0d\u5b58\u5728\uff0c\u5219\u8fd4\u56de\u6dfb\u52a0\u70b9\u7684\u7d22\u5f15\n    return firstTombstone == -1 ? index : firstTombstone;\n}\n\n/* \u67e5\u8be2\u64cd\u4f5c */\nchar *get(HashMapOpenAddressing *hashMap, int key) {\n    // \u641c\u7d22 key \u5bf9\u5e94\u7684\u6876\u7d22\u5f15\n    int index = findBucket(hashMap, key);\n    // \u82e5\u627e\u5230\u952e\u503c\u5bf9\uff0c\u5219\u8fd4\u56de\u5bf9\u5e94 val\n    if (hashMap->buckets[index] != NULL && hashMap->buckets[index] != hashMap->TOMBSTONE) {\n        return hashMap->buckets[index]->val;\n    }\n    // \u82e5\u952e\u503c\u5bf9\u4e0d\u5b58\u5728\uff0c\u5219\u8fd4\u56de\u7a7a\u5b57\u7b26\u4e32\n    return \"\";\n}\n\n/* \u6dfb\u52a0\u64cd\u4f5c */\nvoid put(HashMapOpenAddressing *hashMap, int key, char *val) {\n    // \u5f53\u8d1f\u8f7d\u56e0\u5b50\u8d85\u8fc7\u9608\u503c\u65f6\uff0c\u6267\u884c\u6269\u5bb9\n    if (loadFactor(hashMap) > hashMap->loadThres) {\n        extend(hashMap);\n    }\n    // \u641c\u7d22 key \u5bf9\u5e94\u7684\u6876\u7d22\u5f15\n    int index = findBucket(hashMap, key);\n    // \u82e5\u627e\u5230\u952e\u503c\u5bf9\uff0c\u5219\u8986\u76d6 val \u5e76\u8fd4\u56de\n    if (hashMap->buckets[index] != NULL && hashMap->buckets[index] != hashMap->TOMBSTONE) {\n        free(hashMap->buckets[index]->val);\n        hashMap->buckets[index]->val = (char *)malloc(sizeof(strlen(val) + 1));\n        strcpy(hashMap->buckets[index]->val, val);\n        hashMap->buckets[index]->val[strlen(val)] = '\\0';\n        return;\n    }\n    // \u82e5\u952e\u503c\u5bf9\u4e0d\u5b58\u5728\uff0c\u5219\u6dfb\u52a0\u8be5\u952e\u503c\u5bf9\n    Pair *pair = (Pair *)malloc(sizeof(Pair));\n    pair->key = key;\n    pair->val = (char *)malloc(sizeof(strlen(val) + 1));\n    strcpy(pair->val, val);\n    pair->val[strlen(val)] = '\\0';\n\n    hashMap->buckets[index] = pair;\n    hashMap->size++;\n}\n\n/* \u5220\u9664\u64cd\u4f5c */\nvoid removeItem(HashMapOpenAddressing *hashMap, int key) {\n    // \u641c\u7d22 key \u5bf9\u5e94\u7684\u6876\u7d22\u5f15\n    int index = findBucket(hashMap, key);\n    // \u82e5\u627e\u5230\u952e\u503c\u5bf9\uff0c\u5219\u7528\u5220\u9664\u6807\u8bb0\u8986\u76d6\u5b83\n    if (hashMap->buckets[index] != NULL && hashMap->buckets[index] != hashMap->TOMBSTONE) {\n        Pair *pair = hashMap->buckets[index];\n        free(pair->val);\n        free(pair);\n        hashMap->buckets[index] = hashMap->TOMBSTONE;\n        hashMap->size--;\n    }\n}\n\n/* \u6269\u5bb9\u54c8\u5e0c\u8868 */\nvoid extend(HashMapOpenAddressing *hashMap) {\n    // \u6682\u5b58\u539f\u54c8\u5e0c\u8868\n    Pair **bucketsTmp = hashMap->buckets;\n    int oldCapacity = hashMap->capacity;\n    // \u521d\u59cb\u5316\u6269\u5bb9\u540e\u7684\u65b0\u54c8\u5e0c\u8868\n    hashMap->capacity *= hashMap->extendRatio;\n    hashMap->buckets = (Pair **)malloc(sizeof(Pair *) * hashMap->capacity);\n    hashMap->size = 0;\n    // \u5c06\u952e\u503c\u5bf9\u4ece\u539f\u54c8\u5e0c\u8868\u642c\u8fd0\u81f3\u65b0\u54c8\u5e0c\u8868\n    for (int i = 0; i < oldCapacity; i++) {\n        Pair *pair = bucketsTmp[i];\n        if (pair != NULL && pair != hashMap->TOMBSTONE) {\n            put(hashMap, pair->key, pair->val);\n            free(pair->val);\n            free(pair);\n        }\n    }\n    free(bucketsTmp);\n}\n\n/* \u6253\u5370\u54c8\u5e0c\u8868 */\nvoid print(HashMapOpenAddressing *hashMap) {\n    for (int i = 0; i < hashMap->capacity; i++) {\n        Pair *pair = hashMap->buckets[i];\n        if (pair == NULL) {\n            printf(\"NULL\\n\");\n        } else if (pair == hashMap->TOMBSTONE) {\n            printf(\"TOMBSTONE\\n\");\n        } else {\n            printf(\"%d -> %s\\n\", pair->key, pair->val);\n        }\n    }\n}\n
hash_map_open_addressing.zig
[class]{HashMapOpenAddressing}-[func]{}\n
"},{"location":"chapter_hashing/hash_collision/#2-quadratic-probing","title":"2. \u00a0 Quadratic Probing","text":"

Quadratic probing is similar to linear probing and is one of the common strategies of open addressing. When a collision occurs, quadratic probing does not simply skip a fixed number of steps but skips \"the square of the number of probes,\" i.e., \\(1, 4, 9, \\dots\\) steps.

Quadratic probing has the following advantages:

  • Quadratic probing attempts to alleviate the clustering effect of linear probing by skipping the distance of the square of the number of probes.
  • Quadratic probing skips larger distances to find empty positions, helping to distribute data more evenly.

However, quadratic probing is not perfect:

  • Clustering still exists, i.e., some positions are more likely to be occupied than others.
  • Due to the growth of squares, quadratic probing may not probe the entire hash table, meaning it might not access empty buckets even if they exist in the hash table.
"},{"location":"chapter_hashing/hash_collision/#3-double-hashing","title":"3. \u00a0 Double Hashing","text":"

As the name suggests, the double hashing method uses multiple hash functions \\(f_1(x)\\), \\(f_2(x)\\), \\(f_3(x)\\), \\(\\dots\\) for probing.

  • Inserting Elements: If hash function \\(f_1(x)\\) encounters a conflict, try \\(f_2(x)\\), and so on, until an empty position is found and the element is inserted.
  • Searching for Elements: Search in the same order of hash functions until the target element is found and returned; if an empty position is encountered or all hash functions have been tried, it indicates the element is not in the hash table, then return None.

Compared to linear probing, double hashing is less prone to clustering but involves additional computation for multiple hash functions.

Tip

Please note that open addressing (linear probing, quadratic probing, and double hashing) hash tables all have the issue of \"not being able to directly delete elements.\"

"},{"location":"chapter_hashing/hash_collision/#623-choice-of-programming-languages","title":"6.2.3 \u00a0 Choice of Programming Languages","text":"

Various programming languages have adopted different hash table implementation strategies, here are a few examples:

  • Python uses open addressing. The dict dictionary uses pseudo-random numbers for probing.
  • Java uses separate chaining. Since JDK 1.8, when the array length in HashMap reaches 64 and the length of a linked list reaches 8, the linked list is converted to a red-black tree to improve search performance.
  • Go uses separate chaining. Go stipulates that each bucket can store up to 8 key-value pairs, and if the capacity is exceeded, an overflow bucket is connected; when there are too many overflow buckets, a special equal-size expansion operation is performed to ensure performance.
"},{"location":"chapter_hashing/hash_map/","title":"6.1 \u00a0 Hash Table","text":"

A \"hash table\", also known as a \"hash map\", achieves efficient element querying by establishing a mapping between keys and values. Specifically, when we input a key into the hash table, we can retrieve the corresponding value in \\(O(1)\\) time.

As shown in the Figure 6-1 , given \\(n\\) students, each with two pieces of data: \"name\" and \"student number\". If we want to implement a query feature that returns the corresponding name when given a student number, we can use the hash table shown in the Figure 6-1 .

Figure 6-1 \u00a0 Abstract representation of a hash table

Apart from hash tables, arrays and linked lists can also be used to implement querying functions. Their efficiency is compared in the Table 6-1 .

  • Adding Elements: Simply add the element to the end of the array (or linked list), using \\(O(1)\\) time.
  • Querying Elements: Since the array (or linked list) is unordered, it requires traversing all the elements, using \\(O(n)\\) time.
  • Deleting Elements: First, locate the element, then delete it from the array (or linked list), using \\(O(n)\\) time.

Table 6-1 \u00a0 Comparison of Element Query Efficiency

Array Linked List Hash Table Find Element \\(O(n)\\) \\(O(n)\\) \\(O(1)\\) Add Element \\(O(1)\\) \\(O(1)\\) \\(O(1)\\) Delete Element \\(O(n)\\) \\(O(n)\\) \\(O(1)\\)

Observations reveal that the time complexity for adding, deleting, and querying in a hash table is \\(O(1)\\), which is highly efficient.

"},{"location":"chapter_hashing/hash_map/#611-common-operations-of-hash-table","title":"6.1.1 \u00a0 Common Operations of Hash Table","text":"

Common operations of a hash table include initialization, querying, adding key-value pairs, and deleting key-value pairs, etc. Example code is as follows:

PythonC++JavaC#GoSwiftJSTSDartRustCZig hash_map.py
# Initialize hash table\nhmap: dict = {}\n\n# Add operation\n# Add key-value pair (key, value) to the hash table\nhmap[12836] = \"Xiao Ha\"\nhmap[15937] = \"Xiao Luo\"\nhmap[16750] = \"Xiao Suan\"\nhmap[13276] = \"Xiao Fa\"\nhmap[10583] = \"Xiao Ya\"\n\n# Query operation\n# Input key into hash table, get value\nname: str = hmap[15937]\n\n# Delete operation\n# Delete key-value pair (key, value) from hash table\nhmap.pop(10583)\n
hash_map.cpp
/* Initialize hash table */\nunordered_map<int, string> map;\n\n/* Add operation */\n// Add key-value pair (key, value) to the hash table\nmap[12836] = \"Xiao Ha\";\nmap[15937] = \"Xiao Luo\";\nmap[16750] = \"Xiao Suan\";\nmap[13276] = \"Xiao Fa\";\nmap[10583] = \"Xiao Ya\";\n\n/* Query operation */\n// Input key into hash table, get value\nstring name = map[15937];\n\n/* Delete operation */\n// Delete key-value pair (key, value) from hash table\nmap.erase(10583);\n
hash_map.java
/* Initialize hash table */\nMap<Integer, String> map = new HashMap<>();\n\n/* Add operation */\n// Add key-value pair (key, value) to the hash table\nmap.put(12836, \"Xiao Ha\");   \nmap.put(15937, \"Xiao Luo\");   \nmap.put(16750, \"Xiao Suan\");   \nmap.put(13276, \"Xiao Fa\");\nmap.put(10583, \"Xiao Ya\");\n\n/* Query operation */\n// Input key into hash table, get value\nString name = map.get(15937);\n\n/* Delete operation */\n// Delete key-value pair (key, value) from hash table\nmap.remove(10583);\n
hash_map.cs
/* Initialize hash table */\nDictionary<int, string> map = new() {\n    /* Add operation */\n    // Add key-value pair (key, value) to the hash table\n    { 12836, \"Xiao Ha\" },\n    { 15937, \"Xiao Luo\" },\n    { 16750, \"Xiao Suan\" },\n    { 13276, \"Xiao Fa\" },\n    { 10583, \"Xiao Ya\" }\n};\n\n/* Query operation */\n// Input key into hash table, get value\nstring name = map[15937];\n\n/* Delete operation */\n// Delete key-value pair (key, value) from hash table\nmap.Remove(10583);\n
hash_map_test.go
/* Initialize hash table */\nhmap := make(map[int]string)\n\n/* Add operation */\n// Add key-value pair (key, value) to the hash table\nhmap[12836] = \"Xiao Ha\"\nhmap[15937] = \"Xiao Luo\"\nhmap[16750] = \"Xiao Suan\"\nhmap[13276] = \"Xiao Fa\"\nhmap[10583] = \"Xiao Ya\"\n\n/* Query operation */\n// Input key into hash table, get value\nname := hmap[15937]\n\n/* Delete operation */\n// Delete key-value pair (key, value) from hash table\ndelete(hmap, 10583)\n
hash_map.swift
/* Initialize hash table */\nvar map: [Int: String] = [:]\n\n/* Add operation */\n// Add key-value pair (key, value) to the hash table\nmap[12836] = \"Xiao Ha\"\nmap[15937] = \"Xiao Luo\"\nmap[16750] = \"Xiao Suan\"\nmap[13276] = \"Xiao Fa\"\nmap[10583] = \"Xiao Ya\"\n\n/* Query operation */\n// Input key into hash table, get value\nlet name = map[15937]!\n\n/* Delete operation */\n// Delete key-value pair (key, value) from hash table\nmap.removeValue(forKey: 10583)\n
hash_map.js
/* Initialize hash table */\nconst map = new Map();\n/* Add operation */\n// Add key-value pair (key, value) to the hash table\nmap.set(12836, 'Xiao Ha');\nmap.set(15937, 'Xiao Luo');\nmap.set(16750, 'Xiao Suan');\nmap.set(13276, 'Xiao Fa');\nmap.set(10583, 'Xiao Ya');\n\n/* Query operation */\n// Input key into hash table, get value\nlet name = map.get(15937);\n\n/* Delete operation */\n// Delete key-value pair (key, value) from hash table\nmap.delete(10583);\n
hash_map.ts
/* Initialize hash table */\nconst map = new Map<number, string>();\n/* Add operation */\n// Add key-value pair (key, value) to the hash table\nmap.set(12836, 'Xiao Ha');\nmap.set(15937, 'Xiao Luo');\nmap.set(16750, 'Xiao Suan');\nmap.set(13276, 'Xiao Fa');\nmap.set(10583, 'Xiao Ya');\nconsole.info('\\nAfter adding, the hash table is\\nKey -> Value');\nconsole.info(map);\n\n/* Query operation */\n// Input key into hash table, get value\nlet name = map.get(15937);\nconsole.info('\\nInput student number 15937, query name ' + name);\n\n/* Delete operation */\n// Delete key-value pair (key, value) from hash table\nmap.delete(10583);\nconsole.info('\\nAfter deleting 10583, the hash table is\\nKey -> Value');\nconsole.info(map);\n
hash_map.dart
/* Initialize hash table */\nMap<int, String> map = {};\n\n/* Add operation */\n// Add key-value pair (key, value) to the hash table\nmap[12836] = \"Xiao Ha\";\nmap[15937] = \"Xiao Luo\";\nmap[16750] = \"Xiao Suan\";\nmap[13276] = \"Xiao Fa\";\nmap[10583] = \"Xiao Ya\";\n\n/* Query operation */\n// Input key into hash table, get value\nString name = map[15937];\n\n/* Delete operation */\n// Delete key-value pair (key, value) from hash table\nmap.remove(10583);\n
hash_map.rs
use std::collections::HashMap;\n\n/* Initialize hash table */\nlet mut map: HashMap<i32, String> = HashMap::new();\n\n/* Add operation */\n// Add key-value pair (key, value) to the hash table\nmap.insert(12836, \"Xiao Ha\".to_string());\nmap.insert(15937, \"Xiao Luo\".to_string());\nmap.insert(16750, \"Xiao Suan\".to_string());\nmap.insert(13279, \"Xiao Fa\".to_string());\nmap.insert(10583, \"Xiao Ya\".to_string());\n\n/* Query operation */\n// Input key into hash table, get value\nlet _name: Option<&String> = map.get(&15937);\n\n/* Delete operation */\n// Delete key-value pair (key, value) from hash table\nlet _removed_value: Option<String> = map.remove(&10583);\n
hash_map.c
// C does not provide a built-in hash table\n
hash_map.zig
\n
Code Visualization

Full Screen >

There are three common ways to traverse a hash table: traversing key-value pairs, keys, and values. Example code is as follows:

PythonC++JavaC#GoSwiftJSTSDartRustCZig hash_map.py
# Traverse hash table\n# Traverse key-value pairs key->value\nfor key, value in hmap.items():\n    print(key, \"->\", value)\n# Traverse keys only\nfor key in hmap.keys():\n    print(key)\n# Traverse values only\nfor value in hmap.values():\n    print(value)\n
hash_map.cpp
/* Traverse hash table */\n// Traverse key-value pairs key->value\nfor (auto kv: map) {\n    cout << kv.first << \" -> \" << kv.second << endl;\n}\n// Traverse using iterator key->value\nfor (auto iter = map.begin(); iter != map.end(); iter++) {\n    cout << iter->first << \"->\" << iter->second << endl;\n}\n
hash_map.java
/* Traverse hash table */\n// Traverse key-value pairs key->value\nfor (Map.Entry<Integer, String> kv: map.entrySet()) {\n    System.out.println(kv.getKey() + \" -> \" + kv.getValue());\n}\n// Traverse keys only\nfor (int key: map.keySet()) {\n    System.out.println(key);\n}\n// Traverse values only\nfor (String val: map.values()) {\n    System.out.println(val);\n}\n
hash_map.cs
/* Traverse hash table */\n// Traverse key-value pairs Key->Value\nforeach (var kv in map) {\n    Console.WriteLine(kv.Key + \" -> \" + kv.Value);\n}\n// Traverse keys only\nforeach (int key in map.Keys) {\n    Console.WriteLine(key);\n}\n// Traverse values only\nforeach (string val in map.Values) {\n    Console.WriteLine(val);\n}\n
hash_map_test.go
/* Traverse hash table */\n// Traverse key-value pairs key->value\nfor key, value := range hmap {\n    fmt.Println(key, \"->\", value)\n}\n// Traverse keys only\nfor key := range hmap {\n    fmt.Println(key)\n}\n// Traverse values only\nfor _, value := range hmap {\n    fmt.Println(value)\n}\n
hash_map.swift
/* Traverse hash table */\n// Traverse key-value pairs Key->Value\nfor (key, value) in map {\n    print(\"\\(key) -> \\(value)\")\n}\n// Traverse keys only\nfor key in map.keys {\n    print(key)\n}\n// Traverse values only\nfor value in map.values {\n    print(value)\n}\n
hash_map.js
/* Traverse hash table */\nconsole.info('\\nTraverse key-value pairs Key->Value');\nfor (const [k, v] of map.entries()) {\n    console.info(k + ' -> ' + v);\n}\nconsole.info('\\nTraverse keys only Key');\nfor (const k of map.keys()) {\n    console.info(k);\n}\nconsole.info('\\nTraverse values only Value');\nfor (const v of map.values()) {\n    console.info(v);\n}\n
hash_map.ts
/* Traverse hash table */\nconsole.info('\\nTraverse key-value pairs Key->Value');\nfor (const [k, v] of map.entries()) {\n    console.info(k + ' -> ' + v);\n}\nconsole.info('\\nTraverse keys only Key');\nfor (const k of map.keys()) {\n    console.info(k);\n}\nconsole.info('\\nTraverse values only Value');\nfor (const v of map.values()) {\n    console.info(v);\n}\n
hash_map.dart
/* Traverse hash table */\n// Traverse key-value pairs Key->Value\nmap.forEach((key, value) {\nprint('$key -> $value');\n});\n\n// Traverse keys only Key\nmap.keys.forEach((key) {\nprint(key);\n});\n\n// Traverse values only Value\nmap.values.forEach((value) {\nprint(value);\n});\n
hash_map.rs
/* Traverse hash table */\n// Traverse key-value pairs Key->Value\nfor (key, value) in &map {\n    println!(\"{key} -> {value}\");\n}\n\n// Traverse keys only Key\nfor key in map.keys() {\n    println!(\"{key}\"); \n}\n\n// Traverse values only Value\nfor value in map.values() {\n    println!(\"{value}\");\n}\n
hash_map.c
// C does not provide a built-in hash table\n
hash_map.zig
// Zig example is not provided\n
Code Visualization

Full Screen >

"},{"location":"chapter_hashing/hash_map/#612-simple-implementation-of-hash-table","title":"6.1.2 \u00a0 Simple Implementation of Hash Table","text":"

First, let's consider the simplest case: implementing a hash table using just an array. In the hash table, each empty slot in the array is called a \"bucket\", and each bucket can store one key-value pair. Therefore, the query operation involves finding the bucket corresponding to the key and retrieving the value from it.

So, how do we locate the appropriate bucket based on the key? This is achieved through a \"hash function\". The role of the hash function is to map a larger input space to a smaller output space. In a hash table, the input space is all possible keys, and the output space is all buckets (array indices). In other words, input a key, and we can use the hash function to determine the storage location of the corresponding key-value pair in the array.

The calculation process of the hash function for a given key is divided into the following two steps:

  1. Calculate the hash value using a certain hash algorithm hash().
  2. Take the modulus of the hash value with the number of buckets (array length) capacity to obtain the array index index.
index = hash(key) % capacity\n

Afterward, we can use index to access the corresponding bucket in the hash table and thereby retrieve the value.

Assuming array length capacity = 100 and hash algorithm hash(key) = key, the hash function is key % 100. The Figure 6-2 uses key as the student number and value as the name to demonstrate the working principle of the hash function.

Figure 6-2 \u00a0 Working principle of hash function

The following code implements a simple hash table. Here, we encapsulate key and value into a class Pair to represent the key-value pair.

PythonC++JavaC#GoSwiftJSTSDartRustCZig array_hash_map.py
class Pair:\n    \"\"\"\u952e\u503c\u5bf9\"\"\"\n\n    def __init__(self, key: int, val: str):\n        self.key = key\n        self.val = val\n\nclass ArrayHashMap:\n    \"\"\"\u57fa\u4e8e\u6570\u7ec4\u5b9e\u73b0\u7684\u54c8\u5e0c\u8868\"\"\"\n\n    def __init__(self):\n        \"\"\"\u6784\u9020\u65b9\u6cd5\"\"\"\n        # \u521d\u59cb\u5316\u6570\u7ec4\uff0c\u5305\u542b 100 \u4e2a\u6876\n        self.buckets: list[Pair | None] = [None] * 100\n\n    def hash_func(self, key: int) -> int:\n        \"\"\"\u54c8\u5e0c\u51fd\u6570\"\"\"\n        index = key % 100\n        return index\n\n    def get(self, key: int) -> str:\n        \"\"\"\u67e5\u8be2\u64cd\u4f5c\"\"\"\n        index: int = self.hash_func(key)\n        pair: Pair = self.buckets[index]\n        if pair is None:\n            return None\n        return pair.val\n\n    def put(self, key: int, val: str):\n        \"\"\"\u6dfb\u52a0\u64cd\u4f5c\"\"\"\n        pair = Pair(key, val)\n        index: int = self.hash_func(key)\n        self.buckets[index] = pair\n\n    def remove(self, key: int):\n        \"\"\"\u5220\u9664\u64cd\u4f5c\"\"\"\n        index: int = self.hash_func(key)\n        # \u7f6e\u4e3a None \uff0c\u4ee3\u8868\u5220\u9664\n        self.buckets[index] = None\n\n    def entry_set(self) -> list[Pair]:\n        \"\"\"\u83b7\u53d6\u6240\u6709\u952e\u503c\u5bf9\"\"\"\n        result: list[Pair] = []\n        for pair in self.buckets:\n            if pair is not None:\n                result.append(pair)\n        return result\n\n    def key_set(self) -> list[int]:\n        \"\"\"\u83b7\u53d6\u6240\u6709\u952e\"\"\"\n        result = []\n        for pair in self.buckets:\n            if pair is not None:\n                result.append(pair.key)\n        return result\n\n    def value_set(self) -> list[str]:\n        \"\"\"\u83b7\u53d6\u6240\u6709\u503c\"\"\"\n        result = []\n        for pair in self.buckets:\n            if pair is not None:\n                result.append(pair.val)\n        return result\n\n    def print(self):\n        \"\"\"\u6253\u5370\u54c8\u5e0c\u8868\"\"\"\n        for pair in self.buckets:\n            if pair is not None:\n                print(pair.key, \"->\", pair.val)\n
array_hash_map.cpp
/* \u952e\u503c\u5bf9 */\nstruct Pair {\n  public:\n    int key;\n    string val;\n    Pair(int key, string val) {\n        this->key = key;\n        this->val = val;\n    }\n};\n\n/* \u57fa\u4e8e\u6570\u7ec4\u5b9e\u73b0\u7684\u54c8\u5e0c\u8868 */\nclass ArrayHashMap {\n  private:\n    vector<Pair *> buckets;\n\n  public:\n    ArrayHashMap() {\n        // \u521d\u59cb\u5316\u6570\u7ec4\uff0c\u5305\u542b 100 \u4e2a\u6876\n        buckets = vector<Pair *>(100);\n    }\n\n    ~ArrayHashMap() {\n        // \u91ca\u653e\u5185\u5b58\n        for (const auto &bucket : buckets) {\n            delete bucket;\n        }\n        buckets.clear();\n    }\n\n    /* \u54c8\u5e0c\u51fd\u6570 */\n    int hashFunc(int key) {\n        int index = key % 100;\n        return index;\n    }\n\n    /* \u67e5\u8be2\u64cd\u4f5c */\n    string get(int key) {\n        int index = hashFunc(key);\n        Pair *pair = buckets[index];\n        if (pair == nullptr)\n            return \"\";\n        return pair->val;\n    }\n\n    /* \u6dfb\u52a0\u64cd\u4f5c */\n    void put(int key, string val) {\n        Pair *pair = new Pair(key, val);\n        int index = hashFunc(key);\n        buckets[index] = pair;\n    }\n\n    /* \u5220\u9664\u64cd\u4f5c */\n    void remove(int key) {\n        int index = hashFunc(key);\n        // \u91ca\u653e\u5185\u5b58\u5e76\u7f6e\u4e3a nullptr\n        delete buckets[index];\n        buckets[index] = nullptr;\n    }\n\n    /* \u83b7\u53d6\u6240\u6709\u952e\u503c\u5bf9 */\n    vector<Pair *> pairSet() {\n        vector<Pair *> pairSet;\n        for (Pair *pair : buckets) {\n            if (pair != nullptr) {\n                pairSet.push_back(pair);\n            }\n        }\n        return pairSet;\n    }\n\n    /* \u83b7\u53d6\u6240\u6709\u952e */\n    vector<int> keySet() {\n        vector<int> keySet;\n        for (Pair *pair : buckets) {\n            if (pair != nullptr) {\n                keySet.push_back(pair->key);\n            }\n        }\n        return keySet;\n    }\n\n    /* \u83b7\u53d6\u6240\u6709\u503c */\n    vector<string> valueSet() {\n        vector<string> valueSet;\n        for (Pair *pair : buckets) {\n            if (pair != nullptr) {\n                valueSet.push_back(pair->val);\n            }\n        }\n        return valueSet;\n    }\n\n    /* \u6253\u5370\u54c8\u5e0c\u8868 */\n    void print() {\n        for (Pair *kv : pairSet()) {\n            cout << kv->key << \" -> \" << kv->val << endl;\n        }\n    }\n};\n
array_hash_map.java
/* \u952e\u503c\u5bf9 */\nclass Pair {\n    public int key;\n    public String val;\n\n    public Pair(int key, String val) {\n        this.key = key;\n        this.val = val;\n    }\n}\n\n/* \u57fa\u4e8e\u6570\u7ec4\u5b9e\u73b0\u7684\u54c8\u5e0c\u8868 */\nclass ArrayHashMap {\n    private List<Pair> buckets;\n\n    public ArrayHashMap() {\n        // \u521d\u59cb\u5316\u6570\u7ec4\uff0c\u5305\u542b 100 \u4e2a\u6876\n        buckets = new ArrayList<>();\n        for (int i = 0; i < 100; i++) {\n            buckets.add(null);\n        }\n    }\n\n    /* \u54c8\u5e0c\u51fd\u6570 */\n    private int hashFunc(int key) {\n        int index = key % 100;\n        return index;\n    }\n\n    /* \u67e5\u8be2\u64cd\u4f5c */\n    public String get(int key) {\n        int index = hashFunc(key);\n        Pair pair = buckets.get(index);\n        if (pair == null)\n            return null;\n        return pair.val;\n    }\n\n    /* \u6dfb\u52a0\u64cd\u4f5c */\n    public void put(int key, String val) {\n        Pair pair = new Pair(key, val);\n        int index = hashFunc(key);\n        buckets.set(index, pair);\n    }\n\n    /* \u5220\u9664\u64cd\u4f5c */\n    public void remove(int key) {\n        int index = hashFunc(key);\n        // \u7f6e\u4e3a null \uff0c\u4ee3\u8868\u5220\u9664\n        buckets.set(index, null);\n    }\n\n    /* \u83b7\u53d6\u6240\u6709\u952e\u503c\u5bf9 */\n    public List<Pair> pairSet() {\n        List<Pair> pairSet = new ArrayList<>();\n        for (Pair pair : buckets) {\n            if (pair != null)\n                pairSet.add(pair);\n        }\n        return pairSet;\n    }\n\n    /* \u83b7\u53d6\u6240\u6709\u952e */\n    public List<Integer> keySet() {\n        List<Integer> keySet = new ArrayList<>();\n        for (Pair pair : buckets) {\n            if (pair != null)\n                keySet.add(pair.key);\n        }\n        return keySet;\n    }\n\n    /* \u83b7\u53d6\u6240\u6709\u503c */\n    public List<String> valueSet() {\n        List<String> valueSet = new ArrayList<>();\n        for (Pair pair : buckets) {\n            if (pair != null)\n                valueSet.add(pair.val);\n        }\n        return valueSet;\n    }\n\n    /* \u6253\u5370\u54c8\u5e0c\u8868 */\n    public void print() {\n        for (Pair kv : pairSet()) {\n            System.out.println(kv.key + \" -> \" + kv.val);\n        }\n    }\n}\n
array_hash_map.cs
/* \u952e\u503c\u5bf9 int->string */\nclass Pair(int key, string val) {\n    public int key = key;\n    public string val = val;\n}\n\n/* \u57fa\u4e8e\u6570\u7ec4\u5b9e\u73b0\u7684\u54c8\u5e0c\u8868 */\nclass ArrayHashMap {\n    List<Pair?> buckets;\n    public ArrayHashMap() {\n        // \u521d\u59cb\u5316\u6570\u7ec4\uff0c\u5305\u542b 100 \u4e2a\u6876\n        buckets = [];\n        for (int i = 0; i < 100; i++) {\n            buckets.Add(null);\n        }\n    }\n\n    /* \u54c8\u5e0c\u51fd\u6570 */\n    int HashFunc(int key) {\n        int index = key % 100;\n        return index;\n    }\n\n    /* \u67e5\u8be2\u64cd\u4f5c */\n    public string? Get(int key) {\n        int index = HashFunc(key);\n        Pair? pair = buckets[index];\n        if (pair == null) return null;\n        return pair.val;\n    }\n\n    /* \u6dfb\u52a0\u64cd\u4f5c */\n    public void Put(int key, string val) {\n        Pair pair = new(key, val);\n        int index = HashFunc(key);\n        buckets[index] = pair;\n    }\n\n    /* \u5220\u9664\u64cd\u4f5c */\n    public void Remove(int key) {\n        int index = HashFunc(key);\n        // \u7f6e\u4e3a null \uff0c\u4ee3\u8868\u5220\u9664\n        buckets[index] = null;\n    }\n\n    /* \u83b7\u53d6\u6240\u6709\u952e\u503c\u5bf9 */\n    public List<Pair> PairSet() {\n        List<Pair> pairSet = [];\n        foreach (Pair? pair in buckets) {\n            if (pair != null)\n                pairSet.Add(pair);\n        }\n        return pairSet;\n    }\n\n    /* \u83b7\u53d6\u6240\u6709\u952e */\n    public List<int> KeySet() {\n        List<int> keySet = [];\n        foreach (Pair? pair in buckets) {\n            if (pair != null)\n                keySet.Add(pair.key);\n        }\n        return keySet;\n    }\n\n    /* \u83b7\u53d6\u6240\u6709\u503c */\n    public List<string> ValueSet() {\n        List<string> valueSet = [];\n        foreach (Pair? pair in buckets) {\n            if (pair != null)\n                valueSet.Add(pair.val);\n        }\n        return valueSet;\n    }\n\n    /* \u6253\u5370\u54c8\u5e0c\u8868 */\n    public void Print() {\n        foreach (Pair kv in PairSet()) {\n            Console.WriteLine(kv.key + \" -> \" + kv.val);\n        }\n    }\n}\n
array_hash_map.go
/* \u952e\u503c\u5bf9 */\ntype pair struct {\n    key int\n    val string\n}\n\n/* \u57fa\u4e8e\u6570\u7ec4\u5b9e\u73b0\u7684\u54c8\u5e0c\u8868 */\ntype arrayHashMap struct {\n    buckets []*pair\n}\n\n/* \u521d\u59cb\u5316\u54c8\u5e0c\u8868 */\nfunc newArrayHashMap() *arrayHashMap {\n    // \u521d\u59cb\u5316\u6570\u7ec4\uff0c\u5305\u542b 100 \u4e2a\u6876\n    buckets := make([]*pair, 100)\n    return &arrayHashMap{buckets: buckets}\n}\n\n/* \u54c8\u5e0c\u51fd\u6570 */\nfunc (a *arrayHashMap) hashFunc(key int) int {\n    index := key % 100\n    return index\n}\n\n/* \u67e5\u8be2\u64cd\u4f5c */\nfunc (a *arrayHashMap) get(key int) string {\n    index := a.hashFunc(key)\n    pair := a.buckets[index]\n    if pair == nil {\n        return \"Not Found\"\n    }\n    return pair.val\n}\n\n/* \u6dfb\u52a0\u64cd\u4f5c */\nfunc (a *arrayHashMap) put(key int, val string) {\n    pair := &pair{key: key, val: val}\n    index := a.hashFunc(key)\n    a.buckets[index] = pair\n}\n\n/* \u5220\u9664\u64cd\u4f5c */\nfunc (a *arrayHashMap) remove(key int) {\n    index := a.hashFunc(key)\n    // \u7f6e\u4e3a nil \uff0c\u4ee3\u8868\u5220\u9664\n    a.buckets[index] = nil\n}\n\n/* \u83b7\u53d6\u6240\u6709\u952e\u5bf9 */\nfunc (a *arrayHashMap) pairSet() []*pair {\n    var pairs []*pair\n    for _, pair := range a.buckets {\n        if pair != nil {\n            pairs = append(pairs, pair)\n        }\n    }\n    return pairs\n}\n\n/* \u83b7\u53d6\u6240\u6709\u952e */\nfunc (a *arrayHashMap) keySet() []int {\n    var keys []int\n    for _, pair := range a.buckets {\n        if pair != nil {\n            keys = append(keys, pair.key)\n        }\n    }\n    return keys\n}\n\n/* \u83b7\u53d6\u6240\u6709\u503c */\nfunc (a *arrayHashMap) valueSet() []string {\n    var values []string\n    for _, pair := range a.buckets {\n        if pair != nil {\n            values = append(values, pair.val)\n        }\n    }\n    return values\n}\n\n/* \u6253\u5370\u54c8\u5e0c\u8868 */\nfunc (a *arrayHashMap) print() {\n    for _, pair := range a.buckets {\n        if pair != nil {\n            fmt.Println(pair.key, \"->\", pair.val)\n        }\n    }\n}\n
array_hash_map.swift
/* \u952e\u503c\u5bf9 */\nclass Pair: Equatable {\n    public var key: Int\n    public var val: String\n\n    public init(key: Int, val: String) {\n        self.key = key\n        self.val = val\n    }\n\n    public static func == (lhs: Pair, rhs: Pair) -> Bool {\n        lhs.key == rhs.key && lhs.val == rhs.val\n    }\n}\n\n/* \u57fa\u4e8e\u6570\u7ec4\u5b9e\u73b0\u7684\u54c8\u5e0c\u8868 */\nclass ArrayHashMap {\n    private var buckets: [Pair?]\n\n    init() {\n        // \u521d\u59cb\u5316\u6570\u7ec4\uff0c\u5305\u542b 100 \u4e2a\u6876\n        buckets = Array(repeating: nil, count: 100)\n    }\n\n    /* \u54c8\u5e0c\u51fd\u6570 */\n    private func hashFunc(key: Int) -> Int {\n        let index = key % 100\n        return index\n    }\n\n    /* \u67e5\u8be2\u64cd\u4f5c */\n    func get(key: Int) -> String? {\n        let index = hashFunc(key: key)\n        let pair = buckets[index]\n        return pair?.val\n    }\n\n    /* \u6dfb\u52a0\u64cd\u4f5c */\n    func put(key: Int, val: String) {\n        let pair = Pair(key: key, val: val)\n        let index = hashFunc(key: key)\n        buckets[index] = pair\n    }\n\n    /* \u5220\u9664\u64cd\u4f5c */\n    func remove(key: Int) {\n        let index = hashFunc(key: key)\n        // \u7f6e\u4e3a nil \uff0c\u4ee3\u8868\u5220\u9664\n        buckets[index] = nil\n    }\n\n    /* \u83b7\u53d6\u6240\u6709\u952e\u503c\u5bf9 */\n    func pairSet() -> [Pair] {\n        buckets.compactMap { $0 }\n    }\n\n    /* \u83b7\u53d6\u6240\u6709\u952e */\n    func keySet() -> [Int] {\n        buckets.compactMap { $0?.key }\n    }\n\n    /* \u83b7\u53d6\u6240\u6709\u503c */\n    func valueSet() -> [String] {\n        buckets.compactMap { $0?.val }\n    }\n\n    /* \u6253\u5370\u54c8\u5e0c\u8868 */\n    func print() {\n        for pair in pairSet() {\n            Swift.print(\"\\(pair.key) -> \\(pair.val)\")\n        }\n    }\n}\n
array_hash_map.js
/* \u952e\u503c\u5bf9 Number -> String */\nclass Pair {\n    constructor(key, val) {\n        this.key = key;\n        this.val = val;\n    }\n}\n\n/* \u57fa\u4e8e\u6570\u7ec4\u5b9e\u73b0\u7684\u54c8\u5e0c\u8868 */\nclass ArrayHashMap {\n    #buckets;\n    constructor() {\n        // \u521d\u59cb\u5316\u6570\u7ec4\uff0c\u5305\u542b 100 \u4e2a\u6876\n        this.#buckets = new Array(100).fill(null);\n    }\n\n    /* \u54c8\u5e0c\u51fd\u6570 */\n    #hashFunc(key) {\n        return key % 100;\n    }\n\n    /* \u67e5\u8be2\u64cd\u4f5c */\n    get(key) {\n        let index = this.#hashFunc(key);\n        let pair = this.#buckets[index];\n        if (pair === null) return null;\n        return pair.val;\n    }\n\n    /* \u6dfb\u52a0\u64cd\u4f5c */\n    set(key, val) {\n        let index = this.#hashFunc(key);\n        this.#buckets[index] = new Pair(key, val);\n    }\n\n    /* \u5220\u9664\u64cd\u4f5c */\n    delete(key) {\n        let index = this.#hashFunc(key);\n        // \u7f6e\u4e3a null \uff0c\u4ee3\u8868\u5220\u9664\n        this.#buckets[index] = null;\n    }\n\n    /* \u83b7\u53d6\u6240\u6709\u952e\u503c\u5bf9 */\n    entries() {\n        let arr = [];\n        for (let i = 0; i < this.#buckets.length; i++) {\n            if (this.#buckets[i]) {\n                arr.push(this.#buckets[i]);\n            }\n        }\n        return arr;\n    }\n\n    /* \u83b7\u53d6\u6240\u6709\u952e */\n    keys() {\n        let arr = [];\n        for (let i = 0; i < this.#buckets.length; i++) {\n            if (this.#buckets[i]) {\n                arr.push(this.#buckets[i].key);\n            }\n        }\n        return arr;\n    }\n\n    /* \u83b7\u53d6\u6240\u6709\u503c */\n    values() {\n        let arr = [];\n        for (let i = 0; i < this.#buckets.length; i++) {\n            if (this.#buckets[i]) {\n                arr.push(this.#buckets[i].val);\n            }\n        }\n        return arr;\n    }\n\n    /* \u6253\u5370\u54c8\u5e0c\u8868 */\n    print() {\n        let pairSet = this.entries();\n        for (const pair of pairSet) {\n            console.info(`${pair.key} -> ${pair.val}`);\n        }\n    }\n}\n
array_hash_map.ts
/* \u952e\u503c\u5bf9 Number -> String */\nclass Pair {\n    public key: number;\n    public val: string;\n\n    constructor(key: number, val: string) {\n        this.key = key;\n        this.val = val;\n    }\n}\n\n/* \u57fa\u4e8e\u6570\u7ec4\u5b9e\u73b0\u7684\u54c8\u5e0c\u8868 */\nclass ArrayHashMap {\n    private readonly buckets: (Pair | null)[];\n\n    constructor() {\n        // \u521d\u59cb\u5316\u6570\u7ec4\uff0c\u5305\u542b 100 \u4e2a\u6876\n        this.buckets = new Array(100).fill(null);\n    }\n\n    /* \u54c8\u5e0c\u51fd\u6570 */\n    private hashFunc(key: number): number {\n        return key % 100;\n    }\n\n    /* \u67e5\u8be2\u64cd\u4f5c */\n    public get(key: number): string | null {\n        let index = this.hashFunc(key);\n        let pair = this.buckets[index];\n        if (pair === null) return null;\n        return pair.val;\n    }\n\n    /* \u6dfb\u52a0\u64cd\u4f5c */\n    public set(key: number, val: string) {\n        let index = this.hashFunc(key);\n        this.buckets[index] = new Pair(key, val);\n    }\n\n    /* \u5220\u9664\u64cd\u4f5c */\n    public delete(key: number) {\n        let index = this.hashFunc(key);\n        // \u7f6e\u4e3a null \uff0c\u4ee3\u8868\u5220\u9664\n        this.buckets[index] = null;\n    }\n\n    /* \u83b7\u53d6\u6240\u6709\u952e\u503c\u5bf9 */\n    public entries(): (Pair | null)[] {\n        let arr: (Pair | null)[] = [];\n        for (let i = 0; i < this.buckets.length; i++) {\n            if (this.buckets[i]) {\n                arr.push(this.buckets[i]);\n            }\n        }\n        return arr;\n    }\n\n    /* \u83b7\u53d6\u6240\u6709\u952e */\n    public keys(): (number | undefined)[] {\n        let arr: (number | undefined)[] = [];\n        for (let i = 0; i < this.buckets.length; i++) {\n            if (this.buckets[i]) {\n                arr.push(this.buckets[i].key);\n            }\n        }\n        return arr;\n    }\n\n    /* \u83b7\u53d6\u6240\u6709\u503c */\n    public values(): (string | undefined)[] {\n        let arr: (string | undefined)[] = [];\n        for (let i = 0; i < this.buckets.length; i++) {\n            if (this.buckets[i]) {\n                arr.push(this.buckets[i].val);\n            }\n        }\n        return arr;\n    }\n\n    /* \u6253\u5370\u54c8\u5e0c\u8868 */\n    public print() {\n        let pairSet = this.entries();\n        for (const pair of pairSet) {\n            console.info(`${pair.key} -> ${pair.val}`);\n        }\n    }\n}\n
array_hash_map.dart
/* \u952e\u503c\u5bf9 */\nclass Pair {\n  int key;\n  String val;\n  Pair(this.key, this.val);\n}\n\n/* \u57fa\u4e8e\u6570\u7ec4\u5b9e\u73b0\u7684\u54c8\u5e0c\u8868 */\nclass ArrayHashMap {\n  late List<Pair?> _buckets;\n\n  ArrayHashMap() {\n    // \u521d\u59cb\u5316\u6570\u7ec4\uff0c\u5305\u542b 100 \u4e2a\u6876\n    _buckets = List.filled(100, null);\n  }\n\n  /* \u54c8\u5e0c\u51fd\u6570 */\n  int _hashFunc(int key) {\n    final int index = key % 100;\n    return index;\n  }\n\n  /* \u67e5\u8be2\u64cd\u4f5c */\n  String? get(int key) {\n    final int index = _hashFunc(key);\n    final Pair? pair = _buckets[index];\n    if (pair == null) {\n      return null;\n    }\n    return pair.val;\n  }\n\n  /* \u6dfb\u52a0\u64cd\u4f5c */\n  void put(int key, String val) {\n    final Pair pair = Pair(key, val);\n    final int index = _hashFunc(key);\n    _buckets[index] = pair;\n  }\n\n  /* \u5220\u9664\u64cd\u4f5c */\n  void remove(int key) {\n    final int index = _hashFunc(key);\n    _buckets[index] = null;\n  }\n\n  /* \u83b7\u53d6\u6240\u6709\u952e\u503c\u5bf9 */\n  List<Pair> pairSet() {\n    List<Pair> pairSet = [];\n    for (final Pair? pair in _buckets) {\n      if (pair != null) {\n        pairSet.add(pair);\n      }\n    }\n    return pairSet;\n  }\n\n  /* \u83b7\u53d6\u6240\u6709\u952e */\n  List<int> keySet() {\n    List<int> keySet = [];\n    for (final Pair? pair in _buckets) {\n      if (pair != null) {\n        keySet.add(pair.key);\n      }\n    }\n    return keySet;\n  }\n\n  /* \u83b7\u53d6\u6240\u6709\u503c */\n  List<String> values() {\n    List<String> valueSet = [];\n    for (final Pair? pair in _buckets) {\n      if (pair != null) {\n        valueSet.add(pair.val);\n      }\n    }\n    return valueSet;\n  }\n\n  /* \u6253\u5370\u54c8\u5e0c\u8868 */\n  void printHashMap() {\n    for (final Pair kv in pairSet()) {\n      print(\"${kv.key} -> ${kv.val}\");\n    }\n  }\n}\n
array_hash_map.rs
/* \u952e\u503c\u5bf9 */\n#[derive(Debug, Clone, PartialEq)]\npub struct Pair {\n    pub key: i32,\n    pub val: String,\n}\n\n/* \u57fa\u4e8e\u6570\u7ec4\u5b9e\u73b0\u7684\u54c8\u5e0c\u8868 */\npub struct ArrayHashMap {\n    buckets: Vec<Option<Pair>>,\n}\n\nimpl ArrayHashMap {\n    pub fn new() -> ArrayHashMap {\n        // \u521d\u59cb\u5316\u6570\u7ec4\uff0c\u5305\u542b 100 \u4e2a\u6876\n        Self {\n            buckets: vec![None; 100],\n        }\n    }\n\n    /* \u54c8\u5e0c\u51fd\u6570 */\n    fn hash_func(&self, key: i32) -> usize {\n        key as usize % 100\n    }\n\n    /* \u67e5\u8be2\u64cd\u4f5c */\n    pub fn get(&self, key: i32) -> Option<&String> {\n        let index = self.hash_func(key);\n        self.buckets[index].as_ref().map(|pair| &pair.val)\n    }\n\n    /* \u6dfb\u52a0\u64cd\u4f5c */\n    pub fn put(&mut self, key: i32, val: &str) {\n        let index = self.hash_func(key);\n        self.buckets[index] = Some(Pair {\n            key,\n            val: val.to_string(),\n        });\n    }\n\n    /* \u5220\u9664\u64cd\u4f5c */\n    pub fn remove(&mut self, key: i32) {\n        let index = self.hash_func(key);\n        // \u7f6e\u4e3a None \uff0c\u4ee3\u8868\u5220\u9664\n        self.buckets[index] = None;\n    }\n\n    /* \u83b7\u53d6\u6240\u6709\u952e\u503c\u5bf9 */\n    pub fn entry_set(&self) -> Vec<&Pair> {\n        self.buckets\n            .iter()\n            .filter_map(|pair| pair.as_ref())\n            .collect()\n    }\n\n    /* \u83b7\u53d6\u6240\u6709\u952e */\n    pub fn key_set(&self) -> Vec<&i32> {\n        self.buckets\n            .iter()\n            .filter_map(|pair| pair.as_ref().map(|pair| &pair.key))\n            .collect()\n    }\n\n    /* \u83b7\u53d6\u6240\u6709\u503c */\n    pub fn value_set(&self) -> Vec<&String> {\n        self.buckets\n            .iter()\n            .filter_map(|pair| pair.as_ref().map(|pair| &pair.val))\n            .collect()\n    }\n\n    /* \u6253\u5370\u54c8\u5e0c\u8868 */\n    pub fn print(&self) {\n        for pair in self.entry_set() {\n            println!(\"{} -> {}\", pair.key, pair.val);\n        }\n    }\n}\n
array_hash_map.c
/* \u952e\u503c\u5bf9 int->string */\ntypedef struct {\n    int key;\n    char *val;\n} Pair;\n\n/* \u57fa\u4e8e\u6570\u7ec4\u5b9e\u73b0\u7684\u54c8\u5e0c\u8868 */\ntypedef struct {\n    Pair *buckets[HASHTABLE_CAPACITY];\n} ArrayHashMap;\n\n/* \u6784\u9020\u51fd\u6570 */\nArrayHashMap *newArrayHashMap() {\n    ArrayHashMap *hmap = malloc(sizeof(ArrayHashMap));\n    return hmap;\n}\n\n/* \u6790\u6784\u51fd\u6570 */\nvoid delArrayHashMap(ArrayHashMap *hmap) {\n    for (int i = 0; i < HASHTABLE_CAPACITY; i++) {\n        if (hmap->buckets[i] != NULL) {\n            free(hmap->buckets[i]->val);\n            free(hmap->buckets[i]);\n        }\n    }\n    free(hmap);\n}\n\n/* \u6dfb\u52a0\u64cd\u4f5c */\nvoid put(ArrayHashMap *hmap, const int key, const char *val) {\n    Pair *Pair = malloc(sizeof(Pair));\n    Pair->key = key;\n    Pair->val = malloc(strlen(val) + 1);\n    strcpy(Pair->val, val);\n\n    int index = hashFunc(key);\n    hmap->buckets[index] = Pair;\n}\n\n/* \u5220\u9664\u64cd\u4f5c */\nvoid removeItem(ArrayHashMap *hmap, const int key) {\n    int index = hashFunc(key);\n    free(hmap->buckets[index]->val);\n    free(hmap->buckets[index]);\n    hmap->buckets[index] = NULL;\n}\n\n/* \u83b7\u53d6\u6240\u6709\u952e\u503c\u5bf9 */\nvoid pairSet(ArrayHashMap *hmap, MapSet *set) {\n    Pair *entries;\n    int i = 0, index = 0;\n    int total = 0;\n    /* \u7edf\u8ba1\u6709\u6548\u952e\u503c\u5bf9\u6570\u91cf */\n    for (i = 0; i < HASHTABLE_CAPACITY; i++) {\n        if (hmap->buckets[i] != NULL) {\n            total++;\n        }\n    }\n    entries = malloc(sizeof(Pair) * total);\n    for (i = 0; i < HASHTABLE_CAPACITY; i++) {\n        if (hmap->buckets[i] != NULL) {\n            entries[index].key = hmap->buckets[i]->key;\n            entries[index].val = malloc(strlen(hmap->buckets[i]->val) + 1);\n            strcpy(entries[index].val, hmap->buckets[i]->val);\n            index++;\n        }\n    }\n    set->set = entries;\n    set->len = total;\n}\n\n/* \u83b7\u53d6\u6240\u6709\u952e */\nvoid keySet(ArrayHashMap *hmap, MapSet *set) {\n    int *keys;\n    int i = 0, index = 0;\n    int total = 0;\n    /* \u7edf\u8ba1\u6709\u6548\u952e\u503c\u5bf9\u6570\u91cf */\n    for (i = 0; i < HASHTABLE_CAPACITY; i++) {\n        if (hmap->buckets[i] != NULL) {\n            total++;\n        }\n    }\n    keys = malloc(total * sizeof(int));\n    for (i = 0; i < HASHTABLE_CAPACITY; i++) {\n        if (hmap->buckets[i] != NULL) {\n            keys[index] = hmap->buckets[i]->key;\n            index++;\n        }\n    }\n    set->set = keys;\n    set->len = total;\n}\n\n/* \u83b7\u53d6\u6240\u6709\u503c */\nvoid valueSet(ArrayHashMap *hmap, MapSet *set) {\n    char **vals;\n    int i = 0, index = 0;\n    int total = 0;\n    /* \u7edf\u8ba1\u6709\u6548\u952e\u503c\u5bf9\u6570\u91cf */\n    for (i = 0; i < HASHTABLE_CAPACITY; i++) {\n        if (hmap->buckets[i] != NULL) {\n            total++;\n        }\n    }\n    vals = malloc(total * sizeof(char *));\n    for (i = 0; i < HASHTABLE_CAPACITY; i++) {\n        if (hmap->buckets[i] != NULL) {\n            vals[index] = hmap->buckets[i]->val;\n            index++;\n        }\n    }\n    set->set = vals;\n    set->len = total;\n}\n\n/* \u6253\u5370\u54c8\u5e0c\u8868 */\nvoid print(ArrayHashMap *hmap) {\n    int i;\n    MapSet set;\n    pairSet(hmap, &set);\n    Pair *entries = (Pair *)set.set;\n    for (i = 0; i < set.len; i++) {\n        printf(\"%d -> %s\\n\", entries[i].key, entries[i].val);\n    }\n    free(set.set);\n}\n
array_hash_map.zig
// \u952e\u503c\u5bf9\nconst Pair = struct {\n    key: usize = undefined,\n    val: []const u8 = undefined,\n\n   pub fn init(key: usize, val: []const u8) Pair {\n        return Pair {\n            .key = key,\n            .val = val,\n        };\n    }\n};\n\n// \u57fa\u4e8e\u6570\u7ec4\u5b9e\u73b0\u7684\u54c8\u5e0c\u8868\nfn ArrayHashMap(comptime T: type) type {\n    return struct {\n        bucket: ?std.ArrayList(?T) = null,\n        mem_allocator: std.mem.Allocator = undefined,\n\n        const Self = @This();\n\n        // \u6784\u9020\u51fd\u6570\n        pub fn init(self: *Self, allocator: std.mem.Allocator) !void {\n            self.mem_allocator = allocator;\n            // \u521d\u59cb\u5316\u4e00\u4e2a\u957f\u5ea6\u4e3a 100 \u7684\u6876\uff08\u6570\u7ec4\uff09\n            self.bucket = std.ArrayList(?T).init(self.mem_allocator);\n            var i: i32 = 0;\n            while (i < 100) : (i += 1) {\n                try self.bucket.?.append(null);\n            }\n        }\n\n        // \u6790\u6784\u51fd\u6570\n        pub fn deinit(self: *Self) void {\n            if (self.bucket != null) self.bucket.?.deinit();\n        }\n\n        // \u54c8\u5e0c\u51fd\u6570\n        fn hashFunc(key: usize) usize {\n            var index = key % 100;\n            return index;\n        }\n\n        // \u67e5\u8be2\u64cd\u4f5c\n        pub fn get(self: *Self, key: usize) []const u8 {\n            var index = hashFunc(key);\n            var pair = self.bucket.?.items[index];\n            return pair.?.val;\n        }\n\n        // \u6dfb\u52a0\u64cd\u4f5c\n        pub fn put(self: *Self, key: usize, val: []const u8) !void {\n            var pair = Pair.init(key, val);\n            var index = hashFunc(key);\n            self.bucket.?.items[index] = pair;\n        }\n\n        // \u5220\u9664\u64cd\u4f5c\n        pub fn remove(self: *Self, key: usize) !void {\n            var index = hashFunc(key);\n            // \u7f6e\u4e3a null \uff0c\u4ee3\u8868\u5220\u9664\n            self.bucket.?.items[index] = null;\n        }       \n\n        // \u83b7\u53d6\u6240\u6709\u952e\u503c\u5bf9\n        pub fn pairSet(self: *Self) !std.ArrayList(T) {\n            var entry_set = std.ArrayList(T).init(self.mem_allocator);\n            for (self.bucket.?.items) |item| {\n                if (item == null) continue;\n                try entry_set.append(item.?);\n            }\n            return entry_set;\n        }  \n\n        // \u83b7\u53d6\u6240\u6709\u952e\n        pub fn keySet(self: *Self) !std.ArrayList(usize) {\n            var key_set = std.ArrayList(usize).init(self.mem_allocator);\n            for (self.bucket.?.items) |item| {\n                if (item == null) continue;\n                try key_set.append(item.?.key);\n            }\n            return key_set;\n        }  \n\n        // \u83b7\u53d6\u6240\u6709\u503c\n        pub fn valueSet(self: *Self) !std.ArrayList([]const u8) {\n            var value_set = std.ArrayList([]const u8).init(self.mem_allocator);\n            for (self.bucket.?.items) |item| {\n                if (item == null) continue;\n                try value_set.append(item.?.val);\n            }\n            return value_set;\n        }\n\n        // \u6253\u5370\u54c8\u5e0c\u8868\n        pub fn print(self: *Self) !void {\n            var entry_set = try self.pairSet();\n            defer entry_set.deinit();\n            for (entry_set.items) |item| {\n                std.debug.print(\"{} -> {s}\\n\", .{item.key, item.val});\n            }\n        }\n    };\n}\n
Code Visualization

Full Screen >

"},{"location":"chapter_hashing/hash_map/#613-hash-collision-and-resizing","title":"6.1.3 \u00a0 Hash Collision and Resizing","text":"

Fundamentally, the role of the hash function is to map the entire input space of all keys to the output space of all array indices. However, the input space is often much larger than the output space. Therefore, theoretically, there must be situations where \"multiple inputs correspond to the same output\".

For the hash function in the above example, if the last two digits of the input key are the same, the output of the hash function will also be the same. For example, when querying for students with student numbers 12836 and 20336, we find:

12836 % 100 = 36\n20336 % 100 = 36\n

As shown in the Figure 6-3 , both student numbers point to the same name, which is obviously incorrect. This situation where multiple inputs correspond to the same output is known as \"hash collision\".

Figure 6-3 \u00a0 Example of hash collision

It is easy to understand that the larger the capacity \\(n\\) of the hash table, the lower the probability of multiple keys being allocated to the same bucket, and the fewer the collisions. Therefore, expanding the capacity of the hash table can reduce hash collisions.

As shown in the Figure 6-4 , before expansion, key-value pairs (136, A) and (236, D) collided; after expansion, the collision is resolved.

Figure 6-4 \u00a0 Hash table expansion

Similar to array expansion, resizing a hash table requires migrating all key-value pairs from the original hash table to the new one, which is time-consuming. Furthermore, since the capacity capacity of the hash table changes, we need to recalculate the storage positions of all key-value pairs using the hash function, which adds to the computational overhead of the resizing process. Therefore, programming languages often reserve a sufficiently large capacity for the hash table to prevent frequent resizing.

The \"load factor\" is an important concept for hash tables. It is defined as the ratio of the number of elements in the hash table to the number of buckets. It is used to measure the severity of hash collisions and is often used as a trigger for resizing the hash table. For example, in Java, when the load factor exceeds \\(0.75\\), the system will resize the hash table to twice its original size.

"},{"location":"chapter_hashing/summary/","title":"6.4 \u00a0 Summary","text":""},{"location":"chapter_hashing/summary/#1-key-review","title":"1. \u00a0 Key Review","text":"
  • Given an input key, a hash table can retrieve the corresponding value in \\(O(1)\\) time, which is highly efficient.
  • Common hash table operations include querying, adding key-value pairs, deleting key-value pairs, and traversing the hash table.
  • The hash function maps a key to an array index, allowing access to the corresponding bucket to retrieve the value.
  • Two different keys may end up with the same array index after hashing, leading to erroneous query results. This phenomenon is known as hash collision.
  • The larger the capacity of the hash table, the lower the probability of hash collisions. Therefore, hash table resizing can mitigate hash collisions. Similar to array resizing, hash table resizing is costly.
  • Load factor, defined as the ratio of the number of elements to the number of buckets in the hash table, reflects the severity of hash collisions and is often used as a trigger for resizing the hash table.
  • Chaining addresses hash collisions by converting each element into a linked list, storing all colliding elements in the same list. However, excessively long lists can reduce query efficiency, which can be improved by converting the lists into red-black trees.
  • Open addressing handles hash collisions through multiple probes. Linear probing uses a fixed step size but cannot delete elements and is prone to clustering. Multiple hashing uses several hash functions for probing, making it less susceptible to clustering but increasing computational load.
  • Different programming languages adopt various hash table implementations. For example, Java's HashMap uses chaining, while Python's dict employs open addressing.
  • In hash tables, we desire hash algorithms with determinism, high efficiency, and uniform distribution. In cryptography, hash algorithms should also possess collision resistance and the avalanche effect.
  • Hash algorithms typically use large prime numbers as moduli to ensure uniform distribution of hash values and reduce hash collisions.
  • Common hash algorithms include MD5, SHA-1, SHA-2, and SHA-3. MD5 is often used for file integrity checks, while SHA-2 is commonly used in secure applications and protocols.
  • Programming languages usually provide built-in hash algorithms for data types to calculate bucket indices in hash tables. Generally, only immutable objects are hashable.
"},{"location":"chapter_hashing/summary/#2-q-a","title":"2. \u00a0 Q & A","text":"

Q: When does the time complexity of a hash table degrade to \\(O(n)\\)?

The time complexity of a hash table can degrade to \\(O(n)\\) when hash collisions are severe. When the hash function is well-designed, the capacity is set appropriately, and collisions are evenly distributed, the time complexity is \\(O(1)\\). We usually consider the time complexity to be \\(O(1)\\) when using built-in hash tables in programming languages.

Q: Why not use the hash function \\(f(x) = x\\)? This would eliminate collisions.

Under the hash function \\(f(x) = x\\), each element corresponds to a unique bucket index, which is equivalent to an array. However, the input space is usually much larger than the output space (array length), so the last step of a hash function is often to take the modulo of the array length. In other words, the goal of a hash table is to map a larger state space to a smaller one while providing \\(O(1)\\) query efficiency.

Q: Why can hash tables be more efficient than arrays, linked lists, or binary trees, even though they are implemented using these structures?

Firstly, hash tables have higher time efficiency but lower space efficiency. A significant portion of memory in hash tables remains unused.

Secondly, they are only more efficient in specific use cases. If a feature can be implemented with the same time complexity using an array or a linked list, it's usually faster than using a hash table. This is because the computation of the hash function incurs overhead, making the constant factor in the time complexity larger.

Lastly, the time complexity of hash tables can degrade. For example, in chaining, we perform search operations in a linked list or red-black tree, which still risks degrading to \\(O(n)\\) time.

Q: Does multiple hashing also have the flaw of not being able to delete elements directly? Can space marked as deleted be reused?

Multiple hashing is a form of open addressing, and all open addressing methods have the drawback of not being able to delete elements directly; they require marking elements as deleted. Marked spaces can be reused. When inserting new elements into the hash table, and the hash function points to a position marked as deleted, that position can be used by the new element. This maintains the probing sequence of the hash table while ensuring efficient use of space.

Q: Why do hash collisions occur during the search process in linear probing?

During the search process, the hash function points to the corresponding bucket and key-value pair. If the key doesn't match, it indicates a hash collision. Therefore, linear probing will search downwards at a predetermined step size until the correct key-value pair is found or the search fails.

Q: Why can resizing a hash table alleviate hash collisions?

The last step of a hash function often involves taking the modulo of the array length \\(n\\), to keep the output within the array index range. When resizing, the array length \\(n\\) changes, and the indices corresponding to the keys may also change. Keys that were previously mapped to the same bucket might be distributed across multiple buckets after resizing, thereby mitigating hash collisions.

"},{"location":"chapter_introduction/","title":"Chapter 1. \u00a0 Introduction to Algorithms","text":"

Abstract

A graceful maiden dances, intertwined with the data, her skirt swaying to the melody of algorithms.

She invites you to a dance, follow her steps, and enter the world of algorithms full of logic and beauty.

"},{"location":"chapter_introduction/#chapter-contents","title":"Chapter Contents","text":"
  • 1.1 \u00a0 Algorithms are Everywhere
  • 1.2 \u00a0 What is an Algorithm
  • 1.3 \u00a0 Summary
"},{"location":"chapter_introduction/algorithms_are_everywhere/","title":"1.1 \u00a0 Algorithms are Everywhere","text":"

When we hear the word \"algorithm,\" we naturally think of mathematics. However, many algorithms do not involve complex mathematics but rely more on basic logic, which can be seen everywhere in our daily lives.

Before formally discussing algorithms, there's an interesting fact worth sharing: you have already unconsciously learned many algorithms and have become accustomed to applying them in your daily life. Here, I will give a few specific examples to prove this point.

Example 1: Looking Up a Dictionary. In an English dictionary, words are listed alphabetically. Suppose we're searching for a word that starts with the letter \\(r\\). This is typically done in the following way:

  1. Open the dictionary to about halfway and check the first letter on the page, let's say the letter is \\(m\\).
  2. Since \\(r\\) comes after \\(m\\) in the alphabet, we can ignore the first half of the dictionary and focus on the latter half.
  3. Repeat steps 1. and 2. until you find the page where the word starts with \\(r\\).
<1><2><3><4><5>

Figure 1-1 \u00a0 Process of Looking Up a Dictionary

This essential skill for elementary students, looking up a dictionary, is actually the famous \"Binary Search\" algorithm. From a data structure perspective, we can consider the dictionary as a sorted \"array\"; from an algorithmic perspective, the series of actions taken to look up a word in the dictionary can be viewed as \"Binary Search.\"

Example 2: Organizing Playing Cards. When playing cards, we need to arrange the cards in our hand in ascending order, as shown in the following process.

  1. Divide the playing cards into \"ordered\" and \"unordered\" sections, assuming initially the leftmost card is already in order.
  2. Take out a card from the unordered section and insert it into the correct position in the ordered section; after this, the leftmost two cards are in order.
  3. Continue to repeat step 2. until all cards are in order.

Figure 1-2 \u00a0 Playing Cards Sorting Process

The above method of organizing playing cards is essentially the \"Insertion Sort\" algorithm, which is very efficient for small datasets. Many programming languages' sorting functions include the insertion sort.

Example 3: Making Change. Suppose we buy goods worth \\(69\\) yuan at a supermarket and give the cashier \\(100\\) yuan, then the cashier needs to give us \\(31\\) yuan in change. They would naturally complete the thought process as shown below.

  1. The options are currencies smaller than \\(31\\), including \\(1\\), \\(5\\), \\(10\\), and \\(20\\).
  2. Take out the largest \\(20\\) from the options, leaving \\(31 - 20 = 11\\).
  3. Take out the largest \\(10\\) from the remaining options, leaving \\(11 - 10 = 1\\).
  4. Take out the largest \\(1\\) from the remaining options, leaving \\(1 - 1 = 0\\).
  5. Complete the change-making, with the solution being \\(20 + 10 + 1 = 31\\).

Figure 1-3 \u00a0 Change making process

In the above steps, we make the best choice at each step (using the largest denomination possible), ultimately resulting in a feasible change-making plan. From the perspective of data structures and algorithms, this method is essentially a \"Greedy\" algorithm.

From cooking a meal to interstellar travel, almost all problem-solving involves algorithms. The advent of computers allows us to store data structures in memory and write code to call the CPU and GPU to execute algorithms. In this way, we can transfer real-life problems to computers, solving various complex issues more efficiently.

Tip

If concepts such as data structures, algorithms, arrays, and binary search still seem somewhat obsecure, I encourage you to continue reading. This book will gently guide you into the realm of understanding data structures and algorithms.

"},{"location":"chapter_introduction/summary/","title":"1.3 \u00a0 Summary","text":"
  • Algorithms are ubiquitous in daily life and are not as inaccessible and complex as they might seem. In fact, we have already unconsciously learned many algorithms to solve various problems in life.
  • The principle of looking up a word in a dictionary is consistent with the binary search algorithm. The binary search algorithm embodies the important algorithmic concept of divide and conquer.
  • The process of organizing playing cards is very similar to the insertion sort algorithm. The insertion sort algorithm is suitable for sorting small datasets.
  • The steps of making change in currency essentially follow the greedy algorithm, where each step involves making the best possible choice at the moment.
  • An algorithm is a set of instructions or steps used to solve a specific problem within a finite amount of time, while a data structure is the way data is organized and stored in a computer.
  • Data structures and algorithms are closely linked. Data structures are the foundation of algorithms, and algorithms are the stage to utilize the functions of data structures.
  • We can liken data structures and algorithms to building blocks. The blocks represent data, the shape and connection method of the blocks represent data structures, and the steps of assembling the blocks correspond to algorithms.
"},{"location":"chapter_introduction/what_is_dsa/","title":"1.2 \u00a0 What is an Algorithm","text":""},{"location":"chapter_introduction/what_is_dsa/#121-definition-of-an-algorithm","title":"1.2.1 \u00a0 Definition of an Algorithm","text":"

An \"algorithm\" is a set of instructions or steps to solve a specific problem within a finite amount of time. It has the following characteristics:

  • The problem is clearly defined, including unambiguous definitions of input and output.
  • The algorithm is feasible, meaning it can be completed within a finite number of steps, time, and memory space.
  • Each step has a definitive meaning. The output is consistently the same under the same inputs and conditions.
"},{"location":"chapter_introduction/what_is_dsa/#122-definition-of-a-data-structure","title":"1.2.2 \u00a0 Definition of a Data Structure","text":"

A \"data structure\" is a way of organizing and storing data in a computer, with the following design goals:

  • Minimize space occupancy to save computer memory.
  • Make data operations as fast as possible, covering data access, addition, deletion, updating, etc.
  • Provide concise data representation and logical information to enable efficient algorithm execution.

Designing data structures is a balancing act, often requiring trade-offs. If you want to improve in one aspect, you often need to compromise in another. Here are two examples:

  • Compared to arrays, linked lists offer more convenience in data addition and deletion but sacrifice data access speed.
  • Graphs, compared to linked lists, provide richer logical information but require more memory space.
"},{"location":"chapter_introduction/what_is_dsa/#123-relationship-between-data-structures-and-algorithms","title":"1.2.3 \u00a0 Relationship Between Data Structures and Algorithms","text":"

As shown in the Figure 1-4 , data structures and algorithms are highly related and closely integrated, specifically in the following three aspects:

  • Data structures are the foundation of algorithms. They provide structured data storage and methods for manipulating data for algorithms.
  • Algorithms are the stage where data structures come into play. The data structure alone only stores data information; it is through the application of algorithms that specific problems can be solved.
  • Algorithms can often be implemented based on different data structures, but their execution efficiency can vary greatly. Choosing the right data structure is key.

Figure 1-4 \u00a0 Relationship between data structures and algorithms

Data structures and algorithms can be likened to a set of building blocks, as illustrated in the Figure 1-5 . A building block set includes numerous pieces, accompanied by detailed assembly instructions. Following these instructions step by step allows us to construct an intricate block model.

Figure 1-5 \u00a0 Assembling blocks

The detailed correspondence between the two is shown in the Table 1-1 .

Table 1-1 \u00a0 Comparing Data Structures and Algorithms to Building Blocks

Data Structures and Algorithms Building Blocks Input data Unassembled blocks Data structure Organization of blocks, including shape, size, connections, etc Algorithm A series of steps to assemble the blocks into the desired shape Output data Completed Block model

It's worth noting that data structures and algorithms are independent of programming languages. For this reason, this book is able to provide implementations in multiple programming languages.

Conventional Abbreviation

In real-life discussions, we often refer to \"Data Structures and Algorithms\" simply as \"Algorithms\". For example, the well-known LeetCode algorithm problems actually test both data structure and algorithm knowledge.

"},{"location":"chapter_preface/","title":"Chapter 0. \u00a0 Preface","text":"

Abstract

Algorithms are like a beautiful symphony, with each line of code flowing like a rhythm.

May this book ring softly in your mind, leaving a unique and profound melody.

"},{"location":"chapter_preface/#chapter-contents","title":"Chapter Contents","text":"
  • 0.1 \u00a0 About This Book
  • 0.2 \u00a0 How to Read
  • 0.3 \u00a0 Summary
"},{"location":"chapter_preface/about_the_book/","title":"0.1 \u00a0 About This Book","text":"

This open-source project aims to create a free, and beginner-friendly crash course on data structures and algorithms.

  • Using animated illustrations, it delivers structured insights into data structures and algorithmic concepts, ensuring comprehensibility and a smooth learning curve.
  • Run code with just one click, supporting Java, C++, Python, Go, JS, TS, C#, Swift, Rust, Dart, Zig and other languages.
  • Readers are encouraged to engage with each other in the discussion area for each section, questions and comments are usually answered within two days.
"},{"location":"chapter_preface/about_the_book/#011-target-audience","title":"0.1.1 \u00a0 Target Audience","text":"

If you are new to algorithms with limited exposure, or you have accumulated some experience in algorithms, but you only have a vague understanding of data structures and algorithms, and you are constantly jumping between \"yep\" and \"hmm\", then this book is for you!

If you have already accumulated a certain amount of problem-solving experience, and are familiar with most types of problems, then this book can help you review and organize your algorithm knowledge system. The repository's source code can be used as a \"problem-solving toolkit\" or an \"algorithm cheat sheet\".

If you are an algorithm expert, we look forward to receiving your valuable suggestions, or join us and collaborate.

Prerequisites

You should know how to write and read simple code in at least one programming language.

"},{"location":"chapter_preface/about_the_book/#012-content-structure","title":"0.1.2 \u00a0 Content Structure","text":"

The main content of the book is shown in the following figure.

  • Complexity Analysis: explores aspects and methods for evaluating data structures and algorithms. Covers methods of deriving time complexity and space complexity, along with common types and examples.
  • Data Structures: focuses on fundamental data types, classification methods, definitions, pros and cons, common operations, types, applications, and implementation methods of data structures such as array, linked list, stack, queue, hash table, tree, heap, graph, etc.
  • Algorithms: defines algorithms, discusses their pros and cons, efficiency, application scenarios, problem-solving steps, and includes sample questions for various algorithms such as search, sorting, divide and conquer, backtracking, dynamic programming, greedy algorithms, and more.

Figure 0-1 \u00a0 Main Content of the Book

"},{"location":"chapter_preface/about_the_book/#013-acknowledgements","title":"0.1.3 \u00a0 Acknowledgements","text":"

This book is continuously improved with the joint efforts of many contributors from the open-source community. Thanks to each writer who invested their time and energy, listed in the order generated by GitHub: krahets, codingonion, nuomi1, Gonglja, Reanon, justin-tse, danielsss, hpstory, S-N-O-R-L-A-X, night-cruise, msk397, gvenusleo, RiverTwilight, gyt95, zhuoqinyue, Zuoxun, Xia-Sang, mingXta, FangYuan33, GN-Yu, IsChristina, xBLACKICEx, guowei-gong, Cathay-Chen, mgisr, JoseHung, qualifier1024, pengchzn, Guanngxu, longsizhuo, L-Super, what-is-me, yuan0221, lhxsm, Slone123c, WSL0809, longranger2, theNefelibatas, xiongsp, JeffersonHuang, hongyun-robot, K3v123, yuelinxin, a16su, gaofer, malone6, Wonderdch, xjr7670, DullSword, Horbin-Magician, NI-SW, reeswell, XC-Zero, XiaChuerwu, yd-j, iron-irax, huawuque404, MolDuM, Nigh, KorsChen, foursevenlove, 52coder, bubble9um, youshaoXG, curly210102, gltianwen, fanchenggang, Transmigration-zhou, FloranceYeh, FreddieLi, ShiMaRing, lipusheng, Javesun99, JackYang-hellobobo, shanghai-Jerry, 0130w, Keynman, psychelzh, logan-qiu, ZnYang2018, MwumLi, 1ch0, Phoenix0415, qingpeng9802, Richard-Zhang1019, QiLOL, Suremotoo, Turing-1024-Lee, Evilrabbit520, GaochaoZhu, ZJKung, linzeyan, hezhizhen, ZongYangL, beintentional, czruby, coderlef, dshlstarr, szu17dmy, fbigm, gledfish, hts0000, boloboloda, iStig, jiaxianhua, wenjianmin, keshida, kilikilikid, lclc6, lwbaptx, liuxjerry, lucaswangdev, lyl625760, chadyi, noobcodemaker, selear, siqyka, syd168, 4yDX3906, tao363, wangwang105, weibk, yabo083, yi427, yishangzhang, zhouLion, baagod, ElaBosak233, xb534, luluxia, yanedie, thomasq0, YangXuanyi and th1nk3r-ing.

The code review work for this book was completed by codingonion, Gonglja, gvenusleo, hpstory, justin\u2010tse, krahets, night-cruise, nuomi1, and Reanon (listed in alphabetical order). Thanks to them for their time and effort, ensuring the standardization and uniformity of the code in various languages.

Throughout the creation of this book, numerous individuals provided invaluable assistance, including but not limited to:

  • Thanks to my mentor at the company, Dr. Xi Li, who encouraged me in a conversation to \"get moving fast,\" which solidified my determination to write this book;
  • Thanks to my girlfriend Bubble, as the first reader of this book, for offering many valuable suggestions from the perspective of a beginner in algorithms, making this book more suitable for newbies;
  • Thanks to Tengbao, Qibao, and Feibao for coming up with a creative name for this book, evoking everyone's fond memories of writing their first line of code \"Hello World!\";
  • Thanks to Xiaoquan for providing professional help in intellectual property, which has played a significant role in the development of this open-source book;
  • Thanks to Sutong for designing a beautiful cover and logo for this book, and for patiently making multiple revisions under my insistence;
  • Thanks to @squidfunk for providing writing and typesetting suggestions, as well as his developed open-source documentation theme Material-for-MkDocs.

Throughout the writing journey, I delved into numerous textbooks and articles on data structures and algorithms. These works served as exemplary models, ensuring the accuracy and quality of this book's content. I extend my gratitude to all who preceded me for their invaluable contributions!

This book advocates a combination of hands-on and minds-on learning, inspired in this regard by \"Dive into Deep Learning\". I highly recommend this excellent book to all readers.

Heartfelt thanks to my parents, whose ongoing support and encouragement have allowed me to do this interesting work.

"},{"location":"chapter_preface/suggestions/","title":"0.2 \u00a0 How to Read","text":"

Tip

For the best reading experience, it is recommended that you read through this section.

"},{"location":"chapter_preface/suggestions/#021-writing-conventions","title":"0.2.1 \u00a0 Writing Conventions","text":"
  • Chapters marked with '*' after the title are optional and contain relatively challenging content. If you are short on time, it is advisable to skip them.
  • Key technical terms and their English equivalents are enclosed in Bold + italics brackets, for example, array. It's advisable to familiarize yourself with these for better comprehension of technical texts.
  • Proprietary terms and words with specific meanings are indicated with \u201cquotation marks\u201d to avoid ambiguity.
  • Bolded text indicates key content or summary statements, which deserve special attention.
  • When it comes to terms that are inconsistent between programming languages, this book follows Python, for example using \\(\\text{None}\\) to mean \"null\".
  • This book partially ignores the comment conventions for programming languages in exchange for a more compact layout of the content. The comments primarily consist of three types: title comments, content comments, and multi-line comments.
PythonC++JavaC#GoSwiftJSTSDartRustCZig
\"\"\"Header comments for labeling functions, classes, test samples, etc\"\"\"\"\n\n# Comments for explaining details\n\n\"\"\"\nMultiline\ncomments\n\"\"\"\n
/* Header comments for labeling functions, classes, test samples, etc */\n\n// Comments for explaining details.\n\n/**\n * Multiline\n * comments\n */\n
/* Header comments for labeling functions, classes, test samples, etc */\n\n// Comments for explaining details.\n\n/**\n * Multiline\n * comments\n */\n
/* Header comments for labeling functions, classes, test samples, etc */\n\n// Comments for explaining details.\n\n/**\n * Multiline\n * comments\n */\n
/* Header comments for labeling functions, classes, test samples, etc */\n\n// Comments for explaining details.\n\n/**\n * Multiline\n * comments\n */\n
/* Header comments for labeling functions, classes, test samples, etc */\n\n// Comments for explaining details.\n\n/**\n * Multiline\n * comments\n */\n
/* Header comments for labeling functions, classes, test samples, etc */\n\n// Comments for explaining details.\n\n/**\n * Multiline\n * comments\n */\n
/* Header comments for labeling functions, classes, test samples, etc */\n\n// Comments for explaining details.\n\n/**\n * Multiline\n * comments\n */\n
/* Header comments for labeling functions, classes, test samples, etc */\n\n// Comments for explaining details.\n\n/**\n * Multiline\n * comments\n */\n
/* Header comments for labeling functions, classes, test samples, etc */\n\n// Comments for explaining details.\n\n/**\n * Multiline\n * comments\n */\n
/* Header comments for labeling functions, classes, test samples, etc */\n\n// Comments for explaining details.\n\n/**\n * Multiline\n * comments\n */\n
// Header comments for labeling functions, classes, test samples, etc\n\n// Comments for explaining details.\n\n// Multiline\n// comments\n
"},{"location":"chapter_preface/suggestions/#022-efficient-learning-via-animated-illustrations","title":"0.2.2 \u00a0 Efficient Learning via Animated Illustrations","text":"

Compared with text, videos and pictures have a higher density of information and are more structured, making them easier to understand. In this book, key and difficult concepts are mainly presented through animations and illustrations, with text serving as explanations and supplements.

When encountering content with animations or illustrations as shown in the Figure 0-2 , prioritize understanding the figure, with text as supplementary, integrating both for a comprehensive understanding.

Figure 0-2 \u00a0 Animated Illustration Example

"},{"location":"chapter_preface/suggestions/#023-deepen-understanding-through-coding-practice","title":"0.2.3 \u00a0 Deepen Understanding through Coding Practice","text":"

The source code of this book is hosted on the GitHub Repository. As shown in the Figure 0-3 , the source code comes with test examples and can be executed with just a single click.

If time permits, it's recommended to type out the code yourself. If pressed for time, at least read and run all the codes.

Compared to just reading code, writing code often yields more learning. Learning by doing is the real way to learn.

Figure 0-3 \u00a0 Running Code Example

Setting up to run the code involves three main steps.

Step 1: Install a local programming environment. Follow the tutorial in the appendix for installation, or skip this step if already installed.

Step 2: Clone or download the code repository. Visit the GitHub Repository.

If Git is installed, use the following command to clone the repository:

git clone https://github.com/krahets/hello-algo.git\n

Alternatively, you can also click the \"Download ZIP\" button at the location shown in the Figure 0-4 to directly download the code as a compressed ZIP file. Then, you can simply extract it locally.

Figure 0-4 \u00a0 Cloning Repository and Downloading Code

Step 3: Run the source code. As shown in the Figure 0-5 , for the code block labeled with the file name at the top, we can find the corresponding source code file in the codes folder of the repository. These files can be executed with a single click, which will help you save unnecessary debugging time and allow you to focus on learning.

Figure 0-5 \u00a0 Code Block and Corresponding Source Code File

"},{"location":"chapter_preface/suggestions/#024-learning-together-in-discussion","title":"0.2.4 \u00a0 Learning Together in Discussion","text":"

While reading this book, please don't skip over the points that you didn't learn. Feel free to post your questions in the comment section. We will be happy to answer them and can usually respond within two days.

As illustrated in the Figure 0-6 , each chapter features a comment section at the bottom. I encourage you to pay attention to these comments. They not only expose you to others' encountered problems, aiding in identifying knowledge gaps and sparking deeper contemplation, but also invite you to generously contribute by answering fellow readers' inquiries, sharing insights, and fostering mutual improvement.

Figure 0-6 \u00a0 Comment Section Example

"},{"location":"chapter_preface/suggestions/#025-algorithm-learning-path","title":"0.2.5 \u00a0 Algorithm Learning Path","text":"

Overall, the journey of mastering data structures and algorithms can be divided into three stages:

  1. Stage 1: Introduction to algorithms. We need to familiarize ourselves with the characteristics and usage of various data structures and learn about the principles, processes, uses, and efficiency of different algorithms.
  2. Stage 2: Practicing algorithm problems. It is recommended to start from popular problems, such as Sword for Offer and LeetCode Hot 100, and accumulate at least 100 questions to familiarize yourself with mainstream algorithmic problems. Forgetfulness can be a challenge when you start practicing, but rest assured that this is normal. We can follow the \"Ebbinghaus Forgetting Curve\" to review the questions, and usually after 3~5 rounds of repetitions, we will be able to memorize them.
  3. Stage 3: Building the knowledge system. In terms of learning, we can read algorithm column articles, solution frameworks, and algorithm textbooks to continuously enrich the knowledge system. In terms of practicing, we can try advanced strategies, such as categorizing by topic, multiple solutions for a single problem, and one solution for multiple problems, etc. Insights on these strategies can be found in various communities.

As shown in the Figure 0-7 , this book mainly covers \u201cStage 1,\u201d aiming to help you more efficiently embark on Stages 2 and 3.

Figure 0-7 \u00a0 Algorithm Learning Path

"},{"location":"chapter_preface/summary/","title":"0.3 \u00a0 Summary","text":"
  • The main audience of this book is beginners in algorithm. If you already have some basic knowledge, this book can help you systematically review your algorithm knowledge, and the source code in this book can also be used as a \"Coding Toolkit\".
  • The book consists of three main sections, Complexity Analysis, Data Structures, and Algorithms, covering most of the topics in the field.
  • For newcomers to algorithms, it is crucial to read an introductory book in the beginning stages to avoid many detours or common pitfalls.
  • Animations and figures within the book are usually used to introduce key points and difficult knowledge. These should be given more attention when reading the book.
  • Practice is the best way to learn programming. It is highly recommended that you run the source code and type in the code yourself.
  • Each chapter in the web version of this book features a discussion section, and you are welcome to share your questions and insights at any time.
"},{"location":"chapter_stack_and_queue/","title":"Chapter 5. \u00a0 Stack and Queue","text":"

Abstract

A stack is like cats placed on top of each other, while a queue is like cats lined up one by one.

They represent the logical relationships of Last-In-First-Out (LIFO) and First-In-First-Out (FIFO), respectively.

"},{"location":"chapter_stack_and_queue/#chapter-contents","title":"Chapter Contents","text":"
  • 5.1 \u00a0 Stack
  • 5.2 \u00a0 Queue
  • 5.3 \u00a0 Double-ended Queue
  • 5.4 \u00a0 Summary
"},{"location":"chapter_stack_and_queue/deque/","title":"5.3 \u00a0 Double-Ended Queue","text":"

In a queue, we can only delete elements from the head or add elements to the tail. As shown in the following diagram, a \"double-ended queue (deque)\" offers more flexibility, allowing the addition or removal of elements at both the head and the tail.

Figure 5-7 \u00a0 Operations in Double-Ended Queue

"},{"location":"chapter_stack_and_queue/deque/#531-common-operations-in-double-ended-queue","title":"5.3.1 \u00a0 Common Operations in Double-Ended Queue","text":"

The common operations in a double-ended queue are listed below, and the names of specific methods depend on the programming language used.

Table 5-3 \u00a0 Efficiency of Double-Ended Queue Operations

Method Name Description Time Complexity pushFirst() Add an element to the head \\(O(1)\\) pushLast() Add an element to the tail \\(O(1)\\) popFirst() Remove the first element \\(O(1)\\) popLast() Remove the last element \\(O(1)\\) peekFirst() Access the first element \\(O(1)\\) peekLast() Access the last element \\(O(1)\\)

Similarly, we can directly use the double-ended queue classes implemented in programming languages:

PythonC++JavaC#GoSwiftJSTSDartRustCZig deque.py
from collections import deque\n\n# Initialize the deque\ndeque: deque[int] = deque()\n\n# Enqueue elements\ndeque.append(2)      # Add to the tail\ndeque.append(5)\ndeque.append(4)\ndeque.appendleft(3)  # Add to the head\ndeque.appendleft(1)\n\n# Access elements\nfront: int = deque[0]  # The first element\nrear: int = deque[-1]  # The last element\n\n# Dequeue elements\npop_front: int = deque.popleft()  # The first element dequeued\npop_rear: int = deque.pop()       # The last element dequeued\n\n# Get the length of the deque\nsize: int = len(deque)\n\n# Check if the deque is empty\nis_empty: bool = len(deque) == 0\n
deque.cpp
/* Initialize the deque */\ndeque<int> deque;\n\n/* Enqueue elements */\ndeque.push_back(2);   // Add to the tail\ndeque.push_back(5);\ndeque.push_back(4);\ndeque.push_front(3);  // Add to the head\ndeque.push_front(1);\n\n/* Access elements */\nint front = deque.front(); // The first element\nint back = deque.back();   // The last element\n\n/* Dequeue elements */\ndeque.pop_front();  // The first element dequeued\ndeque.pop_back();   // The last element dequeued\n\n/* Get the length of the deque */\nint size = deque.size();\n\n/* Check if the deque is empty */\nbool empty = deque.empty();\n
deque.java
/* Initialize the deque */\nDeque<Integer> deque = new LinkedList<>();\n\n/* Enqueue elements */\ndeque.offerLast(2);   // Add to the tail\ndeque.offerLast(5);\ndeque.offerLast(4);\ndeque.offerFirst(3);  // Add to the head\ndeque.offerFirst(1);\n\n/* Access elements */\nint peekFirst = deque.peekFirst();  // The first element\nint peekLast = deque.peekLast();    // The last element\n\n/* Dequeue elements */\nint popFirst = deque.pollFirst();  // The first element dequeued\nint popLast = deque.pollLast();    // The last element dequeued\n\n/* Get the length of the deque */\nint size = deque.size();\n\n/* Check if the deque is empty */\nboolean isEmpty = deque.isEmpty();\n
deque.cs
/* Initialize the deque */\n// In C#, LinkedList is used as a deque\nLinkedList<int> deque = new();\n\n/* Enqueue elements */\ndeque.AddLast(2);   // Add to the tail\ndeque.AddLast(5);\ndeque.AddLast(4);\ndeque.AddFirst(3);  // Add to the head\ndeque.AddFirst(1);\n\n/* Access elements */\nint peekFirst = deque.First.Value;  // The first element\nint peekLast = deque.Last.Value;    // The last element\n\n/* Dequeue elements */\ndeque.RemoveFirst();  // The first element dequeued\ndeque.RemoveLast();   // The last element dequeued\n\n/* Get the length of the deque */\nint size = deque.Count;\n\n/* Check if the deque is empty */\nbool isEmpty = deque.Count == 0;\n
deque_test.go
/* Initialize the deque */\n// In Go, use list as a deque\ndeque := list.New()\n\n/* Enqueue elements */\ndeque.PushBack(2)      // Add to the tail\ndeque.PushBack(5)\ndeque.PushBack(4)\ndeque.PushFront(3)     // Add to the head\ndeque.PushFront(1)\n\n/* Access elements */\nfront := deque.Front() // The first element\nrear := deque.Back()   // The last element\n\n/* Dequeue elements */\ndeque.Remove(front)    // The first element dequeued\ndeque.Remove(rear)     // The last element dequeued\n\n/* Get the length of the deque */\nsize := deque.Len()\n\n/* Check if the deque is empty */\nisEmpty := deque.Len() == 0\n
deque.swift
/* Initialize the deque */\n// Swift does not have a built-in deque class, so Array can be used as a deque\nvar deque: [Int] = []\n\n/* Enqueue elements */\ndeque.append(2) // Add to the tail\ndeque.append(5)\ndeque.append(4)\ndeque.insert(3, at: 0) // Add to the head\ndeque.insert(1, at: 0)\n\n/* Access elements */\nlet peekFirst = deque.first! // The first element\nlet peekLast = deque.last!   // The last element\n\n/* Dequeue elements */\n// Using Array, popFirst has a complexity of O(n)\nlet popFirst = deque.removeFirst() // The first element dequeued\nlet popLast = deque.removeLast()   // The last element dequeued\n\n/* Get the length of the deque */\nlet size = deque.count\n\n/* Check if the deque is empty */\nlet isEmpty = deque.isEmpty\n
deque.js
/* Initialize the deque */\n// JavaScript does not have a built-in deque, so Array is used as a deque\nconst deque = [];\n\n/* Enqueue elements */\ndeque.push(2);\ndeque.push(5);\ndeque.push(4);\n// Note that unshift() has a time complexity of O(n) as it's an array\ndeque.unshift(3);\ndeque.unshift(1);\n\n/* Access elements */\nconst peekFirst = deque[0]; // The first element\nconst peekLast = deque[deque.length - 1]; // The last element\n\n/* Dequeue elements */\n// Note that shift() has a time complexity of O(n) as it's an array\nconst popFront = deque.shift(); // The first element dequeued\nconst popBack = deque.pop();    // The last element dequeued\n\n/* Get the length of the deque */\nconst size = deque.length;\n\n/* Check if the deque is empty */\nconst isEmpty = size === 0;\n
deque.ts
/* Initialize the deque */\n// TypeScript does not have a built-in deque, so Array is used as a deque\nconst deque: number[] = [];\n\n/* Enqueue elements */\ndeque.push(2);\ndeque.push(5);\ndeque.push(4);\n// Note that unshift() has a time complexity of O(n) as it's an array\ndeque.unshift(3);\ndeque.unshift(1);\n\n/* Access elements */\nconst peekFirst: number = deque[0]; // The first element\nconst peekLast: number = deque[deque.length - 1]; // The last element\n\n/* Dequeue elements */\n// Note that shift() has a time complexity of O(n) as it's an array\nconst popFront: number = deque.shift() as number; // The first element dequeued\nconst popBack: number = deque.pop() as number;    // The last element dequeued\n\n/* Get the length of the deque */\nconst size: number = deque.length;\n\n/* Check if the deque is empty */\nconst isEmpty: boolean = size === 0;\n
deque.dart
/* Initialize the deque */\n// In Dart, Queue is defined as a deque\nQueue<int> deque = Queue<int>();\n\n/* Enqueue elements */\ndeque.addLast(2);  // Add to the tail\ndeque.addLast(5);\ndeque.addLast(4);\ndeque.addFirst(3); // Add to the head\ndeque.addFirst(1);\n\n/* Access elements */\nint peekFirst = deque.first; // The first element\nint peekLast = deque.last;   // The last element\n\n/* Dequeue elements */\nint popFirst = deque.removeFirst(); // The first element dequeued\nint popLast = deque.removeLast();   // The last element dequeued\n\n/* Get the length of the deque */\nint size = deque.length;\n\n/* Check if the deque is empty */\nbool isEmpty = deque.isEmpty;\n
deque.rs
/* Initialize the deque */\nlet mut deque: VecDeque<u32> = VecDeque::new();\n\n/* Enqueue elements */\ndeque.push_back(2);  // Add to the tail\ndeque.push_back(5);\ndeque.push_back(4);\ndeque.push_front(3); // Add to the head\ndeque.push_front(1);\n\n/* Access elements */\nif let Some(front) = deque.front() { // The first element\n}\nif let Some(rear) = deque.back() {   // The last element\n}\n\n/* Dequeue elements */\nif let Some(pop_front) = deque.pop_front() { // The first element dequeued\n}\nif let Some(pop_rear) = deque.pop_back() {   // The last element dequeued\n}\n\n/* Get the length of the deque */\nlet size = deque.len();\n\n/* Check if the deque is empty */\nlet is_empty = deque.is_empty();\n
deque.c
// C does not provide a built-in deque\n
deque.zig
\n
Visualizing Code

https://pythontutor.com/render.html#code=from%20collections%20import%20deque%0A%0A%22%22%22Driver%20Code%22%22%22%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%20%20%23%20%E5%88%9D%E5%A7%8B%E5%8C%96%E5%8F%8C%E5%90%91%E9%98%9F%E5%88%97%0A%20%20%20%20deq%20%3D%20deque%28%29%0A%0A%20%20%20%20%23%20%E5%85%83%E7%B4%A0%E5%85%A5%E9%98%9F%0A%20%20%20%20deq.append%282%29%20%20%23%20%E6%B7%BB%E5%8A%A0%E8%87%B3%E9%98%9F%E5%B0%BE%0A%20%20%20%20deq.append%285%29%0A%20%20%20%20deq.append%284%29%0A%20%20%20%20deq.appendleft%283%29%20%20%23%20%E6%B7%BB%E5%8A%A0%E8%87%B3%E9%98%9F%E9%A6%96%0A%20%20%20%20deq.appendleft%281%29%0A%20%20%20%20print%28%22%E5%8F%8C%E5%90%91%E9%98%9F%E5%88%97%20deque%20%3D%22,%20deq%29%0A%0A%20%20%20%20%23%20%E8%AE%BF%E9%97%AE%E5%85%83%E7%B4%A0%0A%20%20%20%20front%20%3D%20deq%5B0%5D%20%20%23%20%E9%98%9F%E9%A6%96%E5%85%83%E7%B4%A0%0A%20%20%20%20print%28%22%E9%98%9F%E9%A6%96%E5%85%83%E7%B4%A0%20front%20%3D%22,%20front%29%0A%20%20%20%20rear%20%3D%20deq%5B-1%5D%20%20%23%20%E9%98%9F%E5%B0%BE%E5%85%83%E7%B4%A0%0A%20%20%20%20print%28%22%E9%98%9F%E5%B0%BE%E5%85%83%E7%B4%A0%20rear%20%3D%22,%20rear%29%0A%0A%20%20%20%20%23%20%E5%85%83%E7%B4%A0%E5%87%BA%E9%98%9F%0A%20%20%20%20pop_front%20%3D%20deq.popleft%28%29%20%20%23%20%E9%98%9F%E9%A6%96%E5%85%83%E7%B4%A0%E5%87%BA%E9%98%9F%0A%20%20%20%20print%28%22%E9%98%9F%E9%A6%96%E5%87%BA%E9%98%9F%E5%85%83%E7%B4%A0%20%20pop_front%20%3D%22,%20pop_front%29%0A%20%20%20%20print%28%22%E9%98%9F%E9%A6%96%E5%87%BA%E9%98%9F%E5%90%8E%20deque%20%3D%22,%20deq%29%0A%20%20%20%20pop_rear%20%3D%20deq.pop%28%29%20%20%23%20%E9%98%9F%E5%B0%BE%E5%85%83%E7%B4%A0%E5%87%BA%E9%98%9F%0A%20%20%20%20print%28%22%E9%98%9F%E5%B0%BE%E5%87%BA%E9%98%9F%E5%85%83%E7%B4%A0%20%20pop_rear%20%3D%22,%20pop_rear%29%0A%20%20%20%20print%28%22%E9%98%9F%E5%B0%BE%E5%87%BA%E9%98%9F%E5%90%8E%20deque%20%3D%22,%20deq%29%0A%0A%20%20%20%20%23%20%E8%8E%B7%E5%8F%96%E5%8F%8C%E5%90%91%E9%98%9F%E5%88%97%E7%9A%84%E9%95%BF%E5%BA%A6%0A%20%20%20%20size%20%3D%20len%28deq%29%0A%20%20%20%20print%28%22%E5%8F%8C%E5%90%91%E9%98%9F%E5%88%97%E9%95%BF%E5%BA%A6%20size%20%3D%22,%20size%29%0A%0A%20%20%20%20%23%20%E5%88%A4%E6%96%AD%E5%8F%8C%E5%90%91%E9%98%9F%E5%88%97%E6%98%AF%E5%90%A6%E4%B8%BA%E7%A9%BA%0A%20%20%20%20is_empty%20%3D%20len%28deq%29%20%3D%3D%200%0A%20%20%20%20print%28%22%E5%8F%8C%E5%90%91%E9%98%9F%E5%88%97%E6%98%AF%E5%90%A6%E4%B8%BA%E7%A9%BA%20%3D%22,%20is_empty%29&cumulative=false&curInstr=3&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=311&rawInputLstJSON=%5B%5D&textReferences=false

"},{"location":"chapter_stack_and_queue/deque/#532-implementing-a-double-ended-queue","title":"5.3.2 \u00a0 Implementing a Double-Ended Queue *","text":"

The implementation of a double-ended queue is similar to that of a regular queue, it can be based on either a linked list or an array as the underlying data structure.

"},{"location":"chapter_stack_and_queue/deque/#1-implementation-based-on-doubly-linked-list","title":"1. \u00a0 Implementation Based on Doubly Linked List","text":"

Recall from the previous section that we used a regular singly linked list to implement a queue, as it conveniently allows for deleting from the head (corresponding to the dequeue operation) and adding new elements after the tail (corresponding to the enqueue operation).

For a double-ended queue, both the head and the tail can perform enqueue and dequeue operations. In other words, a double-ended queue needs to implement operations in the opposite direction as well. For this, we use a \"doubly linked list\" as the underlying data structure of the double-ended queue.

As shown in the Figure 5-8 , we treat the head and tail nodes of the doubly linked list as the front and rear of the double-ended queue, respectively, and implement the functionality to add and remove nodes at both ends.

LinkedListDequepushLast()pushFirst()popLast()popFirst()

Figure 5-8 \u00a0 Implementing Double-Ended Queue with Doubly Linked List for Enqueue and Dequeue Operations

The implementation code is as follows:

PythonC++JavaC#GoSwiftJSTSDartRustCZig linkedlist_deque.py
class ListNode:\n    \"\"\"\u53cc\u5411\u94fe\u8868\u8282\u70b9\"\"\"\n\n    def __init__(self, val: int):\n        \"\"\"\u6784\u9020\u65b9\u6cd5\"\"\"\n        self.val: int = val\n        self.next: ListNode | None = None  # \u540e\u7ee7\u8282\u70b9\u5f15\u7528\n        self.prev: ListNode | None = None  # \u524d\u9a71\u8282\u70b9\u5f15\u7528\n\nclass LinkedListDeque:\n    \"\"\"\u57fa\u4e8e\u53cc\u5411\u94fe\u8868\u5b9e\u73b0\u7684\u53cc\u5411\u961f\u5217\"\"\"\n\n    def __init__(self):\n        \"\"\"\u6784\u9020\u65b9\u6cd5\"\"\"\n        self._front: ListNode | None = None  # \u5934\u8282\u70b9 front\n        self._rear: ListNode | None = None  # \u5c3e\u8282\u70b9 rear\n        self._size: int = 0  # \u53cc\u5411\u961f\u5217\u7684\u957f\u5ea6\n\n    def size(self) -> int:\n        \"\"\"\u83b7\u53d6\u53cc\u5411\u961f\u5217\u7684\u957f\u5ea6\"\"\"\n        return self._size\n\n    def is_empty(self) -> bool:\n        \"\"\"\u5224\u65ad\u53cc\u5411\u961f\u5217\u662f\u5426\u4e3a\u7a7a\"\"\"\n        return self.size() == 0\n\n    def push(self, num: int, is_front: bool):\n        \"\"\"\u5165\u961f\u64cd\u4f5c\"\"\"\n        node = ListNode(num)\n        # \u82e5\u94fe\u8868\u4e3a\u7a7a\uff0c\u5219\u4ee4 front \u548c rear \u90fd\u6307\u5411 node\n        if self.is_empty():\n            self._front = self._rear = node\n        # \u961f\u9996\u5165\u961f\u64cd\u4f5c\n        elif is_front:\n            # \u5c06 node \u6dfb\u52a0\u81f3\u94fe\u8868\u5934\u90e8\n            self._front.prev = node\n            node.next = self._front\n            self._front = node  # \u66f4\u65b0\u5934\u8282\u70b9\n        # \u961f\u5c3e\u5165\u961f\u64cd\u4f5c\n        else:\n            # \u5c06 node \u6dfb\u52a0\u81f3\u94fe\u8868\u5c3e\u90e8\n            self._rear.next = node\n            node.prev = self._rear\n            self._rear = node  # \u66f4\u65b0\u5c3e\u8282\u70b9\n        self._size += 1  # \u66f4\u65b0\u961f\u5217\u957f\u5ea6\n\n    def push_first(self, num: int):\n        \"\"\"\u961f\u9996\u5165\u961f\"\"\"\n        self.push(num, True)\n\n    def push_last(self, num: int):\n        \"\"\"\u961f\u5c3e\u5165\u961f\"\"\"\n        self.push(num, False)\n\n    def pop(self, is_front: bool) -> int:\n        \"\"\"\u51fa\u961f\u64cd\u4f5c\"\"\"\n        if self.is_empty():\n            raise IndexError(\"\u53cc\u5411\u961f\u5217\u4e3a\u7a7a\")\n        # \u961f\u9996\u51fa\u961f\u64cd\u4f5c\n        if is_front:\n            val: int = self._front.val  # \u6682\u5b58\u5934\u8282\u70b9\u503c\n            # \u5220\u9664\u5934\u8282\u70b9\n            fnext: ListNode | None = self._front.next\n            if fnext != None:\n                fnext.prev = None\n                self._front.next = None\n            self._front = fnext  # \u66f4\u65b0\u5934\u8282\u70b9\n        # \u961f\u5c3e\u51fa\u961f\u64cd\u4f5c\n        else:\n            val: int = self._rear.val  # \u6682\u5b58\u5c3e\u8282\u70b9\u503c\n            # \u5220\u9664\u5c3e\u8282\u70b9\n            rprev: ListNode | None = self._rear.prev\n            if rprev != None:\n                rprev.next = None\n                self._rear.prev = None\n            self._rear = rprev  # \u66f4\u65b0\u5c3e\u8282\u70b9\n        self._size -= 1  # \u66f4\u65b0\u961f\u5217\u957f\u5ea6\n        return val\n\n    def pop_first(self) -> int:\n        \"\"\"\u961f\u9996\u51fa\u961f\"\"\"\n        return self.pop(True)\n\n    def pop_last(self) -> int:\n        \"\"\"\u961f\u5c3e\u51fa\u961f\"\"\"\n        return self.pop(False)\n\n    def peek_first(self) -> int:\n        \"\"\"\u8bbf\u95ee\u961f\u9996\u5143\u7d20\"\"\"\n        if self.is_empty():\n            raise IndexError(\"\u53cc\u5411\u961f\u5217\u4e3a\u7a7a\")\n        return self._front.val\n\n    def peek_last(self) -> int:\n        \"\"\"\u8bbf\u95ee\u961f\u5c3e\u5143\u7d20\"\"\"\n        if self.is_empty():\n            raise IndexError(\"\u53cc\u5411\u961f\u5217\u4e3a\u7a7a\")\n        return self._rear.val\n\n    def to_array(self) -> list[int]:\n        \"\"\"\u8fd4\u56de\u6570\u7ec4\u7528\u4e8e\u6253\u5370\"\"\"\n        node = self._front\n        res = [0] * self.size()\n        for i in range(self.size()):\n            res[i] = node.val\n            node = node.next\n        return res\n
linkedlist_deque.cpp
/* \u53cc\u5411\u94fe\u8868\u8282\u70b9 */\nstruct DoublyListNode {\n    int val;              // \u8282\u70b9\u503c\n    DoublyListNode *next; // \u540e\u7ee7\u8282\u70b9\u6307\u9488\n    DoublyListNode *prev; // \u524d\u9a71\u8282\u70b9\u6307\u9488\n    DoublyListNode(int val) : val(val), prev(nullptr), next(nullptr) {\n    }\n};\n\n/* \u57fa\u4e8e\u53cc\u5411\u94fe\u8868\u5b9e\u73b0\u7684\u53cc\u5411\u961f\u5217 */\nclass LinkedListDeque {\n  private:\n    DoublyListNode *front, *rear; // \u5934\u8282\u70b9 front \uff0c\u5c3e\u8282\u70b9 rear\n    int queSize = 0;              // \u53cc\u5411\u961f\u5217\u7684\u957f\u5ea6\n\n  public:\n    /* \u6784\u9020\u65b9\u6cd5 */\n    LinkedListDeque() : front(nullptr), rear(nullptr) {\n    }\n\n    /* \u6790\u6784\u65b9\u6cd5 */\n    ~LinkedListDeque() {\n        // \u904d\u5386\u94fe\u8868\u5220\u9664\u8282\u70b9\uff0c\u91ca\u653e\u5185\u5b58\n        DoublyListNode *pre, *cur = front;\n        while (cur != nullptr) {\n            pre = cur;\n            cur = cur->next;\n            delete pre;\n        }\n    }\n\n    /* \u83b7\u53d6\u53cc\u5411\u961f\u5217\u7684\u957f\u5ea6 */\n    int size() {\n        return queSize;\n    }\n\n    /* \u5224\u65ad\u53cc\u5411\u961f\u5217\u662f\u5426\u4e3a\u7a7a */\n    bool isEmpty() {\n        return size() == 0;\n    }\n\n    /* \u5165\u961f\u64cd\u4f5c */\n    void push(int num, bool isFront) {\n        DoublyListNode *node = new DoublyListNode(num);\n        // \u82e5\u94fe\u8868\u4e3a\u7a7a\uff0c\u5219\u4ee4 front \u548c rear \u90fd\u6307\u5411 node\n        if (isEmpty())\n            front = rear = node;\n        // \u961f\u9996\u5165\u961f\u64cd\u4f5c\n        else if (isFront) {\n            // \u5c06 node \u6dfb\u52a0\u81f3\u94fe\u8868\u5934\u90e8\n            front->prev = node;\n            node->next = front;\n            front = node; // \u66f4\u65b0\u5934\u8282\u70b9\n        // \u961f\u5c3e\u5165\u961f\u64cd\u4f5c\n        } else {\n            // \u5c06 node \u6dfb\u52a0\u81f3\u94fe\u8868\u5c3e\u90e8\n            rear->next = node;\n            node->prev = rear;\n            rear = node; // \u66f4\u65b0\u5c3e\u8282\u70b9\n        }\n        queSize++; // \u66f4\u65b0\u961f\u5217\u957f\u5ea6\n    }\n\n    /* \u961f\u9996\u5165\u961f */\n    void pushFirst(int num) {\n        push(num, true);\n    }\n\n    /* \u961f\u5c3e\u5165\u961f */\n    void pushLast(int num) {\n        push(num, false);\n    }\n\n    /* \u51fa\u961f\u64cd\u4f5c */\n    int pop(bool isFront) {\n        if (isEmpty())\n            throw out_of_range(\"\u961f\u5217\u4e3a\u7a7a\");\n        int val;\n        // \u961f\u9996\u51fa\u961f\u64cd\u4f5c\n        if (isFront) {\n            val = front->val; // \u6682\u5b58\u5934\u8282\u70b9\u503c\n            // \u5220\u9664\u5934\u8282\u70b9\n            DoublyListNode *fNext = front->next;\n            if (fNext != nullptr) {\n                fNext->prev = nullptr;\n                front->next = nullptr;\n            }\n            delete front;\n            front = fNext; // \u66f4\u65b0\u5934\u8282\u70b9\n        // \u961f\u5c3e\u51fa\u961f\u64cd\u4f5c\n        } else {\n            val = rear->val; // \u6682\u5b58\u5c3e\u8282\u70b9\u503c\n            // \u5220\u9664\u5c3e\u8282\u70b9\n            DoublyListNode *rPrev = rear->prev;\n            if (rPrev != nullptr) {\n                rPrev->next = nullptr;\n                rear->prev = nullptr;\n            }\n            delete rear;\n            rear = rPrev; // \u66f4\u65b0\u5c3e\u8282\u70b9\n        }\n        queSize--; // \u66f4\u65b0\u961f\u5217\u957f\u5ea6\n        return val;\n    }\n\n    /* \u961f\u9996\u51fa\u961f */\n    int popFirst() {\n        return pop(true);\n    }\n\n    /* \u961f\u5c3e\u51fa\u961f */\n    int popLast() {\n        return pop(false);\n    }\n\n    /* \u8bbf\u95ee\u961f\u9996\u5143\u7d20 */\n    int peekFirst() {\n        if (isEmpty())\n            throw out_of_range(\"\u53cc\u5411\u961f\u5217\u4e3a\u7a7a\");\n        return front->val;\n    }\n\n    /* \u8bbf\u95ee\u961f\u5c3e\u5143\u7d20 */\n    int peekLast() {\n        if (isEmpty())\n            throw out_of_range(\"\u53cc\u5411\u961f\u5217\u4e3a\u7a7a\");\n        return rear->val;\n    }\n\n    /* \u8fd4\u56de\u6570\u7ec4\u7528\u4e8e\u6253\u5370 */\n    vector<int> toVector() {\n        DoublyListNode *node = front;\n        vector<int> res(size());\n        for (int i = 0; i < res.size(); i++) {\n            res[i] = node->val;\n            node = node->next;\n        }\n        return res;\n    }\n};\n
linkedlist_deque.java
/* \u53cc\u5411\u94fe\u8868\u8282\u70b9 */\nclass ListNode {\n    int val; // \u8282\u70b9\u503c\n    ListNode next; // \u540e\u7ee7\u8282\u70b9\u5f15\u7528\n    ListNode prev; // \u524d\u9a71\u8282\u70b9\u5f15\u7528\n\n    ListNode(int val) {\n        this.val = val;\n        prev = next = null;\n    }\n}\n\n/* \u57fa\u4e8e\u53cc\u5411\u94fe\u8868\u5b9e\u73b0\u7684\u53cc\u5411\u961f\u5217 */\nclass LinkedListDeque {\n    private ListNode front, rear; // \u5934\u8282\u70b9 front \uff0c\u5c3e\u8282\u70b9 rear\n    private int queSize = 0; // \u53cc\u5411\u961f\u5217\u7684\u957f\u5ea6\n\n    public LinkedListDeque() {\n        front = rear = null;\n    }\n\n    /* \u83b7\u53d6\u53cc\u5411\u961f\u5217\u7684\u957f\u5ea6 */\n    public int size() {\n        return queSize;\n    }\n\n    /* \u5224\u65ad\u53cc\u5411\u961f\u5217\u662f\u5426\u4e3a\u7a7a */\n    public boolean isEmpty() {\n        return size() == 0;\n    }\n\n    /* \u5165\u961f\u64cd\u4f5c */\n    private void push(int num, boolean isFront) {\n        ListNode node = new ListNode(num);\n        // \u82e5\u94fe\u8868\u4e3a\u7a7a\uff0c\u5219\u4ee4 front \u548c rear \u90fd\u6307\u5411 node\n        if (isEmpty())\n            front = rear = node;\n        // \u961f\u9996\u5165\u961f\u64cd\u4f5c\n        else if (isFront) {\n            // \u5c06 node \u6dfb\u52a0\u81f3\u94fe\u8868\u5934\u90e8\n            front.prev = node;\n            node.next = front;\n            front = node; // \u66f4\u65b0\u5934\u8282\u70b9\n        // \u961f\u5c3e\u5165\u961f\u64cd\u4f5c\n        } else {\n            // \u5c06 node \u6dfb\u52a0\u81f3\u94fe\u8868\u5c3e\u90e8\n            rear.next = node;\n            node.prev = rear;\n            rear = node; // \u66f4\u65b0\u5c3e\u8282\u70b9\n        }\n        queSize++; // \u66f4\u65b0\u961f\u5217\u957f\u5ea6\n    }\n\n    /* \u961f\u9996\u5165\u961f */\n    public void pushFirst(int num) {\n        push(num, true);\n    }\n\n    /* \u961f\u5c3e\u5165\u961f */\n    public void pushLast(int num) {\n        push(num, false);\n    }\n\n    /* \u51fa\u961f\u64cd\u4f5c */\n    private int pop(boolean isFront) {\n        if (isEmpty())\n            throw new IndexOutOfBoundsException();\n        int val;\n        // \u961f\u9996\u51fa\u961f\u64cd\u4f5c\n        if (isFront) {\n            val = front.val; // \u6682\u5b58\u5934\u8282\u70b9\u503c\n            // \u5220\u9664\u5934\u8282\u70b9\n            ListNode fNext = front.next;\n            if (fNext != null) {\n                fNext.prev = null;\n                front.next = null;\n            }\n            front = fNext; // \u66f4\u65b0\u5934\u8282\u70b9\n        // \u961f\u5c3e\u51fa\u961f\u64cd\u4f5c\n        } else {\n            val = rear.val; // \u6682\u5b58\u5c3e\u8282\u70b9\u503c\n            // \u5220\u9664\u5c3e\u8282\u70b9\n            ListNode rPrev = rear.prev;\n            if (rPrev != null) {\n                rPrev.next = null;\n                rear.prev = null;\n            }\n            rear = rPrev; // \u66f4\u65b0\u5c3e\u8282\u70b9\n        }\n        queSize--; // \u66f4\u65b0\u961f\u5217\u957f\u5ea6\n        return val;\n    }\n\n    /* \u961f\u9996\u51fa\u961f */\n    public int popFirst() {\n        return pop(true);\n    }\n\n    /* \u961f\u5c3e\u51fa\u961f */\n    public int popLast() {\n        return pop(false);\n    }\n\n    /* \u8bbf\u95ee\u961f\u9996\u5143\u7d20 */\n    public int peekFirst() {\n        if (isEmpty())\n            throw new IndexOutOfBoundsException();\n        return front.val;\n    }\n\n    /* \u8bbf\u95ee\u961f\u5c3e\u5143\u7d20 */\n    public int peekLast() {\n        if (isEmpty())\n            throw new IndexOutOfBoundsException();\n        return rear.val;\n    }\n\n    /* \u8fd4\u56de\u6570\u7ec4\u7528\u4e8e\u6253\u5370 */\n    public int[] toArray() {\n        ListNode node = front;\n        int[] res = new int[size()];\n        for (int i = 0; i < res.length; i++) {\n            res[i] = node.val;\n            node = node.next;\n        }\n        return res;\n    }\n}\n
linkedlist_deque.cs
/* \u53cc\u5411\u94fe\u8868\u8282\u70b9 */\nclass ListNode(int val) {\n    public int val = val;       // \u8282\u70b9\u503c\n    public ListNode? next = null; // \u540e\u7ee7\u8282\u70b9\u5f15\u7528\n    public ListNode? prev = null; // \u524d\u9a71\u8282\u70b9\u5f15\u7528\n}\n\n/* \u57fa\u4e8e\u53cc\u5411\u94fe\u8868\u5b9e\u73b0\u7684\u53cc\u5411\u961f\u5217 */\nclass LinkedListDeque {\n    ListNode? front, rear; // \u5934\u8282\u70b9 front, \u5c3e\u8282\u70b9 rear\n    int queSize = 0;      // \u53cc\u5411\u961f\u5217\u7684\u957f\u5ea6\n\n    public LinkedListDeque() {\n        front = null;\n        rear = null;\n    }\n\n    /* \u83b7\u53d6\u53cc\u5411\u961f\u5217\u7684\u957f\u5ea6 */\n    public int Size() {\n        return queSize;\n    }\n\n    /* \u5224\u65ad\u53cc\u5411\u961f\u5217\u662f\u5426\u4e3a\u7a7a */\n    public bool IsEmpty() {\n        return Size() == 0;\n    }\n\n    /* \u5165\u961f\u64cd\u4f5c */\n    void Push(int num, bool isFront) {\n        ListNode node = new(num);\n        // \u82e5\u94fe\u8868\u4e3a\u7a7a\uff0c\u5219\u4ee4 front \u548c rear \u90fd\u6307\u5411 node\n        if (IsEmpty()) {\n            front = node;\n            rear = node;\n        }\n        // \u961f\u9996\u5165\u961f\u64cd\u4f5c\n        else if (isFront) {\n            // \u5c06 node \u6dfb\u52a0\u81f3\u94fe\u8868\u5934\u90e8\n            front!.prev = node;\n            node.next = front;\n            front = node; // \u66f4\u65b0\u5934\u8282\u70b9                           \n        }\n        // \u961f\u5c3e\u5165\u961f\u64cd\u4f5c\n        else {\n            // \u5c06 node \u6dfb\u52a0\u81f3\u94fe\u8868\u5c3e\u90e8\n            rear!.next = node;\n            node.prev = rear;\n            rear = node;  // \u66f4\u65b0\u5c3e\u8282\u70b9\n        }\n\n        queSize++; // \u66f4\u65b0\u961f\u5217\u957f\u5ea6\n    }\n\n    /* \u961f\u9996\u5165\u961f */\n    public void PushFirst(int num) {\n        Push(num, true);\n    }\n\n    /* \u961f\u5c3e\u5165\u961f */\n    public void PushLast(int num) {\n        Push(num, false);\n    }\n\n    /* \u51fa\u961f\u64cd\u4f5c */\n    int? Pop(bool isFront) {\n        if (IsEmpty())\n            throw new Exception();\n        int? val;\n        // \u961f\u9996\u51fa\u961f\u64cd\u4f5c\n        if (isFront) {\n            val = front?.val; // \u6682\u5b58\u5934\u8282\u70b9\u503c\n            // \u5220\u9664\u5934\u8282\u70b9\n            ListNode? fNext = front?.next;\n            if (fNext != null) {\n                fNext.prev = null;\n                front!.next = null;\n            }\n            front = fNext;   // \u66f4\u65b0\u5934\u8282\u70b9\n        }\n        // \u961f\u5c3e\u51fa\u961f\u64cd\u4f5c\n        else {\n            val = rear?.val;  // \u6682\u5b58\u5c3e\u8282\u70b9\u503c\n            // \u5220\u9664\u5c3e\u8282\u70b9\n            ListNode? rPrev = rear?.prev;\n            if (rPrev != null) {\n                rPrev.next = null;\n                rear!.prev = null;\n            }\n            rear = rPrev;    // \u66f4\u65b0\u5c3e\u8282\u70b9\n        }\n\n        queSize--; // \u66f4\u65b0\u961f\u5217\u957f\u5ea6\n        return val;\n    }\n\n    /* \u961f\u9996\u51fa\u961f */\n    public int? PopFirst() {\n        return Pop(true);\n    }\n\n    /* \u961f\u5c3e\u51fa\u961f */\n    public int? PopLast() {\n        return Pop(false);\n    }\n\n    /* \u8bbf\u95ee\u961f\u9996\u5143\u7d20 */\n    public int? PeekFirst() {\n        if (IsEmpty())\n            throw new Exception();\n        return front?.val;\n    }\n\n    /* \u8bbf\u95ee\u961f\u5c3e\u5143\u7d20 */\n    public int? PeekLast() {\n        if (IsEmpty())\n            throw new Exception();\n        return rear?.val;\n    }\n\n    /* \u8fd4\u56de\u6570\u7ec4\u7528\u4e8e\u6253\u5370 */\n    public int?[] ToArray() {\n        ListNode? node = front;\n        int?[] res = new int?[Size()];\n        for (int i = 0; i < res.Length; i++) {\n            res[i] = node?.val;\n            node = node?.next;\n        }\n\n        return res;\n    }\n}\n
linkedlist_deque.go
/* \u57fa\u4e8e\u53cc\u5411\u94fe\u8868\u5b9e\u73b0\u7684\u53cc\u5411\u961f\u5217 */\ntype linkedListDeque struct {\n    // \u4f7f\u7528\u5185\u7f6e\u5305 list\n    data *list.List\n}\n\n/* \u521d\u59cb\u5316\u53cc\u7aef\u961f\u5217 */\nfunc newLinkedListDeque() *linkedListDeque {\n    return &linkedListDeque{\n        data: list.New(),\n    }\n}\n\n/* \u961f\u9996\u5143\u7d20\u5165\u961f */\nfunc (s *linkedListDeque) pushFirst(value any) {\n    s.data.PushFront(value)\n}\n\n/* \u961f\u5c3e\u5143\u7d20\u5165\u961f */\nfunc (s *linkedListDeque) pushLast(value any) {\n    s.data.PushBack(value)\n}\n\n/* \u961f\u9996\u5143\u7d20\u51fa\u961f */\nfunc (s *linkedListDeque) popFirst() any {\n    if s.isEmpty() {\n        return nil\n    }\n    e := s.data.Front()\n    s.data.Remove(e)\n    return e.Value\n}\n\n/* \u961f\u5c3e\u5143\u7d20\u51fa\u961f */\nfunc (s *linkedListDeque) popLast() any {\n    if s.isEmpty() {\n        return nil\n    }\n    e := s.data.Back()\n    s.data.Remove(e)\n    return e.Value\n}\n\n/* \u8bbf\u95ee\u961f\u9996\u5143\u7d20 */\nfunc (s *linkedListDeque) peekFirst() any {\n    if s.isEmpty() {\n        return nil\n    }\n    e := s.data.Front()\n    return e.Value\n}\n\n/* \u8bbf\u95ee\u961f\u5c3e\u5143\u7d20 */\nfunc (s *linkedListDeque) peekLast() any {\n    if s.isEmpty() {\n        return nil\n    }\n    e := s.data.Back()\n    return e.Value\n}\n\n/* \u83b7\u53d6\u961f\u5217\u7684\u957f\u5ea6 */\nfunc (s *linkedListDeque) size() int {\n    return s.data.Len()\n}\n\n/* \u5224\u65ad\u961f\u5217\u662f\u5426\u4e3a\u7a7a */\nfunc (s *linkedListDeque) isEmpty() bool {\n    return s.data.Len() == 0\n}\n\n/* \u83b7\u53d6 List \u7528\u4e8e\u6253\u5370 */\nfunc (s *linkedListDeque) toList() *list.List {\n    return s.data\n}\n
linkedlist_deque.swift
/* \u53cc\u5411\u94fe\u8868\u8282\u70b9 */\nclass ListNode {\n    var val: Int // \u8282\u70b9\u503c\n    var next: ListNode? // \u540e\u7ee7\u8282\u70b9\u5f15\u7528\n    weak var prev: ListNode? // \u524d\u9a71\u8282\u70b9\u5f15\u7528\n\n    init(val: Int) {\n        self.val = val\n    }\n}\n\n/* \u57fa\u4e8e\u53cc\u5411\u94fe\u8868\u5b9e\u73b0\u7684\u53cc\u5411\u961f\u5217 */\nclass LinkedListDeque {\n    private var front: ListNode? // \u5934\u8282\u70b9 front\n    private var rear: ListNode? // \u5c3e\u8282\u70b9 rear\n    private var _size: Int // \u53cc\u5411\u961f\u5217\u7684\u957f\u5ea6\n\n    init() {\n        _size = 0\n    }\n\n    /* \u83b7\u53d6\u53cc\u5411\u961f\u5217\u7684\u957f\u5ea6 */\n    func size() -> Int {\n        _size\n    }\n\n    /* \u5224\u65ad\u53cc\u5411\u961f\u5217\u662f\u5426\u4e3a\u7a7a */\n    func isEmpty() -> Bool {\n        size() == 0\n    }\n\n    /* \u5165\u961f\u64cd\u4f5c */\n    private func push(num: Int, isFront: Bool) {\n        let node = ListNode(val: num)\n        // \u82e5\u94fe\u8868\u4e3a\u7a7a\uff0c\u5219\u4ee4 front \u548c rear \u90fd\u6307\u5411 node\n        if isEmpty() {\n            front = node\n            rear = node\n        }\n        // \u961f\u9996\u5165\u961f\u64cd\u4f5c\n        else if isFront {\n            // \u5c06 node \u6dfb\u52a0\u81f3\u94fe\u8868\u5934\u90e8\n            front?.prev = node\n            node.next = front\n            front = node // \u66f4\u65b0\u5934\u8282\u70b9\n        }\n        // \u961f\u5c3e\u5165\u961f\u64cd\u4f5c\n        else {\n            // \u5c06 node \u6dfb\u52a0\u81f3\u94fe\u8868\u5c3e\u90e8\n            rear?.next = node\n            node.prev = rear\n            rear = node // \u66f4\u65b0\u5c3e\u8282\u70b9\n        }\n        _size += 1 // \u66f4\u65b0\u961f\u5217\u957f\u5ea6\n    }\n\n    /* \u961f\u9996\u5165\u961f */\n    func pushFirst(num: Int) {\n        push(num: num, isFront: true)\n    }\n\n    /* \u961f\u5c3e\u5165\u961f */\n    func pushLast(num: Int) {\n        push(num: num, isFront: false)\n    }\n\n    /* \u51fa\u961f\u64cd\u4f5c */\n    private func pop(isFront: Bool) -> Int {\n        if isEmpty() {\n            fatalError(\"\u53cc\u5411\u961f\u5217\u4e3a\u7a7a\")\n        }\n        let val: Int\n        // \u961f\u9996\u51fa\u961f\u64cd\u4f5c\n        if isFront {\n            val = front!.val // \u6682\u5b58\u5934\u8282\u70b9\u503c\n            // \u5220\u9664\u5934\u8282\u70b9\n            let fNext = front?.next\n            if fNext != nil {\n                fNext?.prev = nil\n                front?.next = nil\n            }\n            front = fNext // \u66f4\u65b0\u5934\u8282\u70b9\n        }\n        // \u961f\u5c3e\u51fa\u961f\u64cd\u4f5c\n        else {\n            val = rear!.val // \u6682\u5b58\u5c3e\u8282\u70b9\u503c\n            // \u5220\u9664\u5c3e\u8282\u70b9\n            let rPrev = rear?.prev\n            if rPrev != nil {\n                rPrev?.next = nil\n                rear?.prev = nil\n            }\n            rear = rPrev // \u66f4\u65b0\u5c3e\u8282\u70b9\n        }\n        _size -= 1 // \u66f4\u65b0\u961f\u5217\u957f\u5ea6\n        return val\n    }\n\n    /* \u961f\u9996\u51fa\u961f */\n    func popFirst() -> Int {\n        pop(isFront: true)\n    }\n\n    /* \u961f\u5c3e\u51fa\u961f */\n    func popLast() -> Int {\n        pop(isFront: false)\n    }\n\n    /* \u8bbf\u95ee\u961f\u9996\u5143\u7d20 */\n    func peekFirst() -> Int {\n        if isEmpty() {\n            fatalError(\"\u53cc\u5411\u961f\u5217\u4e3a\u7a7a\")\n        }\n        return front!.val\n    }\n\n    /* \u8bbf\u95ee\u961f\u5c3e\u5143\u7d20 */\n    func peekLast() -> Int {\n        if isEmpty() {\n            fatalError(\"\u53cc\u5411\u961f\u5217\u4e3a\u7a7a\")\n        }\n        return rear!.val\n    }\n\n    /* \u8fd4\u56de\u6570\u7ec4\u7528\u4e8e\u6253\u5370 */\n    func toArray() -> [Int] {\n        var node = front\n        var res = Array(repeating: 0, count: size())\n        for i in res.indices {\n            res[i] = node!.val\n            node = node?.next\n        }\n        return res\n    }\n}\n
linkedlist_deque.js
/* \u53cc\u5411\u94fe\u8868\u8282\u70b9 */\nclass ListNode {\n    prev; // \u524d\u9a71\u8282\u70b9\u5f15\u7528 (\u6307\u9488)\n    next; // \u540e\u7ee7\u8282\u70b9\u5f15\u7528 (\u6307\u9488)\n    val; // \u8282\u70b9\u503c\n\n    constructor(val) {\n        this.val = val;\n        this.next = null;\n        this.prev = null;\n    }\n}\n\n/* \u57fa\u4e8e\u53cc\u5411\u94fe\u8868\u5b9e\u73b0\u7684\u53cc\u5411\u961f\u5217 */\nclass LinkedListDeque {\n    #front; // \u5934\u8282\u70b9 front\n    #rear; // \u5c3e\u8282\u70b9 rear\n    #queSize; // \u53cc\u5411\u961f\u5217\u7684\u957f\u5ea6\n\n    constructor() {\n        this.#front = null;\n        this.#rear = null;\n        this.#queSize = 0;\n    }\n\n    /* \u961f\u5c3e\u5165\u961f\u64cd\u4f5c */\n    pushLast(val) {\n        const node = new ListNode(val);\n        // \u82e5\u94fe\u8868\u4e3a\u7a7a\uff0c\u5219\u4ee4 front \u548c rear \u90fd\u6307\u5411 node\n        if (this.#queSize === 0) {\n            this.#front = node;\n            this.#rear = node;\n        } else {\n            // \u5c06 node \u6dfb\u52a0\u81f3\u94fe\u8868\u5c3e\u90e8\n            this.#rear.next = node;\n            node.prev = this.#rear;\n            this.#rear = node; // \u66f4\u65b0\u5c3e\u8282\u70b9\n        }\n        this.#queSize++;\n    }\n\n    /* \u961f\u9996\u5165\u961f\u64cd\u4f5c */\n    pushFirst(val) {\n        const node = new ListNode(val);\n        // \u82e5\u94fe\u8868\u4e3a\u7a7a\uff0c\u5219\u4ee4 front \u548c rear \u90fd\u6307\u5411 node\n        if (this.#queSize === 0) {\n            this.#front = node;\n            this.#rear = node;\n        } else {\n            // \u5c06 node \u6dfb\u52a0\u81f3\u94fe\u8868\u5934\u90e8\n            this.#front.prev = node;\n            node.next = this.#front;\n            this.#front = node; // \u66f4\u65b0\u5934\u8282\u70b9\n        }\n        this.#queSize++;\n    }\n\n    /* \u961f\u5c3e\u51fa\u961f\u64cd\u4f5c */\n    popLast() {\n        if (this.#queSize === 0) {\n            return null;\n        }\n        const value = this.#rear.val; // \u5b58\u50a8\u5c3e\u8282\u70b9\u503c\n        // \u5220\u9664\u5c3e\u8282\u70b9\n        let temp = this.#rear.prev;\n        if (temp !== null) {\n            temp.next = null;\n            this.#rear.prev = null;\n        }\n        this.#rear = temp; // \u66f4\u65b0\u5c3e\u8282\u70b9\n        this.#queSize--;\n        return value;\n    }\n\n    /* \u961f\u9996\u51fa\u961f\u64cd\u4f5c */\n    popFirst() {\n        if (this.#queSize === 0) {\n            return null;\n        }\n        const value = this.#front.val; // \u5b58\u50a8\u5c3e\u8282\u70b9\u503c\n        // \u5220\u9664\u5934\u8282\u70b9\n        let temp = this.#front.next;\n        if (temp !== null) {\n            temp.prev = null;\n            this.#front.next = null;\n        }\n        this.#front = temp; // \u66f4\u65b0\u5934\u8282\u70b9\n        this.#queSize--;\n        return value;\n    }\n\n    /* \u8bbf\u95ee\u961f\u5c3e\u5143\u7d20 */\n    peekLast() {\n        return this.#queSize === 0 ? null : this.#rear.val;\n    }\n\n    /* \u8bbf\u95ee\u961f\u9996\u5143\u7d20 */\n    peekFirst() {\n        return this.#queSize === 0 ? null : this.#front.val;\n    }\n\n    /* \u83b7\u53d6\u53cc\u5411\u961f\u5217\u7684\u957f\u5ea6 */\n    size() {\n        return this.#queSize;\n    }\n\n    /* \u5224\u65ad\u53cc\u5411\u961f\u5217\u662f\u5426\u4e3a\u7a7a */\n    isEmpty() {\n        return this.#queSize === 0;\n    }\n\n    /* \u6253\u5370\u53cc\u5411\u961f\u5217 */\n    print() {\n        const arr = [];\n        let temp = this.#front;\n        while (temp !== null) {\n            arr.push(temp.val);\n            temp = temp.next;\n        }\n        console.log('[' + arr.join(', ') + ']');\n    }\n}\n
linkedlist_deque.ts
/* \u53cc\u5411\u94fe\u8868\u8282\u70b9 */\nclass ListNode {\n    prev: ListNode; // \u524d\u9a71\u8282\u70b9\u5f15\u7528 (\u6307\u9488)\n    next: ListNode; // \u540e\u7ee7\u8282\u70b9\u5f15\u7528 (\u6307\u9488)\n    val: number; // \u8282\u70b9\u503c\n\n    constructor(val: number) {\n        this.val = val;\n        this.next = null;\n        this.prev = null;\n    }\n}\n\n/* \u57fa\u4e8e\u53cc\u5411\u94fe\u8868\u5b9e\u73b0\u7684\u53cc\u5411\u961f\u5217 */\nclass LinkedListDeque {\n    private front: ListNode; // \u5934\u8282\u70b9 front\n    private rear: ListNode; // \u5c3e\u8282\u70b9 rear\n    private queSize: number; // \u53cc\u5411\u961f\u5217\u7684\u957f\u5ea6\n\n    constructor() {\n        this.front = null;\n        this.rear = null;\n        this.queSize = 0;\n    }\n\n    /* \u961f\u5c3e\u5165\u961f\u64cd\u4f5c */\n    pushLast(val: number): void {\n        const node: ListNode = new ListNode(val);\n        // \u82e5\u94fe\u8868\u4e3a\u7a7a\uff0c\u5219\u4ee4 front \u548c rear \u90fd\u6307\u5411 node\n        if (this.queSize === 0) {\n            this.front = node;\n            this.rear = node;\n        } else {\n            // \u5c06 node \u6dfb\u52a0\u81f3\u94fe\u8868\u5c3e\u90e8\n            this.rear.next = node;\n            node.prev = this.rear;\n            this.rear = node; // \u66f4\u65b0\u5c3e\u8282\u70b9\n        }\n        this.queSize++;\n    }\n\n    /* \u961f\u9996\u5165\u961f\u64cd\u4f5c */\n    pushFirst(val: number): void {\n        const node: ListNode = new ListNode(val);\n        // \u82e5\u94fe\u8868\u4e3a\u7a7a\uff0c\u5219\u4ee4 front \u548c rear \u90fd\u6307\u5411 node\n        if (this.queSize === 0) {\n            this.front = node;\n            this.rear = node;\n        } else {\n            // \u5c06 node \u6dfb\u52a0\u81f3\u94fe\u8868\u5934\u90e8\n            this.front.prev = node;\n            node.next = this.front;\n            this.front = node; // \u66f4\u65b0\u5934\u8282\u70b9\n        }\n        this.queSize++;\n    }\n\n    /* \u961f\u5c3e\u51fa\u961f\u64cd\u4f5c */\n    popLast(): number {\n        if (this.queSize === 0) {\n            return null;\n        }\n        const value: number = this.rear.val; // \u5b58\u50a8\u5c3e\u8282\u70b9\u503c\n        // \u5220\u9664\u5c3e\u8282\u70b9\n        let temp: ListNode = this.rear.prev;\n        if (temp !== null) {\n            temp.next = null;\n            this.rear.prev = null;\n        }\n        this.rear = temp; // \u66f4\u65b0\u5c3e\u8282\u70b9\n        this.queSize--;\n        return value;\n    }\n\n    /* \u961f\u9996\u51fa\u961f\u64cd\u4f5c */\n    popFirst(): number {\n        if (this.queSize === 0) {\n            return null;\n        }\n        const value: number = this.front.val; // \u5b58\u50a8\u5c3e\u8282\u70b9\u503c\n        // \u5220\u9664\u5934\u8282\u70b9\n        let temp: ListNode = this.front.next;\n        if (temp !== null) {\n            temp.prev = null;\n            this.front.next = null;\n        }\n        this.front = temp; // \u66f4\u65b0\u5934\u8282\u70b9\n        this.queSize--;\n        return value;\n    }\n\n    /* \u8bbf\u95ee\u961f\u5c3e\u5143\u7d20 */\n    peekLast(): number {\n        return this.queSize === 0 ? null : this.rear.val;\n    }\n\n    /* \u8bbf\u95ee\u961f\u9996\u5143\u7d20 */\n    peekFirst(): number {\n        return this.queSize === 0 ? null : this.front.val;\n    }\n\n    /* \u83b7\u53d6\u53cc\u5411\u961f\u5217\u7684\u957f\u5ea6 */\n    size(): number {\n        return this.queSize;\n    }\n\n    /* \u5224\u65ad\u53cc\u5411\u961f\u5217\u662f\u5426\u4e3a\u7a7a */\n    isEmpty(): boolean {\n        return this.queSize === 0;\n    }\n\n    /* \u6253\u5370\u53cc\u5411\u961f\u5217 */\n    print(): void {\n        const arr: number[] = [];\n        let temp: ListNode = this.front;\n        while (temp !== null) {\n            arr.push(temp.val);\n            temp = temp.next;\n        }\n        console.log('[' + arr.join(', ') + ']');\n    }\n}\n
linkedlist_deque.dart
/* \u53cc\u5411\u94fe\u8868\u8282\u70b9 */\nclass ListNode {\n  int val; // \u8282\u70b9\u503c\n  ListNode? next; // \u540e\u7ee7\u8282\u70b9\u5f15\u7528\n  ListNode? prev; // \u524d\u9a71\u8282\u70b9\u5f15\u7528\n\n  ListNode(this.val, {this.next, this.prev});\n}\n\n/* \u57fa\u4e8e\u53cc\u5411\u94fe\u8868\u5b9e\u73b0\u7684\u53cc\u5411\u5bf9\u5217 */\nclass LinkedListDeque {\n  late ListNode? _front; // \u5934\u8282\u70b9 _front\n  late ListNode? _rear; // \u5c3e\u8282\u70b9 _rear\n  int _queSize = 0; // \u53cc\u5411\u961f\u5217\u7684\u957f\u5ea6\n\n  LinkedListDeque() {\n    this._front = null;\n    this._rear = null;\n  }\n\n  /* \u83b7\u53d6\u53cc\u5411\u961f\u5217\u957f\u5ea6 */\n  int size() {\n    return this._queSize;\n  }\n\n  /* \u5224\u65ad\u53cc\u5411\u961f\u5217\u662f\u5426\u4e3a\u7a7a */\n  bool isEmpty() {\n    return size() == 0;\n  }\n\n  /* \u5165\u961f\u64cd\u4f5c */\n  void push(int _num, bool isFront) {\n    final ListNode node = ListNode(_num);\n    if (isEmpty()) {\n      // \u82e5\u94fe\u8868\u4e3a\u7a7a\uff0c\u5219\u4ee4 _front \u548c _rear \u90fd\u6307\u5411 node\n      _front = _rear = node;\n    } else if (isFront) {\n      // \u961f\u9996\u5165\u961f\u64cd\u4f5c\n      // \u5c06 node \u6dfb\u52a0\u81f3\u94fe\u8868\u5934\u90e8\n      _front!.prev = node;\n      node.next = _front;\n      _front = node; // \u66f4\u65b0\u5934\u8282\u70b9\n    } else {\n      // \u961f\u5c3e\u5165\u961f\u64cd\u4f5c\n      // \u5c06 node \u6dfb\u52a0\u81f3\u94fe\u8868\u5c3e\u90e8\n      _rear!.next = node;\n      node.prev = _rear;\n      _rear = node; // \u66f4\u65b0\u5c3e\u8282\u70b9\n    }\n    _queSize++; // \u66f4\u65b0\u961f\u5217\u957f\u5ea6\n  }\n\n  /* \u961f\u9996\u5165\u961f */\n  void pushFirst(int _num) {\n    push(_num, true);\n  }\n\n  /* \u961f\u5c3e\u5165\u961f */\n  void pushLast(int _num) {\n    push(_num, false);\n  }\n\n  /* \u51fa\u961f\u64cd\u4f5c */\n  int? pop(bool isFront) {\n    // \u82e5\u961f\u5217\u4e3a\u7a7a\uff0c\u76f4\u63a5\u8fd4\u56de null\n    if (isEmpty()) {\n      return null;\n    }\n    final int val;\n    if (isFront) {\n      // \u961f\u9996\u51fa\u961f\u64cd\u4f5c\n      val = _front!.val; // \u6682\u5b58\u5934\u8282\u70b9\u503c\n      // \u5220\u9664\u5934\u8282\u70b9\n      ListNode? fNext = _front!.next;\n      if (fNext != null) {\n        fNext.prev = null;\n        _front!.next = null;\n      }\n      _front = fNext; // \u66f4\u65b0\u5934\u8282\u70b9\n    } else {\n      // \u961f\u5c3e\u51fa\u961f\u64cd\u4f5c\n      val = _rear!.val; // \u6682\u5b58\u5c3e\u8282\u70b9\u503c\n      // \u5220\u9664\u5c3e\u8282\u70b9\n      ListNode? rPrev = _rear!.prev;\n      if (rPrev != null) {\n        rPrev.next = null;\n        _rear!.prev = null;\n      }\n      _rear = rPrev; // \u66f4\u65b0\u5c3e\u8282\u70b9\n    }\n    _queSize--; // \u66f4\u65b0\u961f\u5217\u957f\u5ea6\n    return val;\n  }\n\n  /* \u961f\u9996\u51fa\u961f */\n  int? popFirst() {\n    return pop(true);\n  }\n\n  /* \u961f\u5c3e\u51fa\u961f */\n  int? popLast() {\n    return pop(false);\n  }\n\n  /* \u8bbf\u95ee\u961f\u9996\u5143\u7d20 */\n  int? peekFirst() {\n    return _front?.val;\n  }\n\n  /* \u8bbf\u95ee\u961f\u5c3e\u5143\u7d20 */\n  int? peekLast() {\n    return _rear?.val;\n  }\n\n  /* \u8fd4\u56de\u6570\u7ec4\u7528\u4e8e\u6253\u5370 */\n  List<int> toArray() {\n    ListNode? node = _front;\n    final List<int> res = [];\n    for (int i = 0; i < _queSize; i++) {\n      res.add(node!.val);\n      node = node.next;\n    }\n    return res;\n  }\n}\n
linkedlist_deque.rs
/* \u53cc\u5411\u94fe\u8868\u8282\u70b9 */\npub struct ListNode<T> {\n    pub val: T,                                 // \u8282\u70b9\u503c\n    pub next: Option<Rc<RefCell<ListNode<T>>>>, // \u540e\u7ee7\u8282\u70b9\u6307\u9488\n    pub prev: Option<Rc<RefCell<ListNode<T>>>>, // \u524d\u9a71\u8282\u70b9\u6307\u9488\n}\n\nimpl<T> ListNode<T> {\n    pub fn new(val: T) -> Rc<RefCell<ListNode<T>>> {\n        Rc::new(RefCell::new(ListNode {\n            val,\n            next: None,\n            prev: None,\n        }))\n    }\n}\n\n/* \u57fa\u4e8e\u53cc\u5411\u94fe\u8868\u5b9e\u73b0\u7684\u53cc\u5411\u961f\u5217 */\n#[allow(dead_code)]\npub struct LinkedListDeque<T> {\n    front: Option<Rc<RefCell<ListNode<T>>>>, // \u5934\u8282\u70b9 front\n    rear: Option<Rc<RefCell<ListNode<T>>>>,  // \u5c3e\u8282\u70b9 rear\n    que_size: usize,                         // \u53cc\u5411\u961f\u5217\u7684\u957f\u5ea6\n}\n\nimpl<T: Copy> LinkedListDeque<T> {\n    pub fn new() -> Self {\n        Self {\n            front: None,\n            rear: None,\n            que_size: 0,\n        }\n    }\n\n    /* \u83b7\u53d6\u53cc\u5411\u961f\u5217\u7684\u957f\u5ea6 */\n    pub fn size(&self) -> usize {\n        return self.que_size;\n    }\n\n    /* \u5224\u65ad\u53cc\u5411\u961f\u5217\u662f\u5426\u4e3a\u7a7a */\n    pub fn is_empty(&self) -> bool {\n        return self.size() == 0;\n    }\n\n    /* \u5165\u961f\u64cd\u4f5c */\n    pub fn push(&mut self, num: T, is_front: bool) {\n        let node = ListNode::new(num);\n        // \u961f\u9996\u5165\u961f\u64cd\u4f5c\n        if is_front {\n            match self.front.take() {\n                // \u82e5\u94fe\u8868\u4e3a\u7a7a\uff0c\u5219\u4ee4 front \u548c rear \u90fd\u6307\u5411 node\n                None => {\n                    self.rear = Some(node.clone());\n                    self.front = Some(node);\n                }\n                // \u5c06 node \u6dfb\u52a0\u81f3\u94fe\u8868\u5934\u90e8\n                Some(old_front) => {\n                    old_front.borrow_mut().prev = Some(node.clone());\n                    node.borrow_mut().next = Some(old_front);\n                    self.front = Some(node); // \u66f4\u65b0\u5934\u8282\u70b9\n                }\n            }\n        }\n        // \u961f\u5c3e\u5165\u961f\u64cd\u4f5c\n        else {\n            match self.rear.take() {\n                // \u82e5\u94fe\u8868\u4e3a\u7a7a\uff0c\u5219\u4ee4 front \u548c rear \u90fd\u6307\u5411 node\n                None => {\n                    self.front = Some(node.clone());\n                    self.rear = Some(node);\n                }\n                // \u5c06 node \u6dfb\u52a0\u81f3\u94fe\u8868\u5c3e\u90e8\n                Some(old_rear) => {\n                    old_rear.borrow_mut().next = Some(node.clone());\n                    node.borrow_mut().prev = Some(old_rear);\n                    self.rear = Some(node); // \u66f4\u65b0\u5c3e\u8282\u70b9\n                }\n            }\n        }\n        self.que_size += 1; // \u66f4\u65b0\u961f\u5217\u957f\u5ea6\n    }\n\n    /* \u961f\u9996\u5165\u961f */\n    pub fn push_first(&mut self, num: T) {\n        self.push(num, true);\n    }\n\n    /* \u961f\u5c3e\u5165\u961f */\n    pub fn push_last(&mut self, num: T) {\n        self.push(num, false);\n    }\n\n    /* \u51fa\u961f\u64cd\u4f5c */\n    pub fn pop(&mut self, is_front: bool) -> Option<T> {\n        // \u82e5\u961f\u5217\u4e3a\u7a7a\uff0c\u76f4\u63a5\u8fd4\u56de None\n        if self.is_empty() {\n            return None;\n        };\n        // \u961f\u9996\u51fa\u961f\u64cd\u4f5c\n        if is_front {\n            self.front.take().map(|old_front| {\n                match old_front.borrow_mut().next.take() {\n                    Some(new_front) => {\n                        new_front.borrow_mut().prev.take();\n                        self.front = Some(new_front); // \u66f4\u65b0\u5934\u8282\u70b9\n                    }\n                    None => {\n                        self.rear.take();\n                    }\n                }\n                self.que_size -= 1; // \u66f4\u65b0\u961f\u5217\u957f\u5ea6\n                Rc::try_unwrap(old_front).ok().unwrap().into_inner().val\n            })\n        }\n        // \u961f\u5c3e\u51fa\u961f\u64cd\u4f5c\n        else {\n            self.rear.take().map(|old_rear| {\n                match old_rear.borrow_mut().prev.take() {\n                    Some(new_rear) => {\n                        new_rear.borrow_mut().next.take();\n                        self.rear = Some(new_rear); // \u66f4\u65b0\u5c3e\u8282\u70b9\n                    }\n                    None => {\n                        self.front.take();\n                    }\n                }\n                self.que_size -= 1; // \u66f4\u65b0\u961f\u5217\u957f\u5ea6\n                Rc::try_unwrap(old_rear).ok().unwrap().into_inner().val\n            })\n        }\n    }\n\n    /* \u961f\u9996\u51fa\u961f */\n    pub fn pop_first(&mut self) -> Option<T> {\n        return self.pop(true);\n    }\n\n    /* \u961f\u5c3e\u51fa\u961f */\n    pub fn pop_last(&mut self) -> Option<T> {\n        return self.pop(false);\n    }\n\n    /* \u8bbf\u95ee\u961f\u9996\u5143\u7d20 */\n    pub fn peek_first(&self) -> Option<&Rc<RefCell<ListNode<T>>>> {\n        self.front.as_ref()\n    }\n\n    /* \u8bbf\u95ee\u961f\u5c3e\u5143\u7d20 */\n    pub fn peek_last(&self) -> Option<&Rc<RefCell<ListNode<T>>>> {\n        self.rear.as_ref()\n    }\n\n    /* \u8fd4\u56de\u6570\u7ec4\u7528\u4e8e\u6253\u5370 */\n    pub fn to_array(&self, head: Option<&Rc<RefCell<ListNode<T>>>>) -> Vec<T> {\n        if let Some(node) = head {\n            let mut nums = self.to_array(node.borrow().next.as_ref());\n            nums.insert(0, node.borrow().val);\n            return nums;\n        }\n        return Vec::new();\n    }\n}\n
linkedlist_deque.c
/* \u53cc\u5411\u94fe\u8868\u8282\u70b9 */\ntypedef struct DoublyListNode {\n    int val;                     // \u8282\u70b9\u503c\n    struct DoublyListNode *next; // \u540e\u7ee7\u8282\u70b9\n    struct DoublyListNode *prev; // \u524d\u9a71\u8282\u70b9\n} DoublyListNode;\n\n/* \u6784\u9020\u51fd\u6570 */\nDoublyListNode *newDoublyListNode(int num) {\n    DoublyListNode *new = (DoublyListNode *)malloc(sizeof(DoublyListNode));\n    new->val = num;\n    new->next = NULL;\n    new->prev = NULL;\n    return new;\n}\n\n/* \u6790\u6784\u51fd\u6570 */\nvoid delDoublyListNode(DoublyListNode *node) {\n    free(node);\n}\n\n/* \u57fa\u4e8e\u53cc\u5411\u94fe\u8868\u5b9e\u73b0\u7684\u53cc\u5411\u961f\u5217 */\ntypedef struct {\n    DoublyListNode *front, *rear; // \u5934\u8282\u70b9 front \uff0c\u5c3e\u8282\u70b9 rear\n    int queSize;                  // \u53cc\u5411\u961f\u5217\u7684\u957f\u5ea6\n} LinkedListDeque;\n\n/* \u6784\u9020\u51fd\u6570 */\nLinkedListDeque *newLinkedListDeque() {\n    LinkedListDeque *deque = (LinkedListDeque *)malloc(sizeof(LinkedListDeque));\n    deque->front = NULL;\n    deque->rear = NULL;\n    deque->queSize = 0;\n    return deque;\n}\n\n/* \u6790\u6784\u51fd\u6570 */\nvoid delLinkedListdeque(LinkedListDeque *deque) {\n    // \u91ca\u653e\u6240\u6709\u8282\u70b9\n    for (int i = 0; i < deque->queSize && deque->front != NULL; i++) {\n        DoublyListNode *tmp = deque->front;\n        deque->front = deque->front->next;\n        free(tmp);\n    }\n    // \u91ca\u653e deque \u7ed3\u6784\u4f53\n    free(deque);\n}\n\n/* \u83b7\u53d6\u961f\u5217\u7684\u957f\u5ea6 */\nint size(LinkedListDeque *deque) {\n    return deque->queSize;\n}\n\n/* \u5224\u65ad\u961f\u5217\u662f\u5426\u4e3a\u7a7a */\nbool empty(LinkedListDeque *deque) {\n    return (size(deque) == 0);\n}\n\n/* \u5165\u961f */\nvoid push(LinkedListDeque *deque, int num, bool isFront) {\n    DoublyListNode *node = newDoublyListNode(num);\n    // \u82e5\u94fe\u8868\u4e3a\u7a7a\uff0c\u5219\u4ee4 front \u548c rear \u90fd\u6307\u5411node\n    if (empty(deque)) {\n        deque->front = deque->rear = node;\n    }\n    // \u961f\u9996\u5165\u961f\u64cd\u4f5c\n    else if (isFront) {\n        // \u5c06 node \u6dfb\u52a0\u81f3\u94fe\u8868\u5934\u90e8\n        deque->front->prev = node;\n        node->next = deque->front;\n        deque->front = node; // \u66f4\u65b0\u5934\u8282\u70b9\n    }\n    // \u961f\u5c3e\u5165\u961f\u64cd\u4f5c\n    else {\n        // \u5c06 node \u6dfb\u52a0\u81f3\u94fe\u8868\u5c3e\u90e8\n        deque->rear->next = node;\n        node->prev = deque->rear;\n        deque->rear = node;\n    }\n    deque->queSize++; // \u66f4\u65b0\u961f\u5217\u957f\u5ea6\n}\n\n/* \u961f\u9996\u5165\u961f */\nvoid pushFirst(LinkedListDeque *deque, int num) {\n    push(deque, num, true);\n}\n\n/* \u961f\u5c3e\u5165\u961f */\nvoid pushLast(LinkedListDeque *deque, int num) {\n    push(deque, num, false);\n}\n\n/* \u8bbf\u95ee\u961f\u9996\u5143\u7d20 */\nint peekFirst(LinkedListDeque *deque) {\n    assert(size(deque) && deque->front);\n    return deque->front->val;\n}\n\n/* \u8bbf\u95ee\u961f\u5c3e\u5143\u7d20 */\nint peekLast(LinkedListDeque *deque) {\n    assert(size(deque) && deque->rear);\n    return deque->rear->val;\n}\n\n/* \u51fa\u961f */\nint pop(LinkedListDeque *deque, bool isFront) {\n    if (empty(deque))\n        return -1;\n    int val;\n    // \u961f\u9996\u51fa\u961f\u64cd\u4f5c\n    if (isFront) {\n        val = peekFirst(deque); // \u6682\u5b58\u5934\u8282\u70b9\u503c\n        DoublyListNode *fNext = deque->front->next;\n        if (fNext) {\n            fNext->prev = NULL;\n            deque->front->next = NULL;\n            delDoublyListNode(deque->front);\n        }\n        deque->front = fNext; // \u66f4\u65b0\u5934\u8282\u70b9\n    }\n    // \u961f\u5c3e\u51fa\u961f\u64cd\u4f5c\n    else {\n        val = peekLast(deque); // \u6682\u5b58\u5c3e\u8282\u70b9\u503c\n        DoublyListNode *rPrev = deque->rear->prev;\n        if (rPrev) {\n            rPrev->next = NULL;\n            deque->rear->prev = NULL;\n            delDoublyListNode(deque->rear);\n        }\n        deque->rear = rPrev; // \u66f4\u65b0\u5c3e\u8282\u70b9\n    }\n    deque->queSize--; // \u66f4\u65b0\u961f\u5217\u957f\u5ea6\n    return val;\n}\n\n/* \u961f\u9996\u51fa\u961f */\nint popFirst(LinkedListDeque *deque) {\n    return pop(deque, true);\n}\n\n/* \u961f\u5c3e\u51fa\u961f */\nint popLast(LinkedListDeque *deque) {\n    return pop(deque, false);\n}\n\n/* \u6253\u5370\u961f\u5217 */\nvoid printLinkedListDeque(LinkedListDeque *deque) {\n    int *arr = malloc(sizeof(int) * deque->queSize);\n    // \u62f7\u8d1d\u94fe\u8868\u4e2d\u7684\u6570\u636e\u5230\u6570\u7ec4\n    int i;\n    DoublyListNode *node;\n    for (i = 0, node = deque->front; i < deque->queSize; i++) {\n        arr[i] = node->val;\n        node = node->next;\n    }\n    printArray(arr, deque->queSize);\n    free(arr);\n}\n
linkedlist_deque.zig
// \u53cc\u5411\u94fe\u8868\u8282\u70b9\nfn ListNode(comptime T: type) type {\n    return struct {\n        const Self = @This();\n\n        val: T = undefined,     // \u8282\u70b9\u503c\n        next: ?*Self = null,    // \u540e\u7ee7\u8282\u70b9\u6307\u9488\n        prev: ?*Self = null,    // \u524d\u9a71\u8282\u70b9\u6307\u9488\n\n        // Initialize a list node with specific value\n        pub fn init(self: *Self, x: i32) void {\n            self.val = x;\n            self.next = null;\n            self.prev = null;\n        }\n    };\n}\n\n// \u57fa\u4e8e\u53cc\u5411\u94fe\u8868\u5b9e\u73b0\u7684\u53cc\u5411\u961f\u5217\nfn LinkedListDeque(comptime T: type) type {\n    return struct {\n        const Self = @This();\n\n        front: ?*ListNode(T) = null,                    // \u5934\u8282\u70b9 front\n        rear: ?*ListNode(T) = null,                     // \u5c3e\u8282\u70b9 rear\n        que_size: usize = 0,                             // \u53cc\u5411\u961f\u5217\u7684\u957f\u5ea6\n        mem_arena: ?std.heap.ArenaAllocator = null,\n        mem_allocator: std.mem.Allocator = undefined,   // \u5185\u5b58\u5206\u914d\u5668\n\n        // \u6784\u9020\u51fd\u6570\uff08\u5206\u914d\u5185\u5b58+\u521d\u59cb\u5316\u961f\u5217\uff09\n        pub fn init(self: *Self, allocator: std.mem.Allocator) !void {\n            if (self.mem_arena == null) {\n                self.mem_arena = std.heap.ArenaAllocator.init(allocator);\n                self.mem_allocator = self.mem_arena.?.allocator();\n            }\n            self.front = null;\n            self.rear = null;\n            self.que_size = 0;\n        }\n\n        // \u6790\u6784\u51fd\u6570\uff08\u91ca\u653e\u5185\u5b58\uff09\n        pub fn deinit(self: *Self) void {\n            if (self.mem_arena == null) return;\n            self.mem_arena.?.deinit();\n        }\n\n        // \u83b7\u53d6\u53cc\u5411\u961f\u5217\u7684\u957f\u5ea6\n        pub fn size(self: *Self) usize {\n            return self.que_size;\n        }\n\n        // \u5224\u65ad\u53cc\u5411\u961f\u5217\u662f\u5426\u4e3a\u7a7a\n        pub fn isEmpty(self: *Self) bool {\n            return self.size() == 0;\n        }\n\n        // \u5165\u961f\u64cd\u4f5c\n        pub fn push(self: *Self, num: T, is_front: bool) !void {\n            var node = try self.mem_allocator.create(ListNode(T));\n            node.init(num);\n            // \u82e5\u94fe\u8868\u4e3a\u7a7a\uff0c\u5219\u4ee4 front \u548c rear \u90fd\u6307\u5411 node\n            if (self.isEmpty()) {\n                self.front = node;\n                self.rear = node;\n            // \u961f\u9996\u5165\u961f\u64cd\u4f5c\n            } else if (is_front) {\n                // \u5c06 node \u6dfb\u52a0\u81f3\u94fe\u8868\u5934\u90e8\n                self.front.?.prev = node;\n                node.next = self.front;\n                self.front = node;  // \u66f4\u65b0\u5934\u8282\u70b9\n            // \u961f\u5c3e\u5165\u961f\u64cd\u4f5c\n            } else {\n                // \u5c06 node \u6dfb\u52a0\u81f3\u94fe\u8868\u5c3e\u90e8\n                self.rear.?.next = node;\n                node.prev = self.rear;\n                self.rear = node;   // \u66f4\u65b0\u5c3e\u8282\u70b9\n            }\n            self.que_size += 1;      // \u66f4\u65b0\u961f\u5217\u957f\u5ea6\n        } \n\n        // \u961f\u9996\u5165\u961f\n        pub fn pushFirst(self: *Self, num: T) !void {\n            try self.push(num, true);\n        } \n\n        // \u961f\u5c3e\u5165\u961f\n        pub fn pushLast(self: *Self, num: T) !void {\n            try self.push(num, false);\n        } \n\n        // \u51fa\u961f\u64cd\u4f5c\n        pub fn pop(self: *Self, is_front: bool) T {\n            if (self.isEmpty()) @panic(\"\u53cc\u5411\u961f\u5217\u4e3a\u7a7a\");\n            var val: T = undefined;\n            // \u961f\u9996\u51fa\u961f\u64cd\u4f5c\n            if (is_front) {\n                val = self.front.?.val;     // \u6682\u5b58\u5934\u8282\u70b9\u503c\n                // \u5220\u9664\u5934\u8282\u70b9\n                var fNext = self.front.?.next;\n                if (fNext != null) {\n                    fNext.?.prev = null;\n                    self.front.?.next = null;\n                }\n                self.front = fNext;         // \u66f4\u65b0\u5934\u8282\u70b9\n            // \u961f\u5c3e\u51fa\u961f\u64cd\u4f5c\n            } else {\n                val = self.rear.?.val;      // \u6682\u5b58\u5c3e\u8282\u70b9\u503c\n                // \u5220\u9664\u5c3e\u8282\u70b9\n                var rPrev = self.rear.?.prev;\n                if (rPrev != null) {\n                    rPrev.?.next = null;\n                    self.rear.?.prev = null;\n                }\n                self.rear = rPrev;          // \u66f4\u65b0\u5c3e\u8282\u70b9\n            }\n            self.que_size -= 1;              // \u66f4\u65b0\u961f\u5217\u957f\u5ea6\n            return val;\n        } \n\n        // \u961f\u9996\u51fa\u961f\n        pub fn popFirst(self: *Self) T {\n            return self.pop(true);\n        } \n\n        // \u961f\u5c3e\u51fa\u961f\n        pub fn popLast(self: *Self) T {\n            return self.pop(false);\n        } \n\n        // \u8bbf\u95ee\u961f\u9996\u5143\u7d20\n        pub fn peekFirst(self: *Self) T {\n            if (self.isEmpty()) @panic(\"\u53cc\u5411\u961f\u5217\u4e3a\u7a7a\");\n            return self.front.?.val;\n        }  \n\n        // \u8bbf\u95ee\u961f\u5c3e\u5143\u7d20\n        pub fn peekLast(self: *Self) T {\n            if (self.isEmpty()) @panic(\"\u53cc\u5411\u961f\u5217\u4e3a\u7a7a\");\n            return self.rear.?.val;\n        }\n\n        // \u8fd4\u56de\u6570\u7ec4\u7528\u4e8e\u6253\u5370\n        pub fn toArray(self: *Self) ![]T {\n            var node = self.front;\n            var res = try self.mem_allocator.alloc(T, self.size());\n            @memset(res, @as(T, 0));\n            var i: usize = 0;\n            while (i < res.len) : (i += 1) {\n                res[i] = node.?.val;\n                node = node.?.next;\n            }\n            return res;\n        }\n    };\n}\n
"},{"location":"chapter_stack_and_queue/deque/#2-implementation-based-on-array","title":"2. \u00a0 Implementation Based on Array","text":"

As shown in the Figure 5-9 , similar to implementing a queue with an array, we can also use a circular array to implement a double-ended queue.

ArrayDequepushLast()pushFirst()popLast()popFirst()

Figure 5-9 \u00a0 Implementing Double-Ended Queue with Array for Enqueue and Dequeue Operations

The implementation only needs to add methods for \"front enqueue\" and \"rear dequeue\":

[file]{array_deque}-[func]{}\n
"},{"location":"chapter_stack_and_queue/deque/#533-applications-of-double-ended-queue","title":"5.3.3 \u00a0 Applications of Double-Ended Queue","text":"

The double-ended queue combines the logic of both stacks and queues, thus, it can implement all their respective use cases while offering greater flexibility.

We know that software's \"undo\" feature is typically implemented using a stack: the system pushes each change operation onto the stack and then pops to implement undoing. However, considering the limitations of system resources, software often restricts the number of undo steps (for example, only allowing the last 50 steps). When the stack length exceeds 50, the software needs to perform a deletion operation at the bottom of the stack (the front of the queue). But a regular stack cannot perform this function, where a double-ended queue becomes necessary. Note that the core logic of \"undo\" still follows the Last-In-First-Out principle of a stack, but a double-ended queue can more flexibly implement some additional logic.

"},{"location":"chapter_stack_and_queue/queue/","title":"5.2 \u00a0 Queue","text":"

\"Queue\" is a linear data structure that follows the First-In-First-Out (FIFO) rule. As the name suggests, a queue simulates the phenomenon of lining up, where newcomers join the queue at the rear, and the person at the front leaves the queue first.

As shown in the Figure 5-4 , we call the front of the queue the \"head\" and the back the \"tail.\" The operation of adding elements to the rear of the queue is termed \"enqueue,\" and the operation of removing elements from the front is termed \"dequeue.\"

Figure 5-4 \u00a0 Queue's First-In-First-Out Rule

"},{"location":"chapter_stack_and_queue/queue/#521-common-operations-on-queue","title":"5.2.1 \u00a0 Common Operations on Queue","text":"

The common operations on a queue are shown in the Table 5-2 . Note that method names may vary across different programming languages. Here, we use the same naming convention as that used for stacks.

Table 5-2 \u00a0 Efficiency of Queue Operations

Method Name Description Time Complexity push() Enqueue an element, add it to the tail \\(O(1)\\) pop() Dequeue the head element \\(O(1)\\) peek() Access the head element \\(O(1)\\)

We can directly use the ready-made queue classes in programming languages:

PythonC++JavaC#GoSwiftJSTSDartRustCZig queue.py
from collections import deque\n\n# Initialize the queue\n# In Python, we generally use the deque class as a queue\n# Although queue.Queue() is a pure queue class, it's not very user-friendly, so it's not recommended\nque: deque[int] = deque()\n\n# Enqueue elements\nque.append(1)\nque.append(3)\nque.append(2)\nque.append(5)\nque.append(4)\n\n# Access the first element\nfront: int = que[0]\n\n# Dequeue an element\npop: int = que.popleft()\n\n# Get the length of the queue\nsize: int = len(que)\n\n# Check if the queue is empty\nis_empty: bool = len(que) == 0\n
queue.cpp
/* Initialize the queue */\nqueue<int> queue;\n\n/* Enqueue elements */\nqueue.push(1);\nqueue.push(3);\nqueue.push(2);\nqueue.push(5);\nqueue.push(4);\n\n/* Access the first element*/\nint front = queue.front();\n\n/* Dequeue an element */\nqueue.pop();\n\n/* Get the length of the queue */\nint size = queue.size();\n\n/* Check if the queue is empty */\nbool empty = queue.empty();\n
queue.java
/* Initialize the queue */\nQueue<Integer> queue = new LinkedList<>();\n\n/* Enqueue elements */\nqueue.offer(1);\nqueue.offer(3);\nqueue.offer(2);\nqueue.offer(5);\nqueue.offer(4);\n\n/* Access the first element */\nint peek = queue.peek();\n\n/* Dequeue an element */\nint pop = queue.poll();\n\n/* Get the length of the queue */\nint size = queue.size();\n\n/* Check if the queue is empty */\nboolean isEmpty = queue.isEmpty();\n
queue.cs
/* Initialize the queue */\nQueue<int> queue = new();\n\n/* Enqueue elements */\nqueue.Enqueue(1);\nqueue.Enqueue(3);\nqueue.Enqueue(2);\nqueue.Enqueue(5);\nqueue.Enqueue(4);\n\n/* Access the first element */\nint peek = queue.Peek();\n\n/* Dequeue an element */\nint pop = queue.Dequeue();\n\n/* Get the length of the queue */\nint size = queue.Count;\n\n/* Check if the queue is empty */\nbool isEmpty = queue.Count == 0;\n
queue_test.go
/* Initialize the queue */\n// In Go, use list as a queue\nqueue := list.New()\n\n/* Enqueue elements */\nqueue.PushBack(1)\nqueue.PushBack(3)\nqueue.PushBack(2)\nqueue.PushBack(5)\nqueue.PushBack(4)\n\n/* Access the first element */\npeek := queue.Front()\n\n/* Dequeue an element */\npop := queue.Front()\nqueue.Remove(pop)\n\n/* Get the length of the queue */\nsize := queue.Len()\n\n/* Check if the queue is empty */\nisEmpty := queue.Len() == 0\n
queue.swift
/* Initialize the queue */\n// Swift does not have a built-in queue class, so Array can be used as a queue\nvar queue: [Int] = []\n\n/* Enqueue elements */\nqueue.append(1)\nqueue.append(3)\nqueue.append(2)\nqueue.append(5)\nqueue.append(4)\n\n/* Access the first element */\nlet peek = queue.first!\n\n/* Dequeue an element */\n// Since it's an array, removeFirst has a complexity of O(n)\nlet pool = queue.removeFirst()\n\n/* Get the length of the queue */\nlet size = queue.count\n\n/* Check if the queue is empty */\nlet isEmpty = queue.isEmpty\n
queue.js
/* Initialize the queue */\n// JavaScript does not have a built-in queue, so Array can be used as a queue\nconst queue = [];\n\n/* Enqueue elements */\nqueue.push(1);\nqueue.push(3);\nqueue.push(2);\nqueue.push(5);\nqueue.push(4);\n\n/* Access the first element */\nconst peek = queue[0];\n\n/* Dequeue an element */\n// Since the underlying structure is an array, shift() method has a time complexity of O(n)\nconst pop = queue.shift();\n\n/* Get the length of the queue */\nconst size = queue.length;\n\n/* Check if the queue is empty */\nconst empty = queue.length === 0;\n
queue.ts
/* Initialize the queue */\n// TypeScript does not have a built-in queue, so Array can be used as a queue \nconst queue: number[] = [];\n\n/* Enqueue elements */\nqueue.push(1);\nqueue.push(3);\nqueue.push(2);\nqueue.push(5);\nqueue.push(4);\n\n/* Access the first element */\nconst peek = queue[0];\n\n/* Dequeue an element */\n// Since the underlying structure is an array, shift() method has a time complexity of O(n)\nconst pop = queue.shift();\n\n/* Get the length of the queue */\nconst size = queue.length;\n\n/* Check if the queue is empty */\nconst empty = queue.length === 0;\n
queue.dart
/* Initialize the queue */\n// In Dart, the Queue class is a double-ended queue but can be used as a queue\nQueue<int> queue = Queue();\n\n/* Enqueue elements */\nqueue.add(1);\nqueue.add(3);\nqueue.add(2);\nqueue.add(5);\nqueue.add(4);\n\n/* Access the first element */\nint peek = queue.first;\n\n/* Dequeue an element */\nint pop = queue.removeFirst();\n\n/* Get the length of the queue */\nint size = queue.length;\n\n/* Check if the queue is empty */\nbool isEmpty = queue.isEmpty;\n
queue.rs
/* Initialize the double-ended queue */\n// In Rust, use a double-ended queue as a regular queue\nlet mut deque: VecDeque<u32> = VecDeque::new();\n\n/* Enqueue elements */\ndeque.push_back(1);\ndeque.push_back(3);\ndeque.push_back(2);\ndeque.push_back(5);\ndeque.push_back(4);\n\n/* Access the first element */\nif let Some(front) = deque.front() {\n}\n\n/* Dequeue an element */\nif let Some(pop) = deque.pop_front() {\n}\n\n/* Get the length of the queue */\nlet size = deque.len();\n\n/* Check if the queue is empty */\nlet is_empty = deque.is_empty();\n
queue.c
// C does not provide a built-in queue\n
queue.zig
\n
Code Visualization

Full Screen >

"},{"location":"chapter_stack_and_queue/queue/#522-implementing-a-queue","title":"5.2.2 \u00a0 Implementing a Queue","text":"

To implement a queue, we need a data structure that allows adding elements at one end and removing them at the other. Both linked lists and arrays meet this requirement.

"},{"location":"chapter_stack_and_queue/queue/#1-implementation-based-on-a-linked-list","title":"1. \u00a0 Implementation Based on a Linked List","text":"

As shown in the Figure 5-5 , we can consider the \"head node\" and \"tail node\" of a linked list as the \"front\" and \"rear\" of the queue, respectively. It is stipulated that nodes can only be added at the rear and removed at the front.

LinkedListQueuepush()pop()

Figure 5-5 \u00a0 Implementing Queue with Linked List for Enqueue and Dequeue Operations

Below is the code for implementing a queue using a linked list:

PythonC++JavaC#GoSwiftJSTSDartRustCZig linkedlist_queue.py
class LinkedListQueue:\n    \"\"\"\u57fa\u4e8e\u94fe\u8868\u5b9e\u73b0\u7684\u961f\u5217\"\"\"\n\n    def __init__(self):\n        \"\"\"\u6784\u9020\u65b9\u6cd5\"\"\"\n        self._front: ListNode | None = None  # \u5934\u8282\u70b9 front\n        self._rear: ListNode | None = None  # \u5c3e\u8282\u70b9 rear\n        self._size: int = 0\n\n    def size(self) -> int:\n        \"\"\"\u83b7\u53d6\u961f\u5217\u7684\u957f\u5ea6\"\"\"\n        return self._size\n\n    def is_empty(self) -> bool:\n        \"\"\"\u5224\u65ad\u961f\u5217\u662f\u5426\u4e3a\u7a7a\"\"\"\n        return not self._front\n\n    def push(self, num: int):\n        \"\"\"\u5165\u961f\"\"\"\n        # \u5728\u5c3e\u8282\u70b9\u540e\u6dfb\u52a0 num\n        node = ListNode(num)\n        # \u5982\u679c\u961f\u5217\u4e3a\u7a7a\uff0c\u5219\u4ee4\u5934\u3001\u5c3e\u8282\u70b9\u90fd\u6307\u5411\u8be5\u8282\u70b9\n        if self._front is None:\n            self._front = node\n            self._rear = node\n        # \u5982\u679c\u961f\u5217\u4e0d\u4e3a\u7a7a\uff0c\u5219\u5c06\u8be5\u8282\u70b9\u6dfb\u52a0\u5230\u5c3e\u8282\u70b9\u540e\n        else:\n            self._rear.next = node\n            self._rear = node\n        self._size += 1\n\n    def pop(self) -> int:\n        \"\"\"\u51fa\u961f\"\"\"\n        num = self.peek()\n        # \u5220\u9664\u5934\u8282\u70b9\n        self._front = self._front.next\n        self._size -= 1\n        return num\n\n    def peek(self) -> int:\n        \"\"\"\u8bbf\u95ee\u961f\u9996\u5143\u7d20\"\"\"\n        if self.is_empty():\n            raise IndexError(\"\u961f\u5217\u4e3a\u7a7a\")\n        return self._front.val\n\n    def to_list(self) -> list[int]:\n        \"\"\"\u8f6c\u5316\u4e3a\u5217\u8868\u7528\u4e8e\u6253\u5370\"\"\"\n        queue = []\n        temp = self._front\n        while temp:\n            queue.append(temp.val)\n            temp = temp.next\n        return queue\n
linkedlist_queue.cpp
/* \u57fa\u4e8e\u94fe\u8868\u5b9e\u73b0\u7684\u961f\u5217 */\nclass LinkedListQueue {\n  private:\n    ListNode *front, *rear; // \u5934\u8282\u70b9 front \uff0c\u5c3e\u8282\u70b9 rear\n    int queSize;\n\n  public:\n    LinkedListQueue() {\n        front = nullptr;\n        rear = nullptr;\n        queSize = 0;\n    }\n\n    ~LinkedListQueue() {\n        // \u904d\u5386\u94fe\u8868\u5220\u9664\u8282\u70b9\uff0c\u91ca\u653e\u5185\u5b58\n        freeMemoryLinkedList(front);\n    }\n\n    /* \u83b7\u53d6\u961f\u5217\u7684\u957f\u5ea6 */\n    int size() {\n        return queSize;\n    }\n\n    /* \u5224\u65ad\u961f\u5217\u662f\u5426\u4e3a\u7a7a */\n    bool isEmpty() {\n        return queSize == 0;\n    }\n\n    /* \u5165\u961f */\n    void push(int num) {\n        // \u5728\u5c3e\u8282\u70b9\u540e\u6dfb\u52a0 num\n        ListNode *node = new ListNode(num);\n        // \u5982\u679c\u961f\u5217\u4e3a\u7a7a\uff0c\u5219\u4ee4\u5934\u3001\u5c3e\u8282\u70b9\u90fd\u6307\u5411\u8be5\u8282\u70b9\n        if (front == nullptr) {\n            front = node;\n            rear = node;\n        }\n        // \u5982\u679c\u961f\u5217\u4e0d\u4e3a\u7a7a\uff0c\u5219\u5c06\u8be5\u8282\u70b9\u6dfb\u52a0\u5230\u5c3e\u8282\u70b9\u540e\n        else {\n            rear->next = node;\n            rear = node;\n        }\n        queSize++;\n    }\n\n    /* \u51fa\u961f */\n    int pop() {\n        int num = peek();\n        // \u5220\u9664\u5934\u8282\u70b9\n        ListNode *tmp = front;\n        front = front->next;\n        // \u91ca\u653e\u5185\u5b58\n        delete tmp;\n        queSize--;\n        return num;\n    }\n\n    /* \u8bbf\u95ee\u961f\u9996\u5143\u7d20 */\n    int peek() {\n        if (size() == 0)\n            throw out_of_range(\"\u961f\u5217\u4e3a\u7a7a\");\n        return front->val;\n    }\n\n    /* \u5c06\u94fe\u8868\u8f6c\u5316\u4e3a Vector \u5e76\u8fd4\u56de */\n    vector<int> toVector() {\n        ListNode *node = front;\n        vector<int> res(size());\n        for (int i = 0; i < res.size(); i++) {\n            res[i] = node->val;\n            node = node->next;\n        }\n        return res;\n    }\n};\n
linkedlist_queue.java
/* \u57fa\u4e8e\u94fe\u8868\u5b9e\u73b0\u7684\u961f\u5217 */\nclass LinkedListQueue {\n    private ListNode front, rear; // \u5934\u8282\u70b9 front \uff0c\u5c3e\u8282\u70b9 rear\n    private int queSize = 0;\n\n    public LinkedListQueue() {\n        front = null;\n        rear = null;\n    }\n\n    /* \u83b7\u53d6\u961f\u5217\u7684\u957f\u5ea6 */\n    public int size() {\n        return queSize;\n    }\n\n    /* \u5224\u65ad\u961f\u5217\u662f\u5426\u4e3a\u7a7a */\n    public boolean isEmpty() {\n        return size() == 0;\n    }\n\n    /* \u5165\u961f */\n    public void push(int num) {\n        // \u5728\u5c3e\u8282\u70b9\u540e\u6dfb\u52a0 num\n        ListNode node = new ListNode(num);\n        // \u5982\u679c\u961f\u5217\u4e3a\u7a7a\uff0c\u5219\u4ee4\u5934\u3001\u5c3e\u8282\u70b9\u90fd\u6307\u5411\u8be5\u8282\u70b9\n        if (front == null) {\n            front = node;\n            rear = node;\n        // \u5982\u679c\u961f\u5217\u4e0d\u4e3a\u7a7a\uff0c\u5219\u5c06\u8be5\u8282\u70b9\u6dfb\u52a0\u5230\u5c3e\u8282\u70b9\u540e\n        } else {\n            rear.next = node;\n            rear = node;\n        }\n        queSize++;\n    }\n\n    /* \u51fa\u961f */\n    public int pop() {\n        int num = peek();\n        // \u5220\u9664\u5934\u8282\u70b9\n        front = front.next;\n        queSize--;\n        return num;\n    }\n\n    /* \u8bbf\u95ee\u961f\u9996\u5143\u7d20 */\n    public int peek() {\n        if (isEmpty())\n            throw new IndexOutOfBoundsException();\n        return front.val;\n    }\n\n    /* \u5c06\u94fe\u8868\u8f6c\u5316\u4e3a Array \u5e76\u8fd4\u56de */\n    public int[] toArray() {\n        ListNode node = front;\n        int[] res = new int[size()];\n        for (int i = 0; i < res.length; i++) {\n            res[i] = node.val;\n            node = node.next;\n        }\n        return res;\n    }\n}\n
linkedlist_queue.cs
/* \u57fa\u4e8e\u94fe\u8868\u5b9e\u73b0\u7684\u961f\u5217 */\nclass LinkedListQueue {\n    ListNode? front, rear;  // \u5934\u8282\u70b9 front \uff0c\u5c3e\u8282\u70b9 rear \n    int queSize = 0;\n\n    public LinkedListQueue() {\n        front = null;\n        rear = null;\n    }\n\n    /* \u83b7\u53d6\u961f\u5217\u7684\u957f\u5ea6 */\n    public int Size() {\n        return queSize;\n    }\n\n    /* \u5224\u65ad\u961f\u5217\u662f\u5426\u4e3a\u7a7a */\n    public bool IsEmpty() {\n        return Size() == 0;\n    }\n\n    /* \u5165\u961f */\n    public void Push(int num) {\n        // \u5728\u5c3e\u8282\u70b9\u540e\u6dfb\u52a0 num\n        ListNode node = new(num);\n        // \u5982\u679c\u961f\u5217\u4e3a\u7a7a\uff0c\u5219\u4ee4\u5934\u3001\u5c3e\u8282\u70b9\u90fd\u6307\u5411\u8be5\u8282\u70b9\n        if (front == null) {\n            front = node;\n            rear = node;\n            // \u5982\u679c\u961f\u5217\u4e0d\u4e3a\u7a7a\uff0c\u5219\u5c06\u8be5\u8282\u70b9\u6dfb\u52a0\u5230\u5c3e\u8282\u70b9\u540e\n        } else if (rear != null) {\n            rear.next = node;\n            rear = node;\n        }\n        queSize++;\n    }\n\n    /* \u51fa\u961f */\n    public int Pop() {\n        int num = Peek();\n        // \u5220\u9664\u5934\u8282\u70b9\n        front = front?.next;\n        queSize--;\n        return num;\n    }\n\n    /* \u8bbf\u95ee\u961f\u9996\u5143\u7d20 */\n    public int Peek() {\n        if (IsEmpty())\n            throw new Exception();\n        return front!.val;\n    }\n\n    /* \u5c06\u94fe\u8868\u8f6c\u5316\u4e3a Array \u5e76\u8fd4\u56de */\n    public int[] ToArray() {\n        if (front == null)\n            return [];\n\n        ListNode? node = front;\n        int[] res = new int[Size()];\n        for (int i = 0; i < res.Length; i++) {\n            res[i] = node!.val;\n            node = node.next;\n        }\n        return res;\n    }\n}\n
linkedlist_queue.go
/* \u57fa\u4e8e\u94fe\u8868\u5b9e\u73b0\u7684\u961f\u5217 */\ntype linkedListQueue struct {\n    // \u4f7f\u7528\u5185\u7f6e\u5305 list \u6765\u5b9e\u73b0\u961f\u5217\n    data *list.List\n}\n\n/* \u521d\u59cb\u5316\u961f\u5217 */\nfunc newLinkedListQueue() *linkedListQueue {\n    return &linkedListQueue{\n        data: list.New(),\n    }\n}\n\n/* \u5165\u961f */\nfunc (s *linkedListQueue) push(value any) {\n    s.data.PushBack(value)\n}\n\n/* \u51fa\u961f */\nfunc (s *linkedListQueue) pop() any {\n    if s.isEmpty() {\n        return nil\n    }\n    e := s.data.Front()\n    s.data.Remove(e)\n    return e.Value\n}\n\n/* \u8bbf\u95ee\u961f\u9996\u5143\u7d20 */\nfunc (s *linkedListQueue) peek() any {\n    if s.isEmpty() {\n        return nil\n    }\n    e := s.data.Front()\n    return e.Value\n}\n\n/* \u83b7\u53d6\u961f\u5217\u7684\u957f\u5ea6 */\nfunc (s *linkedListQueue) size() int {\n    return s.data.Len()\n}\n\n/* \u5224\u65ad\u961f\u5217\u662f\u5426\u4e3a\u7a7a */\nfunc (s *linkedListQueue) isEmpty() bool {\n    return s.data.Len() == 0\n}\n\n/* \u83b7\u53d6 List \u7528\u4e8e\u6253\u5370 */\nfunc (s *linkedListQueue) toList() *list.List {\n    return s.data\n}\n
linkedlist_queue.swift
/* \u57fa\u4e8e\u94fe\u8868\u5b9e\u73b0\u7684\u961f\u5217 */\nclass LinkedListQueue {\n    private var front: ListNode? // \u5934\u8282\u70b9\n    private var rear: ListNode? // \u5c3e\u8282\u70b9\n    private var _size: Int\n\n    init() {\n        _size = 0\n    }\n\n    /* \u83b7\u53d6\u961f\u5217\u7684\u957f\u5ea6 */\n    func size() -> Int {\n        _size\n    }\n\n    /* \u5224\u65ad\u961f\u5217\u662f\u5426\u4e3a\u7a7a */\n    func isEmpty() -> Bool {\n        size() == 0\n    }\n\n    /* \u5165\u961f */\n    func push(num: Int) {\n        // \u5728\u5c3e\u8282\u70b9\u540e\u6dfb\u52a0 num\n        let node = ListNode(x: num)\n        // \u5982\u679c\u961f\u5217\u4e3a\u7a7a\uff0c\u5219\u4ee4\u5934\u3001\u5c3e\u8282\u70b9\u90fd\u6307\u5411\u8be5\u8282\u70b9\n        if front == nil {\n            front = node\n            rear = node\n        }\n        // \u5982\u679c\u961f\u5217\u4e0d\u4e3a\u7a7a\uff0c\u5219\u5c06\u8be5\u8282\u70b9\u6dfb\u52a0\u5230\u5c3e\u8282\u70b9\u540e\n        else {\n            rear?.next = node\n            rear = node\n        }\n        _size += 1\n    }\n\n    /* \u51fa\u961f */\n    @discardableResult\n    func pop() -> Int {\n        let num = peek()\n        // \u5220\u9664\u5934\u8282\u70b9\n        front = front?.next\n        _size -= 1\n        return num\n    }\n\n    /* \u8bbf\u95ee\u961f\u9996\u5143\u7d20 */\n    func peek() -> Int {\n        if isEmpty() {\n            fatalError(\"\u961f\u5217\u4e3a\u7a7a\")\n        }\n        return front!.val\n    }\n\n    /* \u5c06\u94fe\u8868\u8f6c\u5316\u4e3a Array \u5e76\u8fd4\u56de */\n    func toArray() -> [Int] {\n        var node = front\n        var res = Array(repeating: 0, count: size())\n        for i in res.indices {\n            res[i] = node!.val\n            node = node?.next\n        }\n        return res\n    }\n}\n
linkedlist_queue.js
/* \u57fa\u4e8e\u94fe\u8868\u5b9e\u73b0\u7684\u961f\u5217 */\nclass LinkedListQueue {\n    #front; // \u5934\u8282\u70b9 #front\n    #rear; // \u5c3e\u8282\u70b9 #rear\n    #queSize = 0;\n\n    constructor() {\n        this.#front = null;\n        this.#rear = null;\n    }\n\n    /* \u83b7\u53d6\u961f\u5217\u7684\u957f\u5ea6 */\n    get size() {\n        return this.#queSize;\n    }\n\n    /* \u5224\u65ad\u961f\u5217\u662f\u5426\u4e3a\u7a7a */\n    isEmpty() {\n        return this.size === 0;\n    }\n\n    /* \u5165\u961f */\n    push(num) {\n        // \u5728\u5c3e\u8282\u70b9\u540e\u6dfb\u52a0 num\n        const node = new ListNode(num);\n        // \u5982\u679c\u961f\u5217\u4e3a\u7a7a\uff0c\u5219\u4ee4\u5934\u3001\u5c3e\u8282\u70b9\u90fd\u6307\u5411\u8be5\u8282\u70b9\n        if (!this.#front) {\n            this.#front = node;\n            this.#rear = node;\n            // \u5982\u679c\u961f\u5217\u4e0d\u4e3a\u7a7a\uff0c\u5219\u5c06\u8be5\u8282\u70b9\u6dfb\u52a0\u5230\u5c3e\u8282\u70b9\u540e\n        } else {\n            this.#rear.next = node;\n            this.#rear = node;\n        }\n        this.#queSize++;\n    }\n\n    /* \u51fa\u961f */\n    pop() {\n        const num = this.peek();\n        // \u5220\u9664\u5934\u8282\u70b9\n        this.#front = this.#front.next;\n        this.#queSize--;\n        return num;\n    }\n\n    /* \u8bbf\u95ee\u961f\u9996\u5143\u7d20 */\n    peek() {\n        if (this.size === 0) throw new Error('\u961f\u5217\u4e3a\u7a7a');\n        return this.#front.val;\n    }\n\n    /* \u5c06\u94fe\u8868\u8f6c\u5316\u4e3a Array \u5e76\u8fd4\u56de */\n    toArray() {\n        let node = this.#front;\n        const res = new Array(this.size);\n        for (let i = 0; i < res.length; i++) {\n            res[i] = node.val;\n            node = node.next;\n        }\n        return res;\n    }\n}\n
linkedlist_queue.ts
/* \u57fa\u4e8e\u94fe\u8868\u5b9e\u73b0\u7684\u961f\u5217 */\nclass LinkedListQueue {\n    private front: ListNode | null; // \u5934\u8282\u70b9 front\n    private rear: ListNode | null; // \u5c3e\u8282\u70b9 rear\n    private queSize: number = 0;\n\n    constructor() {\n        this.front = null;\n        this.rear = null;\n    }\n\n    /* \u83b7\u53d6\u961f\u5217\u7684\u957f\u5ea6 */\n    get size(): number {\n        return this.queSize;\n    }\n\n    /* \u5224\u65ad\u961f\u5217\u662f\u5426\u4e3a\u7a7a */\n    isEmpty(): boolean {\n        return this.size === 0;\n    }\n\n    /* \u5165\u961f */\n    push(num: number): void {\n        // \u5728\u5c3e\u8282\u70b9\u540e\u6dfb\u52a0 num\n        const node = new ListNode(num);\n        // \u5982\u679c\u961f\u5217\u4e3a\u7a7a\uff0c\u5219\u4ee4\u5934\u3001\u5c3e\u8282\u70b9\u90fd\u6307\u5411\u8be5\u8282\u70b9\n        if (!this.front) {\n            this.front = node;\n            this.rear = node;\n            // \u5982\u679c\u961f\u5217\u4e0d\u4e3a\u7a7a\uff0c\u5219\u5c06\u8be5\u8282\u70b9\u6dfb\u52a0\u5230\u5c3e\u8282\u70b9\u540e\n        } else {\n            this.rear!.next = node;\n            this.rear = node;\n        }\n        this.queSize++;\n    }\n\n    /* \u51fa\u961f */\n    pop(): number {\n        const num = this.peek();\n        if (!this.front) throw new Error('\u961f\u5217\u4e3a\u7a7a');\n        // \u5220\u9664\u5934\u8282\u70b9\n        this.front = this.front.next;\n        this.queSize--;\n        return num;\n    }\n\n    /* \u8bbf\u95ee\u961f\u9996\u5143\u7d20 */\n    peek(): number {\n        if (this.size === 0) throw new Error('\u961f\u5217\u4e3a\u7a7a');\n        return this.front!.val;\n    }\n\n    /* \u5c06\u94fe\u8868\u8f6c\u5316\u4e3a Array \u5e76\u8fd4\u56de */\n    toArray(): number[] {\n        let node = this.front;\n        const res = new Array<number>(this.size);\n        for (let i = 0; i < res.length; i++) {\n            res[i] = node!.val;\n            node = node!.next;\n        }\n        return res;\n    }\n}\n
linkedlist_queue.dart
/* \u57fa\u4e8e\u94fe\u8868\u5b9e\u73b0\u7684\u961f\u5217 */\nclass LinkedListQueue {\n  ListNode? _front; // \u5934\u8282\u70b9 _front\n  ListNode? _rear; // \u5c3e\u8282\u70b9 _rear\n  int _queSize = 0; // \u961f\u5217\u957f\u5ea6\n\n  LinkedListQueue() {\n    _front = null;\n    _rear = null;\n  }\n\n  /* \u83b7\u53d6\u961f\u5217\u7684\u957f\u5ea6 */\n  int size() {\n    return _queSize;\n  }\n\n  /* \u5224\u65ad\u961f\u5217\u662f\u5426\u4e3a\u7a7a */\n  bool isEmpty() {\n    return _queSize == 0;\n  }\n\n  /* \u5165\u961f */\n  void push(int _num) {\n    // \u5728\u5c3e\u8282\u70b9\u540e\u6dfb\u52a0 _num\n    final node = ListNode(_num);\n    // \u5982\u679c\u961f\u5217\u4e3a\u7a7a\uff0c\u5219\u4ee4\u5934\u3001\u5c3e\u8282\u70b9\u90fd\u6307\u5411\u8be5\u8282\u70b9\n    if (_front == null) {\n      _front = node;\n      _rear = node;\n    } else {\n      // \u5982\u679c\u961f\u5217\u4e0d\u4e3a\u7a7a\uff0c\u5219\u5c06\u8be5\u8282\u70b9\u6dfb\u52a0\u5230\u5c3e\u8282\u70b9\u540e\n      _rear!.next = node;\n      _rear = node;\n    }\n    _queSize++;\n  }\n\n  /* \u51fa\u961f */\n  int pop() {\n    final int _num = peek();\n    // \u5220\u9664\u5934\u8282\u70b9\n    _front = _front!.next;\n    _queSize--;\n    return _num;\n  }\n\n  /* \u8bbf\u95ee\u961f\u9996\u5143\u7d20 */\n  int peek() {\n    if (_queSize == 0) {\n      throw Exception('\u961f\u5217\u4e3a\u7a7a');\n    }\n    return _front!.val;\n  }\n\n  /* \u5c06\u94fe\u8868\u8f6c\u5316\u4e3a Array \u5e76\u8fd4\u56de */\n  List<int> toArray() {\n    ListNode? node = _front;\n    final List<int> queue = [];\n    while (node != null) {\n      queue.add(node.val);\n      node = node.next;\n    }\n    return queue;\n  }\n}\n
linkedlist_queue.rs
/* \u57fa\u4e8e\u94fe\u8868\u5b9e\u73b0\u7684\u961f\u5217 */\n#[allow(dead_code)]\npub struct LinkedListQueue<T> {\n    front: Option<Rc<RefCell<ListNode<T>>>>, // \u5934\u8282\u70b9 front\n    rear: Option<Rc<RefCell<ListNode<T>>>>,  // \u5c3e\u8282\u70b9 rear\n    que_size: usize,                         // \u961f\u5217\u7684\u957f\u5ea6\n}\n\nimpl<T: Copy> LinkedListQueue<T> {\n    pub fn new() -> Self {\n        Self {\n            front: None,\n            rear: None,\n            que_size: 0,\n        }\n    }\n\n    /* \u83b7\u53d6\u961f\u5217\u7684\u957f\u5ea6 */\n    pub fn size(&self) -> usize {\n        return self.que_size;\n    }\n\n    /* \u5224\u65ad\u961f\u5217\u662f\u5426\u4e3a\u7a7a */\n    pub fn is_empty(&self) -> bool {\n        return self.size() == 0;\n    }\n\n    /* \u5165\u961f */\n    pub fn push(&mut self, num: T) {\n        // \u5728\u5c3e\u8282\u70b9\u540e\u6dfb\u52a0 num\n        let new_rear = ListNode::new(num);\n        match self.rear.take() {\n            // \u5982\u679c\u961f\u5217\u4e0d\u4e3a\u7a7a\uff0c\u5219\u5c06\u8be5\u8282\u70b9\u6dfb\u52a0\u5230\u5c3e\u8282\u70b9\u540e\n            Some(old_rear) => {\n                old_rear.borrow_mut().next = Some(new_rear.clone());\n                self.rear = Some(new_rear);\n            }\n            // \u5982\u679c\u961f\u5217\u4e3a\u7a7a\uff0c\u5219\u4ee4\u5934\u3001\u5c3e\u8282\u70b9\u90fd\u6307\u5411\u8be5\u8282\u70b9\n            None => {\n                self.front = Some(new_rear.clone());\n                self.rear = Some(new_rear);\n            }\n        }\n        self.que_size += 1;\n    }\n\n    /* \u51fa\u961f */\n    pub fn pop(&mut self) -> Option<T> {\n        self.front.take().map(|old_front| {\n            match old_front.borrow_mut().next.take() {\n                Some(new_front) => {\n                    self.front = Some(new_front);\n                }\n                None => {\n                    self.rear.take();\n                }\n            }\n            self.que_size -= 1;\n            Rc::try_unwrap(old_front).ok().unwrap().into_inner().val\n        })\n    }\n\n    /* \u8bbf\u95ee\u961f\u9996\u5143\u7d20 */\n    pub fn peek(&self) -> Option<&Rc<RefCell<ListNode<T>>>> {\n        self.front.as_ref()\n    }\n\n    /* \u5c06\u94fe\u8868\u8f6c\u5316\u4e3a Array \u5e76\u8fd4\u56de */\n    pub fn to_array(&self, head: Option<&Rc<RefCell<ListNode<T>>>>) -> Vec<T> {\n        if let Some(node) = head {\n            let mut nums = self.to_array(node.borrow().next.as_ref());\n            nums.insert(0, node.borrow().val);\n            return nums;\n        }\n        return Vec::new();\n    }\n}\n
linkedlist_queue.c
/* \u57fa\u4e8e\u94fe\u8868\u5b9e\u73b0\u7684\u961f\u5217 */\ntypedef struct {\n    ListNode *front, *rear;\n    int queSize;\n} LinkedListQueue;\n\n/* \u6784\u9020\u51fd\u6570 */\nLinkedListQueue *newLinkedListQueue() {\n    LinkedListQueue *queue = (LinkedListQueue *)malloc(sizeof(LinkedListQueue));\n    queue->front = NULL;\n    queue->rear = NULL;\n    queue->queSize = 0;\n    return queue;\n}\n\n/* \u6790\u6784\u51fd\u6570 */\nvoid delLinkedListQueue(LinkedListQueue *queue) {\n    // \u91ca\u653e\u6240\u6709\u8282\u70b9\n    while (queue->front != NULL) {\n        ListNode *tmp = queue->front;\n        queue->front = queue->front->next;\n        free(tmp);\n    }\n    // \u91ca\u653e queue \u7ed3\u6784\u4f53\n    free(queue);\n}\n\n/* \u83b7\u53d6\u961f\u5217\u7684\u957f\u5ea6 */\nint size(LinkedListQueue *queue) {\n    return queue->queSize;\n}\n\n/* \u5224\u65ad\u961f\u5217\u662f\u5426\u4e3a\u7a7a */\nbool empty(LinkedListQueue *queue) {\n    return (size(queue) == 0);\n}\n\n/* \u5165\u961f */\nvoid push(LinkedListQueue *queue, int num) {\n    // \u5c3e\u8282\u70b9\u5904\u6dfb\u52a0 node\n    ListNode *node = newListNode(num);\n    // \u5982\u679c\u961f\u5217\u4e3a\u7a7a\uff0c\u5219\u4ee4\u5934\u3001\u5c3e\u8282\u70b9\u90fd\u6307\u5411\u8be5\u8282\u70b9\n    if (queue->front == NULL) {\n        queue->front = node;\n        queue->rear = node;\n    }\n    // \u5982\u679c\u961f\u5217\u4e0d\u4e3a\u7a7a\uff0c\u5219\u5c06\u8be5\u8282\u70b9\u6dfb\u52a0\u5230\u5c3e\u8282\u70b9\u540e\n    else {\n        queue->rear->next = node;\n        queue->rear = node;\n    }\n    queue->queSize++;\n}\n\n/* \u8bbf\u95ee\u961f\u9996\u5143\u7d20 */\nint peek(LinkedListQueue *queue) {\n    assert(size(queue) && queue->front);\n    return queue->front->val;\n}\n\n/* \u51fa\u961f */\nint pop(LinkedListQueue *queue) {\n    int num = peek(queue);\n    ListNode *tmp = queue->front;\n    queue->front = queue->front->next;\n    free(tmp);\n    queue->queSize--;\n    return num;\n}\n\n/* \u6253\u5370\u961f\u5217 */\nvoid printLinkedListQueue(LinkedListQueue *queue) {\n    int *arr = malloc(sizeof(int) * queue->queSize);\n    // \u62f7\u8d1d\u94fe\u8868\u4e2d\u7684\u6570\u636e\u5230\u6570\u7ec4\n    int i;\n    ListNode *node;\n    for (i = 0, node = queue->front; i < queue->queSize; i++) {\n        arr[i] = node->val;\n        node = node->next;\n    }\n    printArray(arr, queue->queSize);\n    free(arr);\n}\n
linkedlist_queue.zig
// \u57fa\u4e8e\u94fe\u8868\u5b9e\u73b0\u7684\u961f\u5217\nfn LinkedListQueue(comptime T: type) type {\n    return struct {\n        const Self = @This();\n\n        front: ?*inc.ListNode(T) = null,                // \u5934\u8282\u70b9 front\n        rear: ?*inc.ListNode(T) = null,                 // \u5c3e\u8282\u70b9 rear\n        que_size: usize = 0,                            // \u961f\u5217\u7684\u957f\u5ea6\n        mem_arena: ?std.heap.ArenaAllocator = null,\n        mem_allocator: std.mem.Allocator = undefined,   // \u5185\u5b58\u5206\u914d\u5668\n\n        // \u6784\u9020\u51fd\u6570\uff08\u5206\u914d\u5185\u5b58+\u521d\u59cb\u5316\u961f\u5217\uff09\n        pub fn init(self: *Self, allocator: std.mem.Allocator) !void {\n            if (self.mem_arena == null) {\n                self.mem_arena = std.heap.ArenaAllocator.init(allocator);\n                self.mem_allocator = self.mem_arena.?.allocator();\n            }\n            self.front = null;\n            self.rear = null;\n            self.que_size = 0;\n        }\n\n        // \u6790\u6784\u51fd\u6570\uff08\u91ca\u653e\u5185\u5b58\uff09\n        pub fn deinit(self: *Self) void {\n            if (self.mem_arena == null) return;\n            self.mem_arena.?.deinit();\n        }\n\n        // \u83b7\u53d6\u961f\u5217\u7684\u957f\u5ea6\n        pub fn size(self: *Self) usize {\n            return self.que_size;\n        }\n\n        // \u5224\u65ad\u961f\u5217\u662f\u5426\u4e3a\u7a7a\n        pub fn isEmpty(self: *Self) bool {\n            return self.size() == 0;\n        }\n\n        // \u8bbf\u95ee\u961f\u9996\u5143\u7d20\n        pub fn peek(self: *Self) T {\n            if (self.size() == 0) @panic(\"\u961f\u5217\u4e3a\u7a7a\");\n            return self.front.?.val;\n        }  \n\n        // \u5165\u961f\n        pub fn push(self: *Self, num: T) !void {\n            // \u5728\u5c3e\u8282\u70b9\u540e\u6dfb\u52a0 num\n            var node = try self.mem_allocator.create(inc.ListNode(T));\n            node.init(num);\n            // \u5982\u679c\u961f\u5217\u4e3a\u7a7a\uff0c\u5219\u4ee4\u5934\u3001\u5c3e\u8282\u70b9\u90fd\u6307\u5411\u8be5\u8282\u70b9\n            if (self.front == null) {\n                self.front = node;\n                self.rear = node;\n            // \u5982\u679c\u961f\u5217\u4e0d\u4e3a\u7a7a\uff0c\u5219\u5c06\u8be5\u8282\u70b9\u6dfb\u52a0\u5230\u5c3e\u8282\u70b9\u540e\n            } else {\n                self.rear.?.next = node;\n                self.rear = node;\n            }\n            self.que_size += 1;\n        } \n\n        // \u51fa\u961f\n        pub fn pop(self: *Self) T {\n            var num = self.peek();\n            // \u5220\u9664\u5934\u8282\u70b9\n            self.front = self.front.?.next;\n            self.que_size -= 1;\n            return num;\n        } \n\n        // \u5c06\u94fe\u8868\u8f6c\u6362\u4e3a\u6570\u7ec4\n        pub fn toArray(self: *Self) ![]T {\n            var node = self.front;\n            var res = try self.mem_allocator.alloc(T, self.size());\n            @memset(res, @as(T, 0));\n            var i: usize = 0;\n            while (i < res.len) : (i += 1) {\n                res[i] = node.?.val;\n                node = node.?.next;\n            }\n            return res;\n        }\n    };\n}\n
Code Visualization

Full Screen >

"},{"location":"chapter_stack_and_queue/queue/#2-implementation-based-on-an-array","title":"2. \u00a0 Implementation Based on an Array","text":"

Deleting the first element in an array has a time complexity of \\(O(n)\\), which would make the dequeue operation inefficient. However, this problem can be cleverly avoided as follows.

We use a variable front to indicate the index of the front element and maintain a variable size to record the queue's length. Define rear = front + size, which points to the position immediately following the tail element.

With this design, the effective interval of elements in the array is [front, rear - 1]. The implementation methods for various operations are shown in the Figure 5-6 .

  • Enqueue operation: Assign the input element to the rear index and increase size by 1.
  • Dequeue operation: Simply increase front by 1 and decrease size by 1.

Both enqueue and dequeue operations only require a single operation, each with a time complexity of \\(O(1)\\).

ArrayQueuepush()pop()

Figure 5-6 \u00a0 Implementing Queue with Array for Enqueue and Dequeue Operations

You might notice a problem: as enqueue and dequeue operations are continuously performed, both front and rear move to the right and will eventually reach the end of the array and can't move further. To resolve this, we can treat the array as a \"circular array\" where connecting the end of the array back to its beginning.

In a circular array, front or rear needs to loop back to the start of the array upon reaching the end. This cyclical pattern can be achieved with a \"modulo operation\" as shown in the code below:

PythonC++JavaC#GoSwiftJSTSDartRustCZig array_queue.py
class ArrayQueue:\n    \"\"\"\u57fa\u4e8e\u73af\u5f62\u6570\u7ec4\u5b9e\u73b0\u7684\u961f\u5217\"\"\"\n\n    def __init__(self, size: int):\n        \"\"\"\u6784\u9020\u65b9\u6cd5\"\"\"\n        self._nums: list[int] = [0] * size  # \u7528\u4e8e\u5b58\u50a8\u961f\u5217\u5143\u7d20\u7684\u6570\u7ec4\n        self._front: int = 0  # \u961f\u9996\u6307\u9488\uff0c\u6307\u5411\u961f\u9996\u5143\u7d20\n        self._size: int = 0  # \u961f\u5217\u957f\u5ea6\n\n    def capacity(self) -> int:\n        \"\"\"\u83b7\u53d6\u961f\u5217\u7684\u5bb9\u91cf\"\"\"\n        return len(self._nums)\n\n    def size(self) -> int:\n        \"\"\"\u83b7\u53d6\u961f\u5217\u7684\u957f\u5ea6\"\"\"\n        return self._size\n\n    def is_empty(self) -> bool:\n        \"\"\"\u5224\u65ad\u961f\u5217\u662f\u5426\u4e3a\u7a7a\"\"\"\n        return self._size == 0\n\n    def push(self, num: int):\n        \"\"\"\u5165\u961f\"\"\"\n        if self._size == self.capacity():\n            raise IndexError(\"\u961f\u5217\u5df2\u6ee1\")\n        # \u8ba1\u7b97\u961f\u5c3e\u6307\u9488\uff0c\u6307\u5411\u961f\u5c3e\u7d22\u5f15 + 1\n        # \u901a\u8fc7\u53d6\u4f59\u64cd\u4f5c\u5b9e\u73b0 rear \u8d8a\u8fc7\u6570\u7ec4\u5c3e\u90e8\u540e\u56de\u5230\u5934\u90e8\n        rear: int = (self._front + self._size) % self.capacity()\n        # \u5c06 num \u6dfb\u52a0\u81f3\u961f\u5c3e\n        self._nums[rear] = num\n        self._size += 1\n\n    def pop(self) -> int:\n        \"\"\"\u51fa\u961f\"\"\"\n        num: int = self.peek()\n        # \u961f\u9996\u6307\u9488\u5411\u540e\u79fb\u52a8\u4e00\u4f4d\uff0c\u82e5\u8d8a\u8fc7\u5c3e\u90e8\uff0c\u5219\u8fd4\u56de\u5230\u6570\u7ec4\u5934\u90e8\n        self._front = (self._front + 1) % self.capacity()\n        self._size -= 1\n        return num\n\n    def peek(self) -> int:\n        \"\"\"\u8bbf\u95ee\u961f\u9996\u5143\u7d20\"\"\"\n        if self.is_empty():\n            raise IndexError(\"\u961f\u5217\u4e3a\u7a7a\")\n        return self._nums[self._front]\n\n    def to_list(self) -> list[int]:\n        \"\"\"\u8fd4\u56de\u5217\u8868\u7528\u4e8e\u6253\u5370\"\"\"\n        res = [0] * self.size()\n        j: int = self._front\n        for i in range(self.size()):\n            res[i] = self._nums[(j % self.capacity())]\n            j += 1\n        return res\n
array_queue.cpp
/* \u57fa\u4e8e\u73af\u5f62\u6570\u7ec4\u5b9e\u73b0\u7684\u961f\u5217 */\nclass ArrayQueue {\n  private:\n    int *nums;       // \u7528\u4e8e\u5b58\u50a8\u961f\u5217\u5143\u7d20\u7684\u6570\u7ec4\n    int front;       // \u961f\u9996\u6307\u9488\uff0c\u6307\u5411\u961f\u9996\u5143\u7d20\n    int queSize;     // \u961f\u5217\u957f\u5ea6\n    int queCapacity; // \u961f\u5217\u5bb9\u91cf\n\n  public:\n    ArrayQueue(int capacity) {\n        // \u521d\u59cb\u5316\u6570\u7ec4\n        nums = new int[capacity];\n        queCapacity = capacity;\n        front = queSize = 0;\n    }\n\n    ~ArrayQueue() {\n        delete[] nums;\n    }\n\n    /* \u83b7\u53d6\u961f\u5217\u7684\u5bb9\u91cf */\n    int capacity() {\n        return queCapacity;\n    }\n\n    /* \u83b7\u53d6\u961f\u5217\u7684\u957f\u5ea6 */\n    int size() {\n        return queSize;\n    }\n\n    /* \u5224\u65ad\u961f\u5217\u662f\u5426\u4e3a\u7a7a */\n    bool isEmpty() {\n        return size() == 0;\n    }\n\n    /* \u5165\u961f */\n    void push(int num) {\n        if (queSize == queCapacity) {\n            cout << \"\u961f\u5217\u5df2\u6ee1\" << endl;\n            return;\n        }\n        // \u8ba1\u7b97\u961f\u5c3e\u6307\u9488\uff0c\u6307\u5411\u961f\u5c3e\u7d22\u5f15 + 1\n        // \u901a\u8fc7\u53d6\u4f59\u64cd\u4f5c\u5b9e\u73b0 rear \u8d8a\u8fc7\u6570\u7ec4\u5c3e\u90e8\u540e\u56de\u5230\u5934\u90e8\n        int rear = (front + queSize) % queCapacity;\n        // \u5c06 num \u6dfb\u52a0\u81f3\u961f\u5c3e\n        nums[rear] = num;\n        queSize++;\n    }\n\n    /* \u51fa\u961f */\n    int pop() {\n        int num = peek();\n        // \u961f\u9996\u6307\u9488\u5411\u540e\u79fb\u52a8\u4e00\u4f4d\uff0c\u82e5\u8d8a\u8fc7\u5c3e\u90e8\uff0c\u5219\u8fd4\u56de\u5230\u6570\u7ec4\u5934\u90e8\n        front = (front + 1) % queCapacity;\n        queSize--;\n        return num;\n    }\n\n    /* \u8bbf\u95ee\u961f\u9996\u5143\u7d20 */\n    int peek() {\n        if (isEmpty())\n            throw out_of_range(\"\u961f\u5217\u4e3a\u7a7a\");\n        return nums[front];\n    }\n\n    /* \u5c06\u6570\u7ec4\u8f6c\u5316\u4e3a Vector \u5e76\u8fd4\u56de */\n    vector<int> toVector() {\n        // \u4ec5\u8f6c\u6362\u6709\u6548\u957f\u5ea6\u8303\u56f4\u5185\u7684\u5217\u8868\u5143\u7d20\n        vector<int> arr(queSize);\n        for (int i = 0, j = front; i < queSize; i++, j++) {\n            arr[i] = nums[j % queCapacity];\n        }\n        return arr;\n    }\n};\n
array_queue.java
/* \u57fa\u4e8e\u73af\u5f62\u6570\u7ec4\u5b9e\u73b0\u7684\u961f\u5217 */\nclass ArrayQueue {\n    private int[] nums; // \u7528\u4e8e\u5b58\u50a8\u961f\u5217\u5143\u7d20\u7684\u6570\u7ec4\n    private int front; // \u961f\u9996\u6307\u9488\uff0c\u6307\u5411\u961f\u9996\u5143\u7d20\n    private int queSize; // \u961f\u5217\u957f\u5ea6\n\n    public ArrayQueue(int capacity) {\n        nums = new int[capacity];\n        front = queSize = 0;\n    }\n\n    /* \u83b7\u53d6\u961f\u5217\u7684\u5bb9\u91cf */\n    public int capacity() {\n        return nums.length;\n    }\n\n    /* \u83b7\u53d6\u961f\u5217\u7684\u957f\u5ea6 */\n    public int size() {\n        return queSize;\n    }\n\n    /* \u5224\u65ad\u961f\u5217\u662f\u5426\u4e3a\u7a7a */\n    public boolean isEmpty() {\n        return queSize == 0;\n    }\n\n    /* \u5165\u961f */\n    public void push(int num) {\n        if (queSize == capacity()) {\n            System.out.println(\"\u961f\u5217\u5df2\u6ee1\");\n            return;\n        }\n        // \u8ba1\u7b97\u961f\u5c3e\u6307\u9488\uff0c\u6307\u5411\u961f\u5c3e\u7d22\u5f15 + 1\n        // \u901a\u8fc7\u53d6\u4f59\u64cd\u4f5c\u5b9e\u73b0 rear \u8d8a\u8fc7\u6570\u7ec4\u5c3e\u90e8\u540e\u56de\u5230\u5934\u90e8\n        int rear = (front + queSize) % capacity();\n        // \u5c06 num \u6dfb\u52a0\u81f3\u961f\u5c3e\n        nums[rear] = num;\n        queSize++;\n    }\n\n    /* \u51fa\u961f */\n    public int pop() {\n        int num = peek();\n        // \u961f\u9996\u6307\u9488\u5411\u540e\u79fb\u52a8\u4e00\u4f4d\uff0c\u82e5\u8d8a\u8fc7\u5c3e\u90e8\uff0c\u5219\u8fd4\u56de\u5230\u6570\u7ec4\u5934\u90e8\n        front = (front + 1) % capacity();\n        queSize--;\n        return num;\n    }\n\n    /* \u8bbf\u95ee\u961f\u9996\u5143\u7d20 */\n    public int peek() {\n        if (isEmpty())\n            throw new IndexOutOfBoundsException();\n        return nums[front];\n    }\n\n    /* \u8fd4\u56de\u6570\u7ec4 */\n    public int[] toArray() {\n        // \u4ec5\u8f6c\u6362\u6709\u6548\u957f\u5ea6\u8303\u56f4\u5185\u7684\u5217\u8868\u5143\u7d20\n        int[] res = new int[queSize];\n        for (int i = 0, j = front; i < queSize; i++, j++) {\n            res[i] = nums[j % capacity()];\n        }\n        return res;\n    }\n}\n
array_queue.cs
/* \u57fa\u4e8e\u73af\u5f62\u6570\u7ec4\u5b9e\u73b0\u7684\u961f\u5217 */\nclass ArrayQueue {\n    int[] nums;  // \u7528\u4e8e\u5b58\u50a8\u961f\u5217\u5143\u7d20\u7684\u6570\u7ec4\n    int front;   // \u961f\u9996\u6307\u9488\uff0c\u6307\u5411\u961f\u9996\u5143\u7d20\n    int queSize; // \u961f\u5217\u957f\u5ea6\n\n    public ArrayQueue(int capacity) {\n        nums = new int[capacity];\n        front = queSize = 0;\n    }\n\n    /* \u83b7\u53d6\u961f\u5217\u7684\u5bb9\u91cf */\n    int Capacity() {\n        return nums.Length;\n    }\n\n    /* \u83b7\u53d6\u961f\u5217\u7684\u957f\u5ea6 */\n    public int Size() {\n        return queSize;\n    }\n\n    /* \u5224\u65ad\u961f\u5217\u662f\u5426\u4e3a\u7a7a */\n    public bool IsEmpty() {\n        return queSize == 0;\n    }\n\n    /* \u5165\u961f */\n    public void Push(int num) {\n        if (queSize == Capacity()) {\n            Console.WriteLine(\"\u961f\u5217\u5df2\u6ee1\");\n            return;\n        }\n        // \u8ba1\u7b97\u961f\u5c3e\u6307\u9488\uff0c\u6307\u5411\u961f\u5c3e\u7d22\u5f15 + 1\n        // \u901a\u8fc7\u53d6\u4f59\u64cd\u4f5c\u5b9e\u73b0 rear \u8d8a\u8fc7\u6570\u7ec4\u5c3e\u90e8\u540e\u56de\u5230\u5934\u90e8\n        int rear = (front + queSize) % Capacity();\n        // \u5c06 num \u6dfb\u52a0\u81f3\u961f\u5c3e\n        nums[rear] = num;\n        queSize++;\n    }\n\n    /* \u51fa\u961f */\n    public int Pop() {\n        int num = Peek();\n        // \u961f\u9996\u6307\u9488\u5411\u540e\u79fb\u52a8\u4e00\u4f4d\uff0c\u82e5\u8d8a\u8fc7\u5c3e\u90e8\uff0c\u5219\u8fd4\u56de\u5230\u6570\u7ec4\u5934\u90e8\n        front = (front + 1) % Capacity();\n        queSize--;\n        return num;\n    }\n\n    /* \u8bbf\u95ee\u961f\u9996\u5143\u7d20 */\n    public int Peek() {\n        if (IsEmpty())\n            throw new Exception();\n        return nums[front];\n    }\n\n    /* \u8fd4\u56de\u6570\u7ec4 */\n    public int[] ToArray() {\n        // \u4ec5\u8f6c\u6362\u6709\u6548\u957f\u5ea6\u8303\u56f4\u5185\u7684\u5217\u8868\u5143\u7d20\n        int[] res = new int[queSize];\n        for (int i = 0, j = front; i < queSize; i++, j++) {\n            res[i] = nums[j % this.Capacity()];\n        }\n        return res;\n    }\n}\n
array_queue.go
/* \u57fa\u4e8e\u73af\u5f62\u6570\u7ec4\u5b9e\u73b0\u7684\u961f\u5217 */\ntype arrayQueue struct {\n    nums        []int // \u7528\u4e8e\u5b58\u50a8\u961f\u5217\u5143\u7d20\u7684\u6570\u7ec4\n    front       int   // \u961f\u9996\u6307\u9488\uff0c\u6307\u5411\u961f\u9996\u5143\u7d20\n    queSize     int   // \u961f\u5217\u957f\u5ea6\n    queCapacity int   // \u961f\u5217\u5bb9\u91cf\uff08\u5373\u6700\u5927\u5bb9\u7eb3\u5143\u7d20\u6570\u91cf\uff09\n}\n\n/* \u521d\u59cb\u5316\u961f\u5217 */\nfunc newArrayQueue(queCapacity int) *arrayQueue {\n    return &arrayQueue{\n        nums:        make([]int, queCapacity),\n        queCapacity: queCapacity,\n        front:       0,\n        queSize:     0,\n    }\n}\n\n/* \u83b7\u53d6\u961f\u5217\u7684\u957f\u5ea6 */\nfunc (q *arrayQueue) size() int {\n    return q.queSize\n}\n\n/* \u5224\u65ad\u961f\u5217\u662f\u5426\u4e3a\u7a7a */\nfunc (q *arrayQueue) isEmpty() bool {\n    return q.queSize == 0\n}\n\n/* \u5165\u961f */\nfunc (q *arrayQueue) push(num int) {\n    // \u5f53 rear == queCapacity \u8868\u793a\u961f\u5217\u5df2\u6ee1\n    if q.queSize == q.queCapacity {\n        return\n    }\n    // \u8ba1\u7b97\u961f\u5c3e\u6307\u9488\uff0c\u6307\u5411\u961f\u5c3e\u7d22\u5f15 + 1\n    // \u901a\u8fc7\u53d6\u4f59\u64cd\u4f5c\u5b9e\u73b0 rear \u8d8a\u8fc7\u6570\u7ec4\u5c3e\u90e8\u540e\u56de\u5230\u5934\u90e8\n    rear := (q.front + q.queSize) % q.queCapacity\n    // \u5c06 num \u6dfb\u52a0\u81f3\u961f\u5c3e\n    q.nums[rear] = num\n    q.queSize++\n}\n\n/* \u51fa\u961f */\nfunc (q *arrayQueue) pop() any {\n    num := q.peek()\n    // \u961f\u9996\u6307\u9488\u5411\u540e\u79fb\u52a8\u4e00\u4f4d\uff0c\u82e5\u8d8a\u8fc7\u5c3e\u90e8\uff0c\u5219\u8fd4\u56de\u5230\u6570\u7ec4\u5934\u90e8\n    q.front = (q.front + 1) % q.queCapacity\n    q.queSize--\n    return num\n}\n\n/* \u8bbf\u95ee\u961f\u9996\u5143\u7d20 */\nfunc (q *arrayQueue) peek() any {\n    if q.isEmpty() {\n        return nil\n    }\n    return q.nums[q.front]\n}\n\n/* \u83b7\u53d6 Slice \u7528\u4e8e\u6253\u5370 */\nfunc (q *arrayQueue) toSlice() []int {\n    rear := (q.front + q.queSize)\n    if rear >= q.queCapacity {\n        rear %= q.queCapacity\n        return append(q.nums[q.front:], q.nums[:rear]...)\n    }\n    return q.nums[q.front:rear]\n}\n
array_queue.swift
/* \u57fa\u4e8e\u73af\u5f62\u6570\u7ec4\u5b9e\u73b0\u7684\u961f\u5217 */\nclass ArrayQueue {\n    private var nums: [Int] // \u7528\u4e8e\u5b58\u50a8\u961f\u5217\u5143\u7d20\u7684\u6570\u7ec4\n    private var front: Int // \u961f\u9996\u6307\u9488\uff0c\u6307\u5411\u961f\u9996\u5143\u7d20\n    private var _size: Int // \u961f\u5217\u957f\u5ea6\n\n    init(capacity: Int) {\n        // \u521d\u59cb\u5316\u6570\u7ec4\n        nums = Array(repeating: 0, count: capacity)\n        front = 0\n        _size = 0\n    }\n\n    /* \u83b7\u53d6\u961f\u5217\u7684\u5bb9\u91cf */\n    func capacity() -> Int {\n        nums.count\n    }\n\n    /* \u83b7\u53d6\u961f\u5217\u7684\u957f\u5ea6 */\n    func size() -> Int {\n        _size\n    }\n\n    /* \u5224\u65ad\u961f\u5217\u662f\u5426\u4e3a\u7a7a */\n    func isEmpty() -> Bool {\n        size() == 0\n    }\n\n    /* \u5165\u961f */\n    func push(num: Int) {\n        if size() == capacity() {\n            print(\"\u961f\u5217\u5df2\u6ee1\")\n            return\n        }\n        // \u8ba1\u7b97\u961f\u5c3e\u6307\u9488\uff0c\u6307\u5411\u961f\u5c3e\u7d22\u5f15 + 1\n        // \u901a\u8fc7\u53d6\u4f59\u64cd\u4f5c\u5b9e\u73b0 rear \u8d8a\u8fc7\u6570\u7ec4\u5c3e\u90e8\u540e\u56de\u5230\u5934\u90e8\n        let rear = (front + size()) % capacity()\n        // \u5c06 num \u6dfb\u52a0\u81f3\u961f\u5c3e\n        nums[rear] = num\n        _size += 1\n    }\n\n    /* \u51fa\u961f */\n    @discardableResult\n    func pop() -> Int {\n        let num = peek()\n        // \u961f\u9996\u6307\u9488\u5411\u540e\u79fb\u52a8\u4e00\u4f4d\uff0c\u82e5\u8d8a\u8fc7\u5c3e\u90e8\uff0c\u5219\u8fd4\u56de\u5230\u6570\u7ec4\u5934\u90e8\n        front = (front + 1) % capacity()\n        _size -= 1\n        return num\n    }\n\n    /* \u8bbf\u95ee\u961f\u9996\u5143\u7d20 */\n    func peek() -> Int {\n        if isEmpty() {\n            fatalError(\"\u961f\u5217\u4e3a\u7a7a\")\n        }\n        return nums[front]\n    }\n\n    /* \u8fd4\u56de\u6570\u7ec4 */\n    func toArray() -> [Int] {\n        // \u4ec5\u8f6c\u6362\u6709\u6548\u957f\u5ea6\u8303\u56f4\u5185\u7684\u5217\u8868\u5143\u7d20\n        (front ..< front + size()).map { nums[$0 % capacity()] }\n    }\n}\n
array_queue.js
/* \u57fa\u4e8e\u73af\u5f62\u6570\u7ec4\u5b9e\u73b0\u7684\u961f\u5217 */\nclass ArrayQueue {\n    #nums; // \u7528\u4e8e\u5b58\u50a8\u961f\u5217\u5143\u7d20\u7684\u6570\u7ec4\n    #front = 0; // \u961f\u9996\u6307\u9488\uff0c\u6307\u5411\u961f\u9996\u5143\u7d20\n    #queSize = 0; // \u961f\u5217\u957f\u5ea6\n\n    constructor(capacity) {\n        this.#nums = new Array(capacity);\n    }\n\n    /* \u83b7\u53d6\u961f\u5217\u7684\u5bb9\u91cf */\n    get capacity() {\n        return this.#nums.length;\n    }\n\n    /* \u83b7\u53d6\u961f\u5217\u7684\u957f\u5ea6 */\n    get size() {\n        return this.#queSize;\n    }\n\n    /* \u5224\u65ad\u961f\u5217\u662f\u5426\u4e3a\u7a7a */\n    isEmpty() {\n        return this.#queSize === 0;\n    }\n\n    /* \u5165\u961f */\n    push(num) {\n        if (this.size === this.capacity) {\n            console.log('\u961f\u5217\u5df2\u6ee1');\n            return;\n        }\n        // \u8ba1\u7b97\u961f\u5c3e\u6307\u9488\uff0c\u6307\u5411\u961f\u5c3e\u7d22\u5f15 + 1\n        // \u901a\u8fc7\u53d6\u4f59\u64cd\u4f5c\u5b9e\u73b0 rear \u8d8a\u8fc7\u6570\u7ec4\u5c3e\u90e8\u540e\u56de\u5230\u5934\u90e8\n        const rear = (this.#front + this.size) % this.capacity;\n        // \u5c06 num \u6dfb\u52a0\u81f3\u961f\u5c3e\n        this.#nums[rear] = num;\n        this.#queSize++;\n    }\n\n    /* \u51fa\u961f */\n    pop() {\n        const num = this.peek();\n        // \u961f\u9996\u6307\u9488\u5411\u540e\u79fb\u52a8\u4e00\u4f4d\uff0c\u82e5\u8d8a\u8fc7\u5c3e\u90e8\uff0c\u5219\u8fd4\u56de\u5230\u6570\u7ec4\u5934\u90e8\n        this.#front = (this.#front + 1) % this.capacity;\n        this.#queSize--;\n        return num;\n    }\n\n    /* \u8bbf\u95ee\u961f\u9996\u5143\u7d20 */\n    peek() {\n        if (this.isEmpty()) throw new Error('\u961f\u5217\u4e3a\u7a7a');\n        return this.#nums[this.#front];\n    }\n\n    /* \u8fd4\u56de Array */\n    toArray() {\n        // \u4ec5\u8f6c\u6362\u6709\u6548\u957f\u5ea6\u8303\u56f4\u5185\u7684\u5217\u8868\u5143\u7d20\n        const arr = new Array(this.size);\n        for (let i = 0, j = this.#front; i < this.size; i++, j++) {\n            arr[i] = this.#nums[j % this.capacity];\n        }\n        return arr;\n    }\n}\n
array_queue.ts
/* \u57fa\u4e8e\u73af\u5f62\u6570\u7ec4\u5b9e\u73b0\u7684\u961f\u5217 */\nclass ArrayQueue {\n    private nums: number[]; // \u7528\u4e8e\u5b58\u50a8\u961f\u5217\u5143\u7d20\u7684\u6570\u7ec4\n    private front: number; // \u961f\u9996\u6307\u9488\uff0c\u6307\u5411\u961f\u9996\u5143\u7d20\n    private queSize: number; // \u961f\u5217\u957f\u5ea6\n\n    constructor(capacity: number) {\n        this.nums = new Array(capacity);\n        this.front = this.queSize = 0;\n    }\n\n    /* \u83b7\u53d6\u961f\u5217\u7684\u5bb9\u91cf */\n    get capacity(): number {\n        return this.nums.length;\n    }\n\n    /* \u83b7\u53d6\u961f\u5217\u7684\u957f\u5ea6 */\n    get size(): number {\n        return this.queSize;\n    }\n\n    /* \u5224\u65ad\u961f\u5217\u662f\u5426\u4e3a\u7a7a */\n    isEmpty(): boolean {\n        return this.queSize === 0;\n    }\n\n    /* \u5165\u961f */\n    push(num: number): void {\n        if (this.size === this.capacity) {\n            console.log('\u961f\u5217\u5df2\u6ee1');\n            return;\n        }\n        // \u8ba1\u7b97\u961f\u5c3e\u6307\u9488\uff0c\u6307\u5411\u961f\u5c3e\u7d22\u5f15 + 1\n        // \u901a\u8fc7\u53d6\u4f59\u64cd\u4f5c\u5b9e\u73b0 rear \u8d8a\u8fc7\u6570\u7ec4\u5c3e\u90e8\u540e\u56de\u5230\u5934\u90e8\n        const rear = (this.front + this.queSize) % this.capacity;\n        // \u5c06 num \u6dfb\u52a0\u81f3\u961f\u5c3e\n        this.nums[rear] = num;\n        this.queSize++;\n    }\n\n    /* \u51fa\u961f */\n    pop(): number {\n        const num = this.peek();\n        // \u961f\u9996\u6307\u9488\u5411\u540e\u79fb\u52a8\u4e00\u4f4d\uff0c\u82e5\u8d8a\u8fc7\u5c3e\u90e8\uff0c\u5219\u8fd4\u56de\u5230\u6570\u7ec4\u5934\u90e8\n        this.front = (this.front + 1) % this.capacity;\n        this.queSize--;\n        return num;\n    }\n\n    /* \u8bbf\u95ee\u961f\u9996\u5143\u7d20 */\n    peek(): number {\n        if (this.isEmpty()) throw new Error('\u961f\u5217\u4e3a\u7a7a');\n        return this.nums[this.front];\n    }\n\n    /* \u8fd4\u56de Array */\n    toArray(): number[] {\n        // \u4ec5\u8f6c\u6362\u6709\u6548\u957f\u5ea6\u8303\u56f4\u5185\u7684\u5217\u8868\u5143\u7d20\n        const arr = new Array(this.size);\n        for (let i = 0, j = this.front; i < this.size; i++, j++) {\n            arr[i] = this.nums[j % this.capacity];\n        }\n        return arr;\n    }\n}\n
array_queue.dart
/* \u57fa\u4e8e\u73af\u5f62\u6570\u7ec4\u5b9e\u73b0\u7684\u961f\u5217 */\nclass ArrayQueue {\n  late List<int> _nums; // \u7528\u4e8e\u50a8\u5b58\u961f\u5217\u5143\u7d20\u7684\u6570\u7ec4\n  late int _front; // \u961f\u9996\u6307\u9488\uff0c\u6307\u5411\u961f\u9996\u5143\u7d20\n  late int _queSize; // \u961f\u5217\u957f\u5ea6\n\n  ArrayQueue(int capacity) {\n    _nums = List.filled(capacity, 0);\n    _front = _queSize = 0;\n  }\n\n  /* \u83b7\u53d6\u961f\u5217\u7684\u5bb9\u91cf */\n  int capaCity() {\n    return _nums.length;\n  }\n\n  /* \u83b7\u53d6\u961f\u5217\u7684\u957f\u5ea6 */\n  int size() {\n    return _queSize;\n  }\n\n  /* \u5224\u65ad\u961f\u5217\u662f\u5426\u4e3a\u7a7a */\n  bool isEmpty() {\n    return _queSize == 0;\n  }\n\n  /* \u5165\u961f */\n  void push(int _num) {\n    if (_queSize == capaCity()) {\n      throw Exception(\"\u961f\u5217\u5df2\u6ee1\");\n    }\n    // \u8ba1\u7b97\u961f\u5c3e\u6307\u9488\uff0c\u6307\u5411\u961f\u5c3e\u7d22\u5f15 + 1\n    // \u901a\u8fc7\u53d6\u4f59\u64cd\u4f5c\u5b9e\u73b0 rear \u8d8a\u8fc7\u6570\u7ec4\u5c3e\u90e8\u540e\u56de\u5230\u5934\u90e8\n    int rear = (_front + _queSize) % capaCity();\n    // \u5c06 _num \u6dfb\u52a0\u81f3\u961f\u5c3e\n    _nums[rear] = _num;\n    _queSize++;\n  }\n\n  /* \u51fa\u961f */\n  int pop() {\n    int _num = peek();\n    // \u961f\u9996\u6307\u9488\u5411\u540e\u79fb\u52a8\u4e00\u4f4d\uff0c\u82e5\u8d8a\u8fc7\u5c3e\u90e8\uff0c\u5219\u8fd4\u56de\u5230\u6570\u7ec4\u5934\u90e8\n    _front = (_front + 1) % capaCity();\n    _queSize--;\n    return _num;\n  }\n\n  /* \u8bbf\u95ee\u961f\u9996\u5143\u7d20 */\n  int peek() {\n    if (isEmpty()) {\n      throw Exception(\"\u961f\u5217\u4e3a\u7a7a\");\n    }\n    return _nums[_front];\n  }\n\n  /* \u8fd4\u56de Array */\n  List<int> toArray() {\n    // \u4ec5\u8f6c\u6362\u6709\u6548\u957f\u5ea6\u8303\u56f4\u5185\u7684\u5217\u8868\u5143\u7d20\n    final List<int> res = List.filled(_queSize, 0);\n    for (int i = 0, j = _front; i < _queSize; i++, j++) {\n      res[i] = _nums[j % capaCity()];\n    }\n    return res;\n  }\n}\n
array_queue.rs
/* \u57fa\u4e8e\u73af\u5f62\u6570\u7ec4\u5b9e\u73b0\u7684\u961f\u5217 */\nstruct ArrayQueue {\n    nums: Vec<i32>,    // \u7528\u4e8e\u5b58\u50a8\u961f\u5217\u5143\u7d20\u7684\u6570\u7ec4\n    front: i32,        // \u961f\u9996\u6307\u9488\uff0c\u6307\u5411\u961f\u9996\u5143\u7d20\n    que_size: i32,     // \u961f\u5217\u957f\u5ea6\n    que_capacity: i32, // \u961f\u5217\u5bb9\u91cf\n}\n\nimpl ArrayQueue {\n    /* \u6784\u9020\u65b9\u6cd5 */\n    fn new(capacity: i32) -> ArrayQueue {\n        ArrayQueue {\n            nums: vec![0; capacity as usize],\n            front: 0,\n            que_size: 0,\n            que_capacity: capacity,\n        }\n    }\n\n    /* \u83b7\u53d6\u961f\u5217\u7684\u5bb9\u91cf */\n    fn capacity(&self) -> i32 {\n        self.que_capacity\n    }\n\n    /* \u83b7\u53d6\u961f\u5217\u7684\u957f\u5ea6 */\n    fn size(&self) -> i32 {\n        self.que_size\n    }\n\n    /* \u5224\u65ad\u961f\u5217\u662f\u5426\u4e3a\u7a7a */\n    fn is_empty(&self) -> bool {\n        self.que_size == 0\n    }\n\n    /* \u5165\u961f */\n    fn push(&mut self, num: i32) {\n        if self.que_size == self.capacity() {\n            println!(\"\u961f\u5217\u5df2\u6ee1\");\n            return;\n        }\n        // \u8ba1\u7b97\u961f\u5c3e\u6307\u9488\uff0c\u6307\u5411\u961f\u5c3e\u7d22\u5f15 + 1\n        // \u901a\u8fc7\u53d6\u4f59\u64cd\u4f5c\u5b9e\u73b0 rear \u8d8a\u8fc7\u6570\u7ec4\u5c3e\u90e8\u540e\u56de\u5230\u5934\u90e8\n        let rear = (self.front + self.que_size) % self.que_capacity;\n        // \u5c06 num \u6dfb\u52a0\u81f3\u961f\u5c3e\n        self.nums[rear as usize] = num;\n        self.que_size += 1;\n    }\n\n    /* \u51fa\u961f */\n    fn pop(&mut self) -> i32 {\n        let num = self.peek();\n        // \u961f\u9996\u6307\u9488\u5411\u540e\u79fb\u52a8\u4e00\u4f4d\uff0c\u82e5\u8d8a\u8fc7\u5c3e\u90e8\uff0c\u5219\u8fd4\u56de\u5230\u6570\u7ec4\u5934\u90e8\n        self.front = (self.front + 1) % self.que_capacity;\n        self.que_size -= 1;\n        num\n    }\n\n    /* \u8bbf\u95ee\u961f\u9996\u5143\u7d20 */\n    fn peek(&self) -> i32 {\n        if self.is_empty() {\n            panic!(\"index out of bounds\");\n        }\n        self.nums[self.front as usize]\n    }\n\n    /* \u8fd4\u56de\u6570\u7ec4 */\n    fn to_vector(&self) -> Vec<i32> {\n        let cap = self.que_capacity;\n        let mut j = self.front;\n        let mut arr = vec![0; self.que_size as usize];\n        for i in 0..self.que_size {\n            arr[i as usize] = self.nums[(j % cap) as usize];\n            j += 1;\n        }\n        arr\n    }\n}\n
array_queue.c
/* \u57fa\u4e8e\u73af\u5f62\u6570\u7ec4\u5b9e\u73b0\u7684\u961f\u5217 */\ntypedef struct {\n    int *nums;       // \u7528\u4e8e\u5b58\u50a8\u961f\u5217\u5143\u7d20\u7684\u6570\u7ec4\n    int front;       // \u961f\u9996\u6307\u9488\uff0c\u6307\u5411\u961f\u9996\u5143\u7d20\n    int queSize;     // \u5c3e\u6307\u9488\uff0c\u6307\u5411\u961f\u5c3e + 1\n    int queCapacity; // \u961f\u5217\u5bb9\u91cf\n} ArrayQueue;\n\n/* \u6784\u9020\u51fd\u6570 */\nArrayQueue *newArrayQueue(int capacity) {\n    ArrayQueue *queue = (ArrayQueue *)malloc(sizeof(ArrayQueue));\n    // \u521d\u59cb\u5316\u6570\u7ec4\n    queue->queCapacity = capacity;\n    queue->nums = (int *)malloc(sizeof(int) * queue->queCapacity);\n    queue->front = queue->queSize = 0;\n    return queue;\n}\n\n/* \u6790\u6784\u51fd\u6570 */\nvoid delArrayQueue(ArrayQueue *queue) {\n    free(queue->nums);\n    free(queue);\n}\n\n/* \u83b7\u53d6\u961f\u5217\u7684\u5bb9\u91cf */\nint capacity(ArrayQueue *queue) {\n    return queue->queCapacity;\n}\n\n/* \u83b7\u53d6\u961f\u5217\u7684\u957f\u5ea6 */\nint size(ArrayQueue *queue) {\n    return queue->queSize;\n}\n\n/* \u5224\u65ad\u961f\u5217\u662f\u5426\u4e3a\u7a7a */\nbool empty(ArrayQueue *queue) {\n    return queue->queSize == 0;\n}\n\n/* \u8bbf\u95ee\u961f\u9996\u5143\u7d20 */\nint peek(ArrayQueue *queue) {\n    assert(size(queue) != 0);\n    return queue->nums[queue->front];\n}\n\n/* \u5165\u961f */\nvoid push(ArrayQueue *queue, int num) {\n    if (size(queue) == capacity(queue)) {\n        printf(\"\u961f\u5217\u5df2\u6ee1\\r\\n\");\n        return;\n    }\n    // \u8ba1\u7b97\u961f\u5c3e\u6307\u9488\uff0c\u6307\u5411\u961f\u5c3e\u7d22\u5f15 + 1\n    // \u901a\u8fc7\u53d6\u4f59\u64cd\u4f5c\u5b9e\u73b0 rear \u8d8a\u8fc7\u6570\u7ec4\u5c3e\u90e8\u540e\u56de\u5230\u5934\u90e8\n    int rear = (queue->front + queue->queSize) % queue->queCapacity;\n    // \u5c06 num \u6dfb\u52a0\u81f3\u961f\u5c3e\n    queue->nums[rear] = num;\n    queue->queSize++;\n}\n\n/* \u51fa\u961f */\nint pop(ArrayQueue *queue) {\n    int num = peek(queue);\n    // \u961f\u9996\u6307\u9488\u5411\u540e\u79fb\u52a8\u4e00\u4f4d\uff0c\u82e5\u8d8a\u8fc7\u5c3e\u90e8\uff0c\u5219\u8fd4\u56de\u5230\u6570\u7ec4\u5934\u90e8\n    queue->front = (queue->front + 1) % queue->queCapacity;\n    queue->queSize--;\n    return num;\n}\n
array_queue.zig
// \u57fa\u4e8e\u73af\u5f62\u6570\u7ec4\u5b9e\u73b0\u7684\u961f\u5217\nfn ArrayQueue(comptime T: type) type {\n    return struct {\n        const Self = @This();\n\n        nums: []T = undefined,                          // \u7528\u4e8e\u5b58\u50a8\u961f\u5217\u5143\u7d20\u7684\u6570\u7ec4     \n        cap: usize = 0,                                 // \u961f\u5217\u5bb9\u91cf\n        front: usize = 0,                               // \u961f\u9996\u6307\u9488\uff0c\u6307\u5411\u961f\u9996\u5143\u7d20\n        queSize: usize = 0,                             // \u5c3e\u6307\u9488\uff0c\u6307\u5411\u961f\u5c3e + 1\n        mem_arena: ?std.heap.ArenaAllocator = null,\n        mem_allocator: std.mem.Allocator = undefined,   // \u5185\u5b58\u5206\u914d\u5668\n\n        // \u6784\u9020\u51fd\u6570\uff08\u5206\u914d\u5185\u5b58+\u521d\u59cb\u5316\u6570\u7ec4\uff09\n        pub fn init(self: *Self, allocator: std.mem.Allocator, cap: usize) !void {\n            if (self.mem_arena == null) {\n                self.mem_arena = std.heap.ArenaAllocator.init(allocator);\n                self.mem_allocator = self.mem_arena.?.allocator();\n            }\n            self.cap = cap;\n            self.nums = try self.mem_allocator.alloc(T, self.cap);\n            @memset(self.nums, @as(T, 0));\n        }\n\n        // \u6790\u6784\u51fd\u6570\uff08\u91ca\u653e\u5185\u5b58\uff09\n        pub fn deinit(self: *Self) void {\n            if (self.mem_arena == null) return;\n            self.mem_arena.?.deinit();\n        }\n\n        // \u83b7\u53d6\u961f\u5217\u7684\u5bb9\u91cf\n        pub fn capacity(self: *Self) usize {\n            return self.cap;\n        }\n\n        // \u83b7\u53d6\u961f\u5217\u7684\u957f\u5ea6\n        pub fn size(self: *Self) usize {\n            return self.queSize;\n        }\n\n        // \u5224\u65ad\u961f\u5217\u662f\u5426\u4e3a\u7a7a\n        pub fn isEmpty(self: *Self) bool {\n            return self.queSize == 0;\n        }\n\n        // \u5165\u961f\n        pub fn push(self: *Self, num: T) !void {\n            if (self.size() == self.capacity()) {\n                std.debug.print(\"\u961f\u5217\u5df2\u6ee1\\n\", .{});\n                return;\n            }\n            // \u8ba1\u7b97\u961f\u5c3e\u6307\u9488\uff0c\u6307\u5411\u961f\u5c3e\u7d22\u5f15 + 1\n            // \u901a\u8fc7\u53d6\u4f59\u64cd\u4f5c\u5b9e\u73b0 rear \u8d8a\u8fc7\u6570\u7ec4\u5c3e\u90e8\u540e\u56de\u5230\u5934\u90e8\n            var rear = (self.front + self.queSize) % self.capacity();\n            // \u5728\u5c3e\u8282\u70b9\u540e\u6dfb\u52a0 num\n            self.nums[rear] = num;\n            self.queSize += 1;\n        } \n\n        // \u51fa\u961f\n        pub fn pop(self: *Self) T {\n            var num = self.peek();\n            // \u961f\u9996\u6307\u9488\u5411\u540e\u79fb\u52a8\u4e00\u4f4d\uff0c\u82e5\u8d8a\u8fc7\u5c3e\u90e8\uff0c\u5219\u8fd4\u56de\u5230\u6570\u7ec4\u5934\u90e8\n            self.front = (self.front + 1) % self.capacity();\n            self.queSize -= 1;\n            return num;\n        } \n\n        // \u8bbf\u95ee\u961f\u9996\u5143\u7d20\n        pub fn peek(self: *Self) T {\n            if (self.isEmpty()) @panic(\"\u961f\u5217\u4e3a\u7a7a\");\n            return self.nums[self.front];\n        } \n\n        // \u8fd4\u56de\u6570\u7ec4\n        pub fn toArray(self: *Self) ![]T {\n            // \u4ec5\u8f6c\u6362\u6709\u6548\u957f\u5ea6\u8303\u56f4\u5185\u7684\u5217\u8868\u5143\u7d20\n            var res = try self.mem_allocator.alloc(T, self.size());\n            @memset(res, @as(T, 0));\n            var i: usize = 0;\n            var j: usize = self.front;\n            while (i < self.size()) : ({ i += 1; j += 1; }) {\n                res[i] = self.nums[j % self.capacity()];\n            }\n            return res;\n        }\n    };\n}\n
Code Visualization

Full Screen >

The above implementation of the queue still has its limitations: its length is fixed. However, this issue is not difficult to resolve. We can replace the array with a dynamic array that can expand itself if needed. Interested readers can try to implement this themselves.

The comparison of the two implementations is consistent with that of the stack and is not repeated here.

"},{"location":"chapter_stack_and_queue/queue/#523-typical-applications-of-queue","title":"5.2.3 \u00a0 Typical Applications of Queue","text":"
  • Amazon Orders. After shoppers place orders, these orders join a queue, and the system processes them in order. During events like Singles' Day, a massive number of orders are generated in a short time, making high concurrency a key challenge for engineers.
  • Various To-Do Lists. Any scenario requiring a \"first-come, first-served\" functionality, such as a printer's task queue or a restaurant's food delivery queue, can effectively maintain the order of processing with a queue.
"},{"location":"chapter_stack_and_queue/stack/","title":"5.1 \u00a0 Stack","text":"

A \"Stack\" is a linear data structure that follows the principle of Last-In-First-Out (LIFO).

We can compare a stack to a pile of plates on a table. To access the bottom plate, one must first remove the plates on top. By replacing the plates with various types of elements (such as integers, characters, objects, etc.), we obtain the data structure known as a stack.

As shown in the Figure 5-1 , we refer to the top of the pile of elements as the \"top of the stack\" and the bottom as the \"bottom of the stack.\" The operation of adding elements to the top of the stack is called \"push,\" and the operation of removing the top element is called \"pop.\"

Figure 5-1 \u00a0 Stack's Last-In-First-Out Rule

"},{"location":"chapter_stack_and_queue/stack/#511-common-operations-on-stack","title":"5.1.1 \u00a0 Common Operations on Stack","text":"

The common operations on a stack are shown in the Table 5-1 . The specific method names depend on the programming language used. Here, we use push(), pop(), and peek() as examples.

Table 5-1 \u00a0 Efficiency of Stack Operations

Method Description Time Complexity push() Push an element onto the stack (add to the top) \\(O(1)\\) pop() Pop the top element from the stack \\(O(1)\\) peek() Access the top element of the stack \\(O(1)\\)

Typically, we can directly use the stack class built into the programming language. However, some languages may not specifically provide a stack class. In these cases, we can use the language's \"array\" or \"linked list\" as a stack and ignore operations that are not related to stack logic in the program.

PythonC++JavaC#GoSwiftJSTSDartRustCZig stack.py
# Initialize the stack\n# Python does not have a built-in stack class, so a list can be used as a stack\nstack: list[int] = []\n\n# Push elements onto the stack\nstack.append(1)\nstack.append(3)\nstack.append(2)\nstack.append(5)\nstack.append(4)\n\n# Access the top element of the stack\npeek: int = stack[-1]\n\n# Pop an element from the stack\npop: int = stack.pop()\n\n# Get the length of the stack\nsize: int = len(stack)\n\n# Check if the stack is empty\nis_empty: bool = len(stack) == 0\n
stack.cpp
/* Initialize the stack */\nstack<int> stack;\n\n/* Push elements onto the stack */\nstack.push(1);\nstack.push(3);\nstack.push(2);\nstack.push(5);\nstack.push(4);\n\n/* Access the top element of the stack */\nint top = stack.top();\n\n/* Pop an element from the stack */\nstack.pop(); // No return value\n\n/* Get the length of the stack */\nint size = stack.size();\n\n/* Check if the stack is empty */\nbool empty = stack.empty();\n
stack.java
/* Initialize the stack */\nStack<Integer> stack = new Stack<>();\n\n/* Push elements onto the stack */\nstack.push(1);\nstack.push(3);\nstack.push(2);\nstack.push(5);\nstack.push(4);\n\n/* Access the top element of the stack */\nint peek = stack.peek();\n\n/* Pop an element from the stack */\nint pop = stack.pop();\n\n/* Get the length of the stack */\nint size = stack.size();\n\n/* Check if the stack is empty */\nboolean isEmpty = stack.isEmpty();\n
stack.cs
/* Initialize the stack */\nStack<int> stack = new();\n\n/* Push elements onto the stack */\nstack.Push(1);\nstack.Push(3);\nstack.Push(2);\nstack.Push(5);\nstack.Push(4);\n\n/* Access the top element of the stack */\nint peek = stack.Peek();\n\n/* Pop an element from the stack */\nint pop = stack.Pop();\n\n/* Get the length of the stack */\nint size = stack.Count;\n\n/* Check if the stack is empty */\nbool isEmpty = stack.Count == 0;\n
stack_test.go
/* Initialize the stack */\n// In Go, it is recommended to use a Slice as a stack\nvar stack []int\n\n/* Push elements onto the stack */\nstack = append(stack, 1)\nstack = append(stack, 3)\nstack = append(stack, 2)\nstack = append(stack, 5)\nstack = append(stack, 4)\n\n/* Access the top element of the stack */\npeek := stack[len(stack)-1]\n\n/* Pop an element from the stack */\npop := stack[len(stack)-1]\nstack = stack[:len(stack)-1]\n\n/* Get the length of the stack */\nsize := len(stack)\n\n/* Check if the stack is empty */\nisEmpty := len(stack) == 0\n
stack.swift
/* Initialize the stack */\n// Swift does not have a built-in stack class, so Array can be used as a stack\nvar stack: [Int] = []\n\n/* Push elements onto the stack */\nstack.append(1)\nstack.append(3)\nstack.append(2)\nstack.append(5)\nstack.append(4)\n\n/* Access the top element of the stack */\nlet peek = stack.last!\n\n/* Pop an element from the stack */\nlet pop = stack.removeLast()\n\n/* Get the length of the stack */\nlet size = stack.count\n\n/* Check if the stack is empty */\nlet isEmpty = stack.isEmpty\n
stack.js
/* Initialize the stack */\n// JavaScript does not have a built-in stack class, so Array can be used as a stack\nconst stack = [];\n\n/* Push elements onto the stack */\nstack.push(1);\nstack.push(3);\nstack.push(2);\nstack.push(5);\nstack.push(4);\n\n/* Access the top element of the stack */\nconst peek = stack[stack.length-1];\n\n/* Pop an element from the stack */\nconst pop = stack.pop();\n\n/* Get the length of the stack */\nconst size = stack.length;\n\n/* Check if the stack is empty */\nconst is_empty = stack.length === 0;\n
stack.ts
/* Initialize the stack */\n// TypeScript does not have a built-in stack class, so Array can be used as a stack\nconst stack: number[] = [];\n\n/* Push elements onto the stack */\nstack.push(1);\nstack.push(3);\nstack.push(2);\nstack.push(5);\nstack.push(4);\n\n/* Access the top element of the stack */\nconst peek = stack[stack.length - 1];\n\n/* Pop an element from the stack */\nconst pop = stack.pop();\n\n/* Get the length of the stack */\nconst size = stack.length;\n\n/* Check if the stack is empty */\nconst is_empty = stack.length === 0;\n
stack.dart
/* Initialize the stack */\n// Dart does not have a built-in stack class, so List can be used as a stack\nList<int> stack = [];\n\n/* Push elements onto the stack */\nstack.add(1);\nstack.add(3);\nstack.add(2);\nstack.add(5);\nstack.add(4);\n\n/* Access the top element of the stack */\nint peek = stack.last;\n\n/* Pop an element from the stack */\nint pop = stack.removeLast();\n\n/* Get the length of the stack */\nint size = stack.length;\n\n/* Check if the stack is empty */\nbool isEmpty = stack.isEmpty;\n
stack.rs
/* Initialize the stack */\n// Use Vec as a stack\nlet mut stack: Vec<i32> = Vec::new();\n\n/* Push elements onto the stack */\nstack.push(1);\nstack.push(3);\nstack.push(2);\nstack.push(5);\nstack.push(4);\n\n/* Access the top element of the stack */\nlet top = stack.last().unwrap();\n\n/* Pop an element from the stack */\nlet pop = stack.pop().unwrap();\n\n/* Get the length of the stack */\nlet size = stack.len();\n\n/* Check if the stack is empty */\nlet is_empty = stack.is_empty();\n
stack.c
// C does not provide a built-in stack\n
stack.zig
\n
Code Visualization

Full Screen >

"},{"location":"chapter_stack_and_queue/stack/#512-implementing-a-stack","title":"5.1.2 \u00a0 Implementing a Stack","text":"

To gain a deeper understanding of how a stack operates, let's try implementing a stack class ourselves.

A stack follows the principle of Last-In-First-Out, which means we can only add or remove elements at the top of the stack. However, both arrays and linked lists allow adding and removing elements at any position, therefore a stack can be seen as a restricted array or linked list. In other words, we can \"shield\" certain irrelevant operations of an array or linked list, aligning their external behavior with the characteristics of a stack.

"},{"location":"chapter_stack_and_queue/stack/#1-implementation-based-on-linked-list","title":"1. \u00a0 Implementation Based on Linked List","text":"

When implementing a stack using a linked list, we can consider the head node of the list as the top of the stack and the tail node as the bottom of the stack.

As shown in the Figure 5-2 , for the push operation, we simply insert elements at the head of the linked list. This method of node insertion is known as \"head insertion.\" For the pop operation, we just need to remove the head node from the list.

LinkedListStackpush()pop()

Figure 5-2 \u00a0 Implementing Stack with Linked List for Push and Pop Operations

Below is an example code for implementing a stack based on a linked list:

PythonC++JavaC#GoSwiftJSTSDartRustCZig linkedlist_stack.py
class LinkedListStack:\n    \"\"\"\u57fa\u4e8e\u94fe\u8868\u5b9e\u73b0\u7684\u6808\"\"\"\n\n    def __init__(self):\n        \"\"\"\u6784\u9020\u65b9\u6cd5\"\"\"\n        self._peek: ListNode | None = None\n        self._size: int = 0\n\n    def size(self) -> int:\n        \"\"\"\u83b7\u53d6\u6808\u7684\u957f\u5ea6\"\"\"\n        return self._size\n\n    def is_empty(self) -> bool:\n        \"\"\"\u5224\u65ad\u6808\u662f\u5426\u4e3a\u7a7a\"\"\"\n        return not self._peek\n\n    def push(self, val: int):\n        \"\"\"\u5165\u6808\"\"\"\n        node = ListNode(val)\n        node.next = self._peek\n        self._peek = node\n        self._size += 1\n\n    def pop(self) -> int:\n        \"\"\"\u51fa\u6808\"\"\"\n        num = self.peek()\n        self._peek = self._peek.next\n        self._size -= 1\n        return num\n\n    def peek(self) -> int:\n        \"\"\"\u8bbf\u95ee\u6808\u9876\u5143\u7d20\"\"\"\n        if self.is_empty():\n            raise IndexError(\"\u6808\u4e3a\u7a7a\")\n        return self._peek.val\n\n    def to_list(self) -> list[int]:\n        \"\"\"\u8f6c\u5316\u4e3a\u5217\u8868\u7528\u4e8e\u6253\u5370\"\"\"\n        arr = []\n        node = self._peek\n        while node:\n            arr.append(node.val)\n            node = node.next\n        arr.reverse()\n        return arr\n
linkedlist_stack.cpp
/* \u57fa\u4e8e\u94fe\u8868\u5b9e\u73b0\u7684\u6808 */\nclass LinkedListStack {\n  private:\n    ListNode *stackTop; // \u5c06\u5934\u8282\u70b9\u4f5c\u4e3a\u6808\u9876\n    int stkSize;        // \u6808\u7684\u957f\u5ea6\n\n  public:\n    LinkedListStack() {\n        stackTop = nullptr;\n        stkSize = 0;\n    }\n\n    ~LinkedListStack() {\n        // \u904d\u5386\u94fe\u8868\u5220\u9664\u8282\u70b9\uff0c\u91ca\u653e\u5185\u5b58\n        freeMemoryLinkedList(stackTop);\n    }\n\n    /* \u83b7\u53d6\u6808\u7684\u957f\u5ea6 */\n    int size() {\n        return stkSize;\n    }\n\n    /* \u5224\u65ad\u6808\u662f\u5426\u4e3a\u7a7a */\n    bool isEmpty() {\n        return size() == 0;\n    }\n\n    /* \u5165\u6808 */\n    void push(int num) {\n        ListNode *node = new ListNode(num);\n        node->next = stackTop;\n        stackTop = node;\n        stkSize++;\n    }\n\n    /* \u51fa\u6808 */\n    int pop() {\n        int num = top();\n        ListNode *tmp = stackTop;\n        stackTop = stackTop->next;\n        // \u91ca\u653e\u5185\u5b58\n        delete tmp;\n        stkSize--;\n        return num;\n    }\n\n    /* \u8bbf\u95ee\u6808\u9876\u5143\u7d20 */\n    int top() {\n        if (isEmpty())\n            throw out_of_range(\"\u6808\u4e3a\u7a7a\");\n        return stackTop->val;\n    }\n\n    /* \u5c06 List \u8f6c\u5316\u4e3a Array \u5e76\u8fd4\u56de */\n    vector<int> toVector() {\n        ListNode *node = stackTop;\n        vector<int> res(size());\n        for (int i = res.size() - 1; i >= 0; i--) {\n            res[i] = node->val;\n            node = node->next;\n        }\n        return res;\n    }\n};\n
linkedlist_stack.java
/* \u57fa\u4e8e\u94fe\u8868\u5b9e\u73b0\u7684\u6808 */\nclass LinkedListStack {\n    private ListNode stackPeek; // \u5c06\u5934\u8282\u70b9\u4f5c\u4e3a\u6808\u9876\n    private int stkSize = 0; // \u6808\u7684\u957f\u5ea6\n\n    public LinkedListStack() {\n        stackPeek = null;\n    }\n\n    /* \u83b7\u53d6\u6808\u7684\u957f\u5ea6 */\n    public int size() {\n        return stkSize;\n    }\n\n    /* \u5224\u65ad\u6808\u662f\u5426\u4e3a\u7a7a */\n    public boolean isEmpty() {\n        return size() == 0;\n    }\n\n    /* \u5165\u6808 */\n    public void push(int num) {\n        ListNode node = new ListNode(num);\n        node.next = stackPeek;\n        stackPeek = node;\n        stkSize++;\n    }\n\n    /* \u51fa\u6808 */\n    public int pop() {\n        int num = peek();\n        stackPeek = stackPeek.next;\n        stkSize--;\n        return num;\n    }\n\n    /* \u8bbf\u95ee\u6808\u9876\u5143\u7d20 */\n    public int peek() {\n        if (isEmpty())\n            throw new IndexOutOfBoundsException();\n        return stackPeek.val;\n    }\n\n    /* \u5c06 List \u8f6c\u5316\u4e3a Array \u5e76\u8fd4\u56de */\n    public int[] toArray() {\n        ListNode node = stackPeek;\n        int[] res = new int[size()];\n        for (int i = res.length - 1; i >= 0; i--) {\n            res[i] = node.val;\n            node = node.next;\n        }\n        return res;\n    }\n}\n
linkedlist_stack.cs
/* \u57fa\u4e8e\u94fe\u8868\u5b9e\u73b0\u7684\u6808 */\nclass LinkedListStack {\n    ListNode? stackPeek;  // \u5c06\u5934\u8282\u70b9\u4f5c\u4e3a\u6808\u9876\n    int stkSize = 0;   // \u6808\u7684\u957f\u5ea6\n\n    public LinkedListStack() {\n        stackPeek = null;\n    }\n\n    /* \u83b7\u53d6\u6808\u7684\u957f\u5ea6 */\n    public int Size() {\n        return stkSize;\n    }\n\n    /* \u5224\u65ad\u6808\u662f\u5426\u4e3a\u7a7a */\n    public bool IsEmpty() {\n        return Size() == 0;\n    }\n\n    /* \u5165\u6808 */\n    public void Push(int num) {\n        ListNode node = new(num) {\n            next = stackPeek\n        };\n        stackPeek = node;\n        stkSize++;\n    }\n\n    /* \u51fa\u6808 */\n    public int Pop() {\n        int num = Peek();\n        stackPeek = stackPeek!.next;\n        stkSize--;\n        return num;\n    }\n\n    /* \u8bbf\u95ee\u6808\u9876\u5143\u7d20 */\n    public int Peek() {\n        if (IsEmpty())\n            throw new Exception();\n        return stackPeek!.val;\n    }\n\n    /* \u5c06 List \u8f6c\u5316\u4e3a Array \u5e76\u8fd4\u56de */\n    public int[] ToArray() {\n        if (stackPeek == null)\n            return [];\n\n        ListNode? node = stackPeek;\n        int[] res = new int[Size()];\n        for (int i = res.Length - 1; i >= 0; i--) {\n            res[i] = node!.val;\n            node = node.next;\n        }\n        return res;\n    }\n}\n
linkedlist_stack.go
/* \u57fa\u4e8e\u94fe\u8868\u5b9e\u73b0\u7684\u6808 */\ntype linkedListStack struct {\n    // \u4f7f\u7528\u5185\u7f6e\u5305 list \u6765\u5b9e\u73b0\u6808\n    data *list.List\n}\n\n/* \u521d\u59cb\u5316\u6808 */\nfunc newLinkedListStack() *linkedListStack {\n    return &linkedListStack{\n        data: list.New(),\n    }\n}\n\n/* \u5165\u6808 */\nfunc (s *linkedListStack) push(value int) {\n    s.data.PushBack(value)\n}\n\n/* \u51fa\u6808 */\nfunc (s *linkedListStack) pop() any {\n    if s.isEmpty() {\n        return nil\n    }\n    e := s.data.Back()\n    s.data.Remove(e)\n    return e.Value\n}\n\n/* \u8bbf\u95ee\u6808\u9876\u5143\u7d20 */\nfunc (s *linkedListStack) peek() any {\n    if s.isEmpty() {\n        return nil\n    }\n    e := s.data.Back()\n    return e.Value\n}\n\n/* \u83b7\u53d6\u6808\u7684\u957f\u5ea6 */\nfunc (s *linkedListStack) size() int {\n    return s.data.Len()\n}\n\n/* \u5224\u65ad\u6808\u662f\u5426\u4e3a\u7a7a */\nfunc (s *linkedListStack) isEmpty() bool {\n    return s.data.Len() == 0\n}\n\n/* \u83b7\u53d6 List \u7528\u4e8e\u6253\u5370 */\nfunc (s *linkedListStack) toList() *list.List {\n    return s.data\n}\n
linkedlist_stack.swift
/* \u57fa\u4e8e\u94fe\u8868\u5b9e\u73b0\u7684\u6808 */\nclass LinkedListStack {\n    private var _peek: ListNode? // \u5c06\u5934\u8282\u70b9\u4f5c\u4e3a\u6808\u9876\n    private var _size: Int // \u6808\u7684\u957f\u5ea6\n\n    init() {\n        _size = 0\n    }\n\n    /* \u83b7\u53d6\u6808\u7684\u957f\u5ea6 */\n    func size() -> Int {\n        _size\n    }\n\n    /* \u5224\u65ad\u6808\u662f\u5426\u4e3a\u7a7a */\n    func isEmpty() -> Bool {\n        size() == 0\n    }\n\n    /* \u5165\u6808 */\n    func push(num: Int) {\n        let node = ListNode(x: num)\n        node.next = _peek\n        _peek = node\n        _size += 1\n    }\n\n    /* \u51fa\u6808 */\n    @discardableResult\n    func pop() -> Int {\n        let num = peek()\n        _peek = _peek?.next\n        _size -= 1\n        return num\n    }\n\n    /* \u8bbf\u95ee\u6808\u9876\u5143\u7d20 */\n    func peek() -> Int {\n        if isEmpty() {\n            fatalError(\"\u6808\u4e3a\u7a7a\")\n        }\n        return _peek!.val\n    }\n\n    /* \u5c06 List \u8f6c\u5316\u4e3a Array \u5e76\u8fd4\u56de */\n    func toArray() -> [Int] {\n        var node = _peek\n        var res = Array(repeating: 0, count: size())\n        for i in res.indices.reversed() {\n            res[i] = node!.val\n            node = node?.next\n        }\n        return res\n    }\n}\n
linkedlist_stack.js
/* \u57fa\u4e8e\u94fe\u8868\u5b9e\u73b0\u7684\u6808 */\nclass LinkedListStack {\n    #stackPeek; // \u5c06\u5934\u8282\u70b9\u4f5c\u4e3a\u6808\u9876\n    #stkSize = 0; // \u6808\u7684\u957f\u5ea6\n\n    constructor() {\n        this.#stackPeek = null;\n    }\n\n    /* \u83b7\u53d6\u6808\u7684\u957f\u5ea6 */\n    get size() {\n        return this.#stkSize;\n    }\n\n    /* \u5224\u65ad\u6808\u662f\u5426\u4e3a\u7a7a */\n    isEmpty() {\n        return this.size === 0;\n    }\n\n    /* \u5165\u6808 */\n    push(num) {\n        const node = new ListNode(num);\n        node.next = this.#stackPeek;\n        this.#stackPeek = node;\n        this.#stkSize++;\n    }\n\n    /* \u51fa\u6808 */\n    pop() {\n        const num = this.peek();\n        this.#stackPeek = this.#stackPeek.next;\n        this.#stkSize--;\n        return num;\n    }\n\n    /* \u8bbf\u95ee\u6808\u9876\u5143\u7d20 */\n    peek() {\n        if (!this.#stackPeek) throw new Error('\u6808\u4e3a\u7a7a');\n        return this.#stackPeek.val;\n    }\n\n    /* \u5c06\u94fe\u8868\u8f6c\u5316\u4e3a Array \u5e76\u8fd4\u56de */\n    toArray() {\n        let node = this.#stackPeek;\n        const res = new Array(this.size);\n        for (let i = res.length - 1; i >= 0; i--) {\n            res[i] = node.val;\n            node = node.next;\n        }\n        return res;\n    }\n}\n
linkedlist_stack.ts
/* \u57fa\u4e8e\u94fe\u8868\u5b9e\u73b0\u7684\u6808 */\nclass LinkedListStack {\n    private stackPeek: ListNode | null; // \u5c06\u5934\u8282\u70b9\u4f5c\u4e3a\u6808\u9876\n    private stkSize: number = 0; // \u6808\u7684\u957f\u5ea6\n\n    constructor() {\n        this.stackPeek = null;\n    }\n\n    /* \u83b7\u53d6\u6808\u7684\u957f\u5ea6 */\n    get size(): number {\n        return this.stkSize;\n    }\n\n    /* \u5224\u65ad\u6808\u662f\u5426\u4e3a\u7a7a */\n    isEmpty(): boolean {\n        return this.size === 0;\n    }\n\n    /* \u5165\u6808 */\n    push(num: number): void {\n        const node = new ListNode(num);\n        node.next = this.stackPeek;\n        this.stackPeek = node;\n        this.stkSize++;\n    }\n\n    /* \u51fa\u6808 */\n    pop(): number {\n        const num = this.peek();\n        if (!this.stackPeek) throw new Error('\u6808\u4e3a\u7a7a');\n        this.stackPeek = this.stackPeek.next;\n        this.stkSize--;\n        return num;\n    }\n\n    /* \u8bbf\u95ee\u6808\u9876\u5143\u7d20 */\n    peek(): number {\n        if (!this.stackPeek) throw new Error('\u6808\u4e3a\u7a7a');\n        return this.stackPeek.val;\n    }\n\n    /* \u5c06\u94fe\u8868\u8f6c\u5316\u4e3a Array \u5e76\u8fd4\u56de */\n    toArray(): number[] {\n        let node = this.stackPeek;\n        const res = new Array<number>(this.size);\n        for (let i = res.length - 1; i >= 0; i--) {\n            res[i] = node!.val;\n            node = node!.next;\n        }\n        return res;\n    }\n}\n
linkedlist_stack.dart
/* \u57fa\u4e8e\u94fe\u8868\u7c7b\u5b9e\u73b0\u7684\u6808 */\nclass LinkedListStack {\n  ListNode? _stackPeek; // \u5c06\u5934\u8282\u70b9\u4f5c\u4e3a\u6808\u9876\n  int _stkSize = 0; // \u6808\u7684\u957f\u5ea6\n\n  LinkedListStack() {\n    _stackPeek = null;\n  }\n\n  /* \u83b7\u53d6\u6808\u7684\u957f\u5ea6 */\n  int size() {\n    return _stkSize;\n  }\n\n  /* \u5224\u65ad\u6808\u662f\u5426\u4e3a\u7a7a */\n  bool isEmpty() {\n    return _stkSize == 0;\n  }\n\n  /* \u5165\u6808 */\n  void push(int _num) {\n    final ListNode node = ListNode(_num);\n    node.next = _stackPeek;\n    _stackPeek = node;\n    _stkSize++;\n  }\n\n  /* \u51fa\u6808 */\n  int pop() {\n    final int _num = peek();\n    _stackPeek = _stackPeek!.next;\n    _stkSize--;\n    return _num;\n  }\n\n  /* \u8bbf\u95ee\u6808\u9876\u5143\u7d20 */\n  int peek() {\n    if (_stackPeek == null) {\n      throw Exception(\"\u6808\u4e3a\u7a7a\");\n    }\n    return _stackPeek!.val;\n  }\n\n  /* \u5c06\u94fe\u8868\u8f6c\u5316\u4e3a List \u5e76\u8fd4\u56de */\n  List<int> toList() {\n    ListNode? node = _stackPeek;\n    List<int> list = [];\n    while (node != null) {\n      list.add(node.val);\n      node = node.next;\n    }\n    list = list.reversed.toList();\n    return list;\n  }\n}\n
linkedlist_stack.rs
/* \u57fa\u4e8e\u94fe\u8868\u5b9e\u73b0\u7684\u6808 */\n#[allow(dead_code)]\npub struct LinkedListStack<T> {\n    stack_peek: Option<Rc<RefCell<ListNode<T>>>>, // \u5c06\u5934\u8282\u70b9\u4f5c\u4e3a\u6808\u9876\n    stk_size: usize,                              // \u6808\u7684\u957f\u5ea6\n}\n\nimpl<T: Copy> LinkedListStack<T> {\n    pub fn new() -> Self {\n        Self {\n            stack_peek: None,\n            stk_size: 0,\n        }\n    }\n\n    /* \u83b7\u53d6\u6808\u7684\u957f\u5ea6 */\n    pub fn size(&self) -> usize {\n        return self.stk_size;\n    }\n\n    /* \u5224\u65ad\u6808\u662f\u5426\u4e3a\u7a7a */\n    pub fn is_empty(&self) -> bool {\n        return self.size() == 0;\n    }\n\n    /* \u5165\u6808 */\n    pub fn push(&mut self, num: T) {\n        let node = ListNode::new(num);\n        node.borrow_mut().next = self.stack_peek.take();\n        self.stack_peek = Some(node);\n        self.stk_size += 1;\n    }\n\n    /* \u51fa\u6808 */\n    pub fn pop(&mut self) -> Option<T> {\n        self.stack_peek.take().map(|old_head| {\n            match old_head.borrow_mut().next.take() {\n                Some(new_head) => {\n                    self.stack_peek = Some(new_head);\n                }\n                None => {\n                    self.stack_peek = None;\n                }\n            }\n            self.stk_size -= 1;\n            Rc::try_unwrap(old_head).ok().unwrap().into_inner().val\n        })\n    }\n\n    /* \u8bbf\u95ee\u6808\u9876\u5143\u7d20 */\n    pub fn peek(&self) -> Option<&Rc<RefCell<ListNode<T>>>> {\n        self.stack_peek.as_ref()\n    }\n\n    /* \u5c06 List \u8f6c\u5316\u4e3a Array \u5e76\u8fd4\u56de */\n    pub fn to_array(&self, head: Option<&Rc<RefCell<ListNode<T>>>>) -> Vec<T> {\n        if let Some(node) = head {\n            let mut nums = self.to_array(node.borrow().next.as_ref());\n            nums.push(node.borrow().val);\n            return nums;\n        }\n        return Vec::new();\n    }\n}\n
linkedlist_stack.c
/* \u57fa\u4e8e\u94fe\u8868\u5b9e\u73b0\u7684\u6808 */\ntypedef struct {\n    ListNode *top; // \u5c06\u5934\u8282\u70b9\u4f5c\u4e3a\u6808\u9876\n    int size;      // \u6808\u7684\u957f\u5ea6\n} LinkedListStack;\n\n/* \u6784\u9020\u51fd\u6570 */\nLinkedListStack *newLinkedListStack() {\n    LinkedListStack *s = malloc(sizeof(LinkedListStack));\n    s->top = NULL;\n    s->size = 0;\n    return s;\n}\n\n/* \u6790\u6784\u51fd\u6570 */\nvoid delLinkedListStack(LinkedListStack *s) {\n    while (s->top) {\n        ListNode *n = s->top->next;\n        free(s->top);\n        s->top = n;\n    }\n    free(s);\n}\n\n/* \u83b7\u53d6\u6808\u7684\u957f\u5ea6 */\nint size(LinkedListStack *s) {\n    return s->size;\n}\n\n/* \u5224\u65ad\u6808\u662f\u5426\u4e3a\u7a7a */\nbool isEmpty(LinkedListStack *s) {\n    return size(s) == 0;\n}\n\n/* \u5165\u6808 */\nvoid push(LinkedListStack *s, int num) {\n    ListNode *node = (ListNode *)malloc(sizeof(ListNode));\n    node->next = s->top; // \u66f4\u65b0\u65b0\u52a0\u8282\u70b9\u6307\u9488\u57df\n    node->val = num;     // \u66f4\u65b0\u65b0\u52a0\u8282\u70b9\u6570\u636e\u57df\n    s->top = node;       // \u66f4\u65b0\u6808\u9876\n    s->size++;           // \u66f4\u65b0\u6808\u5927\u5c0f\n}\n\n/* \u8bbf\u95ee\u6808\u9876\u5143\u7d20 */\nint peek(LinkedListStack *s) {\n    if (s->size == 0) {\n        printf(\"\u6808\u4e3a\u7a7a\\n\");\n        return INT_MAX;\n    }\n    return s->top->val;\n}\n\n/* \u51fa\u6808 */\nint pop(LinkedListStack *s) {\n    int val = peek(s);\n    ListNode *tmp = s->top;\n    s->top = s->top->next;\n    // \u91ca\u653e\u5185\u5b58\n    free(tmp);\n    s->size--;\n    return val;\n}\n
linkedlist_stack.zig
// \u57fa\u4e8e\u94fe\u8868\u5b9e\u73b0\u7684\u6808\nfn LinkedListStack(comptime T: type) type {\n    return struct {\n        const Self = @This();\n\n        stack_top: ?*inc.ListNode(T) = null,             // \u5c06\u5934\u8282\u70b9\u4f5c\u4e3a\u6808\u9876\n        stk_size: usize = 0,                             // \u6808\u7684\u957f\u5ea6\n        mem_arena: ?std.heap.ArenaAllocator = null,\n        mem_allocator: std.mem.Allocator = undefined,    // \u5185\u5b58\u5206\u914d\u5668\n\n        // \u6784\u9020\u51fd\u6570\uff08\u5206\u914d\u5185\u5b58+\u521d\u59cb\u5316\u6808\uff09\n        pub fn init(self: *Self, allocator: std.mem.Allocator) !void {\n            if (self.mem_arena == null) {\n                self.mem_arena = std.heap.ArenaAllocator.init(allocator);\n                self.mem_allocator = self.mem_arena.?.allocator();\n            }\n            self.stack_top = null;\n            self.stk_size = 0;\n        }\n\n        // \u6790\u6784\u51fd\u6570\uff08\u91ca\u653e\u5185\u5b58\uff09\n        pub fn deinit(self: *Self) void {\n            if (self.mem_arena == null) return;\n            self.mem_arena.?.deinit();\n        }\n\n        // \u83b7\u53d6\u6808\u7684\u957f\u5ea6\n        pub fn size(self: *Self) usize {\n            return self.stk_size;\n        }\n\n        // \u5224\u65ad\u6808\u662f\u5426\u4e3a\u7a7a\n        pub fn isEmpty(self: *Self) bool {\n            return self.size() == 0;\n        }\n\n        // \u8bbf\u95ee\u6808\u9876\u5143\u7d20\n        pub fn peek(self: *Self) T {\n            if (self.size() == 0) @panic(\"\u6808\u4e3a\u7a7a\");\n            return self.stack_top.?.val;\n        }  \n\n        // \u5165\u6808\n        pub fn push(self: *Self, num: T) !void {\n            var node = try self.mem_allocator.create(inc.ListNode(T));\n            node.init(num);\n            node.next = self.stack_top;\n            self.stack_top = node;\n            self.stk_size += 1;\n        } \n\n        // \u51fa\u6808\n        pub fn pop(self: *Self) T {\n            var num = self.peek();\n            self.stack_top = self.stack_top.?.next;\n            self.stk_size -= 1;\n            return num;\n        } \n\n        // \u5c06\u6808\u8f6c\u6362\u4e3a\u6570\u7ec4\n        pub fn toArray(self: *Self) ![]T {\n            var node = self.stack_top;\n            var res = try self.mem_allocator.alloc(T, self.size());\n            @memset(res, @as(T, 0));\n            var i: usize = 0;\n            while (i < res.len) : (i += 1) {\n                res[res.len - i - 1] = node.?.val;\n                node = node.?.next;\n            }\n            return res;\n        }\n    };\n}\n
Code Visualization

Full Screen >

"},{"location":"chapter_stack_and_queue/stack/#2-implementation-based-on-array","title":"2. \u00a0 Implementation Based on Array","text":"

When implementing a stack using an array, we can consider the end of the array as the top of the stack. As shown in the Figure 5-3 , push and pop operations correspond to adding and removing elements at the end of the array, respectively, both with a time complexity of \\(O(1)\\).

ArrayStackpush()pop()

Figure 5-3 \u00a0 Implementing Stack with Array for Push and Pop Operations

Since the elements to be pushed onto the stack may continuously increase, we can use a dynamic array, thus avoiding the need to handle array expansion ourselves. Here is an example code:

PythonC++JavaC#GoSwiftJSTSDartRustCZig array_stack.py
class ArrayStack:\n    \"\"\"\u57fa\u4e8e\u6570\u7ec4\u5b9e\u73b0\u7684\u6808\"\"\"\n\n    def __init__(self):\n        \"\"\"\u6784\u9020\u65b9\u6cd5\"\"\"\n        self._stack: list[int] = []\n\n    def size(self) -> int:\n        \"\"\"\u83b7\u53d6\u6808\u7684\u957f\u5ea6\"\"\"\n        return len(self._stack)\n\n    def is_empty(self) -> bool:\n        \"\"\"\u5224\u65ad\u6808\u662f\u5426\u4e3a\u7a7a\"\"\"\n        return self._stack == []\n\n    def push(self, item: int):\n        \"\"\"\u5165\u6808\"\"\"\n        self._stack.append(item)\n\n    def pop(self) -> int:\n        \"\"\"\u51fa\u6808\"\"\"\n        if self.is_empty():\n            raise IndexError(\"\u6808\u4e3a\u7a7a\")\n        return self._stack.pop()\n\n    def peek(self) -> int:\n        \"\"\"\u8bbf\u95ee\u6808\u9876\u5143\u7d20\"\"\"\n        if self.is_empty():\n            raise IndexError(\"\u6808\u4e3a\u7a7a\")\n        return self._stack[-1]\n\n    def to_list(self) -> list[int]:\n        \"\"\"\u8fd4\u56de\u5217\u8868\u7528\u4e8e\u6253\u5370\"\"\"\n        return self._stack\n
array_stack.cpp
/* \u57fa\u4e8e\u6570\u7ec4\u5b9e\u73b0\u7684\u6808 */\nclass ArrayStack {\n  private:\n    vector<int> stack;\n\n  public:\n    /* \u83b7\u53d6\u6808\u7684\u957f\u5ea6 */\n    int size() {\n        return stack.size();\n    }\n\n    /* \u5224\u65ad\u6808\u662f\u5426\u4e3a\u7a7a */\n    bool isEmpty() {\n        return stack.size() == 0;\n    }\n\n    /* \u5165\u6808 */\n    void push(int num) {\n        stack.push_back(num);\n    }\n\n    /* \u51fa\u6808 */\n    int pop() {\n        int num = top();\n        stack.pop_back();\n        return num;\n    }\n\n    /* \u8bbf\u95ee\u6808\u9876\u5143\u7d20 */\n    int top() {\n        if (isEmpty())\n            throw out_of_range(\"\u6808\u4e3a\u7a7a\");\n        return stack.back();\n    }\n\n    /* \u8fd4\u56de Vector */\n    vector<int> toVector() {\n        return stack;\n    }\n};\n
array_stack.java
/* \u57fa\u4e8e\u6570\u7ec4\u5b9e\u73b0\u7684\u6808 */\nclass ArrayStack {\n    private ArrayList<Integer> stack;\n\n    public ArrayStack() {\n        // \u521d\u59cb\u5316\u5217\u8868\uff08\u52a8\u6001\u6570\u7ec4\uff09\n        stack = new ArrayList<>();\n    }\n\n    /* \u83b7\u53d6\u6808\u7684\u957f\u5ea6 */\n    public int size() {\n        return stack.size();\n    }\n\n    /* \u5224\u65ad\u6808\u662f\u5426\u4e3a\u7a7a */\n    public boolean isEmpty() {\n        return size() == 0;\n    }\n\n    /* \u5165\u6808 */\n    public void push(int num) {\n        stack.add(num);\n    }\n\n    /* \u51fa\u6808 */\n    public int pop() {\n        if (isEmpty())\n            throw new IndexOutOfBoundsException();\n        return stack.remove(size() - 1);\n    }\n\n    /* \u8bbf\u95ee\u6808\u9876\u5143\u7d20 */\n    public int peek() {\n        if (isEmpty())\n            throw new IndexOutOfBoundsException();\n        return stack.get(size() - 1);\n    }\n\n    /* \u5c06 List \u8f6c\u5316\u4e3a Array \u5e76\u8fd4\u56de */\n    public Object[] toArray() {\n        return stack.toArray();\n    }\n}\n
array_stack.cs
/* \u57fa\u4e8e\u6570\u7ec4\u5b9e\u73b0\u7684\u6808 */\nclass ArrayStack {\n    List<int> stack;\n    public ArrayStack() {\n        // \u521d\u59cb\u5316\u5217\u8868\uff08\u52a8\u6001\u6570\u7ec4\uff09\n        stack = [];\n    }\n\n    /* \u83b7\u53d6\u6808\u7684\u957f\u5ea6 */\n    public int Size() {\n        return stack.Count;\n    }\n\n    /* \u5224\u65ad\u6808\u662f\u5426\u4e3a\u7a7a */\n    public bool IsEmpty() {\n        return Size() == 0;\n    }\n\n    /* \u5165\u6808 */\n    public void Push(int num) {\n        stack.Add(num);\n    }\n\n    /* \u51fa\u6808 */\n    public int Pop() {\n        if (IsEmpty())\n            throw new Exception();\n        var val = Peek();\n        stack.RemoveAt(Size() - 1);\n        return val;\n    }\n\n    /* \u8bbf\u95ee\u6808\u9876\u5143\u7d20 */\n    public int Peek() {\n        if (IsEmpty())\n            throw new Exception();\n        return stack[Size() - 1];\n    }\n\n    /* \u5c06 List \u8f6c\u5316\u4e3a Array \u5e76\u8fd4\u56de */\n    public int[] ToArray() {\n        return [.. stack];\n    }\n}\n
array_stack.go
/* \u57fa\u4e8e\u6570\u7ec4\u5b9e\u73b0\u7684\u6808 */\ntype arrayStack struct {\n    data []int // \u6570\u636e\n}\n\n/* \u521d\u59cb\u5316\u6808 */\nfunc newArrayStack() *arrayStack {\n    return &arrayStack{\n        // \u8bbe\u7f6e\u6808\u7684\u957f\u5ea6\u4e3a 0\uff0c\u5bb9\u91cf\u4e3a 16\n        data: make([]int, 0, 16),\n    }\n}\n\n/* \u6808\u7684\u957f\u5ea6 */\nfunc (s *arrayStack) size() int {\n    return len(s.data)\n}\n\n/* \u6808\u662f\u5426\u4e3a\u7a7a */\nfunc (s *arrayStack) isEmpty() bool {\n    return s.size() == 0\n}\n\n/* \u5165\u6808 */\nfunc (s *arrayStack) push(v int) {\n    // \u5207\u7247\u4f1a\u81ea\u52a8\u6269\u5bb9\n    s.data = append(s.data, v)\n}\n\n/* \u51fa\u6808 */\nfunc (s *arrayStack) pop() any {\n    val := s.peek()\n    s.data = s.data[:len(s.data)-1]\n    return val\n}\n\n/* \u83b7\u53d6\u6808\u9876\u5143\u7d20 */\nfunc (s *arrayStack) peek() any {\n    if s.isEmpty() {\n        return nil\n    }\n    val := s.data[len(s.data)-1]\n    return val\n}\n\n/* \u83b7\u53d6 Slice \u7528\u4e8e\u6253\u5370 */\nfunc (s *arrayStack) toSlice() []int {\n    return s.data\n}\n
array_stack.swift
/* \u57fa\u4e8e\u6570\u7ec4\u5b9e\u73b0\u7684\u6808 */\nclass ArrayStack {\n    private var stack: [Int]\n\n    init() {\n        // \u521d\u59cb\u5316\u5217\u8868\uff08\u52a8\u6001\u6570\u7ec4\uff09\n        stack = []\n    }\n\n    /* \u83b7\u53d6\u6808\u7684\u957f\u5ea6 */\n    func size() -> Int {\n        stack.count\n    }\n\n    /* \u5224\u65ad\u6808\u662f\u5426\u4e3a\u7a7a */\n    func isEmpty() -> Bool {\n        stack.isEmpty\n    }\n\n    /* \u5165\u6808 */\n    func push(num: Int) {\n        stack.append(num)\n    }\n\n    /* \u51fa\u6808 */\n    @discardableResult\n    func pop() -> Int {\n        if isEmpty() {\n            fatalError(\"\u6808\u4e3a\u7a7a\")\n        }\n        return stack.removeLast()\n    }\n\n    /* \u8bbf\u95ee\u6808\u9876\u5143\u7d20 */\n    func peek() -> Int {\n        if isEmpty() {\n            fatalError(\"\u6808\u4e3a\u7a7a\")\n        }\n        return stack.last!\n    }\n\n    /* \u5c06 List \u8f6c\u5316\u4e3a Array \u5e76\u8fd4\u56de */\n    func toArray() -> [Int] {\n        stack\n    }\n}\n
array_stack.js
/* \u57fa\u4e8e\u6570\u7ec4\u5b9e\u73b0\u7684\u6808 */\nclass ArrayStack {\n    #stack;\n    constructor() {\n        this.#stack = [];\n    }\n\n    /* \u83b7\u53d6\u6808\u7684\u957f\u5ea6 */\n    get size() {\n        return this.#stack.length;\n    }\n\n    /* \u5224\u65ad\u6808\u662f\u5426\u4e3a\u7a7a */\n    isEmpty() {\n        return this.#stack.length === 0;\n    }\n\n    /* \u5165\u6808 */\n    push(num) {\n        this.#stack.push(num);\n    }\n\n    /* \u51fa\u6808 */\n    pop() {\n        if (this.isEmpty()) throw new Error('\u6808\u4e3a\u7a7a');\n        return this.#stack.pop();\n    }\n\n    /* \u8bbf\u95ee\u6808\u9876\u5143\u7d20 */\n    top() {\n        if (this.isEmpty()) throw new Error('\u6808\u4e3a\u7a7a');\n        return this.#stack[this.#stack.length - 1];\n    }\n\n    /* \u8fd4\u56de Array */\n    toArray() {\n        return this.#stack;\n    }\n}\n
array_stack.ts
/* \u57fa\u4e8e\u6570\u7ec4\u5b9e\u73b0\u7684\u6808 */\nclass ArrayStack {\n    private stack: number[];\n    constructor() {\n        this.stack = [];\n    }\n\n    /* \u83b7\u53d6\u6808\u7684\u957f\u5ea6 */\n    get size(): number {\n        return this.stack.length;\n    }\n\n    /* \u5224\u65ad\u6808\u662f\u5426\u4e3a\u7a7a */\n    isEmpty(): boolean {\n        return this.stack.length === 0;\n    }\n\n    /* \u5165\u6808 */\n    push(num: number): void {\n        this.stack.push(num);\n    }\n\n    /* \u51fa\u6808 */\n    pop(): number | undefined {\n        if (this.isEmpty()) throw new Error('\u6808\u4e3a\u7a7a');\n        return this.stack.pop();\n    }\n\n    /* \u8bbf\u95ee\u6808\u9876\u5143\u7d20 */\n    top(): number | undefined {\n        if (this.isEmpty()) throw new Error('\u6808\u4e3a\u7a7a');\n        return this.stack[this.stack.length - 1];\n    }\n\n    /* \u8fd4\u56de Array */\n    toArray() {\n        return this.stack;\n    }\n}\n
array_stack.dart
/* \u57fa\u4e8e\u6570\u7ec4\u5b9e\u73b0\u7684\u6808 */\nclass ArrayStack {\n  late List<int> _stack;\n  ArrayStack() {\n    _stack = [];\n  }\n\n  /* \u83b7\u53d6\u6808\u7684\u957f\u5ea6 */\n  int size() {\n    return _stack.length;\n  }\n\n  /* \u5224\u65ad\u6808\u662f\u5426\u4e3a\u7a7a */\n  bool isEmpty() {\n    return _stack.isEmpty;\n  }\n\n  /* \u5165\u6808 */\n  void push(int _num) {\n    _stack.add(_num);\n  }\n\n  /* \u51fa\u6808 */\n  int pop() {\n    if (isEmpty()) {\n      throw Exception(\"\u6808\u4e3a\u7a7a\");\n    }\n    return _stack.removeLast();\n  }\n\n  /* \u8bbf\u95ee\u6808\u9876\u5143\u7d20 */\n  int peek() {\n    if (isEmpty()) {\n      throw Exception(\"\u6808\u4e3a\u7a7a\");\n    }\n    return _stack.last;\n  }\n\n  /* \u5c06\u6808\u8f6c\u5316\u4e3a Array \u5e76\u8fd4\u56de */\n  List<int> toArray() => _stack;\n}\n
array_stack.rs
/* \u57fa\u4e8e\u6570\u7ec4\u5b9e\u73b0\u7684\u6808 */\nstruct ArrayStack<T> {\n    stack: Vec<T>,\n}\n\nimpl<T> ArrayStack<T> {\n    /* \u521d\u59cb\u5316\u6808 */\n    fn new() -> ArrayStack<T> {\n        ArrayStack::<T> {\n            stack: Vec::<T>::new(),\n        }\n    }\n\n    /* \u83b7\u53d6\u6808\u7684\u957f\u5ea6 */\n    fn size(&self) -> usize {\n        self.stack.len()\n    }\n\n    /* \u5224\u65ad\u6808\u662f\u5426\u4e3a\u7a7a */\n    fn is_empty(&self) -> bool {\n        self.size() == 0\n    }\n\n    /* \u5165\u6808 */\n    fn push(&mut self, num: T) {\n        self.stack.push(num);\n    }\n\n    /* \u51fa\u6808 */\n    fn pop(&mut self) -> Option<T> {\n        match self.stack.pop() {\n            Some(num) => Some(num),\n            None => None,\n        }\n    }\n\n    /* \u8bbf\u95ee\u6808\u9876\u5143\u7d20 */\n    fn peek(&self) -> Option<&T> {\n        if self.is_empty() {\n            panic!(\"\u6808\u4e3a\u7a7a\")\n        };\n        self.stack.last()\n    }\n\n    /* \u8fd4\u56de &Vec */\n    fn to_array(&self) -> &Vec<T> {\n        &self.stack\n    }\n}\n
array_stack.c
/* \u57fa\u4e8e\u6570\u7ec4\u5b9e\u73b0\u7684\u6808 */\ntypedef struct {\n    int *data;\n    int size;\n} ArrayStack;\n\n/* \u6784\u9020\u51fd\u6570 */\nArrayStack *newArrayStack() {\n    ArrayStack *stack = malloc(sizeof(ArrayStack));\n    // \u521d\u59cb\u5316\u4e00\u4e2a\u5927\u5bb9\u91cf\uff0c\u907f\u514d\u6269\u5bb9\n    stack->data = malloc(sizeof(int) * MAX_SIZE);\n    stack->size = 0;\n    return stack;\n}\n\n/* \u6790\u6784\u51fd\u6570 */\nvoid delArrayStack(ArrayStack *stack) {\n    free(stack->data);\n    free(stack);\n}\n\n/* \u83b7\u53d6\u6808\u7684\u957f\u5ea6 */\nint size(ArrayStack *stack) {\n    return stack->size;\n}\n\n/* \u5224\u65ad\u6808\u662f\u5426\u4e3a\u7a7a */\nbool isEmpty(ArrayStack *stack) {\n    return stack->size == 0;\n}\n\n/* \u5165\u6808 */\nvoid push(ArrayStack *stack, int num) {\n    if (stack->size == MAX_SIZE) {\n        printf(\"\u6808\u5df2\u6ee1\\n\");\n        return;\n    }\n    stack->data[stack->size] = num;\n    stack->size++;\n}\n\n/* \u8bbf\u95ee\u6808\u9876\u5143\u7d20 */\nint peek(ArrayStack *stack) {\n    if (stack->size == 0) {\n        printf(\"\u6808\u4e3a\u7a7a\\n\");\n        return INT_MAX;\n    }\n    return stack->data[stack->size - 1];\n}\n\n/* \u51fa\u6808 */\nint pop(ArrayStack *stack) {\n    int val = peek(stack);\n    stack->size--;\n    return val;\n}\n
array_stack.zig
// \u57fa\u4e8e\u6570\u7ec4\u5b9e\u73b0\u7684\u6808\nfn ArrayStack(comptime T: type) type {\n    return struct {\n        const Self = @This();\n\n        stack: ?std.ArrayList(T) = null,     \n\n        // \u6784\u9020\u65b9\u6cd5\uff08\u5206\u914d\u5185\u5b58+\u521d\u59cb\u5316\u6808\uff09\n        pub fn init(self: *Self, allocator: std.mem.Allocator) void {\n            if (self.stack == null) {\n                self.stack = std.ArrayList(T).init(allocator);\n            }\n        }\n\n        // \u6790\u6784\u65b9\u6cd5\uff08\u91ca\u653e\u5185\u5b58\uff09\n        pub fn deinit(self: *Self) void {\n            if (self.stack == null) return;\n            self.stack.?.deinit();\n        }\n\n        // \u83b7\u53d6\u6808\u7684\u957f\u5ea6\n        pub fn size(self: *Self) usize {\n            return self.stack.?.items.len;\n        }\n\n        // \u5224\u65ad\u6808\u662f\u5426\u4e3a\u7a7a\n        pub fn isEmpty(self: *Self) bool {\n            return self.size() == 0;\n        }\n\n        // \u8bbf\u95ee\u6808\u9876\u5143\u7d20\n        pub fn peek(self: *Self) T {\n            if (self.isEmpty()) @panic(\"\u6808\u4e3a\u7a7a\");\n            return self.stack.?.items[self.size() - 1];\n        }  \n\n        // \u5165\u6808\n        pub fn push(self: *Self, num: T) !void {\n            try self.stack.?.append(num);\n        } \n\n        // \u51fa\u6808\n        pub fn pop(self: *Self) T {\n            var num = self.stack.?.pop();\n            return num;\n        } \n\n        // \u8fd4\u56de ArrayList\n        pub fn toList(self: *Self) std.ArrayList(T) {\n            return self.stack.?;\n        }\n    };\n}\n
Code Visualization

Full Screen >

"},{"location":"chapter_stack_and_queue/stack/#513-comparison-of-the-two-implementations","title":"5.1.3 \u00a0 Comparison of the Two Implementations","text":"

Supported Operations

Both implementations support all the operations defined in a stack. The array implementation additionally supports random access, but this is beyond the scope of a stack definition and is generally not used.

Time Efficiency

In the array-based implementation, both push and pop operations occur in pre-allocated contiguous memory, which has good cache locality and therefore higher efficiency. However, if the push operation exceeds the array capacity, it triggers a resizing mechanism, making the time complexity of that push operation \\(O(n)\\).

In the linked list implementation, list expansion is very flexible, and there is no efficiency decrease issue as in array expansion. However, the push operation requires initializing a node object and modifying pointers, so its efficiency is relatively lower. If the elements being pushed are already node objects, then the initialization step can be skipped, improving efficiency.

Thus, when the elements for push and pop operations are basic data types like int or double, we can draw the following conclusions:

  • The array-based stack implementation's efficiency decreases during expansion, but since expansion is a low-frequency operation, its average efficiency is higher.
  • The linked list-based stack implementation provides more stable efficiency performance.

Space Efficiency

When initializing a list, the system allocates an \"initial capacity,\" which might exceed the actual need; moreover, the expansion mechanism usually increases capacity by a specific factor (like doubling), which may also exceed the actual need. Therefore, the array-based stack might waste some space.

However, since linked list nodes require extra space for storing pointers, the space occupied by linked list nodes is relatively larger.

In summary, we cannot simply determine which implementation is more memory-efficient. It requires analysis based on specific circumstances.

"},{"location":"chapter_stack_and_queue/stack/#514-typical-applications-of-stack","title":"5.1.4 \u00a0 Typical Applications of Stack","text":"
  • Back and forward in browsers, undo and redo in software. Every time we open a new webpage, the browser pushes the previous page onto the stack, allowing us to go back to the previous page through the back operation, which is essentially a pop operation. To support both back and forward, two stacks are needed to work together.
  • Memory management in programs. Each time a function is called, the system adds a stack frame at the top of the stack to record the function's context information. In recursive functions, the downward recursion phase keeps pushing onto the stack, while the upward backtracking phase keeps popping from the stack.
"},{"location":"chapter_stack_and_queue/summary/","title":"5.4 \u00a0 Summary","text":""},{"location":"chapter_stack_and_queue/summary/#1-key-review","title":"1. \u00a0 Key Review","text":"
  • Stack is a data structure that follows the Last-In-First-Out (LIFO) principle and can be implemented using arrays or linked lists.
  • In terms of time efficiency, the array implementation of the stack has a higher average efficiency. However, during expansion, the time complexity for a single push operation can degrade to \\(O(n)\\). In contrast, the linked list implementation of a stack offers more stable efficiency.
  • Regarding space efficiency, the array implementation of the stack may lead to a certain degree of space wastage. However, it's important to note that the memory space occupied by nodes in a linked list is generally larger than that for elements in an array.
  • A queue is a data structure that follows the First-In-First-Out (FIFO) principle, and it can also be implemented using arrays or linked lists. The conclusions regarding time and space efficiency for queues are similar to those for stacks.
  • A double-ended queue (deque) is a more flexible type of queue that allows adding and removing elements at both ends.
"},{"location":"chapter_stack_and_queue/summary/#2-q-a","title":"2. \u00a0 Q & A","text":"

Q: Is the browser's forward and backward functionality implemented with a doubly linked list?

A browser's forward and backward navigation is essentially a manifestation of the \"stack\" concept. When a user visits a new page, the page is added to the top of the stack; when they click the back button, the page is popped from the top of the stack. A double-ended queue (deque) can conveniently implement some additional operations, as mentioned in the \"Double-Ended Queue\" section.

Q: After popping from a stack, is it necessary to free the memory of the popped node?

If the popped node will still be used later, it's not necessary to free its memory. In languages like Java and Python that have automatic garbage collection, manual memory release is not necessary; in C and C++, manual memory release is required.

Q: A double-ended queue seems like two stacks joined together. What are its uses?

A double-ended queue, which is a combination of a stack and a queue or two stacks joined together, exhibits both stack and queue logic. Thus, it can implement all applications of stacks and queues while offering more flexibility.

Q: How exactly are undo and redo implemented?

Undo and redo operations are implemented using two stacks: Stack A for undo and Stack B for redo.

  1. Each time a user performs an operation, it is pushed onto Stack A, and Stack B is cleared.
  2. When the user executes an \"undo\", the most recent operation is popped from Stack A and pushed onto Stack B.
  3. When the user executes a \"redo\", the most recent operation is popped from Stack B and pushed back onto Stack A.
"}]} \ No newline at end of file +{"config":{"lang":["en"],"separator":"[\\s\\-]+","pipeline":["stopWordFilter"]},"docs":[{"location":"","title":"Home","text":"Hello Algo

Data Structures and Algorithms Crash Course with Animated Illustrations and Off-the-Shelf Code

Dive In Clone Repo Get PDF

The English edition is brewing...

Feel free to engage in Chinese-to-English translation and pull request review! For guidelines, please see #914.

Quote

\"An easy-to-understand book on data structures and algorithms, which guides readers to learn by minds-on and hands-on. Strongly recommended for algorithm beginners!\"

\u2014\u2014 Junhui Deng, Professor of Computer Science, Tsinghua University

Quote

\"If I had 'Hello Algo' when I was learning data structures and algorithms, it would have been 10 times easier!\"

\u2014\u2014 Mu Li, Senior Principal Scientist, Amazon

Animated illustrations

Easy to understandSmooth learning curve

\"A picture is worth a thousand words.\"

Off-the-Shelf Code

Multi programming languagesRun with one click

\"Talk is cheap. Show me the code.\"

Learning Together

Discussion and questions welcomeReaders progress together

\"Learning by teaching.\"

Preface

Two years ago, I shared the \"Sword Offer\" series of problem solutions on LeetCode, which received much love and support from many students. During my interactions with readers, the most common question I encountered was \"How to get started with algorithms.\" Gradually, I developed a deep interest in this question.

Blindly solving problems seems to be the most popular method, being simple, direct, and effective. However, problem-solving is like playing a \"Minesweeper\" game, where students with strong self-learning abilities can successfully clear the mines one by one, but those with insufficient foundations may end up bruised from explosions, retreating step by step in frustration. Thoroughly reading textbooks is also common, but for students aiming for job applications, the energy consumed by graduation, resume submissions, and preparing for written tests and interviews makes tackling thick books a daunting challenge.

If you are facing similar troubles, then you are lucky to have found this book. This book is my answer to this question, not necessarily the best solution, but at least an active attempt. Although this book won't directly land you an Offer, it will guide you through the \"knowledge map\" of data structures and algorithms, help you understand the shape, size, and distribution of different \"mines,\" and equip you with various \"demining methods.\" With these skills, I believe you can more comfortably solve problems and read literature, gradually building a complete knowledge system.

I deeply agree with Professor Feynman's saying: \"Knowledge isn't free. You have to pay attention.\" In this sense, this book is not entirely \"free.\" To not disappoint the precious \"attention\" you pay to this book, I will do my utmost, investing the greatest \"attention\" to complete the creation of this book.

Author

Yudong Jin(krahets), Senior Algorithm Engineer in a top tech company, Master's degree from Shanghai Jiao Tong University. The highest-read blogger across the entire LeetCode, his published \"Illustration of Algorithm Data Structures\" has been subscribed to by over 300k.

Contribution

This book is continuously improved with the joint efforts of many contributors from the open-source community. Thanks to each writer who invested their time and energy, listed in the order generated by GitHub:

The code review work for this book was completed by codingonion, Gonglja, gvenusleo, hpstory, justin\u2010tse, krahets, night-cruise, nuomi1, and Reanon (listed in alphabetical order). Thanks to them for their time and effort, ensuring the standardization and uniformity of the code in various languages.

codingonionRust, Zig GongljaC, C++ gvenusleoDart hpstoryC# justin-tseJS, TS krahetsJava, Python night-cruiseRust nuomi1Swift ReanonGo, C"},{"location":"chapter_array_and_linkedlist/","title":"Chapter 4. \u00a0 Arrays and Linked Lists","text":"

Abstract

The world of data structures resembles a sturdy brick wall.

In arrays, envision bricks snugly aligned, each resting seamlessly beside the next, creating a unified formation. Meanwhile, in linked lists, these bricks disperse freely, embraced by vines gracefully knitting connections between them.

"},{"location":"chapter_array_and_linkedlist/#chapter-contents","title":"Chapter Contents","text":"
  • 4.1 \u00a0 Array
  • 4.2 \u00a0 Linked List
  • 4.3 \u00a0 List
  • 4.4 \u00a0 Memory and Cache
  • 4.5 \u00a0 Summary
"},{"location":"chapter_array_and_linkedlist/array/","title":"4.1 \u00a0 Arrays","text":"

An \"array\" is a linear data structure that operates as a lineup of similar items, stored together in a computer's memory in contiguous spaces. It's like a sequence that maintains organized storage. Each item in this lineup has its unique 'spot' known as an \"index\". Please refer to the Figure 4-1 to observe how arrays work and grasp these key terms.

Figure 4-1 \u00a0 Array Definition and Storage Method

"},{"location":"chapter_array_and_linkedlist/array/#411-common-operations-on-arrays","title":"4.1.1 \u00a0 Common Operations on Arrays","text":""},{"location":"chapter_array_and_linkedlist/array/#1-initializing-arrays","title":"1. \u00a0 Initializing Arrays","text":"

Arrays can be initialized in two ways depending on the needs: either without initial values or with specified initial values. When initial values are not specified, most programming languages will set the array elements to \\(0\\):

PythonC++JavaC#GoSwiftJSTSDartRustCZig array.py
# Initialize array\narr: list[int] = [0] * 5  # [ 0, 0, 0, 0, 0 ]\nnums: list[int] = [1, 3, 2, 5, 4]\n
array.cpp
/* Initialize array */\n// Stored on stack\nint arr[5];\nint nums[5] = { 1, 3, 2, 5, 4 };\n// Stored on heap (manual memory release needed)\nint* arr1 = new int[5];\nint* nums1 = new int[5] { 1, 3, 2, 5, 4 };\n
array.java
/* Initialize array */\nint[] arr = new int[5]; // { 0, 0, 0, 0, 0 }\nint[] nums = { 1, 3, 2, 5, 4 };\n
array.cs
/* Initialize array */\nint[] arr = new int[5]; // [ 0, 0, 0, 0, 0 ]\nint[] nums = [1, 3, 2, 5, 4];\n
array.go
/* Initialize array */\nvar arr [5]int\n// In Go, specifying the length ([5]int) denotes an array, while not specifying it ([]int) denotes a slice.\n// Since Go's arrays are designed to have compile-time fixed length, only constants can be used to specify the length.\n// For convenience in implementing the extend() method, the Slice will be considered as an Array here.\nnums := []int{1, 3, 2, 5, 4}\n
array.swift
/* Initialize array */\nlet arr = Array(repeating: 0, count: 5) // [0, 0, 0, 0, 0]\nlet nums = [1, 3, 2, 5, 4]\n
array.js
/* Initialize array */\nvar arr = new Array(5).fill(0);\nvar nums = [1, 3, 2, 5, 4];\n
array.ts
/* Initialize array */\nlet arr: number[] = new Array(5).fill(0);\nlet nums: number[] = [1, 3, 2, 5, 4];\n
array.dart
/* Initialize array */\nList<int> arr = List.filled(5, 0); // [0, 0, 0, 0, 0]\nList<int> nums = [1, 3, 2, 5, 4];\n
array.rs
/* Initialize array */\nlet arr: Vec<i32> = vec![0; 5]; // [0, 0, 0, 0, 0]\nlet nums: Vec<i32> = vec![1, 3, 2, 5, 4];\n
array.c
/* Initialize array */\nint arr[5] = { 0 }; // { 0, 0, 0, 0, 0 }\nint nums[5] = { 1, 3, 2, 5, 4 };\n
array.zig
// Initialize array\nvar arr = [_]i32{0} ** 5; // { 0, 0, 0, 0, 0 }\nvar nums = [_]i32{ 1, 3, 2, 5, 4 };\n
"},{"location":"chapter_array_and_linkedlist/array/#2-accessing-elements","title":"2. \u00a0 Accessing Elements","text":"

Elements in an array are stored in contiguous memory spaces, making it simpler to compute each element's memory address. The formula shown in the Figure below aids in determining an element's memory address, utilizing the array's memory address (specifically, the first element's address) and the element's index. This computation streamlines direct access to the desired element.

Figure 4-2 \u00a0 Memory Address Calculation for Array Elements

As observed in the above illustration, array indexing conventionally begins at \\(0\\). While this might appear counterintuitive, considering counting usually starts at \\(1\\), within the address calculation formula, an index is essentially an offset from the memory address. For the first element's address, this offset is \\(0\\), validating its index as \\(0\\).

Accessing elements in an array is highly efficient, allowing us to randomly access any element in \\(O(1)\\) time.

PythonC++JavaC#GoSwiftJSTSDartRustCZig array.py
def random_access(nums: list[int]) -> int:\n    \"\"\"\u968f\u673a\u8bbf\u95ee\u5143\u7d20\"\"\"\n    # \u5728\u533a\u95f4 [0, len(nums)-1] \u4e2d\u968f\u673a\u62bd\u53d6\u4e00\u4e2a\u6570\u5b57\n    random_index = random.randint(0, len(nums) - 1)\n    # \u83b7\u53d6\u5e76\u8fd4\u56de\u968f\u673a\u5143\u7d20\n    random_num = nums[random_index]\n    return random_num\n
array.cpp
/* \u968f\u673a\u8bbf\u95ee\u5143\u7d20 */\nint randomAccess(int *nums, int size) {\n    // \u5728\u533a\u95f4 [0, size) \u4e2d\u968f\u673a\u62bd\u53d6\u4e00\u4e2a\u6570\u5b57\n    int randomIndex = rand() % size;\n    // \u83b7\u53d6\u5e76\u8fd4\u56de\u968f\u673a\u5143\u7d20\n    int randomNum = nums[randomIndex];\n    return randomNum;\n}\n
array.java
/* \u968f\u673a\u8bbf\u95ee\u5143\u7d20 */\nint randomAccess(int[] nums) {\n    // \u5728\u533a\u95f4 [0, nums.length) \u4e2d\u968f\u673a\u62bd\u53d6\u4e00\u4e2a\u6570\u5b57\n    int randomIndex = ThreadLocalRandom.current().nextInt(0, nums.length);\n    // \u83b7\u53d6\u5e76\u8fd4\u56de\u968f\u673a\u5143\u7d20\n    int randomNum = nums[randomIndex];\n    return randomNum;\n}\n
array.cs
/* \u968f\u673a\u8bbf\u95ee\u5143\u7d20 */\nint RandomAccess(int[] nums) {\n    Random random = new();\n    // \u5728\u533a\u95f4 [0, nums.Length) \u4e2d\u968f\u673a\u62bd\u53d6\u4e00\u4e2a\u6570\u5b57\n    int randomIndex = random.Next(nums.Length);\n    // \u83b7\u53d6\u5e76\u8fd4\u56de\u968f\u673a\u5143\u7d20\n    int randomNum = nums[randomIndex];\n    return randomNum;\n}\n
array.go
/* \u968f\u673a\u8bbf\u95ee\u5143\u7d20 */\nfunc randomAccess(nums []int) (randomNum int) {\n    // \u5728\u533a\u95f4 [0, nums.length) \u4e2d\u968f\u673a\u62bd\u53d6\u4e00\u4e2a\u6570\u5b57\n    randomIndex := rand.Intn(len(nums))\n    // \u83b7\u53d6\u5e76\u8fd4\u56de\u968f\u673a\u5143\u7d20\n    randomNum = nums[randomIndex]\n    return\n}\n
array.swift
/* \u968f\u673a\u8bbf\u95ee\u5143\u7d20 */\nfunc randomAccess(nums: [Int]) -> Int {\n    // \u5728\u533a\u95f4 [0, nums.count) \u4e2d\u968f\u673a\u62bd\u53d6\u4e00\u4e2a\u6570\u5b57\n    let randomIndex = nums.indices.randomElement()!\n    // \u83b7\u53d6\u5e76\u8fd4\u56de\u968f\u673a\u5143\u7d20\n    let randomNum = nums[randomIndex]\n    return randomNum\n}\n
array.js
/* \u968f\u673a\u8bbf\u95ee\u5143\u7d20 */\nfunction randomAccess(nums) {\n    // \u5728\u533a\u95f4 [0, nums.length) \u4e2d\u968f\u673a\u62bd\u53d6\u4e00\u4e2a\u6570\u5b57\n    const random_index = Math.floor(Math.random() * nums.length);\n    // \u83b7\u53d6\u5e76\u8fd4\u56de\u968f\u673a\u5143\u7d20\n    const random_num = nums[random_index];\n    return random_num;\n}\n
array.ts
/* \u968f\u673a\u8bbf\u95ee\u5143\u7d20 */\nfunction randomAccess(nums: number[]): number {\n    // \u5728\u533a\u95f4 [0, nums.length) \u4e2d\u968f\u673a\u62bd\u53d6\u4e00\u4e2a\u6570\u5b57\n    const random_index = Math.floor(Math.random() * nums.length);\n    // \u83b7\u53d6\u5e76\u8fd4\u56de\u968f\u673a\u5143\u7d20\n    const random_num = nums[random_index];\n    return random_num;\n}\n
array.dart
/* \u968f\u673a\u8bbf\u95ee\u5143\u7d20 */\nint randomAccess(List<int> nums) {\n  // \u5728\u533a\u95f4 [0, nums.length) \u4e2d\u968f\u673a\u62bd\u53d6\u4e00\u4e2a\u6570\u5b57\n  int randomIndex = Random().nextInt(nums.length);\n  // \u83b7\u53d6\u5e76\u8fd4\u56de\u968f\u673a\u5143\u7d20\n  int randomNum = nums[randomIndex];\n  return randomNum;\n}\n
array.rs
/* \u968f\u673a\u8bbf\u95ee\u5143\u7d20 */\nfn random_access(nums: &[i32]) -> i32 {\n    // \u5728\u533a\u95f4 [0, nums.len()) \u4e2d\u968f\u673a\u62bd\u53d6\u4e00\u4e2a\u6570\u5b57\n    let random_index = rand::thread_rng().gen_range(0..nums.len());\n    // \u83b7\u53d6\u5e76\u8fd4\u56de\u968f\u673a\u5143\u7d20\n    let random_num = nums[random_index];\n    random_num\n}\n
array.c
/* \u968f\u673a\u8bbf\u95ee\u5143\u7d20 */\nint randomAccess(int *nums, int size) {\n    // \u5728\u533a\u95f4 [0, size) \u4e2d\u968f\u673a\u62bd\u53d6\u4e00\u4e2a\u6570\u5b57\n    int randomIndex = rand() % size;\n    // \u83b7\u53d6\u5e76\u8fd4\u56de\u968f\u673a\u5143\u7d20\n    int randomNum = nums[randomIndex];\n    return randomNum;\n}\n
array.zig
// \u968f\u673a\u8bbf\u95ee\u5143\u7d20\nfn randomAccess(nums: []i32) i32 {\n    // \u5728\u533a\u95f4 [0, nums.len) \u4e2d\u968f\u673a\u62bd\u53d6\u4e00\u4e2a\u6574\u6570\n    var randomIndex = std.crypto.random.intRangeLessThan(usize, 0, nums.len);\n    // \u83b7\u53d6\u5e76\u8fd4\u56de\u968f\u673a\u5143\u7d20\n    var randomNum = nums[randomIndex];\n    return randomNum;\n}\n
Code Visualization

Full Screen >

"},{"location":"chapter_array_and_linkedlist/array/#3-inserting-elements","title":"3. \u00a0 Inserting Elements","text":"

Array elements are tightly packed in memory, with no space available to accommodate additional data between them. Illustrated in Figure below, inserting an element in the middle of an array requires shifting all subsequent elements back by one position to create room for the new element.

Figure 4-3 \u00a0 Array Element Insertion Example

It's important to note that due to the fixed length of an array, inserting an element will unavoidably result in the loss of the last element in the array. Solutions to address this issue will be explored in the \"List\" chapter.

PythonC++JavaC#GoSwiftJSTSDartRustCZig array.py
def insert(nums: list[int], num: int, index: int):\n    \"\"\"\u5728\u6570\u7ec4\u7684\u7d22\u5f15 index \u5904\u63d2\u5165\u5143\u7d20 num\"\"\"\n    # \u628a\u7d22\u5f15 index \u4ee5\u53ca\u4e4b\u540e\u7684\u6240\u6709\u5143\u7d20\u5411\u540e\u79fb\u52a8\u4e00\u4f4d\n    for i in range(len(nums) - 1, index, -1):\n        nums[i] = nums[i - 1]\n    # \u5c06 num \u8d4b\u7ed9 index \u5904\u7684\u5143\u7d20\n    nums[index] = num\n
array.cpp
/* \u5728\u6570\u7ec4\u7684\u7d22\u5f15 index \u5904\u63d2\u5165\u5143\u7d20 num */\nvoid insert(int *nums, int size, int num, int index) {\n    // \u628a\u7d22\u5f15 index \u4ee5\u53ca\u4e4b\u540e\u7684\u6240\u6709\u5143\u7d20\u5411\u540e\u79fb\u52a8\u4e00\u4f4d\n    for (int i = size - 1; i > index; i--) {\n        nums[i] = nums[i - 1];\n    }\n    // \u5c06 num \u8d4b\u7ed9 index \u5904\u7684\u5143\u7d20\n    nums[index] = num;\n}\n
array.java
/* \u5728\u6570\u7ec4\u7684\u7d22\u5f15 index \u5904\u63d2\u5165\u5143\u7d20 num */\nvoid insert(int[] nums, int num, int index) {\n    // \u628a\u7d22\u5f15 index \u4ee5\u53ca\u4e4b\u540e\u7684\u6240\u6709\u5143\u7d20\u5411\u540e\u79fb\u52a8\u4e00\u4f4d\n    for (int i = nums.length - 1; i > index; i--) {\n        nums[i] = nums[i - 1];\n    }\n    // \u5c06 num \u8d4b\u7ed9 index \u5904\u7684\u5143\u7d20\n    nums[index] = num;\n}\n
array.cs
/* \u5728\u6570\u7ec4\u7684\u7d22\u5f15 index \u5904\u63d2\u5165\u5143\u7d20 num */\nvoid Insert(int[] nums, int num, int index) {\n    // \u628a\u7d22\u5f15 index \u4ee5\u53ca\u4e4b\u540e\u7684\u6240\u6709\u5143\u7d20\u5411\u540e\u79fb\u52a8\u4e00\u4f4d\n    for (int i = nums.Length - 1; i > index; i--) {\n        nums[i] = nums[i - 1];\n    }\n    // \u5c06 num \u8d4b\u7ed9 index \u5904\u7684\u5143\u7d20\n    nums[index] = num;\n}\n
array.go
/* \u5728\u6570\u7ec4\u7684\u7d22\u5f15 index \u5904\u63d2\u5165\u5143\u7d20 num */\nfunc insert(nums []int, num int, index int) {\n    // \u628a\u7d22\u5f15 index \u4ee5\u53ca\u4e4b\u540e\u7684\u6240\u6709\u5143\u7d20\u5411\u540e\u79fb\u52a8\u4e00\u4f4d\n    for i := len(nums) - 1; i > index; i-- {\n        nums[i] = nums[i-1]\n    }\n    // \u5c06 num \u8d4b\u7ed9 index \u5904\u7684\u5143\u7d20\n    nums[index] = num\n}\n
array.swift
/* \u5728\u6570\u7ec4\u7684\u7d22\u5f15 index \u5904\u63d2\u5165\u5143\u7d20 num */\nfunc insert(nums: inout [Int], num: Int, index: Int) {\n    // \u628a\u7d22\u5f15 index \u4ee5\u53ca\u4e4b\u540e\u7684\u6240\u6709\u5143\u7d20\u5411\u540e\u79fb\u52a8\u4e00\u4f4d\n    for i in nums.indices.dropFirst(index).reversed() {\n        nums[i] = nums[i - 1]\n    }\n    // \u5c06 num \u8d4b\u7ed9 index \u5904\u7684\u5143\u7d20\n    nums[index] = num\n}\n
array.js
/* \u5728\u6570\u7ec4\u7684\u7d22\u5f15 index \u5904\u63d2\u5165\u5143\u7d20 num */\nfunction insert(nums, num, index) {\n    // \u628a\u7d22\u5f15 index \u4ee5\u53ca\u4e4b\u540e\u7684\u6240\u6709\u5143\u7d20\u5411\u540e\u79fb\u52a8\u4e00\u4f4d\n    for (let i = nums.length - 1; i > index; i--) {\n        nums[i] = nums[i - 1];\n    }\n    // \u5c06 num \u8d4b\u7ed9 index \u5904\u7684\u5143\u7d20\n    nums[index] = num;\n}\n
array.ts
/* \u5728\u6570\u7ec4\u7684\u7d22\u5f15 index \u5904\u63d2\u5165\u5143\u7d20 num */\nfunction insert(nums: number[], num: number, index: number): void {\n    // \u628a\u7d22\u5f15 index \u4ee5\u53ca\u4e4b\u540e\u7684\u6240\u6709\u5143\u7d20\u5411\u540e\u79fb\u52a8\u4e00\u4f4d\n    for (let i = nums.length - 1; i > index; i--) {\n        nums[i] = nums[i - 1];\n    }\n    // \u5c06 num \u8d4b\u7ed9 index \u5904\u7684\u5143\u7d20\n    nums[index] = num;\n}\n
array.dart
/* \u5728\u6570\u7ec4\u7684\u7d22\u5f15 index \u5904\u63d2\u5165\u5143\u7d20 _num */\nvoid insert(List<int> nums, int _num, int index) {\n  // \u628a\u7d22\u5f15 index \u4ee5\u53ca\u4e4b\u540e\u7684\u6240\u6709\u5143\u7d20\u5411\u540e\u79fb\u52a8\u4e00\u4f4d\n  for (var i = nums.length - 1; i > index; i--) {\n    nums[i] = nums[i - 1];\n  }\n  // \u5c06 _num \u8d4b\u7ed9 index \u5904\u5143\u7d20\n  nums[index] = _num;\n}\n
array.rs
/* \u5728\u6570\u7ec4\u7684\u7d22\u5f15 index \u5904\u63d2\u5165\u5143\u7d20 num */\nfn insert(nums: &mut Vec<i32>, num: i32, index: usize) {\n    // \u628a\u7d22\u5f15 index \u4ee5\u53ca\u4e4b\u540e\u7684\u6240\u6709\u5143\u7d20\u5411\u540e\u79fb\u52a8\u4e00\u4f4d\n    for i in (index + 1..nums.len()).rev() {\n        nums[i] = nums[i - 1];\n    }\n    // \u5c06 num \u8d4b\u7ed9 index \u5904\u7684\u5143\u7d20\n    nums[index] = num;\n}\n
array.c
/* \u5728\u6570\u7ec4\u7684\u7d22\u5f15 index \u5904\u63d2\u5165\u5143\u7d20 num */\nvoid insert(int *nums, int size, int num, int index) {\n    // \u628a\u7d22\u5f15 index \u4ee5\u53ca\u4e4b\u540e\u7684\u6240\u6709\u5143\u7d20\u5411\u540e\u79fb\u52a8\u4e00\u4f4d\n    for (int i = size - 1; i > index; i--) {\n        nums[i] = nums[i - 1];\n    }\n    // \u5c06 num \u8d4b\u7ed9 index \u5904\u7684\u5143\u7d20\n    nums[index] = num;\n}\n
array.zig
// \u5728\u6570\u7ec4\u7684\u7d22\u5f15 index \u5904\u63d2\u5165\u5143\u7d20 num\nfn insert(nums: []i32, num: i32, index: usize) void {\n    // \u628a\u7d22\u5f15 index \u4ee5\u53ca\u4e4b\u540e\u7684\u6240\u6709\u5143\u7d20\u5411\u540e\u79fb\u52a8\u4e00\u4f4d\n    var i = nums.len - 1;\n    while (i > index) : (i -= 1) {\n        nums[i] = nums[i - 1];\n    }\n    // \u5c06 num \u8d4b\u7ed9 index \u5904\u7684\u5143\u7d20\n    nums[index] = num;\n}\n
Code Visualization

Full Screen >

"},{"location":"chapter_array_and_linkedlist/array/#4-deleting-elements","title":"4. \u00a0 Deleting Elements","text":"

Similarly, as depicted in the Figure 4-4 , to delete an element at index \\(i\\), all elements following index \\(i\\) must be moved forward by one position.

Figure 4-4 \u00a0 Array Element Deletion Example

Please note that after deletion, the former last element becomes \"meaningless,\" hence requiring no specific modification.

PythonC++JavaC#GoSwiftJSTSDartRustCZig array.py
def remove(nums: list[int], index: int):\n    \"\"\"\u5220\u9664\u7d22\u5f15 index \u5904\u7684\u5143\u7d20\"\"\"\n    # \u628a\u7d22\u5f15 index \u4e4b\u540e\u7684\u6240\u6709\u5143\u7d20\u5411\u524d\u79fb\u52a8\u4e00\u4f4d\n    for i in range(index, len(nums) - 1):\n        nums[i] = nums[i + 1]\n
array.cpp
/* \u5220\u9664\u7d22\u5f15 index \u5904\u7684\u5143\u7d20 */\nvoid remove(int *nums, int size, int index) {\n    // \u628a\u7d22\u5f15 index \u4e4b\u540e\u7684\u6240\u6709\u5143\u7d20\u5411\u524d\u79fb\u52a8\u4e00\u4f4d\n    for (int i = index; i < size - 1; i++) {\n        nums[i] = nums[i + 1];\n    }\n}\n
array.java
/* \u5220\u9664\u7d22\u5f15 index \u5904\u7684\u5143\u7d20 */\nvoid remove(int[] nums, int index) {\n    // \u628a\u7d22\u5f15 index \u4e4b\u540e\u7684\u6240\u6709\u5143\u7d20\u5411\u524d\u79fb\u52a8\u4e00\u4f4d\n    for (int i = index; i < nums.length - 1; i++) {\n        nums[i] = nums[i + 1];\n    }\n}\n
array.cs
/* \u5220\u9664\u7d22\u5f15 index \u5904\u7684\u5143\u7d20 */\nvoid Remove(int[] nums, int index) {\n    // \u628a\u7d22\u5f15 index \u4e4b\u540e\u7684\u6240\u6709\u5143\u7d20\u5411\u524d\u79fb\u52a8\u4e00\u4f4d\n    for (int i = index; i < nums.Length - 1; i++) {\n        nums[i] = nums[i + 1];\n    }\n}\n
array.go
/* \u5220\u9664\u7d22\u5f15 index \u5904\u7684\u5143\u7d20 */\nfunc remove(nums []int, index int) {\n    // \u628a\u7d22\u5f15 index \u4e4b\u540e\u7684\u6240\u6709\u5143\u7d20\u5411\u524d\u79fb\u52a8\u4e00\u4f4d\n    for i := index; i < len(nums)-1; i++ {\n        nums[i] = nums[i+1]\n    }\n}\n
array.swift
/* \u5220\u9664\u7d22\u5f15 index \u5904\u7684\u5143\u7d20 */\nfunc remove(nums: inout [Int], index: Int) {\n    // \u628a\u7d22\u5f15 index \u4e4b\u540e\u7684\u6240\u6709\u5143\u7d20\u5411\u524d\u79fb\u52a8\u4e00\u4f4d\n    for i in nums.indices.dropFirst(index).dropLast() {\n        nums[i] = nums[i + 1]\n    }\n}\n
array.js
/* \u5220\u9664\u7d22\u5f15 index \u5904\u7684\u5143\u7d20 */\nfunction remove(nums, index) {\n    // \u628a\u7d22\u5f15 index \u4e4b\u540e\u7684\u6240\u6709\u5143\u7d20\u5411\u524d\u79fb\u52a8\u4e00\u4f4d\n    for (let i = index; i < nums.length - 1; i++) {\n        nums[i] = nums[i + 1];\n    }\n}\n
array.ts
/* \u5220\u9664\u7d22\u5f15 index \u5904\u7684\u5143\u7d20 */\nfunction remove(nums: number[], index: number): void {\n    // \u628a\u7d22\u5f15 index \u4e4b\u540e\u7684\u6240\u6709\u5143\u7d20\u5411\u524d\u79fb\u52a8\u4e00\u4f4d\n    for (let i = index; i < nums.length - 1; i++) {\n        nums[i] = nums[i + 1];\n    }\n}\n
array.dart
/* \u5220\u9664\u7d22\u5f15 index \u5904\u7684\u5143\u7d20 */\nvoid remove(List<int> nums, int index) {\n  // \u628a\u7d22\u5f15 index \u4e4b\u540e\u7684\u6240\u6709\u5143\u7d20\u5411\u524d\u79fb\u52a8\u4e00\u4f4d\n  for (var i = index; i < nums.length - 1; i++) {\n    nums[i] = nums[i + 1];\n  }\n}\n
array.rs
/* \u5220\u9664\u7d22\u5f15 index \u5904\u7684\u5143\u7d20 */\nfn remove(nums: &mut Vec<i32>, index: usize) {\n    // \u628a\u7d22\u5f15 index \u4e4b\u540e\u7684\u6240\u6709\u5143\u7d20\u5411\u524d\u79fb\u52a8\u4e00\u4f4d\n    for i in index..nums.len() - 1 {\n        nums[i] = nums[i + 1];\n    }\n}\n
array.c
/* \u5220\u9664\u7d22\u5f15 index \u5904\u7684\u5143\u7d20 */\n// \u6ce8\u610f\uff1astdio.h \u5360\u7528\u4e86 remove \u5173\u952e\u8bcd\nvoid removeItem(int *nums, int size, int index) {\n    // \u628a\u7d22\u5f15 index \u4e4b\u540e\u7684\u6240\u6709\u5143\u7d20\u5411\u524d\u79fb\u52a8\u4e00\u4f4d\n    for (int i = index; i < size - 1; i++) {\n        nums[i] = nums[i + 1];\n    }\n}\n
array.zig
// \u5220\u9664\u7d22\u5f15 index \u5904\u7684\u5143\u7d20\nfn remove(nums: []i32, index: usize) void {\n    // \u628a\u7d22\u5f15 index \u4e4b\u540e\u7684\u6240\u6709\u5143\u7d20\u5411\u524d\u79fb\u52a8\u4e00\u4f4d\n    var i = index;\n    while (i < nums.len - 1) : (i += 1) {\n        nums[i] = nums[i + 1];\n    }\n}\n
Code Visualization

Full Screen >

In summary, the insertion and deletion operations in arrays present the following disadvantages:

  • High Time Complexity: Both insertion and deletion in an array have an average time complexity of \\(O(n)\\), where \\(n\\) is the length of the array.
  • Loss of Elements: Due to the fixed length of arrays, elements that exceed the array's capacity are lost during insertion.
  • Waste of Memory: Initializing a longer array and utilizing only the front part results in \"meaningless\" end elements during insertion, leading to some wasted memory space.
"},{"location":"chapter_array_and_linkedlist/array/#5-traversing-arrays","title":"5. \u00a0 Traversing Arrays","text":"

In most programming languages, we can traverse an array either by using indices or by directly iterating over each element:

PythonC++JavaC#GoSwiftJSTSDartRustCZig array.py
def traverse(nums: list[int]):\n    \"\"\"\u904d\u5386\u6570\u7ec4\"\"\"\n    count = 0\n    # \u901a\u8fc7\u7d22\u5f15\u904d\u5386\u6570\u7ec4\n    for i in range(len(nums)):\n        count += nums[i]\n    # \u76f4\u63a5\u904d\u5386\u6570\u7ec4\u5143\u7d20\n    for num in nums:\n        count += num\n    # \u540c\u65f6\u904d\u5386\u6570\u636e\u7d22\u5f15\u548c\u5143\u7d20\n    for i, num in enumerate(nums):\n        count += nums[i]\n        count += num\n
array.cpp
/* \u904d\u5386\u6570\u7ec4 */\nvoid traverse(int *nums, int size) {\n    int count = 0;\n    // \u901a\u8fc7\u7d22\u5f15\u904d\u5386\u6570\u7ec4\n    for (int i = 0; i < size; i++) {\n        count += nums[i];\n    }\n}\n
array.java
/* \u904d\u5386\u6570\u7ec4 */\nvoid traverse(int[] nums) {\n    int count = 0;\n    // \u901a\u8fc7\u7d22\u5f15\u904d\u5386\u6570\u7ec4\n    for (int i = 0; i < nums.length; i++) {\n        count += nums[i];\n    }\n    // \u76f4\u63a5\u904d\u5386\u6570\u7ec4\u5143\u7d20\n    for (int num : nums) {\n        count += num;\n    }\n}\n
array.cs
/* \u904d\u5386\u6570\u7ec4 */\nvoid Traverse(int[] nums) {\n    int count = 0;\n    // \u901a\u8fc7\u7d22\u5f15\u904d\u5386\u6570\u7ec4\n    for (int i = 0; i < nums.Length; i++) {\n        count += nums[i];\n    }\n    // \u76f4\u63a5\u904d\u5386\u6570\u7ec4\u5143\u7d20\n    foreach (int num in nums) {\n        count += num;\n    }\n}\n
array.go
/* \u904d\u5386\u6570\u7ec4 */\nfunc traverse(nums []int) {\n    count := 0\n    // \u901a\u8fc7\u7d22\u5f15\u904d\u5386\u6570\u7ec4\n    for i := 0; i < len(nums); i++ {\n        count += nums[i]\n    }\n    count = 0\n    // \u76f4\u63a5\u904d\u5386\u6570\u7ec4\u5143\u7d20\n    for _, num := range nums {\n        count += num\n    }\n    // \u540c\u65f6\u904d\u5386\u6570\u636e\u7d22\u5f15\u548c\u5143\u7d20\n    for i, num := range nums {\n        count += nums[i]\n        count += num\n    }\n}\n
array.swift
/* \u904d\u5386\u6570\u7ec4 */\nfunc traverse(nums: [Int]) {\n    var count = 0\n    // \u901a\u8fc7\u7d22\u5f15\u904d\u5386\u6570\u7ec4\n    for i in nums.indices {\n        count += nums[i]\n    }\n    // \u76f4\u63a5\u904d\u5386\u6570\u7ec4\u5143\u7d20\n    for num in nums {\n        count += num\n    }\n    // \u540c\u65f6\u904d\u5386\u6570\u636e\u7d22\u5f15\u548c\u5143\u7d20\n    for (i, num) in nums.enumerated() {\n        count += nums[i]\n        count += num\n    }\n}\n
array.js
/* \u904d\u5386\u6570\u7ec4 */\nfunction traverse(nums) {\n    let count = 0;\n    // \u901a\u8fc7\u7d22\u5f15\u904d\u5386\u6570\u7ec4\n    for (let i = 0; i < nums.length; i++) {\n        count += nums[i];\n    }\n    // \u76f4\u63a5\u904d\u5386\u6570\u7ec4\u5143\u7d20\n    for (const num of nums) {\n        count += num;\n    }\n}\n
array.ts
/* \u904d\u5386\u6570\u7ec4 */\nfunction traverse(nums: number[]): void {\n    let count = 0;\n    // \u901a\u8fc7\u7d22\u5f15\u904d\u5386\u6570\u7ec4\n    for (let i = 0; i < nums.length; i++) {\n        count += nums[i];\n    }\n    // \u76f4\u63a5\u904d\u5386\u6570\u7ec4\u5143\u7d20\n    for (const num of nums) {\n        count += num;\n    }\n}\n
array.dart
/* \u904d\u5386\u6570\u7ec4\u5143\u7d20 */\nvoid traverse(List<int> nums) {\n  int count = 0;\n  // \u901a\u8fc7\u7d22\u5f15\u904d\u5386\u6570\u7ec4\n  for (var i = 0; i < nums.length; i++) {\n    count += nums[i];\n  }\n  // \u76f4\u63a5\u904d\u5386\u6570\u7ec4\u5143\u7d20\n  for (int _num in nums) {\n    count += _num;\n  }\n  // \u901a\u8fc7 forEach \u65b9\u6cd5\u904d\u5386\u6570\u7ec4\n  nums.forEach((_num) {\n    count += _num;\n  });\n}\n
array.rs
/* \u904d\u5386\u6570\u7ec4 */\nfn traverse(nums: &[i32]) {\n    let mut _count = 0;\n    // \u901a\u8fc7\u7d22\u5f15\u904d\u5386\u6570\u7ec4\n    for i in 0..nums.len() {\n        _count += nums[i];\n    }\n    // \u76f4\u63a5\u904d\u5386\u6570\u7ec4\u5143\u7d20\n    for num in nums {\n        _count += num;\n    }\n}\n
array.c
/* \u904d\u5386\u6570\u7ec4 */\nvoid traverse(int *nums, int size) {\n    int count = 0;\n    // \u901a\u8fc7\u7d22\u5f15\u904d\u5386\u6570\u7ec4\n    for (int i = 0; i < size; i++) {\n        count += nums[i];\n    }\n}\n
array.zig
// \u904d\u5386\u6570\u7ec4\nfn traverse(nums: []i32) void {\n    var count: i32 = 0;\n    // \u901a\u8fc7\u7d22\u5f15\u904d\u5386\u6570\u7ec4\n    var i: i32 = 0;\n    while (i < nums.len) : (i += 1) {\n        count += nums[i];\n    }\n    count = 0;\n    // \u76f4\u63a5\u904d\u5386\u6570\u7ec4\u5143\u7d20\n    for (nums) |num| {\n        count += num;\n    }\n}\n
Code Visualization

Full Screen >

"},{"location":"chapter_array_and_linkedlist/array/#6-finding-elements","title":"6. \u00a0 Finding Elements","text":"

Locating a specific element within an array involves iterating through the array, checking each element to determine if it matches the desired value.

Because arrays are linear data structures, this operation is commonly referred to as \"linear search.\"

PythonC++JavaC#GoSwiftJSTSDartRustCZig array.py
def find(nums: list[int], target: int) -> int:\n    \"\"\"\u5728\u6570\u7ec4\u4e2d\u67e5\u627e\u6307\u5b9a\u5143\u7d20\"\"\"\n    for i in range(len(nums)):\n        if nums[i] == target:\n            return i\n    return -1\n
array.cpp
/* \u5728\u6570\u7ec4\u4e2d\u67e5\u627e\u6307\u5b9a\u5143\u7d20 */\nint find(int *nums, int size, int target) {\n    for (int i = 0; i < size; i++) {\n        if (nums[i] == target)\n            return i;\n    }\n    return -1;\n}\n
array.java
/* \u5728\u6570\u7ec4\u4e2d\u67e5\u627e\u6307\u5b9a\u5143\u7d20 */\nint find(int[] nums, int target) {\n    for (int i = 0; i < nums.length; i++) {\n        if (nums[i] == target)\n            return i;\n    }\n    return -1;\n}\n
array.cs
/* \u5728\u6570\u7ec4\u4e2d\u67e5\u627e\u6307\u5b9a\u5143\u7d20 */\nint Find(int[] nums, int target) {\n    for (int i = 0; i < nums.Length; i++) {\n        if (nums[i] == target)\n            return i;\n    }\n    return -1;\n}\n
array.go
/* \u5728\u6570\u7ec4\u4e2d\u67e5\u627e\u6307\u5b9a\u5143\u7d20 */\nfunc find(nums []int, target int) (index int) {\n    index = -1\n    for i := 0; i < len(nums); i++ {\n        if nums[i] == target {\n            index = i\n            break\n        }\n    }\n    return\n}\n
array.swift
/* \u5728\u6570\u7ec4\u4e2d\u67e5\u627e\u6307\u5b9a\u5143\u7d20 */\nfunc find(nums: [Int], target: Int) -> Int {\n    for i in nums.indices {\n        if nums[i] == target {\n            return i\n        }\n    }\n    return -1\n}\n
array.js
/* \u5728\u6570\u7ec4\u4e2d\u67e5\u627e\u6307\u5b9a\u5143\u7d20 */\nfunction find(nums, target) {\n    for (let i = 0; i < nums.length; i++) {\n        if (nums[i] === target) return i;\n    }\n    return -1;\n}\n
array.ts
/* \u5728\u6570\u7ec4\u4e2d\u67e5\u627e\u6307\u5b9a\u5143\u7d20 */\nfunction find(nums: number[], target: number): number {\n    for (let i = 0; i < nums.length; i++) {\n        if (nums[i] === target) {\n            return i;\n        }\n    }\n    return -1;\n}\n
array.dart
/* \u5728\u6570\u7ec4\u4e2d\u67e5\u627e\u6307\u5b9a\u5143\u7d20 */\nint find(List<int> nums, int target) {\n  for (var i = 0; i < nums.length; i++) {\n    if (nums[i] == target) return i;\n  }\n  return -1;\n}\n
array.rs
/* \u5728\u6570\u7ec4\u4e2d\u67e5\u627e\u6307\u5b9a\u5143\u7d20 */\nfn find(nums: &[i32], target: i32) -> Option<usize> {\n    for i in 0..nums.len() {\n        if nums[i] == target {\n            return Some(i);\n        }\n    }\n    None\n}\n
array.c
/* \u5728\u6570\u7ec4\u4e2d\u67e5\u627e\u6307\u5b9a\u5143\u7d20 */\nint find(int *nums, int size, int target) {\n    for (int i = 0; i < size; i++) {\n        if (nums[i] == target)\n            return i;\n    }\n    return -1;\n}\n
array.zig
// \u5728\u6570\u7ec4\u4e2d\u67e5\u627e\u6307\u5b9a\u5143\u7d20\nfn find(nums: []i32, target: i32) i32 {\n    for (nums, 0..) |num, i| {\n        if (num == target) return @intCast(i);\n    }\n    return -1;\n}\n
Code Visualization

Full Screen >

"},{"location":"chapter_array_and_linkedlist/array/#7-expanding-arrays","title":"7. \u00a0 Expanding Arrays","text":"

In complex system environments, ensuring the availability of memory space after an array for safe capacity extension becomes challenging. Consequently, in most programming languages, the length of an array is immutable.

To expand an array, it's necessary to create a larger array and then copy the elements from the original array. This operation has a time complexity of \\(O(n)\\) and can be time-consuming for large arrays. The code are as follows:

PythonC++JavaC#GoSwiftJSTSDartRustCZig array.py
def extend(nums: list[int], enlarge: int) -> list[int]:\n    \"\"\"\u6269\u5c55\u6570\u7ec4\u957f\u5ea6\"\"\"\n    # \u521d\u59cb\u5316\u4e00\u4e2a\u6269\u5c55\u957f\u5ea6\u540e\u7684\u6570\u7ec4\n    res = [0] * (len(nums) + enlarge)\n    # \u5c06\u539f\u6570\u7ec4\u4e2d\u7684\u6240\u6709\u5143\u7d20\u590d\u5236\u5230\u65b0\u6570\u7ec4\n    for i in range(len(nums)):\n        res[i] = nums[i]\n    # \u8fd4\u56de\u6269\u5c55\u540e\u7684\u65b0\u6570\u7ec4\n    return res\n
array.cpp
/* \u6269\u5c55\u6570\u7ec4\u957f\u5ea6 */\nint *extend(int *nums, int size, int enlarge) {\n    // \u521d\u59cb\u5316\u4e00\u4e2a\u6269\u5c55\u957f\u5ea6\u540e\u7684\u6570\u7ec4\n    int *res = new int[size + enlarge];\n    // \u5c06\u539f\u6570\u7ec4\u4e2d\u7684\u6240\u6709\u5143\u7d20\u590d\u5236\u5230\u65b0\u6570\u7ec4\n    for (int i = 0; i < size; i++) {\n        res[i] = nums[i];\n    }\n    // \u91ca\u653e\u5185\u5b58\n    delete[] nums;\n    // \u8fd4\u56de\u6269\u5c55\u540e\u7684\u65b0\u6570\u7ec4\n    return res;\n}\n
array.java
/* \u6269\u5c55\u6570\u7ec4\u957f\u5ea6 */\nint[] extend(int[] nums, int enlarge) {\n    // \u521d\u59cb\u5316\u4e00\u4e2a\u6269\u5c55\u957f\u5ea6\u540e\u7684\u6570\u7ec4\n    int[] res = new int[nums.length + enlarge];\n    // \u5c06\u539f\u6570\u7ec4\u4e2d\u7684\u6240\u6709\u5143\u7d20\u590d\u5236\u5230\u65b0\u6570\u7ec4\n    for (int i = 0; i < nums.length; i++) {\n        res[i] = nums[i];\n    }\n    // \u8fd4\u56de\u6269\u5c55\u540e\u7684\u65b0\u6570\u7ec4\n    return res;\n}\n
array.cs
/* \u6269\u5c55\u6570\u7ec4\u957f\u5ea6 */\nint[] Extend(int[] nums, int enlarge) {\n    // \u521d\u59cb\u5316\u4e00\u4e2a\u6269\u5c55\u957f\u5ea6\u540e\u7684\u6570\u7ec4\n    int[] res = new int[nums.Length + enlarge];\n    // \u5c06\u539f\u6570\u7ec4\u4e2d\u7684\u6240\u6709\u5143\u7d20\u590d\u5236\u5230\u65b0\u6570\u7ec4\n    for (int i = 0; i < nums.Length; i++) {\n        res[i] = nums[i];\n    }\n    // \u8fd4\u56de\u6269\u5c55\u540e\u7684\u65b0\u6570\u7ec4\n    return res;\n}\n
array.go
/* \u6269\u5c55\u6570\u7ec4\u957f\u5ea6 */\nfunc extend(nums []int, enlarge int) []int {\n    // \u521d\u59cb\u5316\u4e00\u4e2a\u6269\u5c55\u957f\u5ea6\u540e\u7684\u6570\u7ec4\n    res := make([]int, len(nums)+enlarge)\n    // \u5c06\u539f\u6570\u7ec4\u4e2d\u7684\u6240\u6709\u5143\u7d20\u590d\u5236\u5230\u65b0\u6570\u7ec4\n    for i, num := range nums {\n        res[i] = num\n    }\n    // \u8fd4\u56de\u6269\u5c55\u540e\u7684\u65b0\u6570\u7ec4\n    return res\n}\n
array.swift
/* \u6269\u5c55\u6570\u7ec4\u957f\u5ea6 */\nfunc extend(nums: [Int], enlarge: Int) -> [Int] {\n    // \u521d\u59cb\u5316\u4e00\u4e2a\u6269\u5c55\u957f\u5ea6\u540e\u7684\u6570\u7ec4\n    var res = Array(repeating: 0, count: nums.count + enlarge)\n    // \u5c06\u539f\u6570\u7ec4\u4e2d\u7684\u6240\u6709\u5143\u7d20\u590d\u5236\u5230\u65b0\u6570\u7ec4\n    for i in nums.indices {\n        res[i] = nums[i]\n    }\n    // \u8fd4\u56de\u6269\u5c55\u540e\u7684\u65b0\u6570\u7ec4\n    return res\n}\n
array.js
/* \u6269\u5c55\u6570\u7ec4\u957f\u5ea6 */\n// \u8bf7\u6ce8\u610f\uff0cJavaScript \u7684 Array \u662f\u52a8\u6001\u6570\u7ec4\uff0c\u53ef\u4ee5\u76f4\u63a5\u6269\u5c55\n// \u4e3a\u4e86\u65b9\u4fbf\u5b66\u4e60\uff0c\u672c\u51fd\u6570\u5c06 Array \u770b\u4f5c\u957f\u5ea6\u4e0d\u53ef\u53d8\u7684\u6570\u7ec4\nfunction extend(nums, enlarge) {\n    // \u521d\u59cb\u5316\u4e00\u4e2a\u6269\u5c55\u957f\u5ea6\u540e\u7684\u6570\u7ec4\n    const res = new Array(nums.length + enlarge).fill(0);\n    // \u5c06\u539f\u6570\u7ec4\u4e2d\u7684\u6240\u6709\u5143\u7d20\u590d\u5236\u5230\u65b0\u6570\u7ec4\n    for (let i = 0; i < nums.length; i++) {\n        res[i] = nums[i];\n    }\n    // \u8fd4\u56de\u6269\u5c55\u540e\u7684\u65b0\u6570\u7ec4\n    return res;\n}\n
array.ts
/* \u6269\u5c55\u6570\u7ec4\u957f\u5ea6 */\n// \u8bf7\u6ce8\u610f\uff0cTypeScript \u7684 Array \u662f\u52a8\u6001\u6570\u7ec4\uff0c\u53ef\u4ee5\u76f4\u63a5\u6269\u5c55\n// \u4e3a\u4e86\u65b9\u4fbf\u5b66\u4e60\uff0c\u672c\u51fd\u6570\u5c06 Array \u770b\u4f5c\u957f\u5ea6\u4e0d\u53ef\u53d8\u7684\u6570\u7ec4\nfunction extend(nums: number[], enlarge: number): number[] {\n    // \u521d\u59cb\u5316\u4e00\u4e2a\u6269\u5c55\u957f\u5ea6\u540e\u7684\u6570\u7ec4\n    const res = new Array(nums.length + enlarge).fill(0);\n    // \u5c06\u539f\u6570\u7ec4\u4e2d\u7684\u6240\u6709\u5143\u7d20\u590d\u5236\u5230\u65b0\u6570\u7ec4\n    for (let i = 0; i < nums.length; i++) {\n        res[i] = nums[i];\n    }\n    // \u8fd4\u56de\u6269\u5c55\u540e\u7684\u65b0\u6570\u7ec4\n    return res;\n}\n
array.dart
/* \u6269\u5c55\u6570\u7ec4\u957f\u5ea6 */\nList<int> extend(List<int> nums, int enlarge) {\n  // \u521d\u59cb\u5316\u4e00\u4e2a\u6269\u5c55\u957f\u5ea6\u540e\u7684\u6570\u7ec4\n  List<int> res = List.filled(nums.length + enlarge, 0);\n  // \u5c06\u539f\u6570\u7ec4\u4e2d\u7684\u6240\u6709\u5143\u7d20\u590d\u5236\u5230\u65b0\u6570\u7ec4\n  for (var i = 0; i < nums.length; i++) {\n    res[i] = nums[i];\n  }\n  // \u8fd4\u56de\u6269\u5c55\u540e\u7684\u65b0\u6570\u7ec4\n  return res;\n}\n
array.rs
/* \u6269\u5c55\u6570\u7ec4\u957f\u5ea6 */\nfn extend(nums: Vec<i32>, enlarge: usize) -> Vec<i32> {\n    // \u521d\u59cb\u5316\u4e00\u4e2a\u6269\u5c55\u957f\u5ea6\u540e\u7684\u6570\u7ec4\n    let mut res: Vec<i32> = vec![0; nums.len() + enlarge];\n    // \u5c06\u539f\u6570\u7ec4\u4e2d\u7684\u6240\u6709\u5143\u7d20\u590d\u5236\u5230\u65b0\n    for i in 0..nums.len() {\n        res[i] = nums[i];\n    }\n    // \u8fd4\u56de\u6269\u5c55\u540e\u7684\u65b0\u6570\u7ec4\n    res\n}\n
array.c
/* \u6269\u5c55\u6570\u7ec4\u957f\u5ea6 */\nint *extend(int *nums, int size, int enlarge) {\n    // \u521d\u59cb\u5316\u4e00\u4e2a\u6269\u5c55\u957f\u5ea6\u540e\u7684\u6570\u7ec4\n    int *res = (int *)malloc(sizeof(int) * (size + enlarge));\n    // \u5c06\u539f\u6570\u7ec4\u4e2d\u7684\u6240\u6709\u5143\u7d20\u590d\u5236\u5230\u65b0\u6570\u7ec4\n    for (int i = 0; i < size; i++) {\n        res[i] = nums[i];\n    }\n    // \u521d\u59cb\u5316\u6269\u5c55\u540e\u7684\u7a7a\u95f4\n    for (int i = size; i < size + enlarge; i++) {\n        res[i] = 0;\n    }\n    // \u8fd4\u56de\u6269\u5c55\u540e\u7684\u65b0\u6570\u7ec4\n    return res;\n}\n
array.zig
// \u6269\u5c55\u6570\u7ec4\u957f\u5ea6\nfn extend(mem_allocator: std.mem.Allocator, nums: []i32, enlarge: usize) ![]i32 {\n    // \u521d\u59cb\u5316\u4e00\u4e2a\u6269\u5c55\u957f\u5ea6\u540e\u7684\u6570\u7ec4\n    var res = try mem_allocator.alloc(i32, nums.len + enlarge);\n    @memset(res, 0);\n    // \u5c06\u539f\u6570\u7ec4\u4e2d\u7684\u6240\u6709\u5143\u7d20\u590d\u5236\u5230\u65b0\u6570\u7ec4\n    std.mem.copy(i32, res, nums);\n    // \u8fd4\u56de\u6269\u5c55\u540e\u7684\u65b0\u6570\u7ec4\n    return res;\n}\n
Code Visualization

Full Screen >

"},{"location":"chapter_array_and_linkedlist/array/#412-advantages-and-limitations-of-arrays","title":"4.1.2 \u00a0 Advantages and Limitations of Arrays","text":"

Arrays are stored in contiguous memory spaces and consist of elements of the same type. This approach provides substantial prior information that systems can leverage to optimize the efficiency of data structure operations.

  • High Space Efficiency: Arrays allocate a contiguous block of memory for data, eliminating the need for additional structural overhead.
  • Support for Random Access: Arrays allow \\(O(1)\\) time access to any element.
  • Cache Locality: When accessing array elements, the computer not only loads them but also caches the surrounding data, utilizing high-speed cache to enchance subsequent operation speeds.

However, continuous space storage is a double-edged sword, with the following limitations:

  • Low Efficiency in Insertion and Deletion: As arrays accumulate many elements, inserting or deleting elements requires shifting a large number of elements.
  • Fixed Length: The length of an array is fixed after initialization. Expanding an array requires copying all data to a new array, incurring significant costs.
  • Space Wastage: If the allocated array size exceeds the what is necessary, the extra space is wasted.
"},{"location":"chapter_array_and_linkedlist/array/#413-typical-applications-of-arrays","title":"4.1.3 \u00a0 Typical Applications of Arrays","text":"

Arrays are fundamental and widely used data structures. They find frequent application in various algorithms and serve in the implementation of complex data structures.

  • Random Access: Arrays are ideal for storing data when random sampling is required. By generating a random sequence based on indices, we can achieve random sampling efficiently.
  • Sorting and Searching: Arrays are the most commonly used data structure for sorting and searching algorithms. Techniques like quick sort, merge sort, binary search, etc., are primarily operate on arrays.
  • Lookup Tables: Arrays serve as efficient lookup tables for quick element or relationship retrieval. For instance, mapping characters to ASCII codes becomes seamless by using the ASCII code values as indices and storing corresponding elements in the array.
  • Machine Learning: Within the domain of neural networks, arrays play a pivotal role in executing crucial linear algebra operations involving vectors, matrices, and tensors. Arrays serve as the primary and most extensively used data structure in neural network programming.
  • Data Structure Implementation: Arrays serve as the building blocks for implementing various data structures like stacks, queues, hash tables, heaps, graphs, etc. For instance, the adjacency matrix representation of a graph is essentially a two-dimensional array.
"},{"location":"chapter_array_and_linkedlist/linked_list/","title":"4.2 \u00a0 Linked Lists","text":"

Memory space is a shared resource among all programs. In a complex system environment, available memory can be dispersed throughout the memory space. We understand that the memory allocated for an array must be continuous. However, for very large arrays, finding a sufficiently large contiguous memory space might be challenging. This is where the flexible advantage of linked lists becomes evident.

A \"linked list\" is a linear data structure in which each element is a node object, and the nodes are interconnected through \"references\". These references hold the memory addresses of subsequent nodes, enabling navigation from one node to the next.

The design of linked lists allows for their nodes to be distributed across memory locations without requiring contiguous memory addresses.

Figure 4-5 \u00a0 Linked List Definition and Storage Method

As shown in the figure, we see that the basic building block of a linked list is the \"node\" object. Each node comprises two key components: the node's \"value\" and a \"reference\" to the next node.

  • The first node in a linked list is the \"head node\", and the final one is the \"tail node\".
  • The tail node points to \"null\", designated as null in Java, nullptr in C++, and None in Python.
  • In languages that support pointers, like C, C++, Go, and Rust, this \"reference\" is typically implemented as a \"pointer\".

As the code below illustrates, a ListNode in a linked list, besides holding a value, must also maintain an additional reference (or pointer). Therefore, a linked list occupies more memory space than an array when storing the same quantity of data..

PythonC++JavaC#GoSwiftJSTSDartRustCZig
class ListNode:\n    \"\"\"Linked List Node Class\"\"\"\n    def __init__(self, val: int):\n        self.val: int = val               # Node value\n        self.next: ListNode | None = None # Reference to the next node\n
/* Linked List Node Structure */\nstruct ListNode {\n    int val;         // Node value\n    ListNode *next;  // Pointer to the next node\n    ListNode(int x) : val(x), next(nullptr) {}  // Constructor\n};\n
/* Linked List Node Class */\nclass ListNode {\n    int val;        // Node value\n    ListNode next;  // Reference to the next node\n    ListNode(int x) { val = x; }  // Constructor\n}\n
/* Linked List Node Class */\nclass ListNode(int x) {  // Constructor\n    int val = x;         // Node value\n    ListNode? next;      // Reference to the next node\n}\n
/* Linked List Node Structure */\ntype ListNode struct {\n    Val  int       // Node value\n    Next *ListNode // Pointer to the next node\n}\n\n// NewListNode Constructor, creates a new linked list\nfunc NewListNode(val int) *ListNode {\n    return &ListNode{\n        Val:  val,\n        Next: nil,\n    }\n}\n
/* Linked List Node Class */\nclass ListNode {\n    var val: Int // Node value\n    var next: ListNode? // Reference to the next node\n\n    init(x: Int) { // Constructor\n        val = x\n    }\n}\n
/* Linked List Node Class */\nclass ListNode {\n    constructor(val, next) {\n        this.val = (val === undefined ? 0 : val);       // Node value\n        this.next = (next === undefined ? null : next); // Reference to the next node\n    }\n}\n
/* Linked List Node Class */\nclass ListNode {\n    val: number;\n    next: ListNode | null;\n    constructor(val?: number, next?: ListNode | null) {\n        this.val = val === undefined ? 0 : val;        // Node value\n        this.next = next === undefined ? null : next;  // Reference to the next node\n    }\n}\n
/* \u94fe\u8868\u8282\u70b9\u7c7b */\nclass ListNode {\n  int val; // Node value\n  ListNode? next; // Reference to the next node\n  ListNode(this.val, [this.next]); // Constructor\n}\n
use std::rc::Rc;\nuse std::cell::RefCell;\n/* Linked List Node Class */\n#[derive(Debug)]\nstruct ListNode {\n    val: i32, // Node value\n    next: Option<Rc<RefCell<ListNode>>>, // Pointer to the next node\n}\n
/* Linked List Node Structure */\ntypedef struct ListNode {\n    int val;               // Node value\n    struct ListNode *next; // Pointer to the next node\n} ListNode;\n\n/* Constructor */\nListNode *newListNode(int val) {\n    ListNode *node;\n    node = (ListNode *) malloc(sizeof(ListNode));\n    node->val = val;\n    node->next = NULL;\n    return node;\n}\n
// Linked List Node Class\npub fn ListNode(comptime T: type) type {\n    return struct {\n        const Self = @This();\n\n        val: T = 0, // Node value\n        next: ?*Self = null, // Pointer to the next node\n\n        // Constructor\n        pub fn init(self: *Self, x: i32) void {\n            self.val = x;\n            self.next = null;\n        }\n    };\n}\n
"},{"location":"chapter_array_and_linkedlist/linked_list/#421-common-operations-on-linked-lists","title":"4.2.1 \u00a0 Common Operations on Linked Lists","text":""},{"location":"chapter_array_and_linkedlist/linked_list/#1-initializing-a-linked-list","title":"1. \u00a0 Initializing a Linked List","text":"

Constructing a linked list is a two-step process: first, initializing each node object, and second, forming the reference links between the nodes. After initialization, we can traverse all nodes sequentially from the head node by following the next reference.

PythonC++JavaC#GoSwiftJSTSDartRustCZig linked_list.py
# Initialize linked list: 1 -> 3 -> 2 -> 5 -> 4\n# Initialize each node\nn0 = ListNode(1)\nn1 = ListNode(3)\nn2 = ListNode(2)\nn3 = ListNode(5)\nn4 = ListNode(4)\n# Build references between nodes\nn0.next = n1\nn1.next = n2\nn2.next = n3\nn3.next = n4\n
linked_list.cpp
/* Initialize linked list: 1 -> 3 -> 2 -> 5 -> 4 */\n// Initialize each node\nListNode* n0 = new ListNode(1);\nListNode* n1 = new ListNode(3);\nListNode* n2 = new ListNode(2);\nListNode* n3 = new ListNode(5);\nListNode* n4 = new ListNode(4);\n// Build references between nodes\nn0->next = n1;\nn1->next = n2;\nn2->next = n3;\nn3->next = n4;\n
linked_list.java
/* Initialize linked list: 1 -> 3 -> 2 -> 5 -> 4 */\n// Initialize each node\nListNode n0 = new ListNode(1);\nListNode n1 = new ListNode(3);\nListNode n2 = new ListNode(2);\nListNode n3 = new ListNode(5);\nListNode n4 = new ListNode(4);\n// Build references between nodes\nn0.next = n1;\nn1.next = n2;\nn2.next = n3;\nn3.next = n4;\n
linked_list.cs
/* Initialize linked list: 1 -> 3 -> 2 -> 5 -> 4 */\n// Initialize each node\nListNode n0 = new(1);\nListNode n1 = new(3);\nListNode n2 = new(2);\nListNode n3 = new(5);\nListNode n4 = new(4);\n// Build references between nodes\nn0.next = n1;\nn1.next = n2;\nn2.next = n3;\nn3.next = n4;\n
linked_list.go
/* Initialize linked list: 1 -> 3 -> 2 -> 5 -> 4 */\n// Initialize each node\nn0 := NewListNode(1)\nn1 := NewListNode(3)\nn2 := NewListNode(2)\nn3 := NewListNode(5)\nn4 := NewListNode(4)\n// Build references between nodes\nn0.Next = n1\nn1.Next = n2\nn2.Next = n3\nn3.Next = n4\n
linked_list.swift
/* Initialize linked list: 1 -> 3 -> 2 -> 5 -> 4 */\n// Initialize each node\nlet n0 = ListNode(x: 1)\nlet n1 = ListNode(x: 3)\nlet n2 = ListNode(x: 2)\nlet n3 = ListNode(x: 5)\nlet n4 = ListNode(x: 4)\n// Build references between nodes\nn0.next = n1\nn1.next = n2\nn2.next = n3\nn3.next = n4\n
linked_list.js
/* Initialize linked list: 1 -> 3 -> 2 -> 5 -> 4 */\n// Initialize each node\nconst n0 = new ListNode(1);\nconst n1 = new ListNode(3);\nconst n2 = new ListNode(2);\nconst n3 = new ListNode(5);\nconst n4 = new ListNode(4);\n// Build references between nodes\nn0.next = n1;\nn1.next = n2;\nn2.next = n3;\nn3.next = n4;\n
linked_list.ts
/* Initialize linked list: 1 -> 3 -> 2 -> 5 -> 4 */\n// Initialize each node\nconst n0 = new ListNode(1);\nconst n1 = new ListNode(3);\nconst n2 = new ListNode(2);\nconst n3 = new ListNode(5);\nconst n4 = new ListNode(4);\n// Build references between nodes\nn0.next = n1;\nn1.next = n2;\nn2.next = n3;\nn3.next = n4;\n
linked_list.dart
/* Initialize linked list: 1 -> 3 -> 2 -> 5 -> 4 */\n// Initialize each node\nListNode n0 = ListNode(1);\nListNode n1 = ListNode(3);\nListNode n2 = ListNode(2);\nListNode n3 = ListNode(5);\nListNode n4 = ListNode(4);\n// Build references between nodes\nn0.next = n1;\nn1.next = n2;\nn2.next = n3;\nn3.next = n4;\n
linked_list.rs
/* Initialize linked list: 1 -> 3 -> 2 -> 5 -> 4 */\n// Initialize each node\nlet n0 = Rc::new(RefCell::new(ListNode { val: 1, next: None }));\nlet n1 = Rc::new(RefCell::new(ListNode { val: 3, next: None }));\nlet n2 = Rc::new(RefCell::new(ListNode { val: 2, next: None }));\nlet n3 = Rc::new(RefCell::new(ListNode { val: 5, next: None }));\nlet n4 = Rc::new(RefCell::new(ListNode { val: 4, next: None }));\n\n// Build references between nodes\nn0.borrow_mut().next = Some(n1.clone());\nn1.borrow_mut().next = Some(n2.clone());\nn2.borrow_mut().next = Some(n3.clone());\nn3.borrow_mut().next = Some(n4.clone());\n
linked_list.c
/* Initialize linked list: 1 -> 3 -> 2 -> 5 -> 4 */\n// Initialize each node\nListNode* n0 = newListNode(1);\nListNode* n1 = newListNode(3);\nListNode* n2 = newListNode(2);\nListNode* n3 = newListNode(5);\nListNode* n4 = newListNode(4);\n// Build references between nodes\nn0->next = n1;\nn1->next = n2;\nn2->next = n3;\nn3->next = n4;\n
linked_list.zig
// Initialize linked list\n// Initialize each node\nvar n0 = inc.ListNode(i32){.val = 1};\nvar n1 = inc.ListNode(i32){.val = 3};\nvar n2 = inc.ListNode(i32){.val = 2};\nvar n3 = inc.ListNode(i32){.val = 5};\nvar n4 = inc.ListNode(i32){.val = 4};\n// Build references between nodes\nn0.next = &n1;\nn1.next = &n2;\nn2.next = &n3;\nn3.next = &n4;\n

The array as a whole is a variable, for instance, the array nums includes elements like nums[0], nums[1], and so on, whereas a linked list is made up of several distinct node objects. We typically refer to a linked list by its head node, for example, the linked list in the previous code snippet is referred to as n0.

"},{"location":"chapter_array_and_linkedlist/linked_list/#2-inserting-a-node","title":"2. \u00a0 Inserting a Node","text":"

Inserting a node into a linked list is very easy. As shown in the figure, let's assume we aim to insert a new node P between two adjacent nodes n0 and n1. This can be achieved by simply modifying two node references (pointers), with a time complexity of \\(O(1)\\).

By comparison, inserting an element into an array has a time complexity of \\(O(n)\\), which becomes less efficient when dealing with large data volumes.

Figure 4-6 \u00a0 Linked List Node Insertion Example

PythonC++JavaC#GoSwiftJSTSDartRustCZig linked_list.py
def insert(n0: ListNode, P: ListNode):\n    \"\"\"\u5728\u94fe\u8868\u7684\u8282\u70b9 n0 \u4e4b\u540e\u63d2\u5165\u8282\u70b9 P\"\"\"\n    n1 = n0.next\n    P.next = n1\n    n0.next = P\n
linked_list.cpp
/* \u5728\u94fe\u8868\u7684\u8282\u70b9 n0 \u4e4b\u540e\u63d2\u5165\u8282\u70b9 P */\nvoid insert(ListNode *n0, ListNode *P) {\n    ListNode *n1 = n0->next;\n    P->next = n1;\n    n0->next = P;\n}\n
linked_list.java
/* \u5728\u94fe\u8868\u7684\u8282\u70b9 n0 \u4e4b\u540e\u63d2\u5165\u8282\u70b9 P */\nvoid insert(ListNode n0, ListNode P) {\n    ListNode n1 = n0.next;\n    P.next = n1;\n    n0.next = P;\n}\n
linked_list.cs
/* \u5728\u94fe\u8868\u7684\u8282\u70b9 n0 \u4e4b\u540e\u63d2\u5165\u8282\u70b9 P */\nvoid Insert(ListNode n0, ListNode P) {\n    ListNode? n1 = n0.next;\n    P.next = n1;\n    n0.next = P;\n}\n
linked_list.go
/* \u5728\u94fe\u8868\u7684\u8282\u70b9 n0 \u4e4b\u540e\u63d2\u5165\u8282\u70b9 P */\nfunc insertNode(n0 *ListNode, P *ListNode) {\n    n1 := n0.Next\n    P.Next = n1\n    n0.Next = P\n}\n
linked_list.swift
/* \u5728\u94fe\u8868\u7684\u8282\u70b9 n0 \u4e4b\u540e\u63d2\u5165\u8282\u70b9 P */\nfunc insert(n0: ListNode, P: ListNode) {\n    let n1 = n0.next\n    P.next = n1\n    n0.next = P\n}\n
linked_list.js
/* \u5728\u94fe\u8868\u7684\u8282\u70b9 n0 \u4e4b\u540e\u63d2\u5165\u8282\u70b9 P */\nfunction insert(n0, P) {\n    const n1 = n0.next;\n    P.next = n1;\n    n0.next = P;\n}\n
linked_list.ts
/* \u5728\u94fe\u8868\u7684\u8282\u70b9 n0 \u4e4b\u540e\u63d2\u5165\u8282\u70b9 P */\nfunction insert(n0: ListNode, P: ListNode): void {\n    const n1 = n0.next;\n    P.next = n1;\n    n0.next = P;\n}\n
linked_list.dart
/* \u5728\u94fe\u8868\u7684\u8282\u70b9 n0 \u4e4b\u540e\u63d2\u5165\u8282\u70b9 P */\nvoid insert(ListNode n0, ListNode P) {\n  ListNode? n1 = n0.next;\n  P.next = n1;\n  n0.next = P;\n}\n
linked_list.rs
/* \u5728\u94fe\u8868\u7684\u8282\u70b9 n0 \u4e4b\u540e\u63d2\u5165\u8282\u70b9 P */\n#[allow(non_snake_case)]\npub fn insert<T>(n0: &Rc<RefCell<ListNode<T>>>, P: Rc<RefCell<ListNode<T>>>) {\n    let n1 = n0.borrow_mut().next.take();\n    P.borrow_mut().next = n1;\n    n0.borrow_mut().next = Some(P);\n}\n
linked_list.c
/* \u5728\u94fe\u8868\u7684\u8282\u70b9 n0 \u4e4b\u540e\u63d2\u5165\u8282\u70b9 P */\nvoid insert(ListNode *n0, ListNode *P) {\n    ListNode *n1 = n0->next;\n    P->next = n1;\n    n0->next = P;\n}\n
linked_list.zig
// \u5728\u94fe\u8868\u7684\u8282\u70b9 n0 \u4e4b\u540e\u63d2\u5165\u8282\u70b9 P\nfn insert(n0: ?*inc.ListNode(i32), P: ?*inc.ListNode(i32)) void {\n    var n1 = n0.?.next;\n    P.?.next = n1;\n    n0.?.next = P;\n}\n
Code Visualization

Full Screen >

"},{"location":"chapter_array_and_linkedlist/linked_list/#3-deleting-a-node","title":"3. \u00a0 Deleting a Node","text":"

As shown in the figure, deleting a node from a linked list is also very easy, involving only the modification of a single node's reference (pointer).

It's important to note that even though node P continues to point to n1 after being deleted, it becomes inaccessible during linked list traversal. This effectively means that P is no longer a part of the linked list.

Figure 4-7 \u00a0 Linked List Node Deletion

PythonC++JavaC#GoSwiftJSTSDartRustCZig linked_list.py
def remove(n0: ListNode):\n    \"\"\"\u5220\u9664\u94fe\u8868\u7684\u8282\u70b9 n0 \u4e4b\u540e\u7684\u9996\u4e2a\u8282\u70b9\"\"\"\n    if not n0.next:\n        return\n    # n0 -> P -> n1\n    P = n0.next\n    n1 = P.next\n    n0.next = n1\n
linked_list.cpp
/* \u5220\u9664\u94fe\u8868\u7684\u8282\u70b9 n0 \u4e4b\u540e\u7684\u9996\u4e2a\u8282\u70b9 */\nvoid remove(ListNode *n0) {\n    if (n0->next == nullptr)\n        return;\n    // n0 -> P -> n1\n    ListNode *P = n0->next;\n    ListNode *n1 = P->next;\n    n0->next = n1;\n    // \u91ca\u653e\u5185\u5b58\n    delete P;\n}\n
linked_list.java
/* \u5220\u9664\u94fe\u8868\u7684\u8282\u70b9 n0 \u4e4b\u540e\u7684\u9996\u4e2a\u8282\u70b9 */\nvoid remove(ListNode n0) {\n    if (n0.next == null)\n        return;\n    // n0 -> P -> n1\n    ListNode P = n0.next;\n    ListNode n1 = P.next;\n    n0.next = n1;\n}\n
linked_list.cs
/* \u5220\u9664\u94fe\u8868\u7684\u8282\u70b9 n0 \u4e4b\u540e\u7684\u9996\u4e2a\u8282\u70b9 */\nvoid Remove(ListNode n0) {\n    if (n0.next == null)\n        return;\n    // n0 -> P -> n1\n    ListNode P = n0.next;\n    ListNode? n1 = P.next;\n    n0.next = n1;\n}\n
linked_list.go
/* \u5220\u9664\u94fe\u8868\u7684\u8282\u70b9 n0 \u4e4b\u540e\u7684\u9996\u4e2a\u8282\u70b9 */\nfunc removeItem(n0 *ListNode) {\n    if n0.Next == nil {\n        return\n    }\n    // n0 -> P -> n1\n    P := n0.Next\n    n1 := P.Next\n    n0.Next = n1\n}\n
linked_list.swift
/* \u5220\u9664\u94fe\u8868\u7684\u8282\u70b9 n0 \u4e4b\u540e\u7684\u9996\u4e2a\u8282\u70b9 */\nfunc remove(n0: ListNode) {\n    if n0.next == nil {\n        return\n    }\n    // n0 -> P -> n1\n    let P = n0.next\n    let n1 = P?.next\n    n0.next = n1\n}\n
linked_list.js
/* \u5220\u9664\u94fe\u8868\u7684\u8282\u70b9 n0 \u4e4b\u540e\u7684\u9996\u4e2a\u8282\u70b9 */\nfunction remove(n0) {\n    if (!n0.next) return;\n    // n0 -> P -> n1\n    const P = n0.next;\n    const n1 = P.next;\n    n0.next = n1;\n}\n
linked_list.ts
/* \u5220\u9664\u94fe\u8868\u7684\u8282\u70b9 n0 \u4e4b\u540e\u7684\u9996\u4e2a\u8282\u70b9 */\nfunction remove(n0: ListNode): void {\n    if (!n0.next) {\n        return;\n    }\n    // n0 -> P -> n1\n    const P = n0.next;\n    const n1 = P.next;\n    n0.next = n1;\n}\n
linked_list.dart
/* \u5220\u9664\u94fe\u8868\u7684\u8282\u70b9 n0 \u4e4b\u540e\u7684\u9996\u4e2a\u8282\u70b9 */\nvoid remove(ListNode n0) {\n  if (n0.next == null) return;\n  // n0 -> P -> n1\n  ListNode P = n0.next!;\n  ListNode? n1 = P.next;\n  n0.next = n1;\n}\n
linked_list.rs
/* \u5220\u9664\u94fe\u8868\u7684\u8282\u70b9 n0 \u4e4b\u540e\u7684\u9996\u4e2a\u8282\u70b9 */\n#[allow(non_snake_case)]\npub fn remove<T>(n0: &Rc<RefCell<ListNode<T>>>) {\n    if n0.borrow().next.is_none() {\n        return;\n    };\n    // n0 -> P -> n1\n    let P = n0.borrow_mut().next.take();\n    if let Some(node) = P {\n        let n1 = node.borrow_mut().next.take();\n        n0.borrow_mut().next = n1;\n    }\n}\n
linked_list.c
/* \u5220\u9664\u94fe\u8868\u7684\u8282\u70b9 n0 \u4e4b\u540e\u7684\u9996\u4e2a\u8282\u70b9 */\n// \u6ce8\u610f\uff1astdio.h \u5360\u7528\u4e86 remove \u5173\u952e\u8bcd\nvoid removeItem(ListNode *n0) {\n    if (!n0->next)\n        return;\n    // n0 -> P -> n1\n    ListNode *P = n0->next;\n    ListNode *n1 = P->next;\n    n0->next = n1;\n    // \u91ca\u653e\u5185\u5b58\n    free(P);\n}\n
linked_list.zig
// \u5220\u9664\u94fe\u8868\u7684\u8282\u70b9 n0 \u4e4b\u540e\u7684\u9996\u4e2a\u8282\u70b9\nfn remove(n0: ?*inc.ListNode(i32)) void {\n    if (n0.?.next == null) return;\n    // n0 -> P -> n1\n    var P = n0.?.next;\n    var n1 = P.?.next;\n    n0.?.next = n1;\n}\n
Code Visualization

Full Screen >

"},{"location":"chapter_array_and_linkedlist/linked_list/#4-accessing-nodes","title":"4. \u00a0 Accessing Nodes","text":"

Accessing nodes in a linked list is less efficient. As previously mentioned, any element in an array can be accessed in \\(O(1)\\) time. In contrast, with a linked list, the program involves starting from the head node and sequentially traversing through the nodes until the desired node is found. In other words, to access the \\(i\\)-th node in a linked list, the program must iterate through \\(i - 1\\) nodes, resulting in a time complexity of \\(O(n)\\).

PythonC++JavaC#GoSwiftJSTSDartRustCZig linked_list.py
def access(head: ListNode, index: int) -> ListNode | None:\n    \"\"\"\u8bbf\u95ee\u94fe\u8868\u4e2d\u7d22\u5f15\u4e3a index \u7684\u8282\u70b9\"\"\"\n    for _ in range(index):\n        if not head:\n            return None\n        head = head.next\n    return head\n
linked_list.cpp
/* \u8bbf\u95ee\u94fe\u8868\u4e2d\u7d22\u5f15\u4e3a index \u7684\u8282\u70b9 */\nListNode *access(ListNode *head, int index) {\n    for (int i = 0; i < index; i++) {\n        if (head == nullptr)\n            return nullptr;\n        head = head->next;\n    }\n    return head;\n}\n
linked_list.java
/* \u8bbf\u95ee\u94fe\u8868\u4e2d\u7d22\u5f15\u4e3a index \u7684\u8282\u70b9 */\nListNode access(ListNode head, int index) {\n    for (int i = 0; i < index; i++) {\n        if (head == null)\n            return null;\n        head = head.next;\n    }\n    return head;\n}\n
linked_list.cs
/* \u8bbf\u95ee\u94fe\u8868\u4e2d\u7d22\u5f15\u4e3a index \u7684\u8282\u70b9 */\nListNode? Access(ListNode? head, int index) {\n    for (int i = 0; i < index; i++) {\n        if (head == null)\n            return null;\n        head = head.next;\n    }\n    return head;\n}\n
linked_list.go
/* \u8bbf\u95ee\u94fe\u8868\u4e2d\u7d22\u5f15\u4e3a index \u7684\u8282\u70b9 */\nfunc access(head *ListNode, index int) *ListNode {\n    for i := 0; i < index; i++ {\n        if head == nil {\n            return nil\n        }\n        head = head.Next\n    }\n    return head\n}\n
linked_list.swift
/* \u8bbf\u95ee\u94fe\u8868\u4e2d\u7d22\u5f15\u4e3a index \u7684\u8282\u70b9 */\nfunc access(head: ListNode, index: Int) -> ListNode? {\n    var head: ListNode? = head\n    for _ in 0 ..< index {\n        if head == nil {\n            return nil\n        }\n        head = head?.next\n    }\n    return head\n}\n
linked_list.js
/* \u8bbf\u95ee\u94fe\u8868\u4e2d\u7d22\u5f15\u4e3a index \u7684\u8282\u70b9 */\nfunction access(head, index) {\n    for (let i = 0; i < index; i++) {\n        if (!head) {\n            return null;\n        }\n        head = head.next;\n    }\n    return head;\n}\n
linked_list.ts
/* \u8bbf\u95ee\u94fe\u8868\u4e2d\u7d22\u5f15\u4e3a index \u7684\u8282\u70b9 */\nfunction access(head: ListNode | null, index: number): ListNode | null {\n    for (let i = 0; i < index; i++) {\n        if (!head) {\n            return null;\n        }\n        head = head.next;\n    }\n    return head;\n}\n
linked_list.dart
/* \u8bbf\u95ee\u94fe\u8868\u4e2d\u7d22\u5f15\u4e3a index \u7684\u8282\u70b9 */\nListNode? access(ListNode? head, int index) {\n  for (var i = 0; i < index; i++) {\n    if (head == null) return null;\n    head = head.next;\n  }\n  return head;\n}\n
linked_list.rs
/* \u8bbf\u95ee\u94fe\u8868\u4e2d\u7d22\u5f15\u4e3a index \u7684\u8282\u70b9 */\npub fn access<T>(head: Rc<RefCell<ListNode<T>>>, index: i32) -> Rc<RefCell<ListNode<T>>> {\n    if index <= 0 {\n        return head;\n    };\n    if let Some(node) = &head.borrow().next {\n        return access(node.clone(), index - 1);\n    }\n\n    return head;\n}\n
linked_list.c
/* \u8bbf\u95ee\u94fe\u8868\u4e2d\u7d22\u5f15\u4e3a index \u7684\u8282\u70b9 */\nListNode *access(ListNode *head, int index) {\n    for (int i = 0; i < index; i++) {\n        if (head == NULL)\n            return NULL;\n        head = head->next;\n    }\n    return head;\n}\n
linked_list.zig
// \u8bbf\u95ee\u94fe\u8868\u4e2d\u7d22\u5f15\u4e3a index \u7684\u8282\u70b9\nfn access(node: ?*inc.ListNode(i32), index: i32) ?*inc.ListNode(i32) {\n    var head = node;\n    var i: i32 = 0;\n    while (i < index) : (i += 1) {\n        head = head.?.next;\n        if (head == null) return null;\n    }\n    return head;\n}\n
Code Visualization

Full Screen >

"},{"location":"chapter_array_and_linkedlist/linked_list/#5-finding-nodes","title":"5. \u00a0 Finding Nodes","text":"

Traverse the linked list to locate a node whose value matches target, and then output the index of that node within the linked list. This procedure is also an example of linear search. The corresponding code is provided below:

PythonC++JavaC#GoSwiftJSTSDartRustCZig linked_list.py
def find(head: ListNode, target: int) -> int:\n    \"\"\"\u5728\u94fe\u8868\u4e2d\u67e5\u627e\u503c\u4e3a target \u7684\u9996\u4e2a\u8282\u70b9\"\"\"\n    index = 0\n    while head:\n        if head.val == target:\n            return index\n        head = head.next\n        index += 1\n    return -1\n
linked_list.cpp
/* \u5728\u94fe\u8868\u4e2d\u67e5\u627e\u503c\u4e3a target \u7684\u9996\u4e2a\u8282\u70b9 */\nint find(ListNode *head, int target) {\n    int index = 0;\n    while (head != nullptr) {\n        if (head->val == target)\n            return index;\n        head = head->next;\n        index++;\n    }\n    return -1;\n}\n
linked_list.java
/* \u5728\u94fe\u8868\u4e2d\u67e5\u627e\u503c\u4e3a target \u7684\u9996\u4e2a\u8282\u70b9 */\nint find(ListNode head, int target) {\n    int index = 0;\n    while (head != null) {\n        if (head.val == target)\n            return index;\n        head = head.next;\n        index++;\n    }\n    return -1;\n}\n
linked_list.cs
/* \u5728\u94fe\u8868\u4e2d\u67e5\u627e\u503c\u4e3a target \u7684\u9996\u4e2a\u8282\u70b9 */\nint Find(ListNode? head, int target) {\n    int index = 0;\n    while (head != null) {\n        if (head.val == target)\n            return index;\n        head = head.next;\n        index++;\n    }\n    return -1;\n}\n
linked_list.go
/* \u5728\u94fe\u8868\u4e2d\u67e5\u627e\u503c\u4e3a target \u7684\u9996\u4e2a\u8282\u70b9 */\nfunc findNode(head *ListNode, target int) int {\n    index := 0\n    for head != nil {\n        if head.Val == target {\n            return index\n        }\n        head = head.Next\n        index++\n    }\n    return -1\n}\n
linked_list.swift
/* \u5728\u94fe\u8868\u4e2d\u67e5\u627e\u503c\u4e3a target \u7684\u9996\u4e2a\u8282\u70b9 */\nfunc find(head: ListNode, target: Int) -> Int {\n    var head: ListNode? = head\n    var index = 0\n    while head != nil {\n        if head?.val == target {\n            return index\n        }\n        head = head?.next\n        index += 1\n    }\n    return -1\n}\n
linked_list.js
/* \u5728\u94fe\u8868\u4e2d\u67e5\u627e\u503c\u4e3a target \u7684\u9996\u4e2a\u8282\u70b9 */\nfunction find(head, target) {\n    let index = 0;\n    while (head !== null) {\n        if (head.val === target) {\n            return index;\n        }\n        head = head.next;\n        index += 1;\n    }\n    return -1;\n}\n
linked_list.ts
/* \u5728\u94fe\u8868\u4e2d\u67e5\u627e\u503c\u4e3a target \u7684\u9996\u4e2a\u8282\u70b9 */\nfunction find(head: ListNode | null, target: number): number {\n    let index = 0;\n    while (head !== null) {\n        if (head.val === target) {\n            return index;\n        }\n        head = head.next;\n        index += 1;\n    }\n    return -1;\n}\n
linked_list.dart
/* \u5728\u94fe\u8868\u4e2d\u67e5\u627e\u503c\u4e3a target \u7684\u9996\u4e2a\u8282\u70b9 */\nint find(ListNode? head, int target) {\n  int index = 0;\n  while (head != null) {\n    if (head.val == target) {\n      return index;\n    }\n    head = head.next;\n    index++;\n  }\n  return -1;\n}\n
linked_list.rs
/* \u5728\u94fe\u8868\u4e2d\u67e5\u627e\u503c\u4e3a target \u7684\u9996\u4e2a\u8282\u70b9 */\npub fn find<T: PartialEq>(head: Rc<RefCell<ListNode<T>>>, target: T, index: i32) -> i32 {\n    if head.borrow().val == target {\n        return index;\n    };\n    if let Some(node) = &head.borrow_mut().next {\n        return find(node.clone(), target, index + 1);\n    }\n    return -1;\n}\n
linked_list.c
/* \u5728\u94fe\u8868\u4e2d\u67e5\u627e\u503c\u4e3a target \u7684\u9996\u4e2a\u8282\u70b9 */\nint find(ListNode *head, int target) {\n    int index = 0;\n    while (head) {\n        if (head->val == target)\n            return index;\n        head = head->next;\n        index++;\n    }\n    return -1;\n}\n
linked_list.zig
// \u5728\u94fe\u8868\u4e2d\u67e5\u627e\u503c\u4e3a target \u7684\u9996\u4e2a\u8282\u70b9\nfn find(node: ?*inc.ListNode(i32), target: i32) i32 {\n    var head = node;\n    var index: i32 = 0;\n    while (head != null) {\n        if (head.?.val == target) return index;\n        head = head.?.next;\n        index += 1;\n    }\n    return -1;\n}\n
Code Visualization

Full Screen >

"},{"location":"chapter_array_and_linkedlist/linked_list/#422-arrays-vs-linked-lists","title":"4.2.2 \u00a0 Arrays vs. Linked Lists","text":"

The Table 4-1 summarizes the characteristics of arrays and linked lists, and it also compares their efficiencies in various operations. Because they utilize opposing storage strategies, their respective properties and operational efficiencies exhibit distinct contrasts.

Table 4-1 \u00a0 Efficiency Comparison of Arrays and Linked Lists

Arrays Linked Lists Storage Contiguous Memory Space Dispersed Memory Space Capacity Expansion Fixed Length Flexible Expansion Memory Efficiency Less Memory per Element, Potential Space Wastage More Memory per Element Accessing Elements \\(O(1)\\) \\(O(n)\\) Adding Elements \\(O(n)\\) \\(O(1)\\) Deleting Elements \\(O(n)\\) \\(O(1)\\)"},{"location":"chapter_array_and_linkedlist/linked_list/#423-common-types-of-linked-lists","title":"4.2.3 \u00a0 Common Types of Linked Lists","text":"

As shown in the figure, there are three common types of linked lists.

  • Singly Linked List: This is the standard linked list described earlier. Nodes in a singly linked list include a value and a reference to the next node. The first node is known as the head node, and the last node, which points to null (None), is the tail node.
  • Circular Linked List: This is formed when the tail node of a singly linked list points back to the head node, creating a loop. In a circular linked list, any node can function as the head node.
  • Doubly Linked List: In contrast to a singly linked list, a doubly linked list maintains references in two directions. Each node contains references (pointer) to both its successor (the next node) and predecessor (the previous node). Although doubly linked lists offer more flexibility for traversing in either direction, they also consume more memory space.
PythonC++JavaC#GoSwiftJSTSDartRustCZig
class ListNode:\n    \"\"\"Bidirectional linked list node class\"\"\"\"\n    def __init__(self, val: int):\n        self.val: int = val                # Node value\n        self.next: ListNode | None = None  # Reference to the successor node\n        self.prev: ListNode | None = None  # Reference to a predecessor node\n
/* Bidirectional linked list node structure */\nstruct ListNode {\n    int val;         // Node value\n    ListNode *next;  // Pointer to the successor node\n    ListNode *prev;  // Pointer to the predecessor node\n    ListNode(int x) : val(x), next(nullptr), prev(nullptr) {}  // Constructor\n};\n
/* Bidirectional linked list node class */\nclass ListNode {\n    int val;        // Node value\n    ListNode next;  // Reference to the next node\n    ListNode prev;  // Reference to the predecessor node\n    ListNode(int x) { val = x; }  // Constructor\n}\n
/* Bidirectional linked list node class */\nclass ListNode(int x) {  // Constructor\n    int val = x;    // Node value\n    ListNode next;  // Reference to the next node\n    ListNode prev;  // Reference to the predecessor node\n}\n
/* Bidirectional linked list node structure */\ntype DoublyListNode struct {\n    Val  int             // Node value\n    Next *DoublyListNode // Pointer to the successor node\n    Prev *DoublyListNode // Pointer to the predecessor node\n}\n\n// NewDoublyListNode initialization\nfunc NewDoublyListNode(val int) *DoublyListNode {\n    return &DoublyListNode{\n        Val:  val,\n        Next: nil,\n        Prev: nil,\n    }\n}\n
/* Bidirectional linked list node class */\nclass ListNode {\n    var val: Int // Node value\n    var next: ListNode? // Reference to the next node\n    var prev: ListNode? // Reference to the predecessor node\n\n    init(x: Int) { // Constructor\n        val = x\n    }\n}\n
/* Bidirectional linked list node class */\nclass ListNode {\n    constructor(val, next, prev) {\n        this.val = val  ===  undefined ? 0 : val;        // Node value\n        this.next = next  ===  undefined ? null : next;  // Reference to the successor node\n        this.prev = prev  ===  undefined ? null : prev;  // Reference to the predecessor node\n    }\n}\n
/* Bidirectional linked list node class */\nclass ListNode {\n    val: number;\n    next: ListNode | null;\n    prev: ListNode | null;\n    constructor(val?: number, next?: ListNode | null, prev?: ListNode | null) {\n        this.val = val  ===  undefined ? 0 : val;        // Node value\n        this.next = next  ===  undefined ? null : next;  // Reference to the successor node\n        this.prev = prev  ===  undefined ? null : prev;  // Reference to the predecessor node\n    }\n}\n
/* Bidirectional linked list node class */\nclass ListNode {\n    int val;        // Node value\n    ListNode next;  // Reference to the next node\n    ListNode prev;  // Reference to the predecessor node\n    ListNode(this.val, [this.next, this.prev]);  // Constructor\n}\n
use std::rc::Rc;\nuse std::cell::RefCell;\n\n/* Bidirectional linked list node type */\n#[derive(Debug)]\nstruct ListNode {\n    val: i32, // Node value\n    next: Option<Rc<RefCell<ListNode>>>, // Pointer to successor node\n    prev: Option<Rc<RefCell<ListNode>>>, // Pointer to predecessor node\n}\n\n/* Constructors */\nimpl ListNode {\n    fn new(val: i32) -> Self {\n        ListNode {\n            val,\n            next: None,\n            prev: None,\n        }\n    }\n}\n
/* Bidirectional linked list node structure */\ntypedef struct ListNode {\n    int val;               // Node value\n    struct ListNode *next; // Pointer to the successor node\n    struct ListNode *prev; // Pointer to the predecessor node\n} ListNode;\n\n/* Constructors */\nListNode *newListNode(int val) {\n    ListNode *node, *next;\n    node = (ListNode *) malloc(sizeof(ListNode));\n    node->val = val;\n    node->next = NULL;\n    node->prev = NULL;\n    return node;\n}\n
// Bidirectional linked list node class\npub fn ListNode(comptime T: type) type {\n    return struct {\n        const Self = @This();\n\n        val: T = 0, // Node value\n        next: ?*Self = null, // Pointer to the successor node\n        prev: ?*Self = null, // Pointer to the predecessor node\n\n        // Constructor\n        pub fn init(self: *Self, x: i32) void {\n            self.val = x;\n            self.next = null;\n            self.prev = null;\n        }\n    };\n}\n

Figure 4-8 \u00a0 Common Types of Linked Lists

"},{"location":"chapter_array_and_linkedlist/linked_list/#424-typical-applications-of-linked-lists","title":"4.2.4 \u00a0 Typical Applications of Linked Lists","text":"

Singly linked lists are frequently utilized in implementing stacks, queues, hash tables, and graphs.

  • Stacks and Queues: In singly linked lists, if insertions and deletions occur at the same end, it behaves like a stack (last-in-first-out). Conversely, if insertions are at one end and deletions at the other, it functions like a queue (first-in-first-out).
  • Hash Tables: Linked lists are used in chaining, a popular method for resolving hash collisions. Here, all collided elements are grouped into a linked list.
  • Graphs: Adjacency lists, a standard method for graph representation, associate each graph vertex with a linked list. This list contains elements that represent vertices connected to the corresponding vertex.

Doubly linked lists are ideal for scenarios requiring rapid access to preceding and succeeding elements.

  • Advanced Data Structures: In structures like red-black trees and B-trees, accessing a node's parent is essential. This is achieved by incorporating a reference to the parent node in each node, akin to a doubly linked list.
  • Browser History: In web browsers, doubly linked lists facilitate navigating the history of visited pages when users click forward or back.
  • LRU Algorithm: Doubly linked lists are apt for Least Recently Used (LRU) cache eviction algorithms, enabling swift identification of the least recently used data and facilitating fast node addition and removal.

Circular linked lists are ideal for applications that require periodic operations, such as resource scheduling in operating systems.

  • Round-Robin Scheduling Algorithm: In operating systems, the round-robin scheduling algorithm is a common CPU scheduling method, requiring cycling through a group of processes. Each process is assigned a time slice, and upon expiration, the CPU rotates to the next process. This cyclical operation can be efficiently realized using a circular linked list, allowing for a fair and time-shared system among all processes.
  • Data Buffers: Circular linked lists are also used in data buffers, like in audio and video players, where the data stream is divided into multiple buffer blocks arranged in a circular fashion for seamless playback.
"},{"location":"chapter_array_and_linkedlist/list/","title":"4.3 \u00a0 List","text":"

A \"list\" is an abstract data structure concept that represents an ordered collection of elements, supporting operations such as element access, modification, addition, deletion, and traversal, without requiring users to consider capacity limitations. Lists can be implemented based on linked lists or arrays.

  • A linked list inherently serves as a list, supporting operations for adding, deleting, searching, and modifying elements, with the flexibility to dynamically adjust its size.
  • Arrays also support these operations, but due to their immutable length, they can be considered as a list with a length limit.

When implementing lists using arrays, the immutability of length reduces the practicality of the list. This is because predicting the amount of data to be stored in advance is often challenging, making it difficult to choose an appropriate list length. If the length is too small, it may not meet the requirements; if too large, it may waste memory space.

To solve this problem, we can implement lists using a \"dynamic array.\" It inherits the advantages of arrays and can dynamically expand during program execution.

In fact, many programming languages' standard libraries implement lists using dynamic arrays, such as Python's list, Java's ArrayList, C++'s vector, and C#'s List. In the following discussion, we will consider \"list\" and \"dynamic array\" as synonymous concepts.

"},{"location":"chapter_array_and_linkedlist/list/#431-common-list-operations","title":"4.3.1 \u00a0 Common List Operations","text":""},{"location":"chapter_array_and_linkedlist/list/#1-initializing-a-list","title":"1. \u00a0 Initializing a List","text":"

We typically use two initialization methods: \"without initial values\" and \"with initial values\".

PythonC++JavaC#GoSwiftJSTSDartRustCZig list.py
# Initialize list\n# Without initial values\nnums1: list[int] = []\n# With initial values\nnums: list[int] = [1, 3, 2, 5, 4]\n
list.cpp
/* Initialize list */\n// Note, in C++ the vector is the equivalent of nums described here\n// Without initial values\nvector<int> nums1;\n// With initial values\nvector<int> nums = { 1, 3, 2, 5, 4 };\n
list.java
/* Initialize list */\n// Without initial values\nList<Integer> nums1 = new ArrayList<>();\n// With initial values (note the element type should be the wrapper class Integer[] for int[])\nInteger[] numbers = new Integer[] { 1, 3, 2, 5, 4 };\nList<Integer> nums = new ArrayList<>(Arrays.asList(numbers));\n
list.cs
/* Initialize list */\n// Without initial values\nList<int> nums1 = [];\n// With initial values\nint[] numbers = [1, 3, 2, 5, 4];\nList<int> nums = [.. numbers];\n
list_test.go
/* Initialize list */\n// Without initial values\nnums1 := []int{}\n// With initial values\nnums := []int{1, 3, 2, 5, 4}\n
list.swift
/* Initialize list */\n// Without initial values\nlet nums1: [Int] = []\n// With initial values\nvar nums = [1, 3, 2, 5, 4]\n
list.js
/* Initialize list */\n// Without initial values\nconst nums1 = [];\n// With initial values\nconst nums = [1, 3, 2, 5, 4];\n
list.ts
/* Initialize list */\n// Without initial values\nconst nums1: number[] = [];\n// With initial values\nconst nums: number[] = [1, 3, 2, 5, 4];\n
list.dart
/* Initialize list */\n// Without initial values\nList<int> nums1 = [];\n// With initial values\nList<int> nums = [1, 3, 2, 5, 4];\n
list.rs
/* Initialize list */\n// Without initial values\nlet nums1: Vec<i32> = Vec::new();\n// With initial values\nlet nums: Vec<i32> = vec![1, 3, 2, 5, 4];\n
list.c
// C does not provide built-in dynamic arrays\n
list.zig
// Initialize list\nvar nums = std.ArrayList(i32).init(std.heap.page_allocator);\ndefer nums.deinit();\ntry nums.appendSlice(&[_]i32{ 1, 3, 2, 5, 4 });\n
"},{"location":"chapter_array_and_linkedlist/list/#2-accessing-elements","title":"2. \u00a0 Accessing Elements","text":"

Lists are essentially arrays, thus they can access and update elements in \\(O(1)\\) time, which is very efficient.

PythonC++JavaC#GoSwiftJSTSDartRustCZig list.py
# Access elements\nnum: int = nums[1]  # Access the element at index 1\n\n# Update elements\nnums[1] = 0    # Update the element at index 1 to 0\n
list.cpp
/* Access elements */\nint num = nums[1];  // Access the element at index 1\n\n/* Update elements */\nnums[1] = 0;  // Update the element at index 1 to 0\n
list.java
/* Access elements */\nint num = nums.get(1);  // Access the element at index 1\n\n/* Update elements */\nnums.set(1, 0);  // Update the element at index 1 to 0\n
list.cs
/* Access elements */\nint num = nums[1];  // Access the element at index 1\n\n/* Update elements */\nnums[1] = 0;  // Update the element at index 1 to 0\n
list_test.go
/* Access elements */\nnum := nums[1]  // Access the element at index 1\n\n/* Update elements */\nnums[1] = 0     // Update the element at index 1 to 0\n
list.swift
/* Access elements */\nlet num = nums[1] // Access the element at index 1\n\n/* Update elements */\nnums[1] = 0 // Update the element at index 1 to 0\n
list.js
/* Access elements */\nconst num = nums[1];  // Access the element at index 1\n\n/* Update elements */\nnums[1] = 0;  // Update the element at index 1 to 0\n
list.ts
/* Access elements */\nconst num: number = nums[1];  // Access the element at index 1\n\n/* Update elements */\nnums[1] = 0;  // Update the element at index 1 to 0\n
list.dart
/* Access elements */\nint num = nums[1];  // Access the element at index 1\n\n/* Update elements */\nnums[1] = 0;  // Update the element at index 1 to 0\n
list.rs
/* Access elements */\nlet num: i32 = nums[1];  // Access the element at index 1\n/* Update elements */\nnums[1] = 0;             // Update the element at index 1 to 0\n
list.c
// C does not provide built-in dynamic arrays\n
list.zig
// Access elements\nvar num = nums.items[1]; // Access the element at index 1\n\n// Update elements\nnums.items[1] = 0; // Update the element at index 1 to 0  \n
"},{"location":"chapter_array_and_linkedlist/list/#3-inserting-and-removing-elements","title":"3. \u00a0 Inserting and Removing Elements","text":"

Compared to arrays, lists offer more flexibility in adding and removing elements. While adding elements to the end of a list is an \\(O(1)\\) operation, the efficiency of inserting and removing elements elsewhere in the list remains the same as in arrays, with a time complexity of \\(O(n)\\).

PythonC++JavaC#GoSwiftJSTSDartRustCZig list.py
# Clear list\nnums.clear()\n\n# Append elements at the end\nnums.append(1)\nnums.append(3)\nnums.append(2)\nnums.append(5)\nnums.append(4)\n\n# Insert element in the middle\nnums.insert(3, 6)  # Insert number 6 at index 3\n\n# Remove elements\nnums.pop(3)        # Remove the element at index 3\n
list.cpp
/* Clear list */\nnums.clear();\n\n/* Append elements at the end */\nnums.push_back(1);\nnums.push_back(3);\nnums.push_back(2);\nnums.push_back(5);\nnums.push_back(4);\n\n/* Insert element in the middle */\nnums.insert(nums.begin() + 3, 6);  // Insert number 6 at index 3\n\n/* Remove elements */\nnums.erase(nums.begin() + 3);      // Remove the element at index 3\n
list.java
/* Clear list */\nnums.clear();\n\n/* Append elements at the end */\nnums.add(1);\nnums.add(3);\nnums.add(2);\nnums.add(5);\nnums.add(4);\n\n/* Insert element in the middle */\nnums.add(3, 6);  // Insert number 6 at index 3\n\n/* Remove elements */\nnums.remove(3);  // Remove the element at index 3\n
list.cs
/* Clear list */\nnums.Clear();\n\n/* Append elements at the end */\nnums.Add(1);\nnums.Add(3);\nnums.Add(2);\nnums.Add(5);\nnums.Add(4);\n\n/* Insert element in the middle */\nnums.Insert(3, 6);\n\n/* Remove elements */\nnums.RemoveAt(3);\n
list_test.go
/* Clear list */\nnums = nil\n\n/* Append elements at the end */\nnums = append(nums, 1)\nnums = append(nums, 3)\nnums = append(nums, 2)\nnums = append(nums, 5)\nnums = append(nums, 4)\n\n/* Insert element in the middle */\nnums = append(nums[:3], append([]int{6}, nums[3:]...)...) // Insert number 6 at index 3\n\n/* Remove elements */\nnums = append(nums[:3], nums[4:]...) // Remove the element at index 3\n
list.swift
/* Clear list */\nnums.removeAll()\n\n/* Append elements at the end */\nnums.append(1)\nnums.append(3)\nnums.append(2)\nnums.append(5)\nnums.append(4)\n\n/* Insert element in the middle */\nnums.insert(6, at: 3) // Insert number 6 at index 3\n\n/* Remove elements */\nnums.remove(at: 3) // Remove the element at index 3\n
list.js
/* Clear list */\nnums.length = 0;\n\n/* Append elements at the end */\nnums.push(1);\nnums.push(3);\nnums.push(2);\nnums.push(5);\nnums.push(4);\n\n/* Insert element in the middle */\nnums.splice(3, 0, 6);\n\n/* Remove elements */\nnums.splice(3, 1);\n
list.ts
/* Clear list */\nnums.length = 0;\n\n/* Append elements at the end */\nnums.push(1);\nnums.push(3);\nnums.push(2);\nnums.push(5);\nnums.push(4);\n\n/* Insert element in the middle */\nnums.splice(3, 0, 6);\n\n/* Remove elements */\nnums.splice(3, 1);\n
list.dart
/* Clear list */\nnums.clear();\n\n/* Append elements at the end */\nnums.add(1);\nnums.add(3);\nnums.add(2);\nnums.add(5);\nnums.add(4);\n\n/* Insert element in the middle */\nnums.insert(3, 6); // Insert number 6 at index 3\n\n/* Remove elements */\nnums.removeAt(3); // Remove the element at index 3\n
list.rs
/* Clear list */\nnums.clear();\n\n/* Append elements at the end */\nnums.push(1);\nnums.push(3);\nnums.push(2);\nnums.push(5);\nnums.push(4);\n\n/* Insert element in the middle */\nnums.insert(3, 6);  // Insert number 6 at index 3\n\n/* Remove elements */\nnums.remove(3);    // Remove the element at index 3\n
list.c
// C does not provide built-in dynamic arrays\n
list.zig
// Clear list\nnums.clearRetainingCapacity();\n\n// Append elements at the end\ntry nums.append(1);\ntry nums.append(3);\ntry nums.append(2);\ntry nums.append(5);\ntry nums.append(4);\n\n// Insert element in the middle\ntry nums.insert(3, 6); // Insert number 6 at index 3\n\n// Remove elements\n_ = nums.orderedRemove(3); // Remove the element at index 3\n
"},{"location":"chapter_array_and_linkedlist/list/#4-iterating-the-list","title":"4. \u00a0 Iterating the List","text":"

Similar to arrays, lists can be iterated either by using indices or by directly iterating through each element.

PythonC++JavaC#GoSwiftJSTSDartRustCZig list.py
# Iterate through the list by index\ncount = 0\nfor i in range(len(nums)):\n    count += nums[i]\n\n# Iterate directly through list elements\nfor num in nums:\n    count += num\n
list.cpp
/* Iterate through the list by index */\nint count = 0;\nfor (int i = 0; i < nums.size(); i++) {\n    count += nums[i];\n}\n\n/* Iterate directly through list elements */\ncount = 0;\nfor (int num : nums) {\n    count += num;\n}\n
list.java
/* Iterate through the list by index */\nint count = 0;\nfor (int i = 0; i < nums.size(); i++) {\n    count += nums.get(i);\n}\n\n/* Iterate directly through list elements */\nfor (int num : nums) {\n    count += num;\n}\n
list.cs
/* Iterate through the list by index */\nint count = 0;\nfor (int i = 0; i < nums.Count; i++) {\n    count += nums[i];\n}\n\n/* Iterate directly through list elements */\ncount = 0;\nforeach (int num in nums) {\n    count += num;\n}\n
list_test.go
/* Iterate through the list by index */\ncount := 0\nfor i := 0; i < len(nums); i++ {\n    count += nums[i]\n}\n\n/* Iterate directly through list elements */\ncount = 0\nfor _, num := range nums {\n    count += num\n}\n
list.swift
/* Iterate through the list by index */\nvar count = 0\nfor i in nums.indices {\n    count += nums[i]\n}\n\n/* Iterate directly through list elements */\ncount = 0\nfor num in nums {\n    count += num\n}\n
list.js
/* Iterate through the list by index */\nlet count = 0;\nfor (let i = 0; i < nums.length; i++) {\n    count += nums[i];\n}\n\n/* Iterate directly through list elements */\ncount = 0;\nfor (const num of nums) {\n    count += num;\n}\n
list.ts
/* Iterate through the list by index */\nlet count = 0;\nfor (let i = 0; i < nums.length; i++) {\n    count += nums[i];\n}\n\n/* Iterate directly through list elements */\ncount = 0;\nfor (const num of nums) {\n    count += num;\n}\n
list.dart
/* Iterate through the list by index */\nint count = 0;\nfor (var i = 0; i < nums.length; i++) {\n    count += nums[i];\n}\n\n/* Iterate directly through list elements */\ncount = 0;\nfor (var num in nums) {\n    count += num;\n}\n
list.rs
// Iterate through the list by index\nlet mut _count = 0;\nfor i in 0..nums.len() {\n    _count += nums[i];\n}\n\n// Iterate directly through list elements\n_count = 0;\nfor num in &nums {\n    _count += num;\n}\n
list.c
// C does not provide built-in dynamic arrays\n
list.zig
// Iterate through the list by index\nvar count: i32 = 0;\nvar i: i32 = 0;\nwhile (i < nums.items.len) : (i += 1) {\n    count += nums[i];\n}\n\n// Iterate directly through list elements\ncount = 0;\nfor (nums.items) |num| {\n    count += num;\n}\n
"},{"location":"chapter_array_and_linkedlist/list/#5-concatenating-lists","title":"5. \u00a0 Concatenating Lists","text":"

Given a new list nums1, we can append it to the end of the original list.

PythonC++JavaC#GoSwiftJSTSDartRustCZig list.py
# Concatenate two lists\nnums1: list[int] = [6, 8, 7, 10, 9]\nnums += nums1  # Concatenate nums1 to the end of nums\n
list.cpp
/* Concatenate two lists */\nvector<int> nums1 = { 6, 8, 7, 10, 9 };\n// Concatenate nums1 to the end of nums\nnums.insert(nums.end(), nums1.begin(), nums1.end());\n
list.java
/* Concatenate two lists */\nList<Integer> nums1 = new ArrayList<>(Arrays.asList(new Integer[] { 6, 8, 7, 10, 9 }));\nnums.addAll(nums1);  // Concatenate nums1 to the end of nums\n
list.cs
/* Concatenate two lists */\nList<int> nums1 = [6, 8, 7, 10, 9];\nnums.AddRange(nums1);  // Concatenate nums1 to the end of nums\n
list_test.go
/* Concatenate two lists */\nnums1 := []int{6, 8, 7, 10, 9}\nnums = append(nums, nums1...)  // Concatenate nums1 to the end of nums\n
list.swift
/* Concatenate two lists */\nlet nums1 = [6, 8, 7, 10, 9]\nnums.append(contentsOf: nums1) // Concatenate nums1 to the end of nums\n
list.js
/* Concatenate two lists */\nconst nums1 = [6, 8, 7, 10, 9];\nnums.push(...nums1);  // Concatenate nums1 to the end of nums\n
list.ts
/* Concatenate two lists */\nconst nums1: number[] = [6, 8, 7, 10, 9];\nnums.push(...nums1);  // Concatenate nums1 to the end of nums\n
list.dart
/* Concatenate two lists */\nList<int> nums1 = [6, 8, 7, 10, 9];\nnums.addAll(nums1);  // Concatenate nums1 to the end of nums\n
list.rs
/* Concatenate two lists */\nlet nums1: Vec<i32> = vec![6, 8, 7, 10, 9];\nnums.extend(nums1);\n
list.c
// C does not provide built-in dynamic arrays\n
list.zig
// Concatenate two lists\nvar nums1 = std.ArrayList(i32).init(std.heap.page_allocator);\ndefer nums1.deinit();\ntry nums1.appendSlice(&[_]i32{ 6, 8, 7, 10, 9 });\ntry nums.insertSlice(nums.items.len, nums1.items); // Concatenate nums1 to the end of nums\n
"},{"location":"chapter_array_and_linkedlist/list/#6-sorting-the-list","title":"6. \u00a0 Sorting the List","text":"

Once the list is sorted, we can employ algorithms commonly used in array-related algorithm problems, such as \"binary search\" and \"two-pointer\" algorithms.

PythonC++JavaC#GoSwiftJSTSDartRustCZig list.py
# Sort the list\nnums.sort()  # After sorting, the list elements are in ascending order\n
list.cpp
/* Sort the list */\nsort(nums.begin(), nums.end());  // After sorting, the list elements are in ascending order\n
list.java
/* Sort the list */\nCollections.sort(nums);  // After sorting, the list elements are in ascending order\n
list.cs
/* Sort the list */\nnums.Sort(); // After sorting, the list elements are in ascending order\n
list_test.go
/* Sort the list */\nsort.Ints(nums)  // After sorting, the list elements are in ascending order\n
list.swift
/* Sort the list */\nnums.sort() // After sorting, the list elements are in ascending order\n
list.js
/* Sort the list */  \nnums.sort((a, b) => a - b);  // After sorting, the list elements are in ascending order\n
list.ts
/* Sort the list */\nnums.sort((a, b) => a - b);  // After sorting, the list elements are in ascending order\n
list.dart
/* Sort the list */\nnums.sort(); // After sorting, the list elements are in ascending order\n
list.rs
/* Sort the list */\nnums.sort(); // After sorting, the list elements are in ascending order\n
list.c
// C does not provide built-in dynamic arrays\n
list.zig
// Sort the list\nstd.sort.sort(i32, nums.items, {}, comptime std.sort.asc(i32));\n
"},{"location":"chapter_array_and_linkedlist/list/#432-list-implementation","title":"4.3.2 \u00a0 List Implementation","text":"

Many programming languages come with built-in lists, including Java, C++, Python, etc. Their implementations tend to be intricate, featuring carefully considered settings for various parameters, like initial capacity and expansion factors. Readers who are curious can delve into the source code for further learning.

To enhance our understanding of how lists work, we will attempt to implement a simplified version of a list, focusing on three crucial design aspects:

  • Initial Capacity: Choose a reasonable initial capacity for the array. In this example, we choose 10 as the initial capacity.
  • Size Recording: Declare a variable size to record the current number of elements in the list, updating in real-time with element insertion and deletion. With this variable, we can locate the end of the list and determine whether expansion is needed.
  • Expansion Mechanism: If the list reaches full capacity upon an element insertion, an expansion process is required. This involves creating a larger array based on the expansion factor, and then transferring all elements from the current array to the new one. In this example, we stipulate that the array size should double with each expansion.
PythonC++JavaC#GoSwiftJSTSDartRustCZig my_list.py
class MyList:\n    \"\"\"\u5217\u8868\u7c7b\"\"\"\n\n    def __init__(self):\n        \"\"\"\u6784\u9020\u65b9\u6cd5\"\"\"\n        self._capacity: int = 10  # \u5217\u8868\u5bb9\u91cf\n        self._arr: list[int] = [0] * self._capacity  # \u6570\u7ec4\uff08\u5b58\u50a8\u5217\u8868\u5143\u7d20\uff09\n        self._size: int = 0  # \u5217\u8868\u957f\u5ea6\uff08\u5f53\u524d\u5143\u7d20\u6570\u91cf\uff09\n        self._extend_ratio: int = 2  # \u6bcf\u6b21\u5217\u8868\u6269\u5bb9\u7684\u500d\u6570\n\n    def size(self) -> int:\n        \"\"\"\u83b7\u53d6\u5217\u8868\u957f\u5ea6\uff08\u5f53\u524d\u5143\u7d20\u6570\u91cf\uff09\"\"\"\n        return self._size\n\n    def capacity(self) -> int:\n        \"\"\"\u83b7\u53d6\u5217\u8868\u5bb9\u91cf\"\"\"\n        return self._capacity\n\n    def get(self, index: int) -> int:\n        \"\"\"\u8bbf\u95ee\u5143\u7d20\"\"\"\n        # \u7d22\u5f15\u5982\u679c\u8d8a\u754c\uff0c\u5219\u629b\u51fa\u5f02\u5e38\uff0c\u4e0b\u540c\n        if index < 0 or index >= self._size:\n            raise IndexError(\"\u7d22\u5f15\u8d8a\u754c\")\n        return self._arr[index]\n\n    def set(self, num: int, index: int):\n        \"\"\"\u66f4\u65b0\u5143\u7d20\"\"\"\n        if index < 0 or index >= self._size:\n            raise IndexError(\"\u7d22\u5f15\u8d8a\u754c\")\n        self._arr[index] = num\n\n    def add(self, num: int):\n        \"\"\"\u5728\u5c3e\u90e8\u6dfb\u52a0\u5143\u7d20\"\"\"\n        # \u5143\u7d20\u6570\u91cf\u8d85\u51fa\u5bb9\u91cf\u65f6\uff0c\u89e6\u53d1\u6269\u5bb9\u673a\u5236\n        if self.size() == self.capacity():\n            self.extend_capacity()\n        self._arr[self._size] = num\n        self._size += 1\n\n    def insert(self, num: int, index: int):\n        \"\"\"\u5728\u4e2d\u95f4\u63d2\u5165\u5143\u7d20\"\"\"\n        if index < 0 or index >= self._size:\n            raise IndexError(\"\u7d22\u5f15\u8d8a\u754c\")\n        # \u5143\u7d20\u6570\u91cf\u8d85\u51fa\u5bb9\u91cf\u65f6\uff0c\u89e6\u53d1\u6269\u5bb9\u673a\u5236\n        if self._size == self.capacity():\n            self.extend_capacity()\n        # \u5c06\u7d22\u5f15 index \u4ee5\u53ca\u4e4b\u540e\u7684\u5143\u7d20\u90fd\u5411\u540e\u79fb\u52a8\u4e00\u4f4d\n        for j in range(self._size - 1, index - 1, -1):\n            self._arr[j + 1] = self._arr[j]\n        self._arr[index] = num\n        # \u66f4\u65b0\u5143\u7d20\u6570\u91cf\n        self._size += 1\n\n    def remove(self, index: int) -> int:\n        \"\"\"\u5220\u9664\u5143\u7d20\"\"\"\n        if index < 0 or index >= self._size:\n            raise IndexError(\"\u7d22\u5f15\u8d8a\u754c\")\n        num = self._arr[index]\n        # \u5c06\u7d22\u5f15 index \u4e4b\u540e\u7684\u5143\u7d20\u90fd\u5411\u524d\u79fb\u52a8\u4e00\u4f4d\n        for j in range(index, self._size - 1):\n            self._arr[j] = self._arr[j + 1]\n        # \u66f4\u65b0\u5143\u7d20\u6570\u91cf\n        self._size -= 1\n        # \u8fd4\u56de\u88ab\u5220\u9664\u7684\u5143\u7d20\n        return num\n\n    def extend_capacity(self):\n        \"\"\"\u5217\u8868\u6269\u5bb9\"\"\"\n        # \u65b0\u5efa\u4e00\u4e2a\u957f\u5ea6\u4e3a\u539f\u6570\u7ec4 _extend_ratio \u500d\u7684\u65b0\u6570\u7ec4\uff0c\u5e76\u5c06\u539f\u6570\u7ec4\u590d\u5236\u5230\u65b0\u6570\u7ec4\n        self._arr = self._arr + [0] * self.capacity() * (self._extend_ratio - 1)\n        # \u66f4\u65b0\u5217\u8868\u5bb9\u91cf\n        self._capacity = len(self._arr)\n\n    def to_array(self) -> list[int]:\n        \"\"\"\u8fd4\u56de\u6709\u6548\u957f\u5ea6\u7684\u5217\u8868\"\"\"\n        return self._arr[: self._size]\n
my_list.cpp
/* \u5217\u8868\u7c7b */\nclass MyList {\n  private:\n    int *arr;             // \u6570\u7ec4\uff08\u5b58\u50a8\u5217\u8868\u5143\u7d20\uff09\n    int arrCapacity = 10; // \u5217\u8868\u5bb9\u91cf\n    int arrSize = 0;      // \u5217\u8868\u957f\u5ea6\uff08\u5f53\u524d\u5143\u7d20\u6570\u91cf\uff09\n    int extendRatio = 2;   // \u6bcf\u6b21\u5217\u8868\u6269\u5bb9\u7684\u500d\u6570\n\n  public:\n    /* \u6784\u9020\u65b9\u6cd5 */\n    MyList() {\n        arr = new int[arrCapacity];\n    }\n\n    /* \u6790\u6784\u65b9\u6cd5 */\n    ~MyList() {\n        delete[] arr;\n    }\n\n    /* \u83b7\u53d6\u5217\u8868\u957f\u5ea6\uff08\u5f53\u524d\u5143\u7d20\u6570\u91cf\uff09*/\n    int size() {\n        return arrSize;\n    }\n\n    /* \u83b7\u53d6\u5217\u8868\u5bb9\u91cf */\n    int capacity() {\n        return arrCapacity;\n    }\n\n    /* \u8bbf\u95ee\u5143\u7d20 */\n    int get(int index) {\n        // \u7d22\u5f15\u5982\u679c\u8d8a\u754c\uff0c\u5219\u629b\u51fa\u5f02\u5e38\uff0c\u4e0b\u540c\n        if (index < 0 || index >= size())\n            throw out_of_range(\"\u7d22\u5f15\u8d8a\u754c\");\n        return arr[index];\n    }\n\n    /* \u66f4\u65b0\u5143\u7d20 */\n    void set(int index, int num) {\n        if (index < 0 || index >= size())\n            throw out_of_range(\"\u7d22\u5f15\u8d8a\u754c\");\n        arr[index] = num;\n    }\n\n    /* \u5728\u5c3e\u90e8\u6dfb\u52a0\u5143\u7d20 */\n    void add(int num) {\n        // \u5143\u7d20\u6570\u91cf\u8d85\u51fa\u5bb9\u91cf\u65f6\uff0c\u89e6\u53d1\u6269\u5bb9\u673a\u5236\n        if (size() == capacity())\n            extendCapacity();\n        arr[size()] = num;\n        // \u66f4\u65b0\u5143\u7d20\u6570\u91cf\n        arrSize++;\n    }\n\n    /* \u5728\u4e2d\u95f4\u63d2\u5165\u5143\u7d20 */\n    void insert(int index, int num) {\n        if (index < 0 || index >= size())\n            throw out_of_range(\"\u7d22\u5f15\u8d8a\u754c\");\n        // \u5143\u7d20\u6570\u91cf\u8d85\u51fa\u5bb9\u91cf\u65f6\uff0c\u89e6\u53d1\u6269\u5bb9\u673a\u5236\n        if (size() == capacity())\n            extendCapacity();\n        // \u5c06\u7d22\u5f15 index \u4ee5\u53ca\u4e4b\u540e\u7684\u5143\u7d20\u90fd\u5411\u540e\u79fb\u52a8\u4e00\u4f4d\n        for (int j = size() - 1; j >= index; j--) {\n            arr[j + 1] = arr[j];\n        }\n        arr[index] = num;\n        // \u66f4\u65b0\u5143\u7d20\u6570\u91cf\n        arrSize++;\n    }\n\n    /* \u5220\u9664\u5143\u7d20 */\n    int remove(int index) {\n        if (index < 0 || index >= size())\n            throw out_of_range(\"\u7d22\u5f15\u8d8a\u754c\");\n        int num = arr[index];\n        // \u5c06\u7d22\u5f15 index \u4e4b\u540e\u7684\u5143\u7d20\u90fd\u5411\u524d\u79fb\u52a8\u4e00\u4f4d\n        for (int j = index; j < size() - 1; j++) {\n            arr[j] = arr[j + 1];\n        }\n        // \u66f4\u65b0\u5143\u7d20\u6570\u91cf\n        arrSize--;\n        // \u8fd4\u56de\u88ab\u5220\u9664\u7684\u5143\u7d20\n        return num;\n    }\n\n    /* \u5217\u8868\u6269\u5bb9 */\n    void extendCapacity() {\n        // \u65b0\u5efa\u4e00\u4e2a\u957f\u5ea6\u4e3a\u539f\u6570\u7ec4 extendRatio \u500d\u7684\u65b0\u6570\u7ec4\n        int newCapacity = capacity() * extendRatio;\n        int *tmp = arr;\n        arr = new int[newCapacity];\n        // \u5c06\u539f\u6570\u7ec4\u4e2d\u7684\u6240\u6709\u5143\u7d20\u590d\u5236\u5230\u65b0\u6570\u7ec4\n        for (int i = 0; i < size(); i++) {\n            arr[i] = tmp[i];\n        }\n        // \u91ca\u653e\u5185\u5b58\n        delete[] tmp;\n        arrCapacity = newCapacity;\n    }\n\n    /* \u5c06\u5217\u8868\u8f6c\u6362\u4e3a Vector \u7528\u4e8e\u6253\u5370 */\n    vector<int> toVector() {\n        // \u4ec5\u8f6c\u6362\u6709\u6548\u957f\u5ea6\u8303\u56f4\u5185\u7684\u5217\u8868\u5143\u7d20\n        vector<int> vec(size());\n        for (int i = 0; i < size(); i++) {\n            vec[i] = arr[i];\n        }\n        return vec;\n    }\n};\n
my_list.java
/* \u5217\u8868\u7c7b */\nclass MyList {\n    private int[] arr; // \u6570\u7ec4\uff08\u5b58\u50a8\u5217\u8868\u5143\u7d20\uff09\n    private int capacity = 10; // \u5217\u8868\u5bb9\u91cf\n    private int size = 0; // \u5217\u8868\u957f\u5ea6\uff08\u5f53\u524d\u5143\u7d20\u6570\u91cf\uff09\n    private int extendRatio = 2; // \u6bcf\u6b21\u5217\u8868\u6269\u5bb9\u7684\u500d\u6570\n\n    /* \u6784\u9020\u65b9\u6cd5 */\n    public MyList() {\n        arr = new int[capacity];\n    }\n\n    /* \u83b7\u53d6\u5217\u8868\u957f\u5ea6\uff08\u5f53\u524d\u5143\u7d20\u6570\u91cf\uff09 */\n    public int size() {\n        return size;\n    }\n\n    /* \u83b7\u53d6\u5217\u8868\u5bb9\u91cf */\n    public int capacity() {\n        return capacity;\n    }\n\n    /* \u8bbf\u95ee\u5143\u7d20 */\n    public int get(int index) {\n        // \u7d22\u5f15\u5982\u679c\u8d8a\u754c\uff0c\u5219\u629b\u51fa\u5f02\u5e38\uff0c\u4e0b\u540c\n        if (index < 0 || index >= size)\n            throw new IndexOutOfBoundsException(\"\u7d22\u5f15\u8d8a\u754c\");\n        return arr[index];\n    }\n\n    /* \u66f4\u65b0\u5143\u7d20 */\n    public void set(int index, int num) {\n        if (index < 0 || index >= size)\n            throw new IndexOutOfBoundsException(\"\u7d22\u5f15\u8d8a\u754c\");\n        arr[index] = num;\n    }\n\n    /* \u5728\u5c3e\u90e8\u6dfb\u52a0\u5143\u7d20 */\n    public void add(int num) {\n        // \u5143\u7d20\u6570\u91cf\u8d85\u51fa\u5bb9\u91cf\u65f6\uff0c\u89e6\u53d1\u6269\u5bb9\u673a\u5236\n        if (size == capacity())\n            extendCapacity();\n        arr[size] = num;\n        // \u66f4\u65b0\u5143\u7d20\u6570\u91cf\n        size++;\n    }\n\n    /* \u5728\u4e2d\u95f4\u63d2\u5165\u5143\u7d20 */\n    public void insert(int index, int num) {\n        if (index < 0 || index >= size)\n            throw new IndexOutOfBoundsException(\"\u7d22\u5f15\u8d8a\u754c\");\n        // \u5143\u7d20\u6570\u91cf\u8d85\u51fa\u5bb9\u91cf\u65f6\uff0c\u89e6\u53d1\u6269\u5bb9\u673a\u5236\n        if (size == capacity())\n            extendCapacity();\n        // \u5c06\u7d22\u5f15 index \u4ee5\u53ca\u4e4b\u540e\u7684\u5143\u7d20\u90fd\u5411\u540e\u79fb\u52a8\u4e00\u4f4d\n        for (int j = size - 1; j >= index; j--) {\n            arr[j + 1] = arr[j];\n        }\n        arr[index] = num;\n        // \u66f4\u65b0\u5143\u7d20\u6570\u91cf\n        size++;\n    }\n\n    /* \u5220\u9664\u5143\u7d20 */\n    public int remove(int index) {\n        if (index < 0 || index >= size)\n            throw new IndexOutOfBoundsException(\"\u7d22\u5f15\u8d8a\u754c\");\n        int num = arr[index];\n        // \u5c06\u5c06\u7d22\u5f15 index \u4e4b\u540e\u7684\u5143\u7d20\u90fd\u5411\u524d\u79fb\u52a8\u4e00\u4f4d\n        for (int j = index; j < size - 1; j++) {\n            arr[j] = arr[j + 1];\n        }\n        // \u66f4\u65b0\u5143\u7d20\u6570\u91cf\n        size--;\n        // \u8fd4\u56de\u88ab\u5220\u9664\u7684\u5143\u7d20\n        return num;\n    }\n\n    /* \u5217\u8868\u6269\u5bb9 */\n    public void extendCapacity() {\n        // \u65b0\u5efa\u4e00\u4e2a\u957f\u5ea6\u4e3a\u539f\u6570\u7ec4 extendRatio \u500d\u7684\u65b0\u6570\u7ec4\uff0c\u5e76\u5c06\u539f\u6570\u7ec4\u590d\u5236\u5230\u65b0\u6570\u7ec4\n        arr = Arrays.copyOf(arr, capacity() * extendRatio);\n        // \u66f4\u65b0\u5217\u8868\u5bb9\u91cf\n        capacity = arr.length;\n    }\n\n    /* \u5c06\u5217\u8868\u8f6c\u6362\u4e3a\u6570\u7ec4 */\n    public int[] toArray() {\n        int size = size();\n        // \u4ec5\u8f6c\u6362\u6709\u6548\u957f\u5ea6\u8303\u56f4\u5185\u7684\u5217\u8868\u5143\u7d20\n        int[] arr = new int[size];\n        for (int i = 0; i < size; i++) {\n            arr[i] = get(i);\n        }\n        return arr;\n    }\n}\n
my_list.cs
/* \u5217\u8868\u7c7b */\nclass MyList {\n    private int[] arr;           // \u6570\u7ec4\uff08\u5b58\u50a8\u5217\u8868\u5143\u7d20\uff09\n    private int arrCapacity = 10;    // \u5217\u8868\u5bb9\u91cf\n    private int arrSize = 0;         // \u5217\u8868\u957f\u5ea6\uff08\u5f53\u524d\u5143\u7d20\u6570\u91cf\uff09\n    private readonly int extendRatio = 2;  // \u6bcf\u6b21\u5217\u8868\u6269\u5bb9\u7684\u500d\u6570\n\n    /* \u6784\u9020\u65b9\u6cd5 */\n    public MyList() {\n        arr = new int[arrCapacity];\n    }\n\n    /* \u83b7\u53d6\u5217\u8868\u957f\u5ea6\uff08\u5f53\u524d\u5143\u7d20\u6570\u91cf\uff09*/\n    public int Size() {\n        return arrSize;\n    }\n\n    /* \u83b7\u53d6\u5217\u8868\u5bb9\u91cf */\n    public int Capacity() {\n        return arrCapacity;\n    }\n\n    /* \u8bbf\u95ee\u5143\u7d20 */\n    public int Get(int index) {\n        // \u7d22\u5f15\u5982\u679c\u8d8a\u754c\uff0c\u5219\u629b\u51fa\u5f02\u5e38\uff0c\u4e0b\u540c\n        if (index < 0 || index >= arrSize)\n            throw new IndexOutOfRangeException(\"\u7d22\u5f15\u8d8a\u754c\");\n        return arr[index];\n    }\n\n    /* \u66f4\u65b0\u5143\u7d20 */\n    public void Set(int index, int num) {\n        if (index < 0 || index >= arrSize)\n            throw new IndexOutOfRangeException(\"\u7d22\u5f15\u8d8a\u754c\");\n        arr[index] = num;\n    }\n\n    /* \u5728\u5c3e\u90e8\u6dfb\u52a0\u5143\u7d20 */\n    public void Add(int num) {\n        // \u5143\u7d20\u6570\u91cf\u8d85\u51fa\u5bb9\u91cf\u65f6\uff0c\u89e6\u53d1\u6269\u5bb9\u673a\u5236\n        if (arrSize == arrCapacity)\n            ExtendCapacity();\n        arr[arrSize] = num;\n        // \u66f4\u65b0\u5143\u7d20\u6570\u91cf\n        arrSize++;\n    }\n\n    /* \u5728\u4e2d\u95f4\u63d2\u5165\u5143\u7d20 */\n    public void Insert(int index, int num) {\n        if (index < 0 || index >= arrSize)\n            throw new IndexOutOfRangeException(\"\u7d22\u5f15\u8d8a\u754c\");\n        // \u5143\u7d20\u6570\u91cf\u8d85\u51fa\u5bb9\u91cf\u65f6\uff0c\u89e6\u53d1\u6269\u5bb9\u673a\u5236\n        if (arrSize == arrCapacity)\n            ExtendCapacity();\n        // \u5c06\u7d22\u5f15 index \u4ee5\u53ca\u4e4b\u540e\u7684\u5143\u7d20\u90fd\u5411\u540e\u79fb\u52a8\u4e00\u4f4d\n        for (int j = arrSize - 1; j >= index; j--) {\n            arr[j + 1] = arr[j];\n        }\n        arr[index] = num;\n        // \u66f4\u65b0\u5143\u7d20\u6570\u91cf\n        arrSize++;\n    }\n\n    /* \u5220\u9664\u5143\u7d20 */\n    public int Remove(int index) {\n        if (index < 0 || index >= arrSize)\n            throw new IndexOutOfRangeException(\"\u7d22\u5f15\u8d8a\u754c\");\n        int num = arr[index];\n        // \u5c06\u5c06\u7d22\u5f15 index \u4e4b\u540e\u7684\u5143\u7d20\u90fd\u5411\u524d\u79fb\u52a8\u4e00\u4f4d\n        for (int j = index; j < arrSize - 1; j++) {\n            arr[j] = arr[j + 1];\n        }\n        // \u66f4\u65b0\u5143\u7d20\u6570\u91cf\n        arrSize--;\n        // \u8fd4\u56de\u88ab\u5220\u9664\u7684\u5143\u7d20\n        return num;\n    }\n\n    /* \u5217\u8868\u6269\u5bb9 */\n    public void ExtendCapacity() {\n        // \u65b0\u5efa\u4e00\u4e2a\u957f\u5ea6\u4e3a arrCapacity * extendRatio \u7684\u6570\u7ec4\uff0c\u5e76\u5c06\u539f\u6570\u7ec4\u590d\u5236\u5230\u65b0\u6570\u7ec4\n        Array.Resize(ref arr, arrCapacity * extendRatio);\n        // \u66f4\u65b0\u5217\u8868\u5bb9\u91cf\n        arrCapacity = arr.Length;\n    }\n\n    /* \u5c06\u5217\u8868\u8f6c\u6362\u4e3a\u6570\u7ec4 */\n    public int[] ToArray() {\n        // \u4ec5\u8f6c\u6362\u6709\u6548\u957f\u5ea6\u8303\u56f4\u5185\u7684\u5217\u8868\u5143\u7d20\n        int[] arr = new int[arrSize];\n        for (int i = 0; i < arrSize; i++) {\n            arr[i] = Get(i);\n        }\n        return arr;\n    }\n}\n
my_list.go
/* \u5217\u8868\u7c7b */\ntype myList struct {\n    arrCapacity int\n    arr         []int\n    arrSize     int\n    extendRatio int\n}\n\n/* \u6784\u9020\u51fd\u6570 */\nfunc newMyList() *myList {\n    return &myList{\n        arrCapacity: 10,              // \u5217\u8868\u5bb9\u91cf\n        arr:         make([]int, 10), // \u6570\u7ec4\uff08\u5b58\u50a8\u5217\u8868\u5143\u7d20\uff09\n        arrSize:     0,               // \u5217\u8868\u957f\u5ea6\uff08\u5f53\u524d\u5143\u7d20\u6570\u91cf\uff09\n        extendRatio: 2,               // \u6bcf\u6b21\u5217\u8868\u6269\u5bb9\u7684\u500d\u6570\n    }\n}\n\n/* \u83b7\u53d6\u5217\u8868\u957f\u5ea6\uff08\u5f53\u524d\u5143\u7d20\u6570\u91cf\uff09 */\nfunc (l *myList) size() int {\n    return l.arrSize\n}\n\n/*  \u83b7\u53d6\u5217\u8868\u5bb9\u91cf */\nfunc (l *myList) capacity() int {\n    return l.arrCapacity\n}\n\n/* \u8bbf\u95ee\u5143\u7d20 */\nfunc (l *myList) get(index int) int {\n    // \u7d22\u5f15\u5982\u679c\u8d8a\u754c\uff0c\u5219\u629b\u51fa\u5f02\u5e38\uff0c\u4e0b\u540c\n    if index < 0 || index >= l.arrSize {\n        panic(\"\u7d22\u5f15\u8d8a\u754c\")\n    }\n    return l.arr[index]\n}\n\n/* \u66f4\u65b0\u5143\u7d20 */\nfunc (l *myList) set(num, index int) {\n    if index < 0 || index >= l.arrSize {\n        panic(\"\u7d22\u5f15\u8d8a\u754c\")\n    }\n    l.arr[index] = num\n}\n\n/* \u5728\u5c3e\u90e8\u6dfb\u52a0\u5143\u7d20 */\nfunc (l *myList) add(num int) {\n    // \u5143\u7d20\u6570\u91cf\u8d85\u51fa\u5bb9\u91cf\u65f6\uff0c\u89e6\u53d1\u6269\u5bb9\u673a\u5236\n    if l.arrSize == l.arrCapacity {\n        l.extendCapacity()\n    }\n    l.arr[l.arrSize] = num\n    // \u66f4\u65b0\u5143\u7d20\u6570\u91cf\n    l.arrSize++\n}\n\n/* \u5728\u4e2d\u95f4\u63d2\u5165\u5143\u7d20 */\nfunc (l *myList) insert(num, index int) {\n    if index < 0 || index >= l.arrSize {\n        panic(\"\u7d22\u5f15\u8d8a\u754c\")\n    }\n    // \u5143\u7d20\u6570\u91cf\u8d85\u51fa\u5bb9\u91cf\u65f6\uff0c\u89e6\u53d1\u6269\u5bb9\u673a\u5236\n    if l.arrSize == l.arrCapacity {\n        l.extendCapacity()\n    }\n    // \u5c06\u7d22\u5f15 index \u4ee5\u53ca\u4e4b\u540e\u7684\u5143\u7d20\u90fd\u5411\u540e\u79fb\u52a8\u4e00\u4f4d\n    for j := l.arrSize - 1; j >= index; j-- {\n        l.arr[j+1] = l.arr[j]\n    }\n    l.arr[index] = num\n    // \u66f4\u65b0\u5143\u7d20\u6570\u91cf\n    l.arrSize++\n}\n\n/* \u5220\u9664\u5143\u7d20 */\nfunc (l *myList) remove(index int) int {\n    if index < 0 || index >= l.arrSize {\n        panic(\"\u7d22\u5f15\u8d8a\u754c\")\n    }\n    num := l.arr[index]\n    // \u5c06\u7d22\u5f15 index \u4e4b\u540e\u7684\u5143\u7d20\u90fd\u5411\u524d\u79fb\u52a8\u4e00\u4f4d\n    for j := index; j < l.arrSize-1; j++ {\n        l.arr[j] = l.arr[j+1]\n    }\n    // \u66f4\u65b0\u5143\u7d20\u6570\u91cf\n    l.arrSize--\n    // \u8fd4\u56de\u88ab\u5220\u9664\u7684\u5143\u7d20\n    return num\n}\n\n/* \u5217\u8868\u6269\u5bb9 */\nfunc (l *myList) extendCapacity() {\n    // \u65b0\u5efa\u4e00\u4e2a\u957f\u5ea6\u4e3a\u539f\u6570\u7ec4 extendRatio \u500d\u7684\u65b0\u6570\u7ec4\uff0c\u5e76\u5c06\u539f\u6570\u7ec4\u590d\u5236\u5230\u65b0\u6570\u7ec4\n    l.arr = append(l.arr, make([]int, l.arrCapacity*(l.extendRatio-1))...)\n    // \u66f4\u65b0\u5217\u8868\u5bb9\u91cf\n    l.arrCapacity = len(l.arr)\n}\n\n/* \u8fd4\u56de\u6709\u6548\u957f\u5ea6\u7684\u5217\u8868 */\nfunc (l *myList) toArray() []int {\n    // \u4ec5\u8f6c\u6362\u6709\u6548\u957f\u5ea6\u8303\u56f4\u5185\u7684\u5217\u8868\u5143\u7d20\n    return l.arr[:l.arrSize]\n}\n
my_list.swift
/* \u5217\u8868\u7c7b */\nclass MyList {\n    private var arr: [Int] // \u6570\u7ec4\uff08\u5b58\u50a8\u5217\u8868\u5143\u7d20\uff09\n    private var _capacity: Int // \u5217\u8868\u5bb9\u91cf\n    private var _size: Int // \u5217\u8868\u957f\u5ea6\uff08\u5f53\u524d\u5143\u7d20\u6570\u91cf\uff09\n    private let extendRatio: Int // \u6bcf\u6b21\u5217\u8868\u6269\u5bb9\u7684\u500d\u6570\n\n    /* \u6784\u9020\u65b9\u6cd5 */\n    init() {\n        _capacity = 10\n        _size = 0\n        extendRatio = 2\n        arr = Array(repeating: 0, count: _capacity)\n    }\n\n    /* \u83b7\u53d6\u5217\u8868\u957f\u5ea6\uff08\u5f53\u524d\u5143\u7d20\u6570\u91cf\uff09*/\n    func size() -> Int {\n        _size\n    }\n\n    /* \u83b7\u53d6\u5217\u8868\u5bb9\u91cf */\n    func capacity() -> Int {\n        _capacity\n    }\n\n    /* \u8bbf\u95ee\u5143\u7d20 */\n    func get(index: Int) -> Int {\n        // \u7d22\u5f15\u5982\u679c\u8d8a\u754c\u5219\u629b\u51fa\u9519\u8bef\uff0c\u4e0b\u540c\n        if index < 0 || index >= size() {\n            fatalError(\"\u7d22\u5f15\u8d8a\u754c\")\n        }\n        return arr[index]\n    }\n\n    /* \u66f4\u65b0\u5143\u7d20 */\n    func set(index: Int, num: Int) {\n        if index < 0 || index >= size() {\n            fatalError(\"\u7d22\u5f15\u8d8a\u754c\")\n        }\n        arr[index] = num\n    }\n\n    /* \u5728\u5c3e\u90e8\u6dfb\u52a0\u5143\u7d20 */\n    func add(num: Int) {\n        // \u5143\u7d20\u6570\u91cf\u8d85\u51fa\u5bb9\u91cf\u65f6\uff0c\u89e6\u53d1\u6269\u5bb9\u673a\u5236\n        if size() == capacity() {\n            extendCapacity()\n        }\n        arr[size()] = num\n        // \u66f4\u65b0\u5143\u7d20\u6570\u91cf\n        _size += 1\n    }\n\n    /* \u5728\u4e2d\u95f4\u63d2\u5165\u5143\u7d20 */\n    func insert(index: Int, num: Int) {\n        if index < 0 || index >= size() {\n            fatalError(\"\u7d22\u5f15\u8d8a\u754c\")\n        }\n        // \u5143\u7d20\u6570\u91cf\u8d85\u51fa\u5bb9\u91cf\u65f6\uff0c\u89e6\u53d1\u6269\u5bb9\u673a\u5236\n        if size() == capacity() {\n            extendCapacity()\n        }\n        // \u5c06\u7d22\u5f15 index \u4ee5\u53ca\u4e4b\u540e\u7684\u5143\u7d20\u90fd\u5411\u540e\u79fb\u52a8\u4e00\u4f4d\n        for j in (index ..< size()).reversed() {\n            arr[j + 1] = arr[j]\n        }\n        arr[index] = num\n        // \u66f4\u65b0\u5143\u7d20\u6570\u91cf\n        _size += 1\n    }\n\n    /* \u5220\u9664\u5143\u7d20 */\n    @discardableResult\n    func remove(index: Int) -> Int {\n        if index < 0 || index >= size() {\n            fatalError(\"\u7d22\u5f15\u8d8a\u754c\")\n        }\n        let num = arr[index]\n        // \u5c06\u5c06\u7d22\u5f15 index \u4e4b\u540e\u7684\u5143\u7d20\u90fd\u5411\u524d\u79fb\u52a8\u4e00\u4f4d\n        for j in index ..< (size() - 1) {\n            arr[j] = arr[j + 1]\n        }\n        // \u66f4\u65b0\u5143\u7d20\u6570\u91cf\n        _size -= 1\n        // \u8fd4\u56de\u88ab\u5220\u9664\u7684\u5143\u7d20\n        return num\n    }\n\n    /* \u5217\u8868\u6269\u5bb9 */\n    func extendCapacity() {\n        // \u65b0\u5efa\u4e00\u4e2a\u957f\u5ea6\u4e3a\u539f\u6570\u7ec4 extendRatio \u500d\u7684\u65b0\u6570\u7ec4\uff0c\u5e76\u5c06\u539f\u6570\u7ec4\u590d\u5236\u5230\u65b0\u6570\u7ec4\n        arr = arr + Array(repeating: 0, count: capacity() * (extendRatio - 1))\n        // \u66f4\u65b0\u5217\u8868\u5bb9\u91cf\n        _capacity = arr.count\n    }\n\n    /* \u5c06\u5217\u8868\u8f6c\u6362\u4e3a\u6570\u7ec4 */\n    func toArray() -> [Int] {\n        Array(arr.prefix(size()))\n    }\n}\n
my_list.js
/* \u5217\u8868\u7c7b */\nclass MyList {\n    #arr = new Array(); // \u6570\u7ec4\uff08\u5b58\u50a8\u5217\u8868\u5143\u7d20\uff09\n    #capacity = 10; // \u5217\u8868\u5bb9\u91cf\n    #size = 0; // \u5217\u8868\u957f\u5ea6\uff08\u5f53\u524d\u5143\u7d20\u6570\u91cf\uff09\n    #extendRatio = 2; // \u6bcf\u6b21\u5217\u8868\u6269\u5bb9\u7684\u500d\u6570\n\n    /* \u6784\u9020\u65b9\u6cd5 */\n    constructor() {\n        this.#arr = new Array(this.#capacity);\n    }\n\n    /* \u83b7\u53d6\u5217\u8868\u957f\u5ea6\uff08\u5f53\u524d\u5143\u7d20\u6570\u91cf\uff09*/\n    size() {\n        return this.#size;\n    }\n\n    /* \u83b7\u53d6\u5217\u8868\u5bb9\u91cf */\n    capacity() {\n        return this.#capacity;\n    }\n\n    /* \u8bbf\u95ee\u5143\u7d20 */\n    get(index) {\n        // \u7d22\u5f15\u5982\u679c\u8d8a\u754c\uff0c\u5219\u629b\u51fa\u5f02\u5e38\uff0c\u4e0b\u540c\n        if (index < 0 || index >= this.#size) throw new Error('\u7d22\u5f15\u8d8a\u754c');\n        return this.#arr[index];\n    }\n\n    /* \u66f4\u65b0\u5143\u7d20 */\n    set(index, num) {\n        if (index < 0 || index >= this.#size) throw new Error('\u7d22\u5f15\u8d8a\u754c');\n        this.#arr[index] = num;\n    }\n\n    /* \u5728\u5c3e\u90e8\u6dfb\u52a0\u5143\u7d20 */\n    add(num) {\n        // \u5982\u679c\u957f\u5ea6\u7b49\u4e8e\u5bb9\u91cf\uff0c\u5219\u9700\u8981\u6269\u5bb9\n        if (this.#size === this.#capacity) {\n            this.extendCapacity();\n        }\n        // \u5c06\u65b0\u5143\u7d20\u6dfb\u52a0\u5230\u5217\u8868\u5c3e\u90e8\n        this.#arr[this.#size] = num;\n        this.#size++;\n    }\n\n    /* \u5728\u4e2d\u95f4\u63d2\u5165\u5143\u7d20 */\n    insert(index, num) {\n        if (index < 0 || index >= this.#size) throw new Error('\u7d22\u5f15\u8d8a\u754c');\n        // \u5143\u7d20\u6570\u91cf\u8d85\u51fa\u5bb9\u91cf\u65f6\uff0c\u89e6\u53d1\u6269\u5bb9\u673a\u5236\n        if (this.#size === this.#capacity) {\n            this.extendCapacity();\n        }\n        // \u5c06\u7d22\u5f15 index \u4ee5\u53ca\u4e4b\u540e\u7684\u5143\u7d20\u90fd\u5411\u540e\u79fb\u52a8\u4e00\u4f4d\n        for (let j = this.#size - 1; j >= index; j--) {\n            this.#arr[j + 1] = this.#arr[j];\n        }\n        // \u66f4\u65b0\u5143\u7d20\u6570\u91cf\n        this.#arr[index] = num;\n        this.#size++;\n    }\n\n    /* \u5220\u9664\u5143\u7d20 */\n    remove(index) {\n        if (index < 0 || index >= this.#size) throw new Error('\u7d22\u5f15\u8d8a\u754c');\n        let num = this.#arr[index];\n        // \u5c06\u5c06\u7d22\u5f15 index \u4e4b\u540e\u7684\u5143\u7d20\u90fd\u5411\u524d\u79fb\u52a8\u4e00\u4f4d\n        for (let j = index; j < this.#size - 1; j++) {\n            this.#arr[j] = this.#arr[j + 1];\n        }\n        // \u66f4\u65b0\u5143\u7d20\u6570\u91cf\n        this.#size--;\n        // \u8fd4\u56de\u88ab\u5220\u9664\u7684\u5143\u7d20\n        return num;\n    }\n\n    /* \u5217\u8868\u6269\u5bb9 */\n    extendCapacity() {\n        // \u65b0\u5efa\u4e00\u4e2a\u957f\u5ea6\u4e3a\u539f\u6570\u7ec4 extendRatio \u500d\u7684\u65b0\u6570\u7ec4\uff0c\u5e76\u5c06\u539f\u6570\u7ec4\u590d\u5236\u5230\u65b0\u6570\u7ec4\n        this.#arr = this.#arr.concat(\n            new Array(this.capacity() * (this.#extendRatio - 1))\n        );\n        // \u66f4\u65b0\u5217\u8868\u5bb9\u91cf\n        this.#capacity = this.#arr.length;\n    }\n\n    /* \u5c06\u5217\u8868\u8f6c\u6362\u4e3a\u6570\u7ec4 */\n    toArray() {\n        let size = this.size();\n        // \u4ec5\u8f6c\u6362\u6709\u6548\u957f\u5ea6\u8303\u56f4\u5185\u7684\u5217\u8868\u5143\u7d20\n        const arr = new Array(size);\n        for (let i = 0; i < size; i++) {\n            arr[i] = this.get(i);\n        }\n        return arr;\n    }\n}\n
my_list.ts
/* \u5217\u8868\u7c7b */\nclass MyList {\n    private arr: Array<number>; // \u6570\u7ec4\uff08\u5b58\u50a8\u5217\u8868\u5143\u7d20\uff09\n    private _capacity: number = 10; // \u5217\u8868\u5bb9\u91cf\n    private _size: number = 0; // \u5217\u8868\u957f\u5ea6\uff08\u5f53\u524d\u5143\u7d20\u6570\u91cf\uff09\n    private extendRatio: number = 2; // \u6bcf\u6b21\u5217\u8868\u6269\u5bb9\u7684\u500d\u6570\n\n    /* \u6784\u9020\u65b9\u6cd5 */\n    constructor() {\n        this.arr = new Array(this._capacity);\n    }\n\n    /* \u83b7\u53d6\u5217\u8868\u957f\u5ea6\uff08\u5f53\u524d\u5143\u7d20\u6570\u91cf\uff09*/\n    public size(): number {\n        return this._size;\n    }\n\n    /* \u83b7\u53d6\u5217\u8868\u5bb9\u91cf */\n    public capacity(): number {\n        return this._capacity;\n    }\n\n    /* \u8bbf\u95ee\u5143\u7d20 */\n    public get(index: number): number {\n        // \u7d22\u5f15\u5982\u679c\u8d8a\u754c\uff0c\u5219\u629b\u51fa\u5f02\u5e38\uff0c\u4e0b\u540c\n        if (index < 0 || index >= this._size) throw new Error('\u7d22\u5f15\u8d8a\u754c');\n        return this.arr[index];\n    }\n\n    /* \u66f4\u65b0\u5143\u7d20 */\n    public set(index: number, num: number): void {\n        if (index < 0 || index >= this._size) throw new Error('\u7d22\u5f15\u8d8a\u754c');\n        this.arr[index] = num;\n    }\n\n    /* \u5728\u5c3e\u90e8\u6dfb\u52a0\u5143\u7d20 */\n    public add(num: number): void {\n        // \u5982\u679c\u957f\u5ea6\u7b49\u4e8e\u5bb9\u91cf\uff0c\u5219\u9700\u8981\u6269\u5bb9\n        if (this._size === this._capacity) this.extendCapacity();\n        // \u5c06\u65b0\u5143\u7d20\u6dfb\u52a0\u5230\u5217\u8868\u5c3e\u90e8\n        this.arr[this._size] = num;\n        this._size++;\n    }\n\n    /* \u5728\u4e2d\u95f4\u63d2\u5165\u5143\u7d20 */\n    public insert(index: number, num: number): void {\n        if (index < 0 || index >= this._size) throw new Error('\u7d22\u5f15\u8d8a\u754c');\n        // \u5143\u7d20\u6570\u91cf\u8d85\u51fa\u5bb9\u91cf\u65f6\uff0c\u89e6\u53d1\u6269\u5bb9\u673a\u5236\n        if (this._size === this._capacity) {\n            this.extendCapacity();\n        }\n        // \u5c06\u7d22\u5f15 index \u4ee5\u53ca\u4e4b\u540e\u7684\u5143\u7d20\u90fd\u5411\u540e\u79fb\u52a8\u4e00\u4f4d\n        for (let j = this._size - 1; j >= index; j--) {\n            this.arr[j + 1] = this.arr[j];\n        }\n        // \u66f4\u65b0\u5143\u7d20\u6570\u91cf\n        this.arr[index] = num;\n        this._size++;\n    }\n\n    /* \u5220\u9664\u5143\u7d20 */\n    public remove(index: number): number {\n        if (index < 0 || index >= this._size) throw new Error('\u7d22\u5f15\u8d8a\u754c');\n        let num = this.arr[index];\n        // \u5c06\u5c06\u7d22\u5f15 index \u4e4b\u540e\u7684\u5143\u7d20\u90fd\u5411\u524d\u79fb\u52a8\u4e00\u4f4d\n        for (let j = index; j < this._size - 1; j++) {\n            this.arr[j] = this.arr[j + 1];\n        }\n        // \u66f4\u65b0\u5143\u7d20\u6570\u91cf\n        this._size--;\n        // \u8fd4\u56de\u88ab\u5220\u9664\u7684\u5143\u7d20\n        return num;\n    }\n\n    /* \u5217\u8868\u6269\u5bb9 */\n    public extendCapacity(): void {\n        // \u65b0\u5efa\u4e00\u4e2a\u957f\u5ea6\u4e3a size \u7684\u6570\u7ec4\uff0c\u5e76\u5c06\u539f\u6570\u7ec4\u590d\u5236\u5230\u65b0\u6570\u7ec4\n        this.arr = this.arr.concat(\n            new Array(this.capacity() * (this.extendRatio - 1))\n        );\n        // \u66f4\u65b0\u5217\u8868\u5bb9\u91cf\n        this._capacity = this.arr.length;\n    }\n\n    /* \u5c06\u5217\u8868\u8f6c\u6362\u4e3a\u6570\u7ec4 */\n    public toArray(): number[] {\n        let size = this.size();\n        // \u4ec5\u8f6c\u6362\u6709\u6548\u957f\u5ea6\u8303\u56f4\u5185\u7684\u5217\u8868\u5143\u7d20\n        const arr = new Array(size);\n        for (let i = 0; i < size; i++) {\n            arr[i] = this.get(i);\n        }\n        return arr;\n    }\n}\n
my_list.dart
/* \u5217\u8868\u7c7b */\nclass MyList {\n  late List<int> _arr; // \u6570\u7ec4\uff08\u5b58\u50a8\u5217\u8868\u5143\u7d20\uff09\n  int _capacity = 10; // \u5217\u8868\u5bb9\u91cf\n  int _size = 0; // \u5217\u8868\u957f\u5ea6\uff08\u5f53\u524d\u5143\u7d20\u6570\u91cf\uff09\n  int _extendRatio = 2; // \u6bcf\u6b21\u5217\u8868\u6269\u5bb9\u7684\u500d\u6570\n\n  /* \u6784\u9020\u65b9\u6cd5 */\n  MyList() {\n    _arr = List.filled(_capacity, 0);\n  }\n\n  /* \u83b7\u53d6\u5217\u8868\u957f\u5ea6\uff08\u5f53\u524d\u5143\u7d20\u6570\u91cf\uff09*/\n  int size() => _size;\n\n  /* \u83b7\u53d6\u5217\u8868\u5bb9\u91cf */\n  int capacity() => _capacity;\n\n  /* \u8bbf\u95ee\u5143\u7d20 */\n  int get(int index) {\n    if (index >= _size) throw RangeError('\u7d22\u5f15\u8d8a\u754c');\n    return _arr[index];\n  }\n\n  /* \u66f4\u65b0\u5143\u7d20 */\n  void set(int index, int _num) {\n    if (index >= _size) throw RangeError('\u7d22\u5f15\u8d8a\u754c');\n    _arr[index] = _num;\n  }\n\n  /* \u5728\u5c3e\u90e8\u6dfb\u52a0\u5143\u7d20 */\n  void add(int _num) {\n    // \u5143\u7d20\u6570\u91cf\u8d85\u51fa\u5bb9\u91cf\u65f6\uff0c\u89e6\u53d1\u6269\u5bb9\u673a\u5236\n    if (_size == _capacity) extendCapacity();\n    _arr[_size] = _num;\n    // \u66f4\u65b0\u5143\u7d20\u6570\u91cf\n    _size++;\n  }\n\n  /* \u5728\u4e2d\u95f4\u63d2\u5165\u5143\u7d20 */\n  void insert(int index, int _num) {\n    if (index >= _size) throw RangeError('\u7d22\u5f15\u8d8a\u754c');\n    // \u5143\u7d20\u6570\u91cf\u8d85\u51fa\u5bb9\u91cf\u65f6\uff0c\u89e6\u53d1\u6269\u5bb9\u673a\u5236\n    if (_size == _capacity) extendCapacity();\n    // \u5c06\u7d22\u5f15 index \u4ee5\u53ca\u4e4b\u540e\u7684\u5143\u7d20\u90fd\u5411\u540e\u79fb\u52a8\u4e00\u4f4d\n    for (var j = _size - 1; j >= index; j--) {\n      _arr[j + 1] = _arr[j];\n    }\n    _arr[index] = _num;\n    // \u66f4\u65b0\u5143\u7d20\u6570\u91cf\n    _size++;\n  }\n\n  /* \u5220\u9664\u5143\u7d20 */\n  int remove(int index) {\n    if (index >= _size) throw RangeError('\u7d22\u5f15\u8d8a\u754c');\n    int _num = _arr[index];\n    // \u5c06\u5c06\u7d22\u5f15 index \u4e4b\u540e\u7684\u5143\u7d20\u90fd\u5411\u524d\u79fb\u52a8\u4e00\u4f4d\n    for (var j = index; j < _size - 1; j++) {\n      _arr[j] = _arr[j + 1];\n    }\n    // \u66f4\u65b0\u5143\u7d20\u6570\u91cf\n    _size--;\n    // \u8fd4\u56de\u88ab\u5220\u9664\u7684\u5143\u7d20\n    return _num;\n  }\n\n  /* \u5217\u8868\u6269\u5bb9 */\n  void extendCapacity() {\n    // \u65b0\u5efa\u4e00\u4e2a\u957f\u5ea6\u4e3a\u539f\u6570\u7ec4 _extendRatio \u500d\u7684\u65b0\u6570\u7ec4\n    final _newNums = List.filled(_capacity * _extendRatio, 0);\n    // \u5c06\u539f\u6570\u7ec4\u590d\u5236\u5230\u65b0\u6570\u7ec4\n    List.copyRange(_newNums, 0, _arr);\n    // \u66f4\u65b0 _arr \u7684\u5f15\u7528\n    _arr = _newNums;\n    // \u66f4\u65b0\u5217\u8868\u5bb9\u91cf\n    _capacity = _arr.length;\n  }\n\n  /* \u5c06\u5217\u8868\u8f6c\u6362\u4e3a\u6570\u7ec4 */\n  List<int> toArray() {\n    List<int> arr = [];\n    for (var i = 0; i < _size; i++) {\n      arr.add(get(i));\n    }\n    return arr;\n  }\n}\n
my_list.rs
/* \u5217\u8868\u7c7b */\n#[allow(dead_code)]\nstruct MyList {\n    arr: Vec<i32>,       // \u6570\u7ec4\uff08\u5b58\u50a8\u5217\u8868\u5143\u7d20\uff09\n    capacity: usize,     // \u5217\u8868\u5bb9\u91cf\n    size: usize,         // \u5217\u8868\u957f\u5ea6\uff08\u5f53\u524d\u5143\u7d20\u6570\u91cf\uff09\n    extend_ratio: usize, // \u6bcf\u6b21\u5217\u8868\u6269\u5bb9\u7684\u500d\u6570\n}\n\n#[allow(unused, unused_comparisons)]\nimpl MyList {\n    /* \u6784\u9020\u65b9\u6cd5 */\n    pub fn new(capacity: usize) -> Self {\n        let mut vec = Vec::new();\n        vec.resize(capacity, 0);\n        Self {\n            arr: vec,\n            capacity,\n            size: 0,\n            extend_ratio: 2,\n        }\n    }\n\n    /* \u83b7\u53d6\u5217\u8868\u957f\u5ea6\uff08\u5f53\u524d\u5143\u7d20\u6570\u91cf\uff09*/\n    pub fn size(&self) -> usize {\n        return self.size;\n    }\n\n    /* \u83b7\u53d6\u5217\u8868\u5bb9\u91cf */\n    pub fn capacity(&self) -> usize {\n        return self.capacity;\n    }\n\n    /* \u8bbf\u95ee\u5143\u7d20 */\n    pub fn get(&self, index: usize) -> i32 {\n        // \u7d22\u5f15\u5982\u679c\u8d8a\u754c\uff0c\u5219\u629b\u51fa\u5f02\u5e38\uff0c\u4e0b\u540c\n        if index >= self.size {\n            panic!(\"\u7d22\u5f15\u8d8a\u754c\")\n        };\n        return self.arr[index];\n    }\n\n    /* \u66f4\u65b0\u5143\u7d20 */\n    pub fn set(&mut self, index: usize, num: i32) {\n        if index >= self.size {\n            panic!(\"\u7d22\u5f15\u8d8a\u754c\")\n        };\n        self.arr[index] = num;\n    }\n\n    /* \u5728\u5c3e\u90e8\u6dfb\u52a0\u5143\u7d20 */\n    pub fn add(&mut self, num: i32) {\n        // \u5143\u7d20\u6570\u91cf\u8d85\u51fa\u5bb9\u91cf\u65f6\uff0c\u89e6\u53d1\u6269\u5bb9\u673a\u5236\n        if self.size == self.capacity() {\n            self.extend_capacity();\n        }\n        self.arr[self.size] = num;\n        // \u66f4\u65b0\u5143\u7d20\u6570\u91cf\n        self.size += 1;\n    }\n\n    /* \u5728\u4e2d\u95f4\u63d2\u5165\u5143\u7d20 */\n    pub fn insert(&mut self, index: usize, num: i32) {\n        if index >= self.size() {\n            panic!(\"\u7d22\u5f15\u8d8a\u754c\")\n        };\n        // \u5143\u7d20\u6570\u91cf\u8d85\u51fa\u5bb9\u91cf\u65f6\uff0c\u89e6\u53d1\u6269\u5bb9\u673a\u5236\n        if self.size == self.capacity() {\n            self.extend_capacity();\n        }\n        // \u5c06\u7d22\u5f15 index \u4ee5\u53ca\u4e4b\u540e\u7684\u5143\u7d20\u90fd\u5411\u540e\u79fb\u52a8\u4e00\u4f4d\n        for j in (index..self.size).rev() {\n            self.arr[j + 1] = self.arr[j];\n        }\n        self.arr[index] = num;\n        // \u66f4\u65b0\u5143\u7d20\u6570\u91cf\n        self.size += 1;\n    }\n\n    /* \u5220\u9664\u5143\u7d20 */\n    pub fn remove(&mut self, index: usize) -> i32 {\n        if index >= self.size() {\n            panic!(\"\u7d22\u5f15\u8d8a\u754c\")\n        };\n        let num = self.arr[index];\n        // \u5c06\u5c06\u7d22\u5f15 index \u4e4b\u540e\u7684\u5143\u7d20\u90fd\u5411\u524d\u79fb\u52a8\u4e00\u4f4d\n        for j in (index..self.size - 1) {\n            self.arr[j] = self.arr[j + 1];\n        }\n        // \u66f4\u65b0\u5143\u7d20\u6570\u91cf\n        self.size -= 1;\n        // \u8fd4\u56de\u88ab\u5220\u9664\u7684\u5143\u7d20\n        return num;\n    }\n\n    /* \u5217\u8868\u6269\u5bb9 */\n    pub fn extend_capacity(&mut self) {\n        // \u65b0\u5efa\u4e00\u4e2a\u957f\u5ea6\u4e3a\u539f\u6570\u7ec4 extend_ratio \u500d\u7684\u65b0\u6570\u7ec4\uff0c\u5e76\u5c06\u539f\u6570\u7ec4\u590d\u5236\u5230\u65b0\u6570\u7ec4\n        let new_capacity = self.capacity * self.extend_ratio;\n        self.arr.resize(new_capacity, 0);\n        // \u66f4\u65b0\u5217\u8868\u5bb9\u91cf\n        self.capacity = new_capacity;\n    }\n\n    /* \u5c06\u5217\u8868\u8f6c\u6362\u4e3a\u6570\u7ec4 */\n    pub fn to_array(&mut self) -> Vec<i32> {\n        // \u4ec5\u8f6c\u6362\u6709\u6548\u957f\u5ea6\u8303\u56f4\u5185\u7684\u5217\u8868\u5143\u7d20\n        let mut arr = Vec::new();\n        for i in 0..self.size {\n            arr.push(self.get(i));\n        }\n        arr\n    }\n}\n
my_list.c
/* \u5217\u8868\u7c7b */\ntypedef struct {\n    int *arr;        // \u6570\u7ec4\uff08\u5b58\u50a8\u5217\u8868\u5143\u7d20\uff09\n    int capacity;    // \u5217\u8868\u5bb9\u91cf\n    int size;        // \u5217\u8868\u5927\u5c0f\n    int extendRatio; // \u5217\u8868\u6bcf\u6b21\u6269\u5bb9\u7684\u500d\u6570\n} MyList;\n\n/* \u6784\u9020\u51fd\u6570 */\nMyList *newMyList() {\n    MyList *nums = malloc(sizeof(MyList));\n    nums->capacity = 10;\n    nums->arr = malloc(sizeof(int) * nums->capacity);\n    nums->size = 0;\n    nums->extendRatio = 2;\n    return nums;\n}\n\n/* \u6790\u6784\u51fd\u6570 */\nvoid delMyList(MyList *nums) {\n    free(nums->arr);\n    free(nums);\n}\n\n/* \u83b7\u53d6\u5217\u8868\u957f\u5ea6 */\nint size(MyList *nums) {\n    return nums->size;\n}\n\n/* \u83b7\u53d6\u5217\u8868\u5bb9\u91cf */\nint capacity(MyList *nums) {\n    return nums->capacity;\n}\n\n/* \u8bbf\u95ee\u5143\u7d20 */\nint get(MyList *nums, int index) {\n    assert(index >= 0 && index < nums->size);\n    return nums->arr[index];\n}\n\n/* \u66f4\u65b0\u5143\u7d20 */\nvoid set(MyList *nums, int index, int num) {\n    assert(index >= 0 && index < nums->size);\n    nums->arr[index] = num;\n}\n\n/* \u5728\u5c3e\u90e8\u6dfb\u52a0\u5143\u7d20 */\nvoid add(MyList *nums, int num) {\n    if (size(nums) == capacity(nums)) {\n        extendCapacity(nums); // \u6269\u5bb9\n    }\n    nums->arr[size(nums)] = num;\n    nums->size++;\n}\n\n/* \u5728\u4e2d\u95f4\u63d2\u5165\u5143\u7d20 */\nvoid insert(MyList *nums, int index, int num) {\n    assert(index >= 0 && index < size(nums));\n    // \u5143\u7d20\u6570\u91cf\u8d85\u51fa\u5bb9\u91cf\u65f6\uff0c\u89e6\u53d1\u6269\u5bb9\u673a\u5236\n    if (size(nums) == capacity(nums)) {\n        extendCapacity(nums); // \u6269\u5bb9\n    }\n    for (int i = size(nums); i > index; --i) {\n        nums->arr[i] = nums->arr[i - 1];\n    }\n    nums->arr[index] = num;\n    nums->size++;\n}\n\n/* \u5220\u9664\u5143\u7d20 */\n// \u6ce8\u610f\uff1astdio.h \u5360\u7528\u4e86 remove \u5173\u952e\u8bcd\nint removeItem(MyList *nums, int index) {\n    assert(index >= 0 && index < size(nums));\n    int num = nums->arr[index];\n    for (int i = index; i < size(nums) - 1; i++) {\n        nums->arr[i] = nums->arr[i + 1];\n    }\n    nums->size--;\n    return num;\n}\n\n/* \u5217\u8868\u6269\u5bb9 */\nvoid extendCapacity(MyList *nums) {\n    // \u5148\u5206\u914d\u7a7a\u95f4\n    int newCapacity = capacity(nums) * nums->extendRatio;\n    int *extend = (int *)malloc(sizeof(int) * newCapacity);\n    int *temp = nums->arr;\n\n    // \u62f7\u8d1d\u65e7\u6570\u636e\u5230\u65b0\u6570\u636e\n    for (int i = 0; i < size(nums); i++)\n        extend[i] = nums->arr[i];\n\n    // \u91ca\u653e\u65e7\u6570\u636e\n    free(temp);\n\n    // \u66f4\u65b0\u65b0\u6570\u636e\n    nums->arr = extend;\n    nums->capacity = newCapacity;\n}\n\n/* \u5c06\u5217\u8868\u8f6c\u6362\u4e3a Array \u7528\u4e8e\u6253\u5370 */\nint *toArray(MyList *nums) {\n    return nums->arr;\n}\n
my_list.zig
// \u5217\u8868\u7c7b\nfn MyList(comptime T: type) type {\n    return struct {\n        const Self = @This();\n\n        arr: []T = undefined,                        // \u6570\u7ec4\uff08\u5b58\u50a8\u5217\u8868\u5143\u7d20\uff09\n        arrCapacity: usize = 10,                     // \u5217\u8868\u5bb9\u91cf\n        numSize: usize = 0,                           // \u5217\u8868\u957f\u5ea6\uff08\u5f53\u524d\u5143\u7d20\u6570\u91cf\uff09\n        extendRatio: usize = 2,                       // \u6bcf\u6b21\u5217\u8868\u6269\u5bb9\u7684\u500d\u6570\n        mem_arena: ?std.heap.ArenaAllocator = null,\n        mem_allocator: std.mem.Allocator = undefined, // \u5185\u5b58\u5206\u914d\u5668\n\n        // \u6784\u9020\u51fd\u6570\uff08\u5206\u914d\u5185\u5b58+\u521d\u59cb\u5316\u5217\u8868\uff09\n        pub fn init(self: *Self, allocator: std.mem.Allocator) !void {\n            if (self.mem_arena == null) {\n                self.mem_arena = std.heap.ArenaAllocator.init(allocator);\n                self.mem_allocator = self.mem_arena.?.allocator();\n            }\n            self.arr = try self.mem_allocator.alloc(T, self.arrCapacity);\n            @memset(self.arr, @as(T, 0));\n        }\n\n        // \u6790\u6784\u51fd\u6570\uff08\u91ca\u653e\u5185\u5b58\uff09\n        pub fn deinit(self: *Self) void {\n            if (self.mem_arena == null) return;\n            self.mem_arena.?.deinit();\n        }\n\n        // \u83b7\u53d6\u5217\u8868\u957f\u5ea6\uff08\u5f53\u524d\u5143\u7d20\u6570\u91cf\uff09\n        pub fn size(self: *Self) usize {\n            return self.numSize;\n        }\n\n        // \u83b7\u53d6\u5217\u8868\u5bb9\u91cf\n        pub fn capacity(self: *Self) usize {\n            return self.arrCapacity;\n        }\n\n        // \u8bbf\u95ee\u5143\u7d20\n        pub fn get(self: *Self, index: usize) T {\n            // \u7d22\u5f15\u5982\u679c\u8d8a\u754c\uff0c\u5219\u629b\u51fa\u5f02\u5e38\uff0c\u4e0b\u540c\n            if (index < 0 or index >= self.size()) @panic(\"\u7d22\u5f15\u8d8a\u754c\");\n            return self.arr[index];\n        }  \n\n        // \u66f4\u65b0\u5143\u7d20\n        pub fn set(self: *Self, index: usize, num: T) void {\n            // \u7d22\u5f15\u5982\u679c\u8d8a\u754c\uff0c\u5219\u629b\u51fa\u5f02\u5e38\uff0c\u4e0b\u540c\n            if (index < 0 or index >= self.size()) @panic(\"\u7d22\u5f15\u8d8a\u754c\");\n            self.arr[index] = num;\n        }  \n\n        // \u5728\u5c3e\u90e8\u6dfb\u52a0\u5143\u7d20\n        pub fn add(self: *Self, num: T) !void {\n            // \u5143\u7d20\u6570\u91cf\u8d85\u51fa\u5bb9\u91cf\u65f6\uff0c\u89e6\u53d1\u6269\u5bb9\u673a\u5236\n            if (self.size() == self.capacity()) try self.extendCapacity();\n            self.arr[self.size()] = num;\n            // \u66f4\u65b0\u5143\u7d20\u6570\u91cf\n            self.numSize += 1;\n        }  \n\n        // \u5728\u4e2d\u95f4\u63d2\u5165\u5143\u7d20\n        pub fn insert(self: *Self, index: usize, num: T) !void {\n            if (index < 0 or index >= self.size()) @panic(\"\u7d22\u5f15\u8d8a\u754c\");\n            // \u5143\u7d20\u6570\u91cf\u8d85\u51fa\u5bb9\u91cf\u65f6\uff0c\u89e6\u53d1\u6269\u5bb9\u673a\u5236\n            if (self.size() == self.capacity()) try self.extendCapacity();\n            // \u5c06\u7d22\u5f15 index \u4ee5\u53ca\u4e4b\u540e\u7684\u5143\u7d20\u90fd\u5411\u540e\u79fb\u52a8\u4e00\u4f4d\n            var j = self.size() - 1;\n            while (j >= index) : (j -= 1) {\n                self.arr[j + 1] = self.arr[j];\n            }\n            self.arr[index] = num;\n            // \u66f4\u65b0\u5143\u7d20\u6570\u91cf\n            self.numSize += 1;\n        }\n\n        // \u5220\u9664\u5143\u7d20\n        pub fn remove(self: *Self, index: usize) T {\n            if (index < 0 or index >= self.size()) @panic(\"\u7d22\u5f15\u8d8a\u754c\");\n            var num = self.arr[index];\n            // \u5c06\u7d22\u5f15 index \u4e4b\u540e\u7684\u5143\u7d20\u90fd\u5411\u524d\u79fb\u52a8\u4e00\u4f4d\n            var j = index;\n            while (j < self.size() - 1) : (j += 1) {\n                self.arr[j] = self.arr[j + 1];\n            }\n            // \u66f4\u65b0\u5143\u7d20\u6570\u91cf\n            self.numSize -= 1;\n            // \u8fd4\u56de\u88ab\u5220\u9664\u7684\u5143\u7d20\n            return num;\n        }\n\n        // \u5217\u8868\u6269\u5bb9\n        pub fn extendCapacity(self: *Self) !void {\n            // \u65b0\u5efa\u4e00\u4e2a\u957f\u5ea6\u4e3a size * extendRatio \u7684\u6570\u7ec4\uff0c\u5e76\u5c06\u539f\u6570\u7ec4\u590d\u5236\u5230\u65b0\u6570\u7ec4\n            var newCapacity = self.capacity() * self.extendRatio;\n            var extend = try self.mem_allocator.alloc(T, newCapacity);\n            @memset(extend, @as(T, 0));\n            // \u5c06\u539f\u6570\u7ec4\u4e2d\u7684\u6240\u6709\u5143\u7d20\u590d\u5236\u5230\u65b0\u6570\u7ec4\n            std.mem.copy(T, extend, self.arr);\n            self.arr = extend;\n            // \u66f4\u65b0\u5217\u8868\u5bb9\u91cf\n            self.arrCapacity = newCapacity;\n        }\n\n        // \u5c06\u5217\u8868\u8f6c\u6362\u4e3a\u6570\u7ec4\n        pub fn toArray(self: *Self) ![]T {\n            // \u4ec5\u8f6c\u6362\u6709\u6548\u957f\u5ea6\u8303\u56f4\u5185\u7684\u5217\u8868\u5143\u7d20\n            var arr = try self.mem_allocator.alloc(T, self.size());\n           @memset(arr, @as(T, 0));\n            for (arr, 0..) |*num, i| {\n                num.* = self.get(i);\n            }\n            return arr;\n        }\n    };\n}\n
Code Visualization

Full Screen >

"},{"location":"chapter_array_and_linkedlist/ram_and_cache/","title":"4.4 \u00a0 Memory and Cache *","text":"

In the first two sections of this chapter, we explored arrays and linked lists, two fundamental and important data structures, representing \"continuous storage\" and \"dispersed storage\" respectively.

In fact, the physical structure largely determines the efficiency of a program's use of memory and cache, which in turn affects the overall performance of the algorithm.

"},{"location":"chapter_array_and_linkedlist/ram_and_cache/#441-computer-storage-devices","title":"4.4.1 \u00a0 Computer Storage Devices","text":"

There are three types of storage devices in computers: \"hard disk,\" \"random-access memory (RAM),\" and \"cache memory.\" The following table shows their different roles and performance characteristics in computer systems.

Table 4-2 \u00a0 Computer Storage Devices

Hard Disk Memory Cache Usage Long-term storage of data, including OS, programs, files, etc. Temporary storage of currently running programs and data being processed Stores frequently accessed data and instructions, reducing the number of CPU accesses to memory Volatility Data is not lost after power off Data is lost after power off Data is lost after power off Capacity Larger, TB level Smaller, GB level Very small, MB level Speed Slower, several hundred to thousands MB/s Faster, several tens of GB/s Very fast, several tens to hundreds of GB/s Price Cheaper, several cents to yuan / GB More expensive, tens to hundreds of yuan / GB Very expensive, priced with CPU

We can imagine the computer storage system as a pyramid structure shown in the Figure 4-9 . The storage devices closer to the top of the pyramid are faster, have smaller capacity, and are more costly. This multi-level design is not accidental, but the result of careful consideration by computer scientists and engineers.

  • Hard disks are difficult to replace with memory. Firstly, data in memory is lost after power off, making it unsuitable for long-term data storage; secondly, the cost of memory is dozens of times that of hard disks, making it difficult to popularize in the consumer market.
  • It is difficult for caches to have both large capacity and high speed. As the capacity of L1, L2, L3 caches gradually increases, their physical size becomes larger, increasing the physical distance from the CPU core, leading to increased data transfer time and higher element access latency. Under current technology, a multi-level cache structure is the best balance between capacity, speed, and cost.

Figure 4-9 \u00a0 Computer Storage System

Note

The storage hierarchy of computers reflects a delicate balance between speed, capacity, and cost. In fact, this kind of trade-off is common in all industrial fields, requiring us to find the best balance between different advantages and limitations.

Overall, hard disks are used for long-term storage of large amounts of data, memory is used for temporary storage of data being processed during program execution, and cache is used to store frequently accessed data and instructions to improve program execution efficiency. Together, they ensure the efficient operation of computer systems.

As shown in the Figure 4-10 , during program execution, data is read from the hard disk into memory for CPU computation. The cache can be considered a part of the CPU, smartly loading data from memory to provide fast data access to the CPU, significantly enhancing program execution efficiency and reducing reliance on slower memory.

Figure 4-10 \u00a0 Data Flow Between Hard Disk, Memory, and Cache

"},{"location":"chapter_array_and_linkedlist/ram_and_cache/#442-memory-efficiency-of-data-structures","title":"4.4.2 \u00a0 Memory Efficiency of Data Structures","text":"

In terms of memory space utilization, arrays and linked lists have their advantages and limitations.

On one hand, memory is limited and cannot be shared by multiple programs, so we hope that data structures can use space as efficiently as possible. The elements of an array are tightly packed without extra space for storing references (pointers) between linked list nodes, making them more space-efficient. However, arrays require allocating sufficient continuous memory space at once, which may lead to memory waste, and array expansion also requires additional time and space costs. In contrast, linked lists allocate and reclaim memory dynamically on a per-node basis, providing greater flexibility.

On the other hand, during program execution, as memory is repeatedly allocated and released, the degree of fragmentation of free memory becomes higher, leading to reduced memory utilization efficiency. Arrays, due to their continuous storage method, are relatively less likely to cause memory fragmentation. In contrast, the elements of a linked list are dispersedly stored, and frequent insertion and deletion operations make memory fragmentation more likely.

"},{"location":"chapter_array_and_linkedlist/ram_and_cache/#443-cache-efficiency-of-data-structures","title":"4.4.3 \u00a0 Cache Efficiency of Data Structures","text":"

Although caches are much smaller in space capacity than memory, they are much faster and play a crucial role in program execution speed. Since the cache's capacity is limited and can only store a small part of frequently accessed data, when the CPU tries to access data not in the cache, a \"cache miss\" occurs, forcing the CPU to load the needed data from slower memory.

Clearly, the fewer the cache misses, the higher the CPU's data read-write efficiency, and the better the program performance. The proportion of successful data retrieval from the cache by the CPU is called the \"cache hit rate,\" a metric often used to measure cache efficiency.

To achieve higher efficiency, caches adopt the following data loading mechanisms.

  • Cache Lines: Caches don't store and load data byte by byte but in units of cache lines. Compared to byte-by-byte transfer, the transmission of cache lines is more efficient.
  • Prefetch Mechanism: Processors try to predict data access patterns (such as sequential access, fixed stride jumping access, etc.) and load data into the cache according to specific patterns to improve the hit rate.
  • Spatial Locality: If data is accessed, data nearby is likely to be accessed in the near future. Therefore, when loading certain data, the cache also loads nearby data to improve the hit rate.
  • Temporal Locality: If data is accessed, it's likely to be accessed again in the near future. Caches use this principle to retain recently accessed data to improve the hit rate.

In fact, arrays and linked lists have different cache utilization efficiencies, mainly reflected in the following aspects.

  • Occupied Space: Linked list elements occupy more space than array elements, resulting in less effective data volume in the cache.
  • Cache Lines: Linked list data is scattered throughout memory, and since caches load \"by line,\" the proportion of loading invalid data is higher.
  • Prefetch Mechanism: The data access pattern of arrays is more \"predictable\" than that of linked lists, meaning the system is more likely to guess which data will be loaded next.
  • Spatial Locality: Arrays are stored in concentrated memory spaces, so the data near the loaded data is more likely to be accessed next.

Overall, arrays have a higher cache hit rate and are generally more efficient in operation than linked lists. This makes data structures based on arrays more popular in solving algorithmic problems.

It should be noted that high cache efficiency does not mean that arrays are always better than linked lists. Which data structure to choose in actual applications should be based on specific requirements. For example, both arrays and linked lists can implement the \"stack\" data structure (which will be detailed in the next chapter), but they are suitable for different scenarios.

  • In algorithm problems, we tend to choose stacks based on arrays because they provide higher operational efficiency and random access capabilities, with the only cost being the need to pre-allocate a certain amount of memory space for the array.
  • If the data volume is very large, highly dynamic, and the expected size of the stack is difficult to estimate, then a stack based on a linked list is more appropriate. Linked lists can disperse a large amount of data in different parts of the memory and avoid the additional overhead of array expansion.
"},{"location":"chapter_array_and_linkedlist/summary/","title":"4.5 \u00a0 Summary","text":""},{"location":"chapter_array_and_linkedlist/summary/#1-key-review","title":"1. \u00a0 Key Review","text":"
  • Arrays and linked lists are two basic data structures, representing two storage methods in computer memory: contiguous space storage and non-contiguous space storage. Their characteristics complement each other.
  • Arrays support random access and use less memory; however, they are inefficient in inserting and deleting elements and have a fixed length after initialization.
  • Linked lists implement efficient node insertion and deletion through changing references (pointers) and can flexibly adjust their length; however, they have lower node access efficiency and consume more memory.
  • Common types of linked lists include singly linked lists, circular linked lists, and doubly linked lists, each with its own application scenarios.
  • Lists are ordered collections of elements that support addition, deletion, and modification, typically implemented based on dynamic arrays, retaining the advantages of arrays while allowing flexible length adjustment.
  • The advent of lists significantly enhanced the practicality of arrays but may lead to some memory space wastage.
  • During program execution, data is mainly stored in memory. Arrays provide higher memory space efficiency, while linked lists are more flexible in memory usage.
  • Caches provide fast data access to CPUs through mechanisms like cache lines, prefetching, spatial locality, and temporal locality, significantly enhancing program execution efficiency.
  • Due to higher cache hit rates, arrays are generally more efficient than linked lists. When choosing a data structure, the appropriate choice should be made based on specific needs and scenarios.
"},{"location":"chapter_array_and_linkedlist/summary/#2-q-a","title":"2. \u00a0 Q & A","text":"

Q: Does storing arrays on the stack versus the heap affect time and space efficiency?

Arrays stored on both the stack and heap are stored in contiguous memory spaces, and data operation efficiency is essentially the same. However, stacks and heaps have their own characteristics, leading to the following differences.

  1. Allocation and release efficiency: The stack is a smaller memory block, allocated automatically by the compiler; the heap memory is relatively larger and can be dynamically allocated in the code, more prone to fragmentation. Therefore, allocation and release operations on the heap are generally slower than on the stack.
  2. Size limitation: Stack memory is relatively small, while the heap size is generally limited by available memory. Therefore, the heap is more suitable for storing large arrays.
  3. Flexibility: The size of arrays on the stack needs to be determined at compile-time, while the size of arrays on the heap can be dynamically determined at runtime.

Q: Why do arrays require elements of the same type, while linked lists do not emphasize same-type elements?

Linked lists consist of nodes connected by references (pointers), and each node can store data of different types, such as int, double, string, object, etc.

In contrast, array elements must be of the same type, allowing the calculation of offsets to access the corresponding element positions. For example, an array containing both int and long types, with single elements occupying 4 bytes and 8 bytes respectively, cannot use the following formula to calculate offsets, as the array contains elements of two different lengths.

# Element memory address = Array memory address + Element length * Element index\n

Q: After deleting a node, is it necessary to set P.next to None?

Not modifying P.next is also acceptable. From the perspective of the linked list, traversing from the head node to the tail node will no longer encounter P. This means that node P has been effectively removed from the list, and where P points no longer affects the list.

From a garbage collection perspective, for languages with automatic garbage collection mechanisms like Java, Python, and Go, whether node P is collected depends on whether there are still references pointing to it, not on the value of P.next. In languages like C and C++, we need to manually free the node's memory.

Q: In linked lists, the time complexity for insertion and deletion operations is O(1). But searching for the element before insertion or deletion takes O(n) time, so why isn't the time complexity O(n)?

If an element is searched first and then deleted, the time complexity is indeed O(n). However, the O(1) advantage of linked lists in insertion and deletion can be realized in other applications. For example, in the implementation of double-ended queues using linked lists, we maintain pointers always pointing to the head and tail nodes, making each insertion and deletion operation O(1).

Q: In the image \"Linked List Definition and Storage Method\", do the light blue storage nodes occupy a single memory address, or do they share half with the node value?

The diagram is just a qualitative representation; quantitative analysis depends on specific situations.

  • Different types of node values occupy different amounts of space, such as int, long, double, and object instances.
  • The memory space occupied by pointer variables depends on the operating system and compilation environment used, usually 8 bytes or 4 bytes.

Q: Is adding elements to the end of a list always O(1)?

If adding an element exceeds the list length, the list needs to be expanded first. The system will request a new memory block and move all elements of the original list over, in which case the time complexity becomes O(n).

Q: The statement \"The emergence of lists greatly improves the practicality of arrays, but may lead to some memory space wastage\" - does this refer to the memory occupied by additional variables like capacity, length, and expansion multiplier?

The space wastage here mainly refers to two aspects: on the one hand, lists are set with an initial length, which we may not always need; on the other hand, to prevent frequent expansion, expansion usually multiplies by a coefficient, such as \\(\\times 1.5\\). This results in many empty slots, which we typically cannot fully fill.

Q: In Python, after initializing n = [1, 2, 3], the addresses of these 3 elements are contiguous, but initializing m = [2, 1, 3] shows that each element's id is not consecutive but identical to those in n. If the addresses of these elements are not contiguous, is m still an array?

If we replace list elements with linked list nodes n = [n1, n2, n3, n4, n5], these 5 node objects are also typically dispersed throughout memory. However, given a list index, we can still access the node's memory address in O(1) time, thereby accessing the corresponding node. This is because the array stores references to the nodes, not the nodes themselves.

Unlike many languages, in Python, numbers are also wrapped as objects, and lists store references to these numbers, not the numbers themselves. Therefore, we find that the same number in two arrays has the same id, and these numbers' memory addresses need not be contiguous.

Q: The std::list in C++ STL has already implemented a doubly linked list, but it seems that some algorithm books don't directly use it. Is there any limitation?

On the one hand, we often prefer to use arrays to implement algorithms, only using linked lists when necessary, mainly for two reasons.

  • Space overhead: Since each element requires two additional pointers (one for the previous element and one for the next), std::list usually occupies more space than std::vector.
  • Cache unfriendly: As the data is not stored continuously, std::list has a lower cache utilization rate. Generally, std::vector performs better.

On the other hand, linked lists are primarily necessary for binary trees and graphs. Stacks and queues are often implemented using the programming language's stack and queue classes, rather than linked lists.

Q: Does initializing a list res = [0] * self.size() result in each element of res referencing the same address?

No. However, this issue arises with two-dimensional arrays, for example, initializing a two-dimensional list res = [[0] * self.size()] would reference the same list [0] multiple times.

Q: In deleting a node, is it necessary to break the reference to its successor node?

From the perspective of data structures and algorithms (problem-solving), it's okay not to break the link, as long as the program's logic is correct. From the perspective of standard libraries, breaking the link is safer and more logically clear. If the link is not broken, and the deleted node is not properly recycled, it could affect the recycling of the successor node's memory.

"},{"location":"chapter_computational_complexity/","title":"Chapter 2. \u00a0 Complexity Analysis","text":"

Abstract

Complexity analysis is like a space-time navigator in the vast universe of algorithms.

It guides us in exploring deeper within the the dimensions of time and space, seeking more elegant solutions.

"},{"location":"chapter_computational_complexity/#chapter-contents","title":"Chapter Contents","text":"
  • 2.1 \u00a0 Algorithm Efficiency Assessment
  • 2.2 \u00a0 Iteration and Recursion
  • 2.3 \u00a0 Time Complexity
  • 2.4 \u00a0 Space Complexity
  • 2.5 \u00a0 Summary
"},{"location":"chapter_computational_complexity/iteration_and_recursion/","title":"2.2 \u00a0 Iteration and Recursion","text":"

In algorithms, the repeated execution of a task is quite common and is closely related to the analysis of complexity. Therefore, before delving into the concepts of time complexity and space complexity, let's first explore how to implement repetitive tasks in programming. This involves understanding two fundamental programming control structures: iteration and recursion.

"},{"location":"chapter_computational_complexity/iteration_and_recursion/#221-iteration","title":"2.2.1 \u00a0 Iteration","text":"

\"Iteration\" is a control structure for repeatedly performing a task. In iteration, a program repeats a block of code as long as a certain condition is met until this condition is no longer satisfied.

"},{"location":"chapter_computational_complexity/iteration_and_recursion/#1-for-loops","title":"1. \u00a0 For Loops","text":"

The for loop is one of the most common forms of iteration, and it's particularly suitable when the number of iterations is known in advance.

The following function uses a for loop to perform a summation of \\(1 + 2 + \\dots + n\\), with the sum being stored in the variable res. It's important to note that in Python, range(a, b) creates an interval that is inclusive of a but exclusive of b, meaning it iterates over the range from \\(a\\) up to \\(b\u22121\\).

PythonC++JavaC#GoSwiftJSTSDartRustCZig iteration.py
def for_loop(n: int) -> int:\n    \"\"\"for \u5faa\u73af\"\"\"\n    res = 0\n    # \u5faa\u73af\u6c42\u548c 1, 2, ..., n-1, n\n    for i in range(1, n + 1):\n        res += i\n    return res\n
iteration.cpp
/* for \u5faa\u73af */\nint forLoop(int n) {\n    int res = 0;\n    // \u5faa\u73af\u6c42\u548c 1, 2, ..., n-1, n\n    for (int i = 1; i <= n; ++i) {\n        res += i;\n    }\n    return res;\n}\n
iteration.java
/* for \u5faa\u73af */\nint forLoop(int n) {\n    int res = 0;\n    // \u5faa\u73af\u6c42\u548c 1, 2, ..., n-1, n\n    for (int i = 1; i <= n; i++) {\n        res += i;\n    }\n    return res;\n}\n
iteration.cs
/* for \u5faa\u73af */\nint ForLoop(int n) {\n    int res = 0;\n    // \u5faa\u73af\u6c42\u548c 1, 2, ..., n-1, n\n    for (int i = 1; i <= n; i++) {\n        res += i;\n    }\n    return res;\n}\n
iteration.go
/* for \u5faa\u73af */\nfunc forLoop(n int) int {\n    res := 0\n    // \u5faa\u73af\u6c42\u548c 1, 2, ..., n-1, n\n    for i := 1; i <= n; i++ {\n        res += i\n    }\n    return res\n}\n
iteration.swift
/* for \u5faa\u73af */\nfunc forLoop(n: Int) -> Int {\n    var res = 0\n    // \u5faa\u73af\u6c42\u548c 1, 2, ..., n-1, n\n    for i in 1 ... n {\n        res += i\n    }\n    return res\n}\n
iteration.js
/* for \u5faa\u73af */\nfunction forLoop(n) {\n    let res = 0;\n    // \u5faa\u73af\u6c42\u548c 1, 2, ..., n-1, n\n    for (let i = 1; i <= n; i++) {\n        res += i;\n    }\n    return res;\n}\n
iteration.ts
/* for \u5faa\u73af */\nfunction forLoop(n: number): number {\n    let res = 0;\n    // \u5faa\u73af\u6c42\u548c 1, 2, ..., n-1, n\n    for (let i = 1; i <= n; i++) {\n        res += i;\n    }\n    return res;\n}\n
iteration.dart
/* for \u5faa\u73af */\nint forLoop(int n) {\n  int res = 0;\n  // \u5faa\u73af\u6c42\u548c 1, 2, ..., n-1, n\n  for (int i = 1; i <= n; i++) {\n    res += i;\n  }\n  return res;\n}\n
iteration.rs
/* for \u5faa\u73af */\nfn for_loop(n: i32) -> i32 {\n    let mut res = 0;\n    // \u5faa\u73af\u6c42\u548c 1, 2, ..., n-1, n\n    for i in 1..=n {\n        res += i;\n    }\n    res\n}\n
iteration.c
/* for \u5faa\u73af */\nint forLoop(int n) {\n    int res = 0;\n    // \u5faa\u73af\u6c42\u548c 1, 2, ..., n-1, n\n    for (int i = 1; i <= n; i++) {\n        res += i;\n    }\n    return res;\n}\n
iteration.zig
// for \u5faa\u73af\nfn forLoop(n: usize) i32 {\n    var res: i32 = 0;\n    // \u5faa\u73af\u6c42\u548c 1, 2, ..., n-1, n\n    for (1..n+1) |i| {\n        res = res + @as(i32, @intCast(i));\n    }\n    return res;\n} \n
Code Visualization

Full Screen >

The flowchart below represents this sum function.

Figure 2-1 \u00a0 Flowchart of the Sum Function

The number of operations in this summation function is proportional to the size of the input data \\(n\\), or in other words, it has a \"linear relationship.\" This \"linear relationship\" is what time complexity describes. This topic will be discussed in more detail in the next section.

"},{"location":"chapter_computational_complexity/iteration_and_recursion/#2-while-loops","title":"2. \u00a0 While Loops","text":"

Similar to for loops, while loops are another approach for implementing iteration. In a while loop, the program checks a condition at the beginning of each iteration; if the condition is true, the execution continues, otherwise, the loop ends.

Below we use a while loop to implement the sum \\(1 + 2 + \\dots + n\\).

PythonC++JavaC#GoSwiftJSTSDartRustCZig iteration.py
def while_loop(n: int) -> int:\n    \"\"\"while \u5faa\u73af\"\"\"\n    res = 0\n    i = 1  # \u521d\u59cb\u5316\u6761\u4ef6\u53d8\u91cf\n    # \u5faa\u73af\u6c42\u548c 1, 2, ..., n-1, n\n    while i <= n:\n        res += i\n        i += 1  # \u66f4\u65b0\u6761\u4ef6\u53d8\u91cf\n    return res\n
iteration.cpp
/* while \u5faa\u73af */\nint whileLoop(int n) {\n    int res = 0;\n    int i = 1; // \u521d\u59cb\u5316\u6761\u4ef6\u53d8\u91cf\n    // \u5faa\u73af\u6c42\u548c 1, 2, ..., n-1, n\n    while (i <= n) {\n        res += i;\n        i++; // \u66f4\u65b0\u6761\u4ef6\u53d8\u91cf\n    }\n    return res;\n}\n
iteration.java
/* while \u5faa\u73af */\nint whileLoop(int n) {\n    int res = 0;\n    int i = 1; // \u521d\u59cb\u5316\u6761\u4ef6\u53d8\u91cf\n    // \u5faa\u73af\u6c42\u548c 1, 2, ..., n-1, n\n    while (i <= n) {\n        res += i;\n        i++; // \u66f4\u65b0\u6761\u4ef6\u53d8\u91cf\n    }\n    return res;\n}\n
iteration.cs
/* while \u5faa\u73af */\nint WhileLoop(int n) {\n    int res = 0;\n    int i = 1; // \u521d\u59cb\u5316\u6761\u4ef6\u53d8\u91cf\n    // \u5faa\u73af\u6c42\u548c 1, 2, ..., n-1, n\n    while (i <= n) {\n        res += i;\n        i += 1; // \u66f4\u65b0\u6761\u4ef6\u53d8\u91cf\n    }\n    return res;\n}\n
iteration.go
/* while \u5faa\u73af */\nfunc whileLoop(n int) int {\n    res := 0\n    // \u521d\u59cb\u5316\u6761\u4ef6\u53d8\u91cf\n    i := 1\n    // \u5faa\u73af\u6c42\u548c 1, 2, ..., n-1, n\n    for i <= n {\n        res += i\n        // \u66f4\u65b0\u6761\u4ef6\u53d8\u91cf\n        i++\n    }\n    return res\n}\n
iteration.swift
/* while \u5faa\u73af */\nfunc whileLoop(n: Int) -> Int {\n    var res = 0\n    var i = 1 // \u521d\u59cb\u5316\u6761\u4ef6\u53d8\u91cf\n    // \u5faa\u73af\u6c42\u548c 1, 2, ..., n-1, n\n    while i <= n {\n        res += i\n        i += 1 // \u66f4\u65b0\u6761\u4ef6\u53d8\u91cf\n    }\n    return res\n}\n
iteration.js
/* while \u5faa\u73af */\nfunction whileLoop(n) {\n    let res = 0;\n    let i = 1; // \u521d\u59cb\u5316\u6761\u4ef6\u53d8\u91cf\n    // \u5faa\u73af\u6c42\u548c 1, 2, ..., n-1, n\n    while (i <= n) {\n        res += i;\n        i++; // \u66f4\u65b0\u6761\u4ef6\u53d8\u91cf\n    }\n    return res;\n}\n
iteration.ts
/* while \u5faa\u73af */\nfunction whileLoop(n: number): number {\n    let res = 0;\n    let i = 1; // \u521d\u59cb\u5316\u6761\u4ef6\u53d8\u91cf\n    // \u5faa\u73af\u6c42\u548c 1, 2, ..., n-1, n\n    while (i <= n) {\n        res += i;\n        i++; // \u66f4\u65b0\u6761\u4ef6\u53d8\u91cf\n    }\n    return res;\n}\n
iteration.dart
/* while \u5faa\u73af */\nint whileLoop(int n) {\n  int res = 0;\n  int i = 1; // \u521d\u59cb\u5316\u6761\u4ef6\u53d8\u91cf\n  // \u5faa\u73af\u6c42\u548c 1, 2, ..., n-1, n\n  while (i <= n) {\n    res += i;\n    i++; // \u66f4\u65b0\u6761\u4ef6\u53d8\u91cf\n  }\n  return res;\n}\n
iteration.rs
/* while \u5faa\u73af */\nfn while_loop(n: i32) -> i32 {\n    let mut res = 0;\n    let mut i = 1; // \u521d\u59cb\u5316\u6761\u4ef6\u53d8\u91cf\n\n    // \u5faa\u73af\u6c42\u548c 1, 2, ..., n-1, n\n    while i <= n {\n        res += i;\n        i += 1; // \u66f4\u65b0\u6761\u4ef6\u53d8\u91cf\n    }\n    res\n}\n
iteration.c
/* while \u5faa\u73af */\nint whileLoop(int n) {\n    int res = 0;\n    int i = 1; // \u521d\u59cb\u5316\u6761\u4ef6\u53d8\u91cf\n    // \u5faa\u73af\u6c42\u548c 1, 2, ..., n-1, n\n    while (i <= n) {\n        res += i;\n        i++; // \u66f4\u65b0\u6761\u4ef6\u53d8\u91cf\n    }\n    return res;\n}\n
iteration.zig
// while \u5faa\u73af\nfn whileLoop(n: i32) i32 {\n    var res: i32 = 0;\n    var i: i32 = 1; // \u521d\u59cb\u5316\u6761\u4ef6\u53d8\u91cf\n    // \u5faa\u73af\u6c42\u548c 1, 2, ..., n-1, n\n    while (i <= n) {\n        res += @intCast(i);\n        i += 1;\n    }\n    return res;\n}\n
Code Visualization

Full Screen >

While loops provide more flexibility than for loops, especially since they allow for custom initialization and modification of the condition variable at each step.

For example, in the following code, the condition variable \\(i\\) is updated twice each round, which would be inconvenient to implement with a for loop.

PythonC++JavaC#GoSwiftJSTSDartRustCZig iteration.py
def while_loop_ii(n: int) -> int:\n    \"\"\"while \u5faa\u73af\uff08\u4e24\u6b21\u66f4\u65b0\uff09\"\"\"\n    res = 0\n    i = 1  # \u521d\u59cb\u5316\u6761\u4ef6\u53d8\u91cf\n    # \u5faa\u73af\u6c42\u548c 1, 4, 10, ...\n    while i <= n:\n        res += i\n        # \u66f4\u65b0\u6761\u4ef6\u53d8\u91cf\n        i += 1\n        i *= 2\n    return res\n
iteration.cpp
/* while \u5faa\u73af\uff08\u4e24\u6b21\u66f4\u65b0\uff09 */\nint whileLoopII(int n) {\n    int res = 0;\n    int i = 1; // \u521d\u59cb\u5316\u6761\u4ef6\u53d8\u91cf\n    // \u5faa\u73af\u6c42\u548c 1, 4, 10, ...\n    while (i <= n) {\n        res += i;\n        // \u66f4\u65b0\u6761\u4ef6\u53d8\u91cf\n        i++;\n        i *= 2;\n    }\n    return res;\n}\n
iteration.java
/* while \u5faa\u73af\uff08\u4e24\u6b21\u66f4\u65b0\uff09 */\nint whileLoopII(int n) {\n    int res = 0;\n    int i = 1; // \u521d\u59cb\u5316\u6761\u4ef6\u53d8\u91cf\n    // \u5faa\u73af\u6c42\u548c 1, 4, 10, ...\n    while (i <= n) {\n        res += i;\n        // \u66f4\u65b0\u6761\u4ef6\u53d8\u91cf\n        i++;\n        i *= 2;\n    }\n    return res;\n}\n
iteration.cs
/* while \u5faa\u73af\uff08\u4e24\u6b21\u66f4\u65b0\uff09 */\nint WhileLoopII(int n) {\n    int res = 0;\n    int i = 1; // \u521d\u59cb\u5316\u6761\u4ef6\u53d8\u91cf\n    // \u5faa\u73af\u6c42\u548c 1, 4, 10, ...\n    while (i <= n) {\n        res += i;\n        // \u66f4\u65b0\u6761\u4ef6\u53d8\u91cf\n        i += 1; \n        i *= 2;\n    }\n    return res;\n}\n
iteration.go
/* while \u5faa\u73af\uff08\u4e24\u6b21\u66f4\u65b0\uff09 */\nfunc whileLoopII(n int) int {\n    res := 0\n    // \u521d\u59cb\u5316\u6761\u4ef6\u53d8\u91cf\n    i := 1\n    // \u5faa\u73af\u6c42\u548c 1, 4, 10, ...\n    for i <= n {\n        res += i\n        // \u66f4\u65b0\u6761\u4ef6\u53d8\u91cf\n        i++\n        i *= 2\n    }\n    return res\n}\n
iteration.swift
/* while \u5faa\u73af\uff08\u4e24\u6b21\u66f4\u65b0\uff09 */\nfunc whileLoopII(n: Int) -> Int {\n    var res = 0\n    var i = 1 // \u521d\u59cb\u5316\u6761\u4ef6\u53d8\u91cf\n    // \u5faa\u73af\u6c42\u548c 1, 4, 10, ...\n    while i <= n {\n        res += i\n        // \u66f4\u65b0\u6761\u4ef6\u53d8\u91cf\n        i += 1\n        i *= 2\n    }\n    return res\n}\n
iteration.js
/* while \u5faa\u73af\uff08\u4e24\u6b21\u66f4\u65b0\uff09 */\nfunction whileLoopII(n) {\n    let res = 0;\n    let i = 1; // \u521d\u59cb\u5316\u6761\u4ef6\u53d8\u91cf\n    // \u5faa\u73af\u6c42\u548c 1, 4, 10, ...\n    while (i <= n) {\n        res += i;\n        // \u66f4\u65b0\u6761\u4ef6\u53d8\u91cf\n        i++;\n        i *= 2;\n    }\n    return res;\n}\n
iteration.ts
/* while \u5faa\u73af\uff08\u4e24\u6b21\u66f4\u65b0\uff09 */\nfunction whileLoopII(n: number): number {\n    let res = 0;\n    let i = 1; // \u521d\u59cb\u5316\u6761\u4ef6\u53d8\u91cf\n    // \u5faa\u73af\u6c42\u548c 1, 4, 10, ...\n    while (i <= n) {\n        res += i;\n        // \u66f4\u65b0\u6761\u4ef6\u53d8\u91cf\n        i++;\n        i *= 2;\n    }\n    return res;\n}\n
iteration.dart
/* while \u5faa\u73af\uff08\u4e24\u6b21\u66f4\u65b0\uff09 */\nint whileLoopII(int n) {\n  int res = 0;\n  int i = 1; // \u521d\u59cb\u5316\u6761\u4ef6\u53d8\u91cf\n  // \u5faa\u73af\u6c42\u548c 1, 4, 10, ...\n  while (i <= n) {\n    res += i;\n    // \u66f4\u65b0\u6761\u4ef6\u53d8\u91cf\n    i++;\n    i *= 2;\n  }\n  return res;\n}\n
iteration.rs
/* while \u5faa\u73af\uff08\u4e24\u6b21\u66f4\u65b0\uff09 */\nfn while_loop_ii(n: i32) -> i32 {\n    let mut res = 0;\n    let mut i = 1; // \u521d\u59cb\u5316\u6761\u4ef6\u53d8\u91cf\n\n    // \u5faa\u73af\u6c42\u548c 1, 4, 10, ...\n    while i <= n {\n        res += i;\n        // \u66f4\u65b0\u6761\u4ef6\u53d8\u91cf\n        i += 1;\n        i *= 2;\n    }\n    res\n}\n
iteration.c
/* while \u5faa\u73af\uff08\u4e24\u6b21\u66f4\u65b0\uff09 */\nint whileLoopII(int n) {\n    int res = 0;\n    int i = 1; // \u521d\u59cb\u5316\u6761\u4ef6\u53d8\u91cf\n    // \u5faa\u73af\u6c42\u548c 1, 4, 10, ...\n    while (i <= n) {\n        res += i;\n        // \u66f4\u65b0\u6761\u4ef6\u53d8\u91cf\n        i++;\n        i *= 2;\n    }\n    return res;\n}\n
iteration.zig
//  while \u5faa\u73af\uff08\u4e24\u6b21\u66f4\u65b0\uff09\nfn whileLoopII(n: i32) i32 {\n    var res: i32 = 0;\n    var i: i32 = 1; // \u521d\u59cb\u5316\u6761\u4ef6\u53d8\u91cf\n    // \u5faa\u73af\u6c42\u548c 1, 4, 10, ...\n    while (i <= n) {\n        res += @intCast(i);\n        // \u66f4\u65b0\u6761\u4ef6\u53d8\u91cf\n        i += 1;\n        i *= 2;\n    }\n    return res;\n}\n
Code Visualization

Full Screen >

Overall, for loops are more concise, while while loops are more flexible. Both can implement iterative structures. Which one to use should be determined based on the specific requirements of the problem.

"},{"location":"chapter_computational_complexity/iteration_and_recursion/#3-nested-loops","title":"3. \u00a0 Nested Loops","text":"

We can nest one loop structure within another. Below is an example using for loops:

PythonC++JavaC#GoSwiftJSTSDartRustCZig iteration.py
def nested_for_loop(n: int) -> str:\n    \"\"\"\u53cc\u5c42 for \u5faa\u73af\"\"\"\n    res = \"\"\n    # \u5faa\u73af i = 1, 2, ..., n-1, n\n    for i in range(1, n + 1):\n        # \u5faa\u73af j = 1, 2, ..., n-1, n\n        for j in range(1, n + 1):\n            res += f\"({i}, {j}), \"\n    return res\n
iteration.cpp
/* \u53cc\u5c42 for \u5faa\u73af */\nstring nestedForLoop(int n) {\n    ostringstream res;\n    // \u5faa\u73af i = 1, 2, ..., n-1, n\n    for (int i = 1; i <= n; ++i) {\n        // \u5faa\u73af j = 1, 2, ..., n-1, n\n        for (int j = 1; j <= n; ++j) {\n            res << \"(\" << i << \", \" << j << \"), \";\n        }\n    }\n    return res.str();\n}\n
iteration.java
/* \u53cc\u5c42 for \u5faa\u73af */\nString nestedForLoop(int n) {\n    StringBuilder res = new StringBuilder();\n    // \u5faa\u73af i = 1, 2, ..., n-1, n\n    for (int i = 1; i <= n; i++) {\n        // \u5faa\u73af j = 1, 2, ..., n-1, n\n        for (int j = 1; j <= n; j++) {\n            res.append(\"(\" + i + \", \" + j + \"), \");\n        }\n    }\n    return res.toString();\n}\n
iteration.cs
/* \u53cc\u5c42 for \u5faa\u73af */\nstring NestedForLoop(int n) {\n    StringBuilder res = new();\n    // \u5faa\u73af i = 1, 2, ..., n-1, n\n    for (int i = 1; i <= n; i++) {\n        // \u5faa\u73af j = 1, 2, ..., n-1, n\n        for (int j = 1; j <= n; j++) {\n            res.Append($\"({i}, {j}), \");\n        }\n    }\n    return res.ToString();\n}\n
iteration.go
/* \u53cc\u5c42 for \u5faa\u73af */\nfunc nestedForLoop(n int) string {\n    res := \"\"\n    // \u5faa\u73af i = 1, 2, ..., n-1, n\n    for i := 1; i <= n; i++ {\n        for j := 1; j <= n; j++ {\n            // \u5faa\u73af j = 1, 2, ..., n-1, n\n            res += fmt.Sprintf(\"(%d, %d), \", i, j)\n        }\n    }\n    return res\n}\n
iteration.swift
/* \u53cc\u5c42 for \u5faa\u73af */\nfunc nestedForLoop(n: Int) -> String {\n    var res = \"\"\n    // \u5faa\u73af i = 1, 2, ..., n-1, n\n    for i in 1 ... n {\n        // \u5faa\u73af j = 1, 2, ..., n-1, n\n        for j in 1 ... n {\n            res.append(\"(\\(i), \\(j)), \")\n        }\n    }\n    return res\n}\n
iteration.js
/* \u53cc\u5c42 for \u5faa\u73af */\nfunction nestedForLoop(n) {\n    let res = '';\n    // \u5faa\u73af i = 1, 2, ..., n-1, n\n    for (let i = 1; i <= n; i++) {\n        // \u5faa\u73af j = 1, 2, ..., n-1, n\n        for (let j = 1; j <= n; j++) {\n            res += `(${i}, ${j}), `;\n        }\n    }\n    return res;\n}\n
iteration.ts
/* \u53cc\u5c42 for \u5faa\u73af */\nfunction nestedForLoop(n: number): string {\n    let res = '';\n    // \u5faa\u73af i = 1, 2, ..., n-1, n\n    for (let i = 1; i <= n; i++) {\n        // \u5faa\u73af j = 1, 2, ..., n-1, n\n        for (let j = 1; j <= n; j++) {\n            res += `(${i}, ${j}), `;\n        }\n    }\n    return res;\n}\n
iteration.dart
/* \u53cc\u5c42 for \u5faa\u73af */\nString nestedForLoop(int n) {\n  String res = \"\";\n  // \u5faa\u73af i = 1, 2, ..., n-1, n\n  for (int i = 1; i <= n; i++) {\n    // \u5faa\u73af j = 1, 2, ..., n-1, n\n    for (int j = 1; j <= n; j++) {\n      res += \"($i, $j), \";\n    }\n  }\n  return res;\n}\n
iteration.rs
/* \u53cc\u5c42 for \u5faa\u73af */\nfn nested_for_loop(n: i32) -> String {\n    let mut res = vec![];\n    // \u5faa\u73af i = 1, 2, ..., n-1, n\n    for i in 1..=n {\n        // \u5faa\u73af j = 1, 2, ..., n-1, n\n        for j in 1..=n {\n            res.push(format!(\"({}, {}), \", i, j));\n        }\n    }\n    res.join(\"\")\n}\n
iteration.c
/* \u53cc\u5c42 for \u5faa\u73af */\nchar *nestedForLoop(int n) {\n    // n * n \u4e3a\u5bf9\u5e94\u70b9\u6570\u91cf\uff0c\"(i, j), \" \u5bf9\u5e94\u5b57\u7b26\u4e32\u957f\u6700\u5927\u4e3a 6+10*2\uff0c\u52a0\u4e0a\u6700\u540e\u4e00\u4e2a\u7a7a\u5b57\u7b26 \\0 \u7684\u989d\u5916\u7a7a\u95f4\n    int size = n * n * 26 + 1;\n    char *res = malloc(size * sizeof(char));\n    // \u5faa\u73af i = 1, 2, ..., n-1, n\n    for (int i = 1; i <= n; i++) {\n        // \u5faa\u73af j = 1, 2, ..., n-1, n\n        for (int j = 1; j <= n; j++) {\n            char tmp[26];\n            snprintf(tmp, sizeof(tmp), \"(%d, %d), \", i, j);\n            strncat(res, tmp, size - strlen(res) - 1);\n        }\n    }\n    return res;\n}\n
iteration.zig
// \u53cc\u5c42 for \u5faa\u73af\nfn nestedForLoop(allocator: Allocator, n: usize) ![]const u8 {\n    var res = std.ArrayList(u8).init(allocator);\n    defer res.deinit();\n    var buffer: [20]u8 = undefined;\n    // \u5faa\u73af i = 1, 2, ..., n-1, n\n    for (1..n+1) |i| {\n        // \u5faa\u73af j = 1, 2, ..., n-1, n\n        for (1..n+1) |j| {\n            var _str = try std.fmt.bufPrint(&buffer, \"({d}, {d}), \", .{i, j});\n            try res.appendSlice(_str);\n        }\n    }\n    return res.toOwnedSlice();\n}\n
Code Visualization

Full Screen >

The flowchart below represents this nested loop.

Figure 2-2 \u00a0 Flowchart of the Nested Loop

In such cases, the number of operations of the function is proportional to \\(n^2\\), meaning the algorithm's runtime and the size of the input data \\(n\\) has a 'quadratic relationship.'

We can further increase the complexity by adding more nested loops, each level of nesting effectively \"increasing the dimension,\" which raises the time complexity to \"cubic,\" \"quartic,\" and so on.

"},{"location":"chapter_computational_complexity/iteration_and_recursion/#222-recursion","title":"2.2.2 \u00a0 Recursion","text":"

\"Recursion\" is an algorithmic strategy where a function solves a problem by calling itself. It primarily involves two phases:

  1. Calling: This is where the program repeatedly calls itself, often with progressively smaller or simpler arguments, moving towards the \"termination condition.\"
  2. Returning: Upon triggering the \"termination condition,\" the program begins to return from the deepest recursive function, aggregating the results of each layer.

From an implementation perspective, recursive code mainly includes three elements.

  1. Termination Condition: Determines when to switch from \"calling\" to \"returning.\"
  2. Recursive Call: Corresponds to \"calling,\" where the function calls itself, usually with smaller or more simplified parameters.
  3. Return Result: Corresponds to \"returning,\" where the result of the current recursion level is returned to the previous layer.

Observe the following code, where simply calling the function recur(n) can compute the sum of \\(1 + 2 + \\dots + n\\):

PythonC++JavaC#GoSwiftJSTSDartRustCZig recursion.py
def recur(n: int) -> int:\n    \"\"\"\u9012\u5f52\"\"\"\n    # \u7ec8\u6b62\u6761\u4ef6\n    if n == 1:\n        return 1\n    # \u9012\uff1a\u9012\u5f52\u8c03\u7528\n    res = recur(n - 1)\n    # \u5f52\uff1a\u8fd4\u56de\u7ed3\u679c\n    return n + res\n
recursion.cpp
/* \u9012\u5f52 */\nint recur(int n) {\n    // \u7ec8\u6b62\u6761\u4ef6\n    if (n == 1)\n        return 1;\n    // \u9012\uff1a\u9012\u5f52\u8c03\u7528\n    int res = recur(n - 1);\n    // \u5f52\uff1a\u8fd4\u56de\u7ed3\u679c\n    return n + res;\n}\n
recursion.java
/* \u9012\u5f52 */\nint recur(int n) {\n    // \u7ec8\u6b62\u6761\u4ef6\n    if (n == 1)\n        return 1;\n    // \u9012\uff1a\u9012\u5f52\u8c03\u7528\n    int res = recur(n - 1);\n    // \u5f52\uff1a\u8fd4\u56de\u7ed3\u679c\n    return n + res;\n}\n
recursion.cs
/* \u9012\u5f52 */\nint Recur(int n) {\n    // \u7ec8\u6b62\u6761\u4ef6\n    if (n == 1)\n        return 1;\n    // \u9012\uff1a\u9012\u5f52\u8c03\u7528\n    int res = Recur(n - 1);\n    // \u5f52\uff1a\u8fd4\u56de\u7ed3\u679c\n    return n + res;\n}\n
recursion.go
/* \u9012\u5f52 */\nfunc recur(n int) int {\n    // \u7ec8\u6b62\u6761\u4ef6\n    if n == 1 {\n        return 1\n    }\n    // \u9012\uff1a\u9012\u5f52\u8c03\u7528\n    res := recur(n - 1)\n    // \u5f52\uff1a\u8fd4\u56de\u7ed3\u679c\n    return n + res\n}\n
recursion.swift
/* \u9012\u5f52 */\nfunc recur(n: Int) -> Int {\n    // \u7ec8\u6b62\u6761\u4ef6\n    if n == 1 {\n        return 1\n    }\n    // \u9012\uff1a\u9012\u5f52\u8c03\u7528\n    let res = recur(n: n - 1)\n    // \u5f52\uff1a\u8fd4\u56de\u7ed3\u679c\n    return n + res\n}\n
recursion.js
/* \u9012\u5f52 */\nfunction recur(n) {\n    // \u7ec8\u6b62\u6761\u4ef6\n    if (n === 1) return 1;\n    // \u9012\uff1a\u9012\u5f52\u8c03\u7528\n    const res = recur(n - 1);\n    // \u5f52\uff1a\u8fd4\u56de\u7ed3\u679c\n    return n + res;\n}\n
recursion.ts
/* \u9012\u5f52 */\nfunction recur(n: number): number {\n    // \u7ec8\u6b62\u6761\u4ef6\n    if (n === 1) return 1;\n    // \u9012\uff1a\u9012\u5f52\u8c03\u7528\n    const res = recur(n - 1);\n    // \u5f52\uff1a\u8fd4\u56de\u7ed3\u679c\n    return n + res;\n}\n
recursion.dart
/* \u9012\u5f52 */\nint recur(int n) {\n  // \u7ec8\u6b62\u6761\u4ef6\n  if (n == 1) return 1;\n  // \u9012\uff1a\u9012\u5f52\u8c03\u7528\n  int res = recur(n - 1);\n  // \u5f52\uff1a\u8fd4\u56de\u7ed3\u679c\n  return n + res;\n}\n
recursion.rs
/* \u9012\u5f52 */\nfn recur(n: i32) -> i32 {\n    // \u7ec8\u6b62\u6761\u4ef6\n    if n == 1 {\n        return 1;\n    }\n    // \u9012\uff1a\u9012\u5f52\u8c03\u7528\n    let res = recur(n - 1);\n    // \u5f52\uff1a\u8fd4\u56de\u7ed3\u679c\n    n + res\n}\n
recursion.c
/* \u9012\u5f52 */\nint recur(int n) {\n    // \u7ec8\u6b62\u6761\u4ef6\n    if (n == 1)\n        return 1;\n    // \u9012\uff1a\u9012\u5f52\u8c03\u7528\n    int res = recur(n - 1);\n    // \u5f52\uff1a\u8fd4\u56de\u7ed3\u679c\n    return n + res;\n}\n
recursion.zig
// \u9012\u5f52\u51fd\u6570\nfn recur(n: i32) i32 {\n    // \u7ec8\u6b62\u6761\u4ef6\n    if (n == 1) {\n        return 1;\n    }\n    // \u9012\uff1a\u9012\u5f52\u8c03\u7528\n    var res: i32 = recur(n - 1);\n    // \u5f52\uff1a\u8fd4\u56de\u7ed3\u679c\n    return n + res;\n}\n
Code Visualization

Full Screen >

The Figure 2-3 shows the recursive process of this function.

Figure 2-3 \u00a0 Recursive Process of the Sum Function

Although iteration and recursion can achieve the same results from a computational standpoint, they represent two entirely different paradigms of thinking and problem-solving.

  • Iteration: Solves problems \"from the bottom up.\" It starts with the most basic steps, and then repeatedly adds or accumulates these steps until the task is complete.
  • Recursion: Solves problems \"from the top down.\" It breaks down the original problem into smaller sub-problems, each of which has the same form as the original problem. These sub-problems are then further decomposed into even smaller sub-problems, stopping at the base case whose solution is known.

Let's take the earlier example of the summation function, defined as \\(f(n) = 1 + 2 + \\dots + n\\).

  • Iteration: In this approach, we simulate the summation process within a loop. Starting from \\(1\\) and traversing to \\(n\\), we perform the summation operation in each iteration to eventually compute \\(f(n)\\).
  • Recursion: Here, the problem is broken down into a sub-problem: \\(f(n) = n + f(n-1)\\). This decomposition continues recursively until reaching the base case, \\(f(1) = 1\\), at which point the recursion terminates.
"},{"location":"chapter_computational_complexity/iteration_and_recursion/#1-call-stack","title":"1. \u00a0 Call Stack","text":"

Every time a recursive function calls itself, the system allocates memory for the newly initiated function to store local variables, the return address, and other relevant information. This leads to two primary outcomes.

  • The function's context data is stored in a memory area called \"stack frame space\" and is only released after the function returns. Therefore, recursion generally consumes more memory space than iteration.
  • Recursive calls introduce additional overhead. Hence, recursion is usually less time-efficient than loops.

As shown in the Figure 2-4 , there are \\(n\\) unreturned recursive functions before triggering the termination condition, indicating a recursion depth of \\(n\\).

Figure 2-4 \u00a0 Recursion Call Depth

In practice, the depth of recursion allowed by programming languages is usually limited, and excessively deep recursion can lead to stack overflow errors.

"},{"location":"chapter_computational_complexity/iteration_and_recursion/#2-tail-recursion","title":"2. \u00a0 Tail Recursion","text":"

Interestingly, if a function performs its recursive call as the very last step before returning, it can be optimized by the compiler or interpreter to be as space-efficient as iteration. This scenario is known as \"tail recursion.\"

  • Regular Recursion: In standard recursion, when the function returns to the previous level, it continues to execute more code, requiring the system to save the context of the previous call.
  • Tail Recursion: Here, the recursive call is the final operation before the function returns. This means that upon returning to the previous level, no further actions are needed, so the system does not need to save the context of the previous level.

For example, in calculating \\(1 + 2 + \\dots + n\\), we can make the result variable res a parameter of the function, thereby achieving tail recursion:

PythonC++JavaC#GoSwiftJSTSDartRustCZig recursion.py
def tail_recur(n, res):\n    \"\"\"\u5c3e\u9012\u5f52\"\"\"\n    # \u7ec8\u6b62\u6761\u4ef6\n    if n == 0:\n        return res\n    # \u5c3e\u9012\u5f52\u8c03\u7528\n    return tail_recur(n - 1, res + n)\n
recursion.cpp
/* \u5c3e\u9012\u5f52 */\nint tailRecur(int n, int res) {\n    // \u7ec8\u6b62\u6761\u4ef6\n    if (n == 0)\n        return res;\n    // \u5c3e\u9012\u5f52\u8c03\u7528\n    return tailRecur(n - 1, res + n);\n}\n
recursion.java
/* \u5c3e\u9012\u5f52 */\nint tailRecur(int n, int res) {\n    // \u7ec8\u6b62\u6761\u4ef6\n    if (n == 0)\n        return res;\n    // \u5c3e\u9012\u5f52\u8c03\u7528\n    return tailRecur(n - 1, res + n);\n}\n
recursion.cs
/* \u5c3e\u9012\u5f52 */\nint TailRecur(int n, int res) {\n    // \u7ec8\u6b62\u6761\u4ef6\n    if (n == 0)\n        return res;\n    // \u5c3e\u9012\u5f52\u8c03\u7528\n    return TailRecur(n - 1, res + n);\n}\n
recursion.go
/* \u5c3e\u9012\u5f52 */\nfunc tailRecur(n int, res int) int {\n    // \u7ec8\u6b62\u6761\u4ef6\n    if n == 0 {\n        return res\n    }\n    // \u5c3e\u9012\u5f52\u8c03\u7528\n    return tailRecur(n-1, res+n)\n}\n
recursion.swift
/* \u5c3e\u9012\u5f52 */\nfunc tailRecur(n: Int, res: Int) -> Int {\n    // \u7ec8\u6b62\u6761\u4ef6\n    if n == 0 {\n        return res\n    }\n    // \u5c3e\u9012\u5f52\u8c03\u7528\n    return tailRecur(n: n - 1, res: res + n)\n}\n
recursion.js
/* \u5c3e\u9012\u5f52 */\nfunction tailRecur(n, res) {\n    // \u7ec8\u6b62\u6761\u4ef6\n    if (n === 0) return res;\n    // \u5c3e\u9012\u5f52\u8c03\u7528\n    return tailRecur(n - 1, res + n);\n}\n
recursion.ts
/* \u5c3e\u9012\u5f52 */\nfunction tailRecur(n: number, res: number): number {\n    // \u7ec8\u6b62\u6761\u4ef6\n    if (n === 0) return res;\n    // \u5c3e\u9012\u5f52\u8c03\u7528\n    return tailRecur(n - 1, res + n);\n}\n
recursion.dart
/* \u5c3e\u9012\u5f52 */\nint tailRecur(int n, int res) {\n  // \u7ec8\u6b62\u6761\u4ef6\n  if (n == 0) return res;\n  // \u5c3e\u9012\u5f52\u8c03\u7528\n  return tailRecur(n - 1, res + n);\n}\n
recursion.rs
/* \u5c3e\u9012\u5f52 */\nfn tail_recur(n: i32, res: i32) -> i32 {\n    // \u7ec8\u6b62\u6761\u4ef6\n    if n == 0 {\n        return res;\n    }\n    // \u5c3e\u9012\u5f52\u8c03\u7528\n    tail_recur(n - 1, res + n)\n}\n
recursion.c
/* \u5c3e\u9012\u5f52 */\nint tailRecur(int n, int res) {\n    // \u7ec8\u6b62\u6761\u4ef6\n    if (n == 0)\n        return res;\n    // \u5c3e\u9012\u5f52\u8c03\u7528\n    return tailRecur(n - 1, res + n);\n}\n
recursion.zig
// \u5c3e\u9012\u5f52\u51fd\u6570\nfn tailRecur(n: i32, res: i32) i32 {\n    // \u7ec8\u6b62\u6761\u4ef6\n    if (n == 0) {\n        return res;\n    }\n    // \u5c3e\u9012\u5f52\u8c03\u7528\n    return tailRecur(n - 1, res + n);\n}\n
Code Visualization

Full Screen >

The execution process of tail recursion is shown in the following figure. Comparing regular recursion and tail recursion, the point of the summation operation is different.

  • Regular Recursion: The summation operation occurs during the \"returning\" phase, requiring another summation after each layer returns.
  • Tail Recursion: The summation operation occurs during the \"calling\" phase, and the \"returning\" phase only involves returning through each layer.

Figure 2-5 \u00a0 Tail Recursion Process

Tip

Note that many compilers or interpreters do not support tail recursion optimization. For example, Python does not support tail recursion optimization by default, so even if the function is in the form of tail recursion, it may still encounter stack overflow issues.

"},{"location":"chapter_computational_complexity/iteration_and_recursion/#3-recursion-tree","title":"3. \u00a0 Recursion Tree","text":"

When dealing with algorithms related to \"divide and conquer\", recursion often offers a more intuitive approach and more readable code than iteration. Take the \"Fibonacci sequence\" as an example.

Question

Given a Fibonacci sequence \\(0, 1, 1, 2, 3, 5, 8, 13, \\dots\\), find the \\(n\\)th number in the sequence.

Let the \\(n\\)th number of the Fibonacci sequence be \\(f(n)\\), it's easy to deduce two conclusions:

  • The first two numbers of the sequence are \\(f(1) = 0\\) and \\(f(2) = 1\\).
  • Each number in the sequence is the sum of the two preceding ones, that is, \\(f(n) = f(n - 1) + f(n - 2)\\).

Using the recursive relation, and considering the first two numbers as termination conditions, we can write the recursive code. Calling fib(n) will yield the \\(n\\)th number of the Fibonacci sequence:

PythonC++JavaC#GoSwiftJSTSDartRustCZig recursion.py
def fib(n: int) -> int:\n    \"\"\"\u6590\u6ce2\u90a3\u5951\u6570\u5217\uff1a\u9012\u5f52\"\"\"\n    # \u7ec8\u6b62\u6761\u4ef6 f(1) = 0, f(2) = 1\n    if n == 1 or n == 2:\n        return n - 1\n    # \u9012\u5f52\u8c03\u7528 f(n) = f(n-1) + f(n-2)\n    res = fib(n - 1) + fib(n - 2)\n    # \u8fd4\u56de\u7ed3\u679c f(n)\n    return res\n
recursion.cpp
/* \u6590\u6ce2\u90a3\u5951\u6570\u5217\uff1a\u9012\u5f52 */\nint fib(int n) {\n    // \u7ec8\u6b62\u6761\u4ef6 f(1) = 0, f(2) = 1\n    if (n == 1 || n == 2)\n        return n - 1;\n    // \u9012\u5f52\u8c03\u7528 f(n) = f(n-1) + f(n-2)\n    int res = fib(n - 1) + fib(n - 2);\n    // \u8fd4\u56de\u7ed3\u679c f(n)\n    return res;\n}\n
recursion.java
/* \u6590\u6ce2\u90a3\u5951\u6570\u5217\uff1a\u9012\u5f52 */\nint fib(int n) {\n    // \u7ec8\u6b62\u6761\u4ef6 f(1) = 0, f(2) = 1\n    if (n == 1 || n == 2)\n        return n - 1;\n    // \u9012\u5f52\u8c03\u7528 f(n) = f(n-1) + f(n-2)\n    int res = fib(n - 1) + fib(n - 2);\n    // \u8fd4\u56de\u7ed3\u679c f(n)\n    return res;\n}\n
recursion.cs
/* \u6590\u6ce2\u90a3\u5951\u6570\u5217\uff1a\u9012\u5f52 */\nint Fib(int n) {\n    // \u7ec8\u6b62\u6761\u4ef6 f(1) = 0, f(2) = 1\n    if (n == 1 || n == 2)\n        return n - 1;\n    // \u9012\u5f52\u8c03\u7528 f(n) = f(n-1) + f(n-2)\n    int res = Fib(n - 1) + Fib(n - 2);\n    // \u8fd4\u56de\u7ed3\u679c f(n)\n    return res;\n}\n
recursion.go
/* \u6590\u6ce2\u90a3\u5951\u6570\u5217\uff1a\u9012\u5f52 */\nfunc fib(n int) int {\n    // \u7ec8\u6b62\u6761\u4ef6 f(1) = 0, f(2) = 1\n    if n == 1 || n == 2 {\n        return n - 1\n    }\n    // \u9012\u5f52\u8c03\u7528 f(n) = f(n-1) + f(n-2)\n    res := fib(n-1) + fib(n-2)\n    // \u8fd4\u56de\u7ed3\u679c f(n)\n    return res\n}\n
recursion.swift
/* \u6590\u6ce2\u90a3\u5951\u6570\u5217\uff1a\u9012\u5f52 */\nfunc fib(n: Int) -> Int {\n    // \u7ec8\u6b62\u6761\u4ef6 f(1) = 0, f(2) = 1\n    if n == 1 || n == 2 {\n        return n - 1\n    }\n    // \u9012\u5f52\u8c03\u7528 f(n) = f(n-1) + f(n-2)\n    let res = fib(n: n - 1) + fib(n: n - 2)\n    // \u8fd4\u56de\u7ed3\u679c f(n)\n    return res\n}\n
recursion.js
/* \u6590\u6ce2\u90a3\u5951\u6570\u5217\uff1a\u9012\u5f52 */\nfunction fib(n) {\n    // \u7ec8\u6b62\u6761\u4ef6 f(1) = 0, f(2) = 1\n    if (n === 1 || n === 2) return n - 1;\n    // \u9012\u5f52\u8c03\u7528 f(n) = f(n-1) + f(n-2)\n    const res = fib(n - 1) + fib(n - 2);\n    // \u8fd4\u56de\u7ed3\u679c f(n)\n    return res;\n}\n
recursion.ts
/* \u6590\u6ce2\u90a3\u5951\u6570\u5217\uff1a\u9012\u5f52 */\nfunction fib(n: number): number {\n    // \u7ec8\u6b62\u6761\u4ef6 f(1) = 0, f(2) = 1\n    if (n === 1 || n === 2) return n - 1;\n    // \u9012\u5f52\u8c03\u7528 f(n) = f(n-1) + f(n-2)\n    const res = fib(n - 1) + fib(n - 2);\n    // \u8fd4\u56de\u7ed3\u679c f(n)\n    return res;\n}\n
recursion.dart
/* \u6590\u6ce2\u90a3\u5951\u6570\u5217\uff1a\u9012\u5f52 */\nint fib(int n) {\n  // \u7ec8\u6b62\u6761\u4ef6 f(1) = 0, f(2) = 1\n  if (n == 1 || n == 2) return n - 1;\n  // \u9012\u5f52\u8c03\u7528 f(n) = f(n-1) + f(n-2)\n  int res = fib(n - 1) + fib(n - 2);\n  // \u8fd4\u56de\u7ed3\u679c f(n)\n  return res;\n}\n
recursion.rs
/* \u6590\u6ce2\u90a3\u5951\u6570\u5217\uff1a\u9012\u5f52 */\nfn fib(n: i32) -> i32 {\n    // \u7ec8\u6b62\u6761\u4ef6 f(1) = 0, f(2) = 1\n    if n == 1 || n == 2 {\n        return n - 1;\n    }\n    // \u9012\u5f52\u8c03\u7528 f(n) = f(n-1) + f(n-2)\n    let res = fib(n - 1) + fib(n - 2);\n    // \u8fd4\u56de\u7ed3\u679c\n    res\n}\n
recursion.c
/* \u6590\u6ce2\u90a3\u5951\u6570\u5217\uff1a\u9012\u5f52 */\nint fib(int n) {\n    // \u7ec8\u6b62\u6761\u4ef6 f(1) = 0, f(2) = 1\n    if (n == 1 || n == 2)\n        return n - 1;\n    // \u9012\u5f52\u8c03\u7528 f(n) = f(n-1) + f(n-2)\n    int res = fib(n - 1) + fib(n - 2);\n    // \u8fd4\u56de\u7ed3\u679c f(n)\n    return res;\n}\n
recursion.zig
// \u6590\u6ce2\u90a3\u5951\u6570\u5217\nfn fib(n: i32) i32 {\n    // \u7ec8\u6b62\u6761\u4ef6 f(1) = 0, f(2) = 1\n    if (n == 1 or n == 2) {\n        return n - 1;\n    }\n    // \u9012\u5f52\u8c03\u7528 f(n) = f(n-1) + f(n-2)\n    var res: i32 = fib(n - 1) + fib(n - 2);\n    // \u8fd4\u56de\u7ed3\u679c f(n)\n    return res;\n}\n
Code Visualization

Full Screen >

Observing the above code, we see that it recursively calls two functions within itself, meaning that one call generates two branching calls. As illustrated below, this continuous recursive calling eventually creates a \"recursion tree\" with a depth of \\(n\\).

Figure 2-6 \u00a0 Fibonacci Sequence Recursion Tree

Fundamentally, recursion embodies the paradigm of \"breaking down a problem into smaller sub-problems.\" This divide-and-conquer strategy is crucial.

  • From an algorithmic perspective, many important strategies like searching, sorting, backtracking, divide-and-conquer, and dynamic programming directly or indirectly use this way of thinking.
  • From a data structure perspective, recursion is naturally suited for dealing with linked lists, trees, and graphs, as they are well suited for analysis using the divide-and-conquer approach.
"},{"location":"chapter_computational_complexity/iteration_and_recursion/#223-comparison","title":"2.2.3 \u00a0 Comparison","text":"

Summarizing the above content, the following table shows the differences between iteration and recursion in terms of implementation, performance, and applicability.

Table: Comparison of Iteration and Recursion Characteristics

Iteration Recursion Approach Loop structure Function calls itself Time Efficiency Generally higher efficiency, no function call overhead Each function call generates overhead Memory Usage Typically uses a fixed size of memory space Accumulative function calls can use a substantial amount of stack frame space Suitable Problems Suitable for simple loop tasks, intuitive and readable code Suitable for problem decomposition, like trees, graphs, divide-and-conquer, backtracking, etc., concise and clear code structure

Tip

If you find the following content difficult to understand, consider revisiting it after reading the \"Stack\" chapter.

So, what is the intrinsic connection between iteration and recursion? Taking the above recursive function as an example, the summation operation occurs during the recursion's \"return\" phase. This means that the initially called function is the last to complete its summation operation, mirroring the \"last in, first out\" principle of a stack.

Recursive terms like \"call stack\" and \"stack frame space\" hint at the close relationship between recursion and stacks.

  1. Calling: When a function is called, the system allocates a new stack frame on the \"call stack\" for that function, storing local variables, parameters, return addresses, and other data.
  2. Returning: When a function completes execution and returns, the corresponding stack frame is removed from the \"call stack,\" restoring the execution environment of the previous function.

Therefore, we can use an explicit stack to simulate the behavior of the call stack, thus transforming recursion into an iterative form:

PythonC++JavaC#GoSwiftJSTSDartRustCZig recursion.py
def for_loop_recur(n: int) -> int:\n    \"\"\"\u4f7f\u7528\u8fed\u4ee3\u6a21\u62df\u9012\u5f52\"\"\"\n    # \u4f7f\u7528\u4e00\u4e2a\u663e\u5f0f\u7684\u6808\u6765\u6a21\u62df\u7cfb\u7edf\u8c03\u7528\u6808\n    stack = []\n    res = 0\n    # \u9012\uff1a\u9012\u5f52\u8c03\u7528\n    for i in range(n, 0, -1):\n        # \u901a\u8fc7\u201c\u5165\u6808\u64cd\u4f5c\u201d\u6a21\u62df\u201c\u9012\u201d\n        stack.append(i)\n    # \u5f52\uff1a\u8fd4\u56de\u7ed3\u679c\n    while stack:\n        # \u901a\u8fc7\u201c\u51fa\u6808\u64cd\u4f5c\u201d\u6a21\u62df\u201c\u5f52\u201d\n        res += stack.pop()\n    # res = 1+2+3+...+n\n    return res\n
recursion.cpp
/* \u4f7f\u7528\u8fed\u4ee3\u6a21\u62df\u9012\u5f52 */\nint forLoopRecur(int n) {\n    // \u4f7f\u7528\u4e00\u4e2a\u663e\u5f0f\u7684\u6808\u6765\u6a21\u62df\u7cfb\u7edf\u8c03\u7528\u6808\n    stack<int> stack;\n    int res = 0;\n    // \u9012\uff1a\u9012\u5f52\u8c03\u7528\n    for (int i = n; i > 0; i--) {\n        // \u901a\u8fc7\u201c\u5165\u6808\u64cd\u4f5c\u201d\u6a21\u62df\u201c\u9012\u201d\n        stack.push(i);\n    }\n    // \u5f52\uff1a\u8fd4\u56de\u7ed3\u679c\n    while (!stack.empty()) {\n        // \u901a\u8fc7\u201c\u51fa\u6808\u64cd\u4f5c\u201d\u6a21\u62df\u201c\u5f52\u201d\n        res += stack.top();\n        stack.pop();\n    }\n    // res = 1+2+3+...+n\n    return res;\n}\n
recursion.java
/* \u4f7f\u7528\u8fed\u4ee3\u6a21\u62df\u9012\u5f52 */\nint forLoopRecur(int n) {\n    // \u4f7f\u7528\u4e00\u4e2a\u663e\u5f0f\u7684\u6808\u6765\u6a21\u62df\u7cfb\u7edf\u8c03\u7528\u6808\n    Stack<Integer> stack = new Stack<>();\n    int res = 0;\n    // \u9012\uff1a\u9012\u5f52\u8c03\u7528\n    for (int i = n; i > 0; i--) {\n        // \u901a\u8fc7\u201c\u5165\u6808\u64cd\u4f5c\u201d\u6a21\u62df\u201c\u9012\u201d\n        stack.push(i);\n    }\n    // \u5f52\uff1a\u8fd4\u56de\u7ed3\u679c\n    while (!stack.isEmpty()) {\n        // \u901a\u8fc7\u201c\u51fa\u6808\u64cd\u4f5c\u201d\u6a21\u62df\u201c\u5f52\u201d\n        res += stack.pop();\n    }\n    // res = 1+2+3+...+n\n    return res;\n}\n
recursion.cs
/* \u4f7f\u7528\u8fed\u4ee3\u6a21\u62df\u9012\u5f52 */\nint ForLoopRecur(int n) {\n    // \u4f7f\u7528\u4e00\u4e2a\u663e\u5f0f\u7684\u6808\u6765\u6a21\u62df\u7cfb\u7edf\u8c03\u7528\u6808\n    Stack<int> stack = new();\n    int res = 0;\n    // \u9012\uff1a\u9012\u5f52\u8c03\u7528\n    for (int i = n; i > 0; i--) {\n        // \u901a\u8fc7\u201c\u5165\u6808\u64cd\u4f5c\u201d\u6a21\u62df\u201c\u9012\u201d\n        stack.Push(i);\n    }\n    // \u5f52\uff1a\u8fd4\u56de\u7ed3\u679c\n    while (stack.Count > 0) {\n        // \u901a\u8fc7\u201c\u51fa\u6808\u64cd\u4f5c\u201d\u6a21\u62df\u201c\u5f52\u201d\n        res += stack.Pop();\n    }\n    // res = 1+2+3+...+n\n    return res;\n}\n
recursion.go
/* \u4f7f\u7528\u8fed\u4ee3\u6a21\u62df\u9012\u5f52 */\nfunc forLoopRecur(n int) int {\n    // \u4f7f\u7528\u4e00\u4e2a\u663e\u5f0f\u7684\u6808\u6765\u6a21\u62df\u7cfb\u7edf\u8c03\u7528\u6808\n    stack := list.New()\n    res := 0\n    // \u9012\uff1a\u9012\u5f52\u8c03\u7528\n    for i := n; i > 0; i-- {\n        // \u901a\u8fc7\u201c\u5165\u6808\u64cd\u4f5c\u201d\u6a21\u62df\u201c\u9012\u201d\n        stack.PushBack(i)\n    }\n    // \u5f52\uff1a\u8fd4\u56de\u7ed3\u679c\n    for stack.Len() != 0 {\n        // \u901a\u8fc7\u201c\u51fa\u6808\u64cd\u4f5c\u201d\u6a21\u62df\u201c\u5f52\u201d\n        res += stack.Back().Value.(int)\n        stack.Remove(stack.Back())\n    }\n    // res = 1+2+3+...+n\n    return res\n}\n
recursion.swift
/* \u4f7f\u7528\u8fed\u4ee3\u6a21\u62df\u9012\u5f52 */\nfunc forLoopRecur(n: Int) -> Int {\n    // \u4f7f\u7528\u4e00\u4e2a\u663e\u5f0f\u7684\u6808\u6765\u6a21\u62df\u7cfb\u7edf\u8c03\u7528\u6808\n    var stack: [Int] = []\n    var res = 0\n    // \u9012\uff1a\u9012\u5f52\u8c03\u7528\n    for i in (1 ... n).reversed() {\n        // \u901a\u8fc7\u201c\u5165\u6808\u64cd\u4f5c\u201d\u6a21\u62df\u201c\u9012\u201d\n        stack.append(i)\n    }\n    // \u5f52\uff1a\u8fd4\u56de\u7ed3\u679c\n    while !stack.isEmpty {\n        // \u901a\u8fc7\u201c\u51fa\u6808\u64cd\u4f5c\u201d\u6a21\u62df\u201c\u5f52\u201d\n        res += stack.removeLast()\n    }\n    // res = 1+2+3+...+n\n    return res\n}\n
recursion.js
/* \u4f7f\u7528\u8fed\u4ee3\u6a21\u62df\u9012\u5f52 */\nfunction forLoopRecur(n) {\n    // \u4f7f\u7528\u4e00\u4e2a\u663e\u5f0f\u7684\u6808\u6765\u6a21\u62df\u7cfb\u7edf\u8c03\u7528\u6808\n    const stack = [];\n    let res = 0;\n    // \u9012\uff1a\u9012\u5f52\u8c03\u7528\n    for (let i = n; i > 0; i--) {\n        // \u901a\u8fc7\u201c\u5165\u6808\u64cd\u4f5c\u201d\u6a21\u62df\u201c\u9012\u201d\n        stack.push(i);\n    }\n    // \u5f52\uff1a\u8fd4\u56de\u7ed3\u679c\n    while (stack.length) {\n        // \u901a\u8fc7\u201c\u51fa\u6808\u64cd\u4f5c\u201d\u6a21\u62df\u201c\u5f52\u201d\n        res += stack.pop();\n    }\n    // res = 1+2+3+...+n\n    return res;\n}\n
recursion.ts
/* \u4f7f\u7528\u8fed\u4ee3\u6a21\u62df\u9012\u5f52 */\nfunction forLoopRecur(n: number): number {\n    // \u4f7f\u7528\u4e00\u4e2a\u663e\u5f0f\u7684\u6808\u6765\u6a21\u62df\u7cfb\u7edf\u8c03\u7528\u6808 \n    const stack: number[] = [];\n    let res: number = 0;\n    // \u9012\uff1a\u9012\u5f52\u8c03\u7528\n    for (let i = n; i > 0; i--) {\n        // \u901a\u8fc7\u201c\u5165\u6808\u64cd\u4f5c\u201d\u6a21\u62df\u201c\u9012\u201d\n        stack.push(i);\n    }\n    // \u5f52\uff1a\u8fd4\u56de\u7ed3\u679c\n    while (stack.length) {\n        // \u901a\u8fc7\u201c\u51fa\u6808\u64cd\u4f5c\u201d\u6a21\u62df\u201c\u5f52\u201d\n        res += stack.pop();\n    }\n    // res = 1+2+3+...+n\n    return res;\n}\n
recursion.dart
/* \u4f7f\u7528\u8fed\u4ee3\u6a21\u62df\u9012\u5f52 */\nint forLoopRecur(int n) {\n  // \u4f7f\u7528\u4e00\u4e2a\u663e\u5f0f\u7684\u6808\u6765\u6a21\u62df\u7cfb\u7edf\u8c03\u7528\u6808\n  List<int> stack = [];\n  int res = 0;\n  // \u9012\uff1a\u9012\u5f52\u8c03\u7528\n  for (int i = n; i > 0; i--) {\n    // \u901a\u8fc7\u201c\u5165\u6808\u64cd\u4f5c\u201d\u6a21\u62df\u201c\u9012\u201d\n    stack.add(i);\n  }\n  // \u5f52\uff1a\u8fd4\u56de\u7ed3\u679c\n  while (!stack.isEmpty) {\n    // \u901a\u8fc7\u201c\u51fa\u6808\u64cd\u4f5c\u201d\u6a21\u62df\u201c\u5f52\u201d\n    res += stack.removeLast();\n  }\n  // res = 1+2+3+...+n\n  return res;\n}\n
recursion.rs
/* \u4f7f\u7528\u8fed\u4ee3\u6a21\u62df\u9012\u5f52 */\nfn for_loop_recur(n: i32) -> i32 {\n    // \u4f7f\u7528\u4e00\u4e2a\u663e\u5f0f\u7684\u6808\u6765\u6a21\u62df\u7cfb\u7edf\u8c03\u7528\u6808\n    let mut stack = Vec::new();\n    let mut res = 0;\n    // \u9012\uff1a\u9012\u5f52\u8c03\u7528\n    for i in (1..=n).rev() {\n        // \u901a\u8fc7\u201c\u5165\u6808\u64cd\u4f5c\u201d\u6a21\u62df\u201c\u9012\u201d\n        stack.push(i);\n    }\n    // \u5f52\uff1a\u8fd4\u56de\u7ed3\u679c\n    while !stack.is_empty() {\n        // \u901a\u8fc7\u201c\u51fa\u6808\u64cd\u4f5c\u201d\u6a21\u62df\u201c\u5f52\u201d\n        res += stack.pop().unwrap();\n    }\n    // res = 1+2+3+...+n\n    res\n}\n
recursion.c
/* \u4f7f\u7528\u8fed\u4ee3\u6a21\u62df\u9012\u5f52 */\nint forLoopRecur(int n) {\n    int stack[1000]; // \u501f\u52a9\u4e00\u4e2a\u5927\u6570\u7ec4\u6765\u6a21\u62df\u6808\n    int top = -1;    // \u6808\u9876\u7d22\u5f15\n    int res = 0;\n    // \u9012\uff1a\u9012\u5f52\u8c03\u7528\n    for (int i = n; i > 0; i--) {\n        // \u901a\u8fc7\u201c\u5165\u6808\u64cd\u4f5c\u201d\u6a21\u62df\u201c\u9012\u201d\n        stack[1 + top++] = i;\n    }\n    // \u5f52\uff1a\u8fd4\u56de\u7ed3\u679c\n    while (top >= 0) {\n        // \u901a\u8fc7\u201c\u51fa\u6808\u64cd\u4f5c\u201d\u6a21\u62df\u201c\u5f52\u201d\n        res += stack[top--];\n    }\n    // res = 1+2+3+...+n\n    return res;\n}\n
recursion.zig
// \u4f7f\u7528\u8fed\u4ee3\u6a21\u62df\u9012\u5f52\nfn forLoopRecur(comptime n: i32) i32 {\n    // \u4f7f\u7528\u4e00\u4e2a\u663e\u5f0f\u7684\u6808\u6765\u6a21\u62df\u7cfb\u7edf\u8c03\u7528\u6808\n    var stack: [n]i32 = undefined;\n    var res: i32 = 0;\n    // \u9012\uff1a\u9012\u5f52\u8c03\u7528\n    var i: usize = n;\n    while (i > 0) {\n        stack[i - 1] = @intCast(i);\n        i -= 1;\n    }\n    // \u5f52\uff1a\u8fd4\u56de\u7ed3\u679c\n    var index: usize = n;\n    while (index > 0) {\n        index -= 1;\n        res += stack[index];\n    }\n    // res = 1+2+3+...+n\n    return res;\n}\n
Code Visualization

Full Screen >

Observing the above code, when recursion is transformed into iteration, the code becomes more complex. Although iteration and recursion can often be transformed into each other, it's not always advisable to do so for two reasons:

  • The transformed code may become more challenging to understand and less readable.
  • For some complex problems, simulating the behavior of the system's call stack can be quite challenging.

In conclusion, whether to choose iteration or recursion depends on the specific nature of the problem. In programming practice, it's crucial to weigh the pros and cons of both and choose the most suitable approach for the situation at hand.

"},{"location":"chapter_computational_complexity/performance_evaluation/","title":"2.1 \u00a0 Algorithm Efficiency Assessment","text":"

In algorithm design, we pursue the following two objectives in sequence.

  1. Finding a Solution to the Problem: The algorithm should reliably find the correct solution within the stipulated range of inputs.
  2. Seeking the Optimal Solution: For the same problem, multiple solutions might exist, and we aim to find the most efficient algorithm possible.

In other words, under the premise of being able to solve the problem, algorithm efficiency has become the main criterion for evaluating the merits of an algorithm, which includes the following two dimensions.

  • Time Efficiency: The speed at which an algorithm runs.
  • Space Efficiency: The size of the memory space occupied by an algorithm.

In short, our goal is to design data structures and algorithms that are both fast and memory-efficient. Effectively assessing algorithm efficiency is crucial because only then can we compare various algorithms and guide the process of algorithm design and optimization.

There are mainly two methods of efficiency assessment: actual testing and theoretical estimation.

"},{"location":"chapter_computational_complexity/performance_evaluation/#211-actual-testing","title":"2.1.1 \u00a0 Actual Testing","text":"

Suppose we have algorithms A and B, both capable of solving the same problem, and we need to compare their efficiencies. The most direct method is to use a computer to run these two algorithms and monitor and record their runtime and memory usage. This assessment method reflects the actual situation but has significant limitations.

On one hand, it's difficult to eliminate interference from the testing environment. Hardware configurations can affect algorithm performance. For example, algorithm A might run faster than B on one computer, but the opposite result may occur on another computer with different configurations. This means we would need to test on a variety of machines to calculate average efficiency, which is impractical.

On the other hand, conducting a full test is very resource-intensive. As the volume of input data changes, the efficiency of the algorithms may vary. For example, with smaller data volumes, algorithm A might run faster than B, but the opposite might be true with larger data volumes. Therefore, to draw convincing conclusions, we need to test a wide range of input data sizes, which requires significant computational resources.

"},{"location":"chapter_computational_complexity/performance_evaluation/#212-theoretical-estimation","title":"2.1.2 \u00a0 Theoretical Estimation","text":"

Due to the significant limitations of actual testing, we can consider evaluating algorithm efficiency solely through calculations. This estimation method is known as \"asymptotic complexity analysis,\" or simply \"complexity analysis.\"

Complexity analysis reflects the relationship between the time and space resources required for algorithm execution and the size of the input data. It describes the trend of growth in the time and space required by the algorithm as the size of the input data increases. This definition might sound complex, but we can break it down into three key points to understand it better.

  • \"Time and space resources\" correspond to \"time complexity\" and \"space complexity,\" respectively.
  • \"As the size of input data increases\" means that complexity reflects the relationship between algorithm efficiency and the volume of input data.
  • \"The trend of growth in time and space\" indicates that complexity analysis focuses not on the specific values of runtime or space occupied but on the \"rate\" at which time or space grows.

Complexity analysis overcomes the disadvantages of actual testing methods, reflected in the following aspects:

  • It is independent of the testing environment and applicable to all operating platforms.
  • It can reflect algorithm efficiency under different data volumes, especially in the performance of algorithms with large data volumes.

Tip

If you're still confused about the concept of complexity, don't worry. We will introduce it in detail in subsequent chapters.

Complexity analysis provides us with a \"ruler\" to measure the time and space resources needed to execute an algorithm and compare the efficiency between different algorithms.

Complexity is a mathematical concept and may be abstract and challenging for beginners. From this perspective, complexity analysis might not be the best content to introduce first. However, when discussing the characteristics of a particular data structure or algorithm, it's hard to avoid analyzing its speed and space usage.

In summary, it's recommended that you establish a preliminary understanding of complexity analysis before diving deep into data structures and algorithms, so that you can carry out simple complexity analyses of algorithms.

"},{"location":"chapter_computational_complexity/space_complexity/","title":"2.4 \u00a0 Space Complexity","text":"

\"Space complexity\" is used to measure the growth trend of the memory space occupied by an algorithm as the amount of data increases. This concept is very similar to time complexity, except that \"running time\" is replaced with \"occupied memory space\".

"},{"location":"chapter_computational_complexity/space_complexity/#241-space-related-to-algorithms","title":"2.4.1 \u00a0 Space Related to Algorithms","text":"

The memory space used by an algorithm during its execution mainly includes the following types.

  • Input Space: Used to store the input data of the algorithm.
  • Temporary Space: Used to store variables, objects, function contexts, and other data during the algorithm's execution.
  • Output Space: Used to store the output data of the algorithm.

Generally, the scope of space complexity statistics includes both \"Temporary Space\" and \"Output Space\".

Temporary space can be further divided into three parts.

  • Temporary Data: Used to save various constants, variables, objects, etc., during the algorithm's execution.
  • Stack Frame Space: Used to save the context data of the called function. The system creates a stack frame at the top of the stack each time a function is called, and the stack frame space is released after the function returns.
  • Instruction Space: Used to store compiled program instructions, which are usually negligible in actual statistics.

When analyzing the space complexity of a program, we typically count the Temporary Data, Stack Frame Space, and Output Data, as shown in the Figure 2-15 .

Figure 2-15 \u00a0 Space Types Used in Algorithms

The relevant code is as follows:

PythonC++JavaC#GoSwiftJSTSDartRustCZig
class Node:\n    \"\"\"Classes\"\"\"\"\n    def __init__(self, x: int):\n        self.val: int = x               # node value\n        self.next: Node | None = None   # reference to the next node\n\ndef function() -> int:\n    \"\"\"\"Functions\"\"\"\"\"\n    # Perform certain operations...\n    return 0\n\ndef algorithm(n) -> int:    # input data\n    A = 0                   # temporary data (constant, usually in uppercase)\n    b = 0                   # temporary data (variable)\n    node = Node(0)          # temporary data (object)\n    c = function()          # Stack frame space (call function)\n    return A + b + c        # output data\n
/* Structures */\nstruct Node {\n    int val;\n    Node *next;\n    Node(int x) : val(x), next(nullptr) {}\n};\n\n/* Functions */\nint func() {\n    // Perform certain operations...\n    return 0;\n}\n\nint algorithm(int n) {          // input data\n    const int a = 0;            // temporary data (constant)\n    int b = 0;                  // temporary data (variable)\n    Node* node = new Node(0);   // temporary data (object)\n    int c = func();             // stack frame space (call function)\n    return a + b + c;           // output data\n}\n
/* Classes */\nclass Node {\n    int val;\n    Node next;\n    Node(int x) { val = x; }\n}\n\n/* Functions */\nint function() {\n    // Perform certain operations...\n    return 0;\n}\n\nint algorithm(int n) {          // input data\n    final int a = 0;            // temporary data (constant)\n    int b = 0;                  // temporary data (variable)\n    Node node = new Node(0);    // temporary data (object)\n    int c = function();         // stack frame space (call function)\n    return a + b + c;           // output data\n}\n
/* Classes */\nclass Node {\n    int val;\n    Node next;\n    Node(int x) { val = x; }\n}\n\n/* Functions */\nint Function() {\n    // Perform certain operations...\n    return 0;\n}\n\nint Algorithm(int n) {  // input data\n    const int a = 0;    // temporary data (constant)\n    int b = 0;          // temporary data (variable)\n    Node node = new(0); // temporary data (object)\n    int c = Function(); // stack frame space (call function)\n    return a + b + c;   // output data\n}\n
/* Structures */\ntype node struct {\n    val  int\n    next *node\n}\n\n/* Create node structure */\nfunc newNode(val int) *node {\n    return &node{val: val}\n}\n\n/* Functions */\nfunc function() int {\n    // Perform certain operations...\n    return 0\n}\n\nfunc algorithm(n int) int { // input data\n    const a = 0             // temporary data (constant)\n    b := 0                  // temporary storage of data (variable)\n    newNode(0)              // temporary data (object)\n    c := function()         // stack frame space (call function)\n    return a + b + c        // output data\n}\n
/* Classes */\nclass Node {\n    var val: Int\n    var next: Node?\n\n    init(x: Int) {\n        val = x\n    }\n}\n\n/* Functions */\nfunc function() -> Int {\n    // Perform certain operations...\n    return 0\n}\n\nfunc algorithm(n: Int) -> Int { // input data\n    let a = 0                   // temporary data (constant)\n    var b = 0                   // temporary data (variable)\n    let node = Node(x: 0)       // temporary data (object)\n    let c = function()          // stack frame space (call function)\n    return a + b + c            // output data\n}\n
/* Classes */\nclass Node {\n    val;\n    next;\n    constructor(val) {\n        this.val = val === undefined ? 0 : val; // node value\n        this.next = null;                       // reference to the next node\n    }\n}\n\n/* Functions */\nfunction constFunc() {\n    // Perform certain operations\n    return 0;\n}\n\nfunction algorithm(n) {         // input data\n    const a = 0;                // temporary data (constant)\n    let b = 0;                  // temporary data (variable)\n    const node = new Node(0);   // temporary data (object)\n    const c = constFunc();      // Stack frame space (calling function)\n    return a + b + c;           // output data\n}\n
/* Classes */\nclass Node {\n    val: number;\n    next: Node | null;\n    constructor(val?: number) {\n        this.val = val === undefined ? 0 : val; // node value\n        this.next = null;                       // reference to the next node\n    }\n}\n\n/* Functions */\nfunction constFunc(): number {\n    // Perform certain operations\n    return 0;\n}\n\nfunction algorithm(n: number): number { // input data\n    const a = 0;                        // temporary data (constant)\n    let b = 0;                          // temporary data (variable)\n    const node = new Node(0);           // temporary data (object)\n    const c = constFunc();              // Stack frame space (calling function)\n    return a + b + c;                   // output data\n}\n
/* Classes */\nclass Node {\n  int val;\n  Node next;\n  Node(this.val, [this.next]);\n}\n\n/* Functions */\nint function() {\n  // Perform certain operations...\n  return 0;\n}\n\nint algorithm(int n) {  // input data\n  const int a = 0;      // temporary data (constant)\n  int b = 0;            // temporary data (variable)\n  Node node = Node(0);  // temporary data (object)\n  int c = function();   // stack frame space (call function)\n  return a + b + c;     // output data\n}\n
use std::rc::Rc;\nuse std::cell::RefCell;\n\n/* Structures */\nstruct Node {\n    val: i32,\n    next: Option<Rc<RefCell<Node>>>,\n}\n\n/* Creating a Node structure */\nimpl Node {\n    fn new(val: i32) -> Self {\n        Self { val: val, next: None }\n    }\n}\n\n/* Functions */\nfn function() -> i32 {     \n    // Perform certain operations...\n    return 0;\n}\n\nfn algorithm(n: i32) -> i32 {   // input data\n    const a: i32 = 0;           // temporary data (constant)\n    let mut b = 0;              // temporary data (variable)\n    let node = Node::new(0);    // temporary data (object)\n    let c = function();         // stack frame space (call function)\n    return a + b + c;           // output data\n}\n
/* Functions */\nint func() {\n    // Perform certain operations...\n    return 0;\n}\n\nint algorithm(int n) {  // input data\n    const int a = 0;    // temporary data (constant)\n    int b = 0;          // temporary data (variable)\n    int c = func();     // stack frame space (call function)\n    return a + b + c;   // output data\n}\n
\n
"},{"location":"chapter_computational_complexity/space_complexity/#242-calculation-method","title":"2.4.2 \u00a0 Calculation Method","text":"

The method for calculating space complexity is roughly similar to that of time complexity, with the only change being the shift of the statistical object from \"number of operations\" to \"size of used space\".

However, unlike time complexity, we usually only focus on the worst-case space complexity. This is because memory space is a hard requirement, and we must ensure that there is enough memory space reserved under all input data.

Consider the following code, the term \"worst-case\" in worst-case space complexity has two meanings.

  1. Based on the worst input data: When \\(n < 10\\), the space complexity is \\(O(1)\\); but when \\(n > 10\\), the initialized array nums occupies \\(O(n)\\) space, thus the worst-case space complexity is \\(O(n)\\).
  2. Based on the peak memory used during the algorithm's execution: For example, before executing the last line, the program occupies \\(O(1)\\) space; when initializing the array nums, the program occupies \\(O(n)\\) space, hence the worst-case space complexity is \\(O(n)\\).
PythonC++JavaC#GoSwiftJSTSDartRustCZig
def algorithm(n: int):\n    a = 0               # O(1)\n    b = [0] * 10000     # O(1)\n    if n > 10:\n        nums = [0] * n  # O(n)\n
void algorithm(int n) {\n    int a = 0;               // O(1)\n    vector<int> b(10000);    // O(1)\n    if (n > 10)\n        vector<int> nums(n); // O(n)\n}\n
void algorithm(int n) {\n    int a = 0;                   // O(1)\n    int[] b = new int[10000];    // O(1)\n    if (n > 10)\n        int[] nums = new int[n]; // O(n)\n}\n
void Algorithm(int n) {\n    int a = 0;                   // O(1)\n    int[] b = new int[10000];    // O(1)\n    if (n > 10) {\n        int[] nums = new int[n]; // O(n)\n    }\n}\n
func algorithm(n int) {\n    a := 0                      // O(1)\n    b := make([]int, 10000)     // O(1)\n    var nums []int\n    if n > 10 {\n        nums := make([]int, n)  // O(n)\n    }\n    fmt.Println(a, b, nums)\n}\n
func algorithm(n: Int) {\n    let a = 0 // O(1)\n    let b = Array(repeating: 0, count: 10000) // O(1)\n    if n > 10 {\n        let nums = Array(repeating: 0, count: n) // O(n)\n    }\n}\n
function algorithm(n) {\n    const a = 0;                   // O(1)\n    const b = new Array(10000);    // O(1)\n    if (n > 10) {\n        const nums = new Array(n); // O(n)\n    }\n}\n
function algorithm(n: number): void {\n    const a = 0;                   // O(1)\n    const b = new Array(10000);    // O(1)\n    if (n > 10) {\n        const nums = new Array(n); // O(n)\n    }\n}\n
void algorithm(int n) {\n  int a = 0;                            // O(1)\n  List<int> b = List.filled(10000, 0);  // O(1)\n  if (n > 10) {\n    List<int> nums = List.filled(n, 0); // O(n)\n  }\n}\n
fn algorithm(n: i32) {\n    let a = 0;                              // O(1)\n    let b = [0; 10000];                     // O(1)\n    if n > 10 {\n        let nums = vec![0; n as usize];     // O(n)\n    }\n}\n
void algorithm(int n) {\n    int a = 0;               // O(1)\n    int b[10000];            // O(1)\n    if (n > 10)\n        int nums[n] = {0};   // O(n)\n}\n
\n

In recursive functions, stack frame space must be taken into count. Consider the following code:

PythonC++JavaC#GoSwiftJSTSDartRustCZig
def function() -> int:\n    # Perform certain operations\n    return 0\n\ndef loop(n: int):\n    \"\"\"Loop O(1)\"\"\"\"\"\n    for _ in range(n):\n        function()\n\ndef recur(n: int) -> int:\n    \"\"\"Recursion O(n)\"\"\"\"\"\n    if n == 1: return\n    return recur(n - 1)\n
int func() {\n    // Perform certain operations\n    return 0;\n}\n/* Cycle O(1) */\nvoid loop(int n) {\n    for (int i = 0; i < n; i++) {\n        func();\n    }\n}\n/* Recursion O(n) */\nvoid recur(int n) {\n    if (n == 1) return;\n    return recur(n - 1);\n}\n
int function() {\n    // Perform certain operations\n    return 0;\n}\n/* Cycle O(1) */\nvoid loop(int n) {\n    for (int i = 0; i < n; i++) {\n        function();\n    }\n}\n/* Recursion O(n) */\nvoid recur(int n) {\n    if (n == 1) return;\n    return recur(n - 1);\n}\n
int Function() {\n    // Perform certain operations\n    return 0;\n}\n/* Cycle O(1) */\nvoid Loop(int n) {\n    for (int i = 0; i < n; i++) {\n        Function();\n    }\n}\n/* Recursion O(n) */\nint Recur(int n) {\n    if (n == 1) return 1;\n    return Recur(n - 1);\n}\n
func function() int {\n    // Perform certain operations\n    return 0\n}\n\n/* Cycle O(1) */\nfunc loop(n int) {\n    for i := 0; i < n; i++ {\n        function()\n    }\n}\n\n/* Recursion O(n) */\nfunc recur(n int) {\n    if n == 1 {\n        return\n    }\n    recur(n - 1)\n}\n
@discardableResult\nfunc function() -> Int {\n    // Perform certain operations\n    return 0\n}\n\n/* Cycle O(1) */\nfunc loop(n: Int) {\n    for _ in 0 ..< n {\n        function()\n    }\n}\n\n/* Recursion O(n) */\nfunc recur(n: Int) {\n    if n == 1 {\n        return\n    }\n    recur(n: n - 1)\n}\n
function constFunc() {\n    // Perform certain operations\n    return 0;\n}\n/* Cycle O(1) */\nfunction loop(n) {\n    for (let i = 0; i < n; i++) {\n        constFunc();\n    }\n}\n/* Recursion O(n) */\nfunction recur(n) {\n    if (n === 1) return;\n    return recur(n - 1);\n}\n
function constFunc(): number {\n    // Perform certain operations\n    return 0;\n}\n/* Cycle O(1) */\nfunction loop(n: number): void {\n    for (let i = 0; i < n; i++) {\n        constFunc();\n    }\n}\n/* Recursion O(n) */\nfunction recur(n: number): void {\n    if (n === 1) return;\n    return recur(n - 1);\n}\n
int function() {\n  // Perform certain operations\n  return 0;\n}\n/* Cycle O(1) */\nvoid loop(int n) {\n  for (int i = 0; i < n; i++) {\n    function();\n  }\n}\n/* Recursion O(n) */\nvoid recur(int n) {\n  if (n == 1) return;\n  return recur(n - 1);\n}\n
fn function() -> i32 {\n    // Perform certain operations\n    return 0;\n}\n/* Cycle O(1) */\nfn loop(n: i32) {\n    for i in 0..n {\n        function();\n    }\n}\n/* Recursion O(n) */\nvoid recur(n: i32) {\n    if n == 1 {\n        return;\n    }\n    recur(n - 1);\n}\n
int func() {\n    // Perform certain operations\n    return 0;\n}\n/* Cycle O(1) */\nvoid loop(int n) {\n    for (int i = 0; i < n; i++) {\n        func();\n    }\n}\n/* Recursion O(n) */\nvoid recur(int n) {\n    if (n == 1) return;\n    return recur(n - 1);\n}\n
\n

The time complexity of both loop() and recur() functions is \\(O(n)\\), but their space complexities differ.

  • The loop() function calls function() \\(n\\) times in a loop, where each iteration's function() returns and releases its stack frame space, so the space complexity remains \\(O(1)\\).
  • The recursive function recur() will have \\(n\\) instances of unreturned recur() existing simultaneously during its execution, thus occupying \\(O(n)\\) stack frame space.
"},{"location":"chapter_computational_complexity/space_complexity/#243-common-types","title":"2.4.3 \u00a0 Common Types","text":"

Let the size of the input data be \\(n\\), the following chart displays common types of space complexities (arranged from low to high).

\\[ \\begin{aligned} O(1) < O(\\log n) < O(n) < O(n^2) < O(2^n) \\newline \\text{Constant Order} < \\text{Logarithmic Order} < \\text{Linear Order} < \\text{Quadratic Order} < \\text{Exponential Order} \\end{aligned} \\]

Figure 2-16 \u00a0 Common Types of Space Complexity

"},{"location":"chapter_computational_complexity/space_complexity/#1-constant-order-o1","title":"1. \u00a0 Constant Order \\(O(1)\\)","text":"

Constant order is common in constants, variables, objects that are independent of the size of input data \\(n\\).

Note that memory occupied by initializing variables or calling functions in a loop, which is released upon entering the next cycle, does not accumulate over space, thus the space complexity remains \\(O(1)\\):

PythonC++JavaC#GoSwiftJSTSDartRustCZig space_complexity.py
def function() -> int:\n    \"\"\"\u51fd\u6570\"\"\"\n    # \u6267\u884c\u67d0\u4e9b\u64cd\u4f5c\n    return 0\n\ndef constant(n: int):\n    \"\"\"\u5e38\u6570\u9636\"\"\"\n    # \u5e38\u91cf\u3001\u53d8\u91cf\u3001\u5bf9\u8c61\u5360\u7528 O(1) \u7a7a\u95f4\n    a = 0\n    nums = [0] * 10000\n    node = ListNode(0)\n    # \u5faa\u73af\u4e2d\u7684\u53d8\u91cf\u5360\u7528 O(1) \u7a7a\u95f4\n    for _ in range(n):\n        c = 0\n    # \u5faa\u73af\u4e2d\u7684\u51fd\u6570\u5360\u7528 O(1) \u7a7a\u95f4\n    for _ in range(n):\n        function()\n
space_complexity.cpp
/* \u51fd\u6570 */\nint func() {\n    // \u6267\u884c\u67d0\u4e9b\u64cd\u4f5c\n    return 0;\n}\n\n/* \u5e38\u6570\u9636 */\nvoid constant(int n) {\n    // \u5e38\u91cf\u3001\u53d8\u91cf\u3001\u5bf9\u8c61\u5360\u7528 O(1) \u7a7a\u95f4\n    const int a = 0;\n    int b = 0;\n    vector<int> nums(10000);\n    ListNode node(0);\n    // \u5faa\u73af\u4e2d\u7684\u53d8\u91cf\u5360\u7528 O(1) \u7a7a\u95f4\n    for (int i = 0; i < n; i++) {\n        int c = 0;\n    }\n    // \u5faa\u73af\u4e2d\u7684\u51fd\u6570\u5360\u7528 O(1) \u7a7a\u95f4\n    for (int i = 0; i < n; i++) {\n        func();\n    }\n}\n
space_complexity.java
/* \u51fd\u6570 */\nint function() {\n    // \u6267\u884c\u67d0\u4e9b\u64cd\u4f5c\n    return 0;\n}\n\n/* \u5e38\u6570\u9636 */\nvoid constant(int n) {\n    // \u5e38\u91cf\u3001\u53d8\u91cf\u3001\u5bf9\u8c61\u5360\u7528 O(1) \u7a7a\u95f4\n    final int a = 0;\n    int b = 0;\n    int[] nums = new int[10000];\n    ListNode node = new ListNode(0);\n    // \u5faa\u73af\u4e2d\u7684\u53d8\u91cf\u5360\u7528 O(1) \u7a7a\u95f4\n    for (int i = 0; i < n; i++) {\n        int c = 0;\n    }\n    // \u5faa\u73af\u4e2d\u7684\u51fd\u6570\u5360\u7528 O(1) \u7a7a\u95f4\n    for (int i = 0; i < n; i++) {\n        function();\n    }\n}\n
space_complexity.cs
/* \u51fd\u6570 */\nint Function() {\n    // \u6267\u884c\u67d0\u4e9b\u64cd\u4f5c\n    return 0;\n}\n\n/* \u5e38\u6570\u9636 */\nvoid Constant(int n) {\n    // \u5e38\u91cf\u3001\u53d8\u91cf\u3001\u5bf9\u8c61\u5360\u7528 O(1) \u7a7a\u95f4\n    int a = 0;\n    int b = 0;\n    int[] nums = new int[10000];\n    ListNode node = new(0);\n    // \u5faa\u73af\u4e2d\u7684\u53d8\u91cf\u5360\u7528 O(1) \u7a7a\u95f4\n    for (int i = 0; i < n; i++) {\n        int c = 0;\n    }\n    // \u5faa\u73af\u4e2d\u7684\u51fd\u6570\u5360\u7528 O(1) \u7a7a\u95f4\n    for (int i = 0; i < n; i++) {\n        Function();\n    }\n}\n
space_complexity.go
/* \u51fd\u6570 */\nfunc function() int {\n    // \u6267\u884c\u67d0\u4e9b\u64cd\u4f5c...\n    return 0\n}\n\n/* \u5e38\u6570\u9636 */\nfunc spaceConstant(n int) {\n    // \u5e38\u91cf\u3001\u53d8\u91cf\u3001\u5bf9\u8c61\u5360\u7528 O(1) \u7a7a\u95f4\n    const a = 0\n    b := 0\n    nums := make([]int, 10000)\n    node := newNode(0)\n    // \u5faa\u73af\u4e2d\u7684\u53d8\u91cf\u5360\u7528 O(1) \u7a7a\u95f4\n    var c int\n    for i := 0; i < n; i++ {\n        c = 0\n    }\n    // \u5faa\u73af\u4e2d\u7684\u51fd\u6570\u5360\u7528 O(1) \u7a7a\u95f4\n    for i := 0; i < n; i++ {\n        function()\n    }\n    b += 0\n    c += 0\n    nums[0] = 0\n    node.val = 0\n}\n
space_complexity.swift
/* \u51fd\u6570 */\n@discardableResult\nfunc function() -> Int {\n    // \u6267\u884c\u67d0\u4e9b\u64cd\u4f5c\n    return 0\n}\n\n/* \u5e38\u6570\u9636 */\nfunc constant(n: Int) {\n    // \u5e38\u91cf\u3001\u53d8\u91cf\u3001\u5bf9\u8c61\u5360\u7528 O(1) \u7a7a\u95f4\n    let a = 0\n    var b = 0\n    let nums = Array(repeating: 0, count: 10000)\n    let node = ListNode(x: 0)\n    // \u5faa\u73af\u4e2d\u7684\u53d8\u91cf\u5360\u7528 O(1) \u7a7a\u95f4\n    for _ in 0 ..< n {\n        let c = 0\n    }\n    // \u5faa\u73af\u4e2d\u7684\u51fd\u6570\u5360\u7528 O(1) \u7a7a\u95f4\n    for _ in 0 ..< n {\n        function()\n    }\n}\n
space_complexity.js
/* \u51fd\u6570 */\nfunction constFunc() {\n    // \u6267\u884c\u67d0\u4e9b\u64cd\u4f5c\n    return 0;\n}\n\n/* \u5e38\u6570\u9636 */\nfunction constant(n) {\n    // \u5e38\u91cf\u3001\u53d8\u91cf\u3001\u5bf9\u8c61\u5360\u7528 O(1) \u7a7a\u95f4\n    const a = 0;\n    const b = 0;\n    const nums = new Array(10000);\n    const node = new ListNode(0);\n    // \u5faa\u73af\u4e2d\u7684\u53d8\u91cf\u5360\u7528 O(1) \u7a7a\u95f4\n    for (let i = 0; i < n; i++) {\n        const c = 0;\n    }\n    // \u5faa\u73af\u4e2d\u7684\u51fd\u6570\u5360\u7528 O(1) \u7a7a\u95f4\n    for (let i = 0; i < n; i++) {\n        constFunc();\n    }\n}\n
space_complexity.ts
/* \u51fd\u6570 */\nfunction constFunc(): number {\n    // \u6267\u884c\u67d0\u4e9b\u64cd\u4f5c\n    return 0;\n}\n\n/* \u5e38\u6570\u9636 */\nfunction constant(n: number): void {\n    // \u5e38\u91cf\u3001\u53d8\u91cf\u3001\u5bf9\u8c61\u5360\u7528 O(1) \u7a7a\u95f4\n    const a = 0;\n    const b = 0;\n    const nums = new Array(10000);\n    const node = new ListNode(0);\n    // \u5faa\u73af\u4e2d\u7684\u53d8\u91cf\u5360\u7528 O(1) \u7a7a\u95f4\n    for (let i = 0; i < n; i++) {\n        const c = 0;\n    }\n    // \u5faa\u73af\u4e2d\u7684\u51fd\u6570\u5360\u7528 O(1) \u7a7a\u95f4\n    for (let i = 0; i < n; i++) {\n        constFunc();\n    }\n}\n
space_complexity.dart
/* \u51fd\u6570 */\nint function() {\n  // \u6267\u884c\u67d0\u4e9b\u64cd\u4f5c\n  return 0;\n}\n\n/* \u5e38\u6570\u9636 */\nvoid constant(int n) {\n  // \u5e38\u91cf\u3001\u53d8\u91cf\u3001\u5bf9\u8c61\u5360\u7528 O(1) \u7a7a\u95f4\n  final int a = 0;\n  int b = 0;\n  List<int> nums = List.filled(10000, 0);\n  ListNode node = ListNode(0);\n  // \u5faa\u73af\u4e2d\u7684\u53d8\u91cf\u5360\u7528 O(1) \u7a7a\u95f4\n  for (var i = 0; i < n; i++) {\n    int c = 0;\n  }\n  // \u5faa\u73af\u4e2d\u7684\u51fd\u6570\u5360\u7528 O(1) \u7a7a\u95f4\n  for (var i = 0; i < n; i++) {\n    function();\n  }\n}\n
space_complexity.rs
/* \u51fd\u6570 */\nfn function() -> i32 {\n    // \u6267\u884c\u67d0\u4e9b\u64cd\u4f5c\n    return 0;\n}\n\n/* \u5e38\u6570\u9636 */\n#[allow(unused)]\nfn constant(n: i32) {\n    // \u5e38\u91cf\u3001\u53d8\u91cf\u3001\u5bf9\u8c61\u5360\u7528 O(1) \u7a7a\u95f4\n    const A: i32 = 0;\n    let b = 0;\n    let nums = vec![0; 10000];\n    let node = ListNode::new(0);\n    // \u5faa\u73af\u4e2d\u7684\u53d8\u91cf\u5360\u7528 O(1) \u7a7a\u95f4\n    for i in 0..n {\n        let c = 0;\n    }\n    // \u5faa\u73af\u4e2d\u7684\u51fd\u6570\u5360\u7528 O(1) \u7a7a\u95f4\n    for i in 0..n {\n        function();\n    }\n}\n
space_complexity.c
/* \u51fd\u6570 */\nint func() {\n    // \u6267\u884c\u67d0\u4e9b\u64cd\u4f5c\n    return 0;\n}\n\n/* \u5e38\u6570\u9636 */\nvoid constant(int n) {\n    // \u5e38\u91cf\u3001\u53d8\u91cf\u3001\u5bf9\u8c61\u5360\u7528 O(1) \u7a7a\u95f4\n    const int a = 0;\n    int b = 0;\n    int nums[1000];\n    ListNode *node = newListNode(0);\n    free(node);\n    // \u5faa\u73af\u4e2d\u7684\u53d8\u91cf\u5360\u7528 O(1) \u7a7a\u95f4\n    for (int i = 0; i < n; i++) {\n        int c = 0;\n    }\n    // \u5faa\u73af\u4e2d\u7684\u51fd\u6570\u5360\u7528 O(1) \u7a7a\u95f4\n    for (int i = 0; i < n; i++) {\n        func();\n    }\n}\n
space_complexity.zig
// \u51fd\u6570\nfn function() i32 {\n    // \u6267\u884c\u67d0\u4e9b\u64cd\u4f5c\n    return 0;\n}\n\n// \u5e38\u6570\u9636\nfn constant(n: i32) void {\n    // \u5e38\u91cf\u3001\u53d8\u91cf\u3001\u5bf9\u8c61\u5360\u7528 O(1) \u7a7a\u95f4\n    const a: i32 = 0;\n    var b: i32 = 0;\n    var nums = [_]i32{0}**10000;\n    var node = inc.ListNode(i32){.val = 0};\n    var i: i32 = 0;\n    // \u5faa\u73af\u4e2d\u7684\u53d8\u91cf\u5360\u7528 O(1) \u7a7a\u95f4\n    while (i < n) : (i += 1) {\n        var c: i32 = 0;\n        _ = c;\n    }\n    // \u5faa\u73af\u4e2d\u7684\u51fd\u6570\u5360\u7528 O(1) \u7a7a\u95f4\n    i = 0;\n    while (i < n) : (i += 1) {\n        _ = function();\n    }\n    _ = a;\n    _ = b;\n    _ = nums;\n    _ = node;\n}\n
Code Visualization

Full Screen >

"},{"location":"chapter_computational_complexity/space_complexity/#2-linear-order-on","title":"2. \u00a0 Linear Order \\(O(n)\\)","text":"

Linear order is common in arrays, linked lists, stacks, queues, etc., where the number of elements is proportional to \\(n\\):

PythonC++JavaC#GoSwiftJSTSDartRustCZig space_complexity.py
def linear(n: int):\n    \"\"\"\u7ebf\u6027\u9636\"\"\"\n    # \u957f\u5ea6\u4e3a n \u7684\u5217\u8868\u5360\u7528 O(n) \u7a7a\u95f4\n    nums = [0] * n\n    # \u957f\u5ea6\u4e3a n \u7684\u54c8\u5e0c\u8868\u5360\u7528 O(n) \u7a7a\u95f4\n    hmap = dict[int, str]()\n    for i in range(n):\n        hmap[i] = str(i)\n
space_complexity.cpp
/* \u7ebf\u6027\u9636 */\nvoid linear(int n) {\n    // \u957f\u5ea6\u4e3a n \u7684\u6570\u7ec4\u5360\u7528 O(n) \u7a7a\u95f4\n    vector<int> nums(n);\n    // \u957f\u5ea6\u4e3a n \u7684\u5217\u8868\u5360\u7528 O(n) \u7a7a\u95f4\n    vector<ListNode> nodes;\n    for (int i = 0; i < n; i++) {\n        nodes.push_back(ListNode(i));\n    }\n    // \u957f\u5ea6\u4e3a n \u7684\u54c8\u5e0c\u8868\u5360\u7528 O(n) \u7a7a\u95f4\n    unordered_map<int, string> map;\n    for (int i = 0; i < n; i++) {\n        map[i] = to_string(i);\n    }\n}\n
space_complexity.java
/* \u7ebf\u6027\u9636 */\nvoid linear(int n) {\n    // \u957f\u5ea6\u4e3a n \u7684\u6570\u7ec4\u5360\u7528 O(n) \u7a7a\u95f4\n    int[] nums = new int[n];\n    // \u957f\u5ea6\u4e3a n \u7684\u5217\u8868\u5360\u7528 O(n) \u7a7a\u95f4\n    List<ListNode> nodes = new ArrayList<>();\n    for (int i = 0; i < n; i++) {\n        nodes.add(new ListNode(i));\n    }\n    // \u957f\u5ea6\u4e3a n \u7684\u54c8\u5e0c\u8868\u5360\u7528 O(n) \u7a7a\u95f4\n    Map<Integer, String> map = new HashMap<>();\n    for (int i = 0; i < n; i++) {\n        map.put(i, String.valueOf(i));\n    }\n}\n
space_complexity.cs
/* \u7ebf\u6027\u9636 */\nvoid Linear(int n) {\n    // \u957f\u5ea6\u4e3a n \u7684\u6570\u7ec4\u5360\u7528 O(n) \u7a7a\u95f4\n    int[] nums = new int[n];\n    // \u957f\u5ea6\u4e3a n \u7684\u5217\u8868\u5360\u7528 O(n) \u7a7a\u95f4\n    List<ListNode> nodes = [];\n    for (int i = 0; i < n; i++) {\n        nodes.Add(new ListNode(i));\n    }\n    // \u957f\u5ea6\u4e3a n \u7684\u54c8\u5e0c\u8868\u5360\u7528 O(n) \u7a7a\u95f4\n    Dictionary<int, string> map = [];\n    for (int i = 0; i < n; i++) {\n        map.Add(i, i.ToString());\n    }\n}\n
space_complexity.go
/* \u7ebf\u6027\u9636 */\nfunc spaceLinear(n int) {\n    // \u957f\u5ea6\u4e3a n \u7684\u6570\u7ec4\u5360\u7528 O(n) \u7a7a\u95f4\n    _ = make([]int, n)\n    // \u957f\u5ea6\u4e3a n \u7684\u5217\u8868\u5360\u7528 O(n) \u7a7a\u95f4\n    var nodes []*node\n    for i := 0; i < n; i++ {\n        nodes = append(nodes, newNode(i))\n    }\n    // \u957f\u5ea6\u4e3a n \u7684\u54c8\u5e0c\u8868\u5360\u7528 O(n) \u7a7a\u95f4\n    m := make(map[int]string, n)\n    for i := 0; i < n; i++ {\n        m[i] = strconv.Itoa(i)\n    }\n}\n
space_complexity.swift
/* \u7ebf\u6027\u9636 */\nfunc linear(n: Int) {\n    // \u957f\u5ea6\u4e3a n \u7684\u6570\u7ec4\u5360\u7528 O(n) \u7a7a\u95f4\n    let nums = Array(repeating: 0, count: n)\n    // \u957f\u5ea6\u4e3a n \u7684\u5217\u8868\u5360\u7528 O(n) \u7a7a\u95f4\n    let nodes = (0 ..< n).map { ListNode(x: $0) }\n    // \u957f\u5ea6\u4e3a n \u7684\u54c8\u5e0c\u8868\u5360\u7528 O(n) \u7a7a\u95f4\n    let map = Dictionary(uniqueKeysWithValues: (0 ..< n).map { ($0, \"\\($0)\") })\n}\n
space_complexity.js
/* \u7ebf\u6027\u9636 */\nfunction linear(n) {\n    // \u957f\u5ea6\u4e3a n \u7684\u6570\u7ec4\u5360\u7528 O(n) \u7a7a\u95f4\n    const nums = new Array(n);\n    // \u957f\u5ea6\u4e3a n \u7684\u5217\u8868\u5360\u7528 O(n) \u7a7a\u95f4\n    const nodes = [];\n    for (let i = 0; i < n; i++) {\n        nodes.push(new ListNode(i));\n    }\n    // \u957f\u5ea6\u4e3a n \u7684\u54c8\u5e0c\u8868\u5360\u7528 O(n) \u7a7a\u95f4\n    const map = new Map();\n    for (let i = 0; i < n; i++) {\n        map.set(i, i.toString());\n    }\n}\n
space_complexity.ts
/* \u7ebf\u6027\u9636 */\nfunction linear(n: number): void {\n    // \u957f\u5ea6\u4e3a n \u7684\u6570\u7ec4\u5360\u7528 O(n) \u7a7a\u95f4\n    const nums = new Array(n);\n    // \u957f\u5ea6\u4e3a n \u7684\u5217\u8868\u5360\u7528 O(n) \u7a7a\u95f4\n    const nodes: ListNode[] = [];\n    for (let i = 0; i < n; i++) {\n        nodes.push(new ListNode(i));\n    }\n    // \u957f\u5ea6\u4e3a n \u7684\u54c8\u5e0c\u8868\u5360\u7528 O(n) \u7a7a\u95f4\n    const map = new Map();\n    for (let i = 0; i < n; i++) {\n        map.set(i, i.toString());\n    }\n}\n
space_complexity.dart
/* \u7ebf\u6027\u9636 */\nvoid linear(int n) {\n  // \u957f\u5ea6\u4e3a n \u7684\u6570\u7ec4\u5360\u7528 O(n) \u7a7a\u95f4\n  List<int> nums = List.filled(n, 0);\n  // \u957f\u5ea6\u4e3a n \u7684\u5217\u8868\u5360\u7528 O(n) \u7a7a\u95f4\n  List<ListNode> nodes = [];\n  for (var i = 0; i < n; i++) {\n    nodes.add(ListNode(i));\n  }\n  // \u957f\u5ea6\u4e3a n \u7684\u54c8\u5e0c\u8868\u5360\u7528 O(n) \u7a7a\u95f4\n  Map<int, String> map = HashMap();\n  for (var i = 0; i < n; i++) {\n    map.putIfAbsent(i, () => i.toString());\n  }\n}\n
space_complexity.rs
/* \u7ebf\u6027\u9636 */\n#[allow(unused)]\nfn linear(n: i32) {\n    // \u957f\u5ea6\u4e3a n \u7684\u6570\u7ec4\u5360\u7528 O(n) \u7a7a\u95f4\n    let mut nums = vec![0; n as usize];\n    // \u957f\u5ea6\u4e3a n \u7684\u5217\u8868\u5360\u7528 O(n) \u7a7a\u95f4\n    let mut nodes = Vec::new();\n    for i in 0..n {\n        nodes.push(ListNode::new(i))\n    }\n    // \u957f\u5ea6\u4e3a n \u7684\u54c8\u5e0c\u8868\u5360\u7528 O(n) \u7a7a\u95f4\n    let mut map = HashMap::new();\n    for i in 0..n {\n        map.insert(i, i.to_string());\n    }\n}\n
space_complexity.c
/* \u54c8\u5e0c\u8868 */\ntypedef struct {\n    int key;\n    int val;\n    UT_hash_handle hh; // \u57fa\u4e8e uthash.h \u5b9e\u73b0\n} HashTable;\n\n/* \u7ebf\u6027\u9636 */\nvoid linear(int n) {\n    // \u957f\u5ea6\u4e3a n \u7684\u6570\u7ec4\u5360\u7528 O(n) \u7a7a\u95f4\n    int *nums = malloc(sizeof(int) * n);\n    free(nums);\n\n    // \u957f\u5ea6\u4e3a n \u7684\u5217\u8868\u5360\u7528 O(n) \u7a7a\u95f4\n    ListNode **nodes = malloc(sizeof(ListNode *) * n);\n    for (int i = 0; i < n; i++) {\n        nodes[i] = newListNode(i);\n    }\n    // \u5185\u5b58\u91ca\u653e\n    for (int i = 0; i < n; i++) {\n        free(nodes[i]);\n    }\n    free(nodes);\n\n    // \u957f\u5ea6\u4e3a n \u7684\u54c8\u5e0c\u8868\u5360\u7528 O(n) \u7a7a\u95f4\n    HashTable *h = NULL;\n    for (int i = 0; i < n; i++) {\n        HashTable *tmp = malloc(sizeof(HashTable));\n        tmp->key = i;\n        tmp->val = i;\n        HASH_ADD_INT(h, key, tmp);\n    }\n\n    // \u5185\u5b58\u91ca\u653e\n    HashTable *curr, *tmp;\n    HASH_ITER(hh, h, curr, tmp) {\n        HASH_DEL(h, curr);\n        free(curr);\n    }\n}\n
space_complexity.zig
// \u7ebf\u6027\u9636\nfn linear(comptime n: i32) !void {\n    // \u957f\u5ea6\u4e3a n \u7684\u6570\u7ec4\u5360\u7528 O(n) \u7a7a\u95f4\n    var nums = [_]i32{0}**n;\n    // \u957f\u5ea6\u4e3a n \u7684\u5217\u8868\u5360\u7528 O(n) \u7a7a\u95f4\n    var nodes = std.ArrayList(i32).init(std.heap.page_allocator);\n    defer nodes.deinit();\n    var i: i32 = 0;\n    while (i < n) : (i += 1) {\n        try nodes.append(i);\n    }\n    // \u957f\u5ea6\u4e3a n \u7684\u54c8\u5e0c\u8868\u5360\u7528 O(n) \u7a7a\u95f4\n    var map = std.AutoArrayHashMap(i32, []const u8).init(std.heap.page_allocator);\n    defer map.deinit();\n    var j: i32 = 0;\n    while (j < n) : (j += 1) {\n        const string = try std.fmt.allocPrint(std.heap.page_allocator, \"{d}\", .{j});\n        defer std.heap.page_allocator.free(string);\n        try map.put(i, string);\n    }\n    _ = nums;\n}\n
Code Visualization

Full Screen >

As shown below, this function's recursive depth is \\(n\\), meaning there are \\(n\\) instances of unreturned linear_recur() function, using \\(O(n)\\) size of stack frame space:

PythonC++JavaC#GoSwiftJSTSDartRustCZig space_complexity.py
def linear_recur(n: int):\n    \"\"\"\u7ebf\u6027\u9636\uff08\u9012\u5f52\u5b9e\u73b0\uff09\"\"\"\n    print(\"\u9012\u5f52 n =\", n)\n    if n == 1:\n        return\n    linear_recur(n - 1)\n
space_complexity.cpp
/* \u7ebf\u6027\u9636\uff08\u9012\u5f52\u5b9e\u73b0\uff09 */\nvoid linearRecur(int n) {\n    cout << \"\u9012\u5f52 n = \" << n << endl;\n    if (n == 1)\n        return;\n    linearRecur(n - 1);\n}\n
space_complexity.java
/* \u7ebf\u6027\u9636\uff08\u9012\u5f52\u5b9e\u73b0\uff09 */\nvoid linearRecur(int n) {\n    System.out.println(\"\u9012\u5f52 n = \" + n);\n    if (n == 1)\n        return;\n    linearRecur(n - 1);\n}\n
space_complexity.cs
/* \u7ebf\u6027\u9636\uff08\u9012\u5f52\u5b9e\u73b0\uff09 */\nvoid LinearRecur(int n) {\n    Console.WriteLine(\"\u9012\u5f52 n = \" + n);\n    if (n == 1) return;\n    LinearRecur(n - 1);\n}\n
space_complexity.go
/* \u7ebf\u6027\u9636\uff08\u9012\u5f52\u5b9e\u73b0\uff09 */\nfunc spaceLinearRecur(n int) {\n    fmt.Println(\"\u9012\u5f52 n =\", n)\n    if n == 1 {\n        return\n    }\n    spaceLinearRecur(n - 1)\n}\n
space_complexity.swift
/* \u7ebf\u6027\u9636\uff08\u9012\u5f52\u5b9e\u73b0\uff09 */\nfunc linearRecur(n: Int) {\n    print(\"\u9012\u5f52 n = \\(n)\")\n    if n == 1 {\n        return\n    }\n    linearRecur(n: n - 1)\n}\n
space_complexity.js
/* \u7ebf\u6027\u9636\uff08\u9012\u5f52\u5b9e\u73b0\uff09 */\nfunction linearRecur(n) {\n    console.log(`\u9012\u5f52 n = ${n}`);\n    if (n === 1) return;\n    linearRecur(n - 1);\n}\n
space_complexity.ts
/* \u7ebf\u6027\u9636\uff08\u9012\u5f52\u5b9e\u73b0\uff09 */\nfunction linearRecur(n: number): void {\n    console.log(`\u9012\u5f52 n = ${n}`);\n    if (n === 1) return;\n    linearRecur(n - 1);\n}\n
space_complexity.dart
/* \u7ebf\u6027\u9636\uff08\u9012\u5f52\u5b9e\u73b0\uff09 */\nvoid linearRecur(int n) {\n  print('\u9012\u5f52 n = $n');\n  if (n == 1) return;\n  linearRecur(n - 1);\n}\n
space_complexity.rs
/* \u7ebf\u6027\u9636\uff08\u9012\u5f52\u5b9e\u73b0\uff09 */\nfn linear_recur(n: i32) {\n    println!(\"\u9012\u5f52 n = {}\", n);\n    if n == 1 {\n        return;\n    };\n    linear_recur(n - 1);\n}\n
space_complexity.c
/* \u7ebf\u6027\u9636\uff08\u9012\u5f52\u5b9e\u73b0\uff09 */\nvoid linearRecur(int n) {\n    printf(\"\u9012\u5f52 n = %d\\r\\n\", n);\n    if (n == 1)\n        return;\n    linearRecur(n - 1);\n}\n
space_complexity.zig
// \u7ebf\u6027\u9636\uff08\u9012\u5f52\u5b9e\u73b0\uff09\nfn linearRecur(comptime n: i32) void {\n    std.debug.print(\"\u9012\u5f52 n = {}\\n\", .{n});\n    if (n == 1) return;\n    linearRecur(n - 1);\n}\n
Code Visualization

Full Screen >

Figure 2-17 \u00a0 Recursive Function Generating Linear Order Space Complexity

"},{"location":"chapter_computational_complexity/space_complexity/#3-quadratic-order-on2","title":"3. \u00a0 Quadratic Order \\(O(n^2)\\)","text":"

Quadratic order is common in matrices and graphs, where the number of elements is quadratic to \\(n\\):

PythonC++JavaC#GoSwiftJSTSDartRustCZig space_complexity.py
def quadratic(n: int):\n    \"\"\"\u5e73\u65b9\u9636\"\"\"\n    # \u4e8c\u7ef4\u5217\u8868\u5360\u7528 O(n^2) \u7a7a\u95f4\n    num_matrix = [[0] * n for _ in range(n)]\n
space_complexity.cpp
/* \u5e73\u65b9\u9636 */\nvoid quadratic(int n) {\n    // \u4e8c\u7ef4\u5217\u8868\u5360\u7528 O(n^2) \u7a7a\u95f4\n    vector<vector<int>> numMatrix;\n    for (int i = 0; i < n; i++) {\n        vector<int> tmp;\n        for (int j = 0; j < n; j++) {\n            tmp.push_back(0);\n        }\n        numMatrix.push_back(tmp);\n    }\n}\n
space_complexity.java
/* \u5e73\u65b9\u9636 */\nvoid quadratic(int n) {\n    // \u77e9\u9635\u5360\u7528 O(n^2) \u7a7a\u95f4\n    int[][] numMatrix = new int[n][n];\n    // \u4e8c\u7ef4\u5217\u8868\u5360\u7528 O(n^2) \u7a7a\u95f4\n    List<List<Integer>> numList = new ArrayList<>();\n    for (int i = 0; i < n; i++) {\n        List<Integer> tmp = new ArrayList<>();\n        for (int j = 0; j < n; j++) {\n            tmp.add(0);\n        }\n        numList.add(tmp);\n    }\n}\n
space_complexity.cs
/* \u5e73\u65b9\u9636 */\nvoid Quadratic(int n) {\n    // \u77e9\u9635\u5360\u7528 O(n^2) \u7a7a\u95f4\n    int[,] numMatrix = new int[n, n];\n    // \u4e8c\u7ef4\u5217\u8868\u5360\u7528 O(n^2) \u7a7a\u95f4\n    List<List<int>> numList = [];\n    for (int i = 0; i < n; i++) {\n        List<int> tmp = [];\n        for (int j = 0; j < n; j++) {\n            tmp.Add(0);\n        }\n        numList.Add(tmp);\n    }\n}\n
space_complexity.go
/* \u5e73\u65b9\u9636 */\nfunc spaceQuadratic(n int) {\n    // \u77e9\u9635\u5360\u7528 O(n^2) \u7a7a\u95f4\n    numMatrix := make([][]int, n)\n    for i := 0; i < n; i++ {\n        numMatrix[i] = make([]int, n)\n    }\n}\n
space_complexity.swift
/* \u5e73\u65b9\u9636 */\nfunc quadratic(n: Int) {\n    // \u4e8c\u7ef4\u5217\u8868\u5360\u7528 O(n^2) \u7a7a\u95f4\n    let numList = Array(repeating: Array(repeating: 0, count: n), count: n)\n}\n
space_complexity.js
/* \u5e73\u65b9\u9636 */\nfunction quadratic(n) {\n    // \u77e9\u9635\u5360\u7528 O(n^2) \u7a7a\u95f4\n    const numMatrix = Array(n)\n        .fill(null)\n        .map(() => Array(n).fill(null));\n    // \u4e8c\u7ef4\u5217\u8868\u5360\u7528 O(n^2) \u7a7a\u95f4\n    const numList = [];\n    for (let i = 0; i < n; i++) {\n        const tmp = [];\n        for (let j = 0; j < n; j++) {\n            tmp.push(0);\n        }\n        numList.push(tmp);\n    }\n}\n
space_complexity.ts
/* \u5e73\u65b9\u9636 */\nfunction quadratic(n: number): void {\n    // \u77e9\u9635\u5360\u7528 O(n^2) \u7a7a\u95f4\n    const numMatrix = Array(n)\n        .fill(null)\n        .map(() => Array(n).fill(null));\n    // \u4e8c\u7ef4\u5217\u8868\u5360\u7528 O(n^2) \u7a7a\u95f4\n    const numList = [];\n    for (let i = 0; i < n; i++) {\n        const tmp = [];\n        for (let j = 0; j < n; j++) {\n            tmp.push(0);\n        }\n        numList.push(tmp);\n    }\n}\n
space_complexity.dart
/* \u5e73\u65b9\u9636 */\nvoid quadratic(int n) {\n  // \u77e9\u9635\u5360\u7528 O(n^2) \u7a7a\u95f4\n  List<List<int>> numMatrix = List.generate(n, (_) => List.filled(n, 0));\n  // \u4e8c\u7ef4\u5217\u8868\u5360\u7528 O(n^2) \u7a7a\u95f4\n  List<List<int>> numList = [];\n  for (var i = 0; i < n; i++) {\n    List<int> tmp = [];\n    for (int j = 0; j < n; j++) {\n      tmp.add(0);\n    }\n    numList.add(tmp);\n  }\n}\n
space_complexity.rs
/* \u5e73\u65b9\u9636 */\n#[allow(unused)]\nfn quadratic(n: i32) {\n    // \u77e9\u9635\u5360\u7528 O(n^2) \u7a7a\u95f4\n    let num_matrix = vec![vec![0; n as usize]; n as usize];\n    // \u4e8c\u7ef4\u5217\u8868\u5360\u7528 O(n^2) \u7a7a\u95f4\n    let mut num_list = Vec::new();\n    for i in 0..n {\n        let mut tmp = Vec::new();\n        for j in 0..n {\n            tmp.push(0);\n        }\n        num_list.push(tmp);\n    }\n}\n
space_complexity.c
/* \u5e73\u65b9\u9636 */\nvoid quadratic(int n) {\n    // \u4e8c\u7ef4\u5217\u8868\u5360\u7528 O(n^2) \u7a7a\u95f4\n    int **numMatrix = malloc(sizeof(int *) * n);\n    for (int i = 0; i < n; i++) {\n        int *tmp = malloc(sizeof(int) * n);\n        for (int j = 0; j < n; j++) {\n            tmp[j] = 0;\n        }\n        numMatrix[i] = tmp;\n    }\n\n    // \u5185\u5b58\u91ca\u653e\n    for (int i = 0; i < n; i++) {\n        free(numMatrix[i]);\n    }\n    free(numMatrix);\n}\n
space_complexity.zig
// \u5e73\u65b9\u9636\nfn quadratic(n: i32) !void {\n    // \u4e8c\u7ef4\u5217\u8868\u5360\u7528 O(n^2) \u7a7a\u95f4\n    var nodes = std.ArrayList(std.ArrayList(i32)).init(std.heap.page_allocator);\n    defer nodes.deinit();\n    var i: i32 = 0;\n    while (i < n) : (i += 1) {\n        var tmp = std.ArrayList(i32).init(std.heap.page_allocator);\n        defer tmp.deinit();\n        var j: i32 = 0;\n        while (j < n) : (j += 1) {\n            try tmp.append(0);\n        }\n        try nodes.append(tmp);\n    }\n}\n
Code Visualization

Full Screen >

As shown below, the recursive depth of this function is \\(n\\), and in each recursive call, an array is initialized with lengths \\(n\\), \\(n-1\\), \\(\\dots\\), \\(2\\), \\(1\\), averaging \\(n/2\\), thus overall occupying \\(O(n^2)\\) space:

PythonC++JavaC#GoSwiftJSTSDartRustCZig space_complexity.py
def quadratic_recur(n: int) -> int:\n    \"\"\"\u5e73\u65b9\u9636\uff08\u9012\u5f52\u5b9e\u73b0\uff09\"\"\"\n    if n <= 0:\n        return 0\n    # \u6570\u7ec4 nums \u957f\u5ea6\u4e3a n, n-1, ..., 2, 1\n    nums = [0] * n\n    return quadratic_recur(n - 1)\n
space_complexity.cpp
/* \u5e73\u65b9\u9636\uff08\u9012\u5f52\u5b9e\u73b0\uff09 */\nint quadraticRecur(int n) {\n    if (n <= 0)\n        return 0;\n    vector<int> nums(n);\n    cout << \"\u9012\u5f52 n = \" << n << \" \u4e2d\u7684 nums \u957f\u5ea6 = \" << nums.size() << endl;\n    return quadraticRecur(n - 1);\n}\n
space_complexity.java
/* \u5e73\u65b9\u9636\uff08\u9012\u5f52\u5b9e\u73b0\uff09 */\nint quadraticRecur(int n) {\n    if (n <= 0)\n        return 0;\n    // \u6570\u7ec4 nums \u957f\u5ea6\u4e3a n, n-1, ..., 2, 1\n    int[] nums = new int[n];\n    System.out.println(\"\u9012\u5f52 n = \" + n + \" \u4e2d\u7684 nums \u957f\u5ea6 = \" + nums.length);\n    return quadraticRecur(n - 1);\n}\n
space_complexity.cs
/* \u5e73\u65b9\u9636\uff08\u9012\u5f52\u5b9e\u73b0\uff09 */\nint QuadraticRecur(int n) {\n    if (n <= 0) return 0;\n    int[] nums = new int[n];\n    Console.WriteLine(\"\u9012\u5f52 n = \" + n + \" \u4e2d\u7684 nums \u957f\u5ea6 = \" + nums.Length);\n    return QuadraticRecur(n - 1);\n}\n
space_complexity.go
/* \u5e73\u65b9\u9636\uff08\u9012\u5f52\u5b9e\u73b0\uff09 */\nfunc spaceQuadraticRecur(n int) int {\n    if n <= 0 {\n        return 0\n    }\n    nums := make([]int, n)\n    fmt.Printf(\"\u9012\u5f52 n = %d \u4e2d\u7684 nums \u957f\u5ea6 = %d \\n\", n, len(nums))\n    return spaceQuadraticRecur(n - 1)\n}\n
space_complexity.swift
/* \u5e73\u65b9\u9636\uff08\u9012\u5f52\u5b9e\u73b0\uff09 */\n@discardableResult\nfunc quadraticRecur(n: Int) -> Int {\n    if n <= 0 {\n        return 0\n    }\n    // \u6570\u7ec4 nums \u957f\u5ea6\u4e3a n, n-1, ..., 2, 1\n    let nums = Array(repeating: 0, count: n)\n    print(\"\u9012\u5f52 n = \\(n) \u4e2d\u7684 nums \u957f\u5ea6 = \\(nums.count)\")\n    return quadraticRecur(n: n - 1)\n}\n
space_complexity.js
/* \u5e73\u65b9\u9636\uff08\u9012\u5f52\u5b9e\u73b0\uff09 */\nfunction quadraticRecur(n) {\n    if (n <= 0) return 0;\n    const nums = new Array(n);\n    console.log(`\u9012\u5f52 n = ${n} \u4e2d\u7684 nums \u957f\u5ea6 = ${nums.length}`);\n    return quadraticRecur(n - 1);\n}\n
space_complexity.ts
/* \u5e73\u65b9\u9636\uff08\u9012\u5f52\u5b9e\u73b0\uff09 */\nfunction quadraticRecur(n: number): number {\n    if (n <= 0) return 0;\n    const nums = new Array(n);\n    console.log(`\u9012\u5f52 n = ${n} \u4e2d\u7684 nums \u957f\u5ea6 = ${nums.length}`);\n    return quadraticRecur(n - 1);\n}\n
space_complexity.dart
/* \u5e73\u65b9\u9636\uff08\u9012\u5f52\u5b9e\u73b0\uff09 */\nint quadraticRecur(int n) {\n  if (n <= 0) return 0;\n  List<int> nums = List.filled(n, 0);\n  print('\u9012\u5f52 n = $n \u4e2d\u7684 nums \u957f\u5ea6 = ${nums.length}');\n  return quadraticRecur(n - 1);\n}\n
space_complexity.rs
/* \u5e73\u65b9\u9636\uff08\u9012\u5f52\u5b9e\u73b0\uff09 */\nfn quadratic_recur(n: i32) -> i32 {\n    if n <= 0 {\n        return 0;\n    };\n    // \u6570\u7ec4 nums \u957f\u5ea6\u4e3a n, n-1, ..., 2, 1\n    let nums = vec![0; n as usize];\n    println!(\"\u9012\u5f52 n = {} \u4e2d\u7684 nums \u957f\u5ea6 = {}\", n, nums.len());\n    return quadratic_recur(n - 1);\n}\n
space_complexity.c
/* \u5e73\u65b9\u9636\uff08\u9012\u5f52\u5b9e\u73b0\uff09 */\nint quadraticRecur(int n) {\n    if (n <= 0)\n        return 0;\n    int *nums = malloc(sizeof(int) * n);\n    printf(\"\u9012\u5f52 n = %d \u4e2d\u7684 nums \u957f\u5ea6 = %d\\r\\n\", n, n);\n    int res = quadraticRecur(n - 1);\n    free(nums);\n    return res;\n}\n
space_complexity.zig
// \u5e73\u65b9\u9636\uff08\u9012\u5f52\u5b9e\u73b0\uff09\nfn quadraticRecur(comptime n: i32) i32 {\n    if (n <= 0) return 0;\n    var nums = [_]i32{0}**n;\n    std.debug.print(\"\u9012\u5f52 n = {} \u4e2d\u7684 nums \u957f\u5ea6 = {}\\n\", .{n, nums.len});\n    return quadraticRecur(n - 1);\n}\n
Code Visualization

Full Screen >

Figure 2-18 \u00a0 Recursive Function Generating Quadratic Order Space Complexity

"},{"location":"chapter_computational_complexity/space_complexity/#4-exponential-order-o2n","title":"4. \u00a0 Exponential Order \\(O(2^n)\\)","text":"

Exponential order is common in binary trees. Observe the below image, a \"full binary tree\" with \\(n\\) levels has \\(2^n - 1\\) nodes, occupying \\(O(2^n)\\) space:

PythonC++JavaC#GoSwiftJSTSDartRustCZig space_complexity.py
def build_tree(n: int) -> TreeNode | None:\n    \"\"\"\u6307\u6570\u9636\uff08\u5efa\u7acb\u6ee1\u4e8c\u53c9\u6811\uff09\"\"\"\n    if n == 0:\n        return None\n    root = TreeNode(0)\n    root.left = build_tree(n - 1)\n    root.right = build_tree(n - 1)\n    return root\n
space_complexity.cpp
/* \u6307\u6570\u9636\uff08\u5efa\u7acb\u6ee1\u4e8c\u53c9\u6811\uff09 */\nTreeNode *buildTree(int n) {\n    if (n == 0)\n        return nullptr;\n    TreeNode *root = new TreeNode(0);\n    root->left = buildTree(n - 1);\n    root->right = buildTree(n - 1);\n    return root;\n}\n
space_complexity.java
/* \u6307\u6570\u9636\uff08\u5efa\u7acb\u6ee1\u4e8c\u53c9\u6811\uff09 */\nTreeNode buildTree(int n) {\n    if (n == 0)\n        return null;\n    TreeNode root = new TreeNode(0);\n    root.left = buildTree(n - 1);\n    root.right = buildTree(n - 1);\n    return root;\n}\n
space_complexity.cs
/* \u6307\u6570\u9636\uff08\u5efa\u7acb\u6ee1\u4e8c\u53c9\u6811\uff09 */\nTreeNode? BuildTree(int n) {\n    if (n == 0) return null;\n    TreeNode root = new(0) {\n        left = BuildTree(n - 1),\n        right = BuildTree(n - 1)\n    };\n    return root;\n}\n
space_complexity.go
/* \u6307\u6570\u9636\uff08\u5efa\u7acb\u6ee1\u4e8c\u53c9\u6811\uff09 */\nfunc buildTree(n int) *TreeNode {\n    if n == 0 {\n        return nil\n    }\n    root := NewTreeNode(0)\n    root.Left = buildTree(n - 1)\n    root.Right = buildTree(n - 1)\n    return root\n}\n
space_complexity.swift
/* \u6307\u6570\u9636\uff08\u5efa\u7acb\u6ee1\u4e8c\u53c9\u6811\uff09 */\nfunc buildTree(n: Int) -> TreeNode? {\n    if n == 0 {\n        return nil\n    }\n    let root = TreeNode(x: 0)\n    root.left = buildTree(n: n - 1)\n    root.right = buildTree(n: n - 1)\n    return root\n}\n
space_complexity.js
/* \u6307\u6570\u9636\uff08\u5efa\u7acb\u6ee1\u4e8c\u53c9\u6811\uff09 */\nfunction buildTree(n) {\n    if (n === 0) return null;\n    const root = new TreeNode(0);\n    root.left = buildTree(n - 1);\n    root.right = buildTree(n - 1);\n    return root;\n}\n
space_complexity.ts
/* \u6307\u6570\u9636\uff08\u5efa\u7acb\u6ee1\u4e8c\u53c9\u6811\uff09 */\nfunction buildTree(n: number): TreeNode | null {\n    if (n === 0) return null;\n    const root = new TreeNode(0);\n    root.left = buildTree(n - 1);\n    root.right = buildTree(n - 1);\n    return root;\n}\n
space_complexity.dart
/* \u6307\u6570\u9636\uff08\u5efa\u7acb\u6ee1\u4e8c\u53c9\u6811\uff09 */\nTreeNode? buildTree(int n) {\n  if (n == 0) return null;\n  TreeNode root = TreeNode(0);\n  root.left = buildTree(n - 1);\n  root.right = buildTree(n - 1);\n  return root;\n}\n
space_complexity.rs
/* \u6307\u6570\u9636\uff08\u5efa\u7acb\u6ee1\u4e8c\u53c9\u6811\uff09 */\nfn build_tree(n: i32) -> Option<Rc<RefCell<TreeNode>>> {\n    if n == 0 {\n        return None;\n    };\n    let root = TreeNode::new(0);\n    root.borrow_mut().left = build_tree(n - 1);\n    root.borrow_mut().right = build_tree(n - 1);\n    return Some(root);\n}\n
space_complexity.c
/* \u6307\u6570\u9636\uff08\u5efa\u7acb\u6ee1\u4e8c\u53c9\u6811\uff09 */\nTreeNode *buildTree(int n) {\n    if (n == 0)\n        return NULL;\n    TreeNode *root = newTreeNode(0);\n    root->left = buildTree(n - 1);\n    root->right = buildTree(n - 1);\n    return root;\n}\n
space_complexity.zig
// \u6307\u6570\u9636\uff08\u5efa\u7acb\u6ee1\u4e8c\u53c9\u6811\uff09\nfn buildTree(mem_allocator: std.mem.Allocator, n: i32) !?*inc.TreeNode(i32) {\n    if (n == 0) return null;\n    const root = try mem_allocator.create(inc.TreeNode(i32));\n    root.init(0);\n    root.left = try buildTree(mem_allocator, n - 1);\n    root.right = try buildTree(mem_allocator, n - 1);\n    return root;\n}\n
Code Visualization

Full Screen >

Figure 2-19 \u00a0 Full Binary Tree Generating Exponential Order Space Complexity

"},{"location":"chapter_computational_complexity/space_complexity/#5-logarithmic-order-olog-n","title":"5. \u00a0 Logarithmic Order \\(O(\\log n)\\)","text":"

Logarithmic order is common in divide-and-conquer algorithms. For example, in merge sort, an array of length \\(n\\) is recursively divided in half each round, forming a recursion tree of height \\(\\log n\\), using \\(O(\\log n)\\) stack frame space.

Another example is converting a number to a string. Given a positive integer \\(n\\), its number of digits is \\(\\log_{10} n + 1\\), corresponding to the length of the string, thus the space complexity is \\(O(\\log_{10} n + 1) = O(\\log n)\\).

"},{"location":"chapter_computational_complexity/space_complexity/#244-balancing-time-and-space","title":"2.4.4 \u00a0 Balancing Time and Space","text":"

Ideally, we aim for both time complexity and space complexity to be optimal. However, in practice, optimizing both simultaneously is often difficult.

Lowering time complexity usually comes at the cost of increased space complexity, and vice versa. The approach of sacrificing memory space to improve algorithm speed is known as \"space-time tradeoff\"; the reverse is known as \"time-space tradeoff\".

The choice depends on which aspect we value more. In most cases, time is more precious than space, so \"space-time tradeoff\" is often the more common strategy. Of course, controlling space complexity is also very important when dealing with large volumes of data.

"},{"location":"chapter_computational_complexity/summary/","title":"2.5 \u00a0 Summary","text":""},{"location":"chapter_computational_complexity/summary/#1-key-review","title":"1. \u00a0 Key Review","text":"

Algorithm Efficiency Assessment

  • Time efficiency and space efficiency are the two main criteria for assessing the merits of an algorithm.
  • We can assess algorithm efficiency through actual testing, but it's challenging to eliminate the influence of the test environment, and it consumes substantial computational resources.
  • Complexity analysis can overcome the disadvantages of actual testing. Its results are applicable across all operating platforms and can reveal the efficiency of algorithms at different data scales.

Time Complexity

  • Time complexity measures the trend of an algorithm's running time with the increase in data volume, effectively assessing algorithm efficiency. However, it can fail in certain cases, such as with small input data volumes or when time complexities are the same, making it challenging to precisely compare the efficiency of algorithms.
  • Worst-case time complexity is denoted using big O notation, representing the asymptotic upper bound, reflecting the growth level of the number of operations \\(T(n)\\) as \\(n\\) approaches infinity.
  • Calculating time complexity involves two steps: first counting the number of operations, then determining the asymptotic upper bound.
  • Common time complexities, arranged from low to high, include \\(O(1)\\), \\(O(\\log n)\\), \\(O(n)\\), \\(O(n \\log n)\\), \\(O(n^2)\\), \\(O(2^n)\\), and \\(O(n!)\\), among others.
  • The time complexity of some algorithms is not fixed and depends on the distribution of input data. Time complexities are divided into worst, best, and average cases. The best case is rarely used because input data generally needs to meet strict conditions to achieve the best case.
  • Average time complexity reflects the efficiency of an algorithm under random data inputs, closely resembling the algorithm's performance in actual applications. Calculating average time complexity requires accounting for the distribution of input data and the subsequent mathematical expectation.

Space Complexity

  • Space complexity, similar to time complexity, measures the trend of memory space occupied by an algorithm with the increase in data volume.
  • The relevant memory space used during the algorithm's execution can be divided into input space, temporary space, and output space. Generally, input space is not included in space complexity calculations. Temporary space can be divided into temporary data, stack frame space, and instruction space, where stack frame space usually affects space complexity only in recursive functions.
  • We usually focus only on the worst-case space complexity, which means calculating the space complexity of the algorithm under the worst input data and at the worst moment of operation.
  • Common space complexities, arranged from low to high, include \\(O(1)\\), \\(O(\\log n)\\), \\(O(n)\\), \\(O(n^2)\\), and \\(O(2^n)\\), among others.
"},{"location":"chapter_computational_complexity/summary/#2-q-a","title":"2. \u00a0 Q & A","text":"

Q: Is the space complexity of tail recursion \\(O(1)\\)?

Theoretically, the space complexity of a tail-recursive function can be optimized to \\(O(1)\\). However, most programming languages (such as Java, Python, C++, Go, C#) do not support automatic optimization of tail recursion, so it's generally considered to have a space complexity of \\(O(n)\\).

Q: What is the difference between the terms \"function\" and \"method\"?

A \"function\" can be executed independently, with all parameters passed explicitly. A \"method\" is associated with an object and is implicitly passed to the object calling it, able to operate on the data contained within an instance of a class.

Here are some examples from common programming languages:

  • C is a procedural programming language without object-oriented concepts, so it only has functions. However, we can simulate object-oriented programming by creating structures (struct), and functions associated with these structures are equivalent to methods in other programming languages.
  • Java and C# are object-oriented programming languages where code blocks (methods) are typically part of a class. Static methods behave like functions because they are bound to the class and cannot access specific instance variables.
  • C++ and Python support both procedural programming (functions) and object-oriented programming (methods).

Q: Does the \"Common Types of Space Complexity\" figure reflect the absolute size of occupied space?

No, the figure shows space complexities, which reflect growth trends, not the absolute size of the occupied space.

If you take \\(n = 8\\), you might find that the values of each curve don't correspond to their functions. This is because each curve includes a constant term, intended to compress the value range into a visually comfortable range.

In practice, since we usually don't know the \"constant term\" complexity of each method, it's generally not possible to choose the best solution for \\(n = 8\\) based solely on complexity. However, for \\(n = 8^5\\), it's much easier to choose, as the growth trend becomes dominant.

"},{"location":"chapter_computational_complexity/time_complexity/","title":"2.3 \u00a0 Time Complexity","text":"

Time complexity is a concept used to measure how the run time of an algorithm increases with the size of the input data. Understanding time complexity is crucial for accurately assessing the efficiency of an algorithm.

  1. Determining the Running Platform: This includes hardware configuration, programming language, system environment, etc., all of which can affect the efficiency of code execution.
  2. Evaluating the Run Time for Various Computational Operations: For instance, an addition operation + might take 1 ns, a multiplication operation * might take 10 ns, a print operation print() might take 5 ns, etc.
  3. Counting All the Computational Operations in the Code: Summing the execution times of all these operations gives the total run time.

For example, consider the following code with an input size of \\(n\\):

PythonC++JavaC#GoSwiftJSTSDartRustCZig
# Under an operating platform\ndef algorithm(n: int):\n    a = 2      # 1 ns\n    a = a + 1  # 1 ns\n    a = a * 2  # 10 ns\n    # Cycle n times\n    for _ in range(n):  # 1 ns\n        print(0)        # 5 ns\n
// Under a particular operating platform\nvoid algorithm(int n) {\n    int a = 2;  // 1 ns\n    a = a + 1;  // 1 ns\n    a = a * 2;  // 10 ns\n    // Loop n times\n    for (int i = 0; i < n; i++) {  // 1 ns , every round i++ is executed\n        cout << 0 << endl;         // 5 ns\n    }\n}\n
// Under a particular operating platform\nvoid algorithm(int n) {\n    int a = 2;  // 1 ns\n    a = a + 1;  // 1 ns\n    a = a * 2;  // 10 ns\n    // Loop n times\n    for (int i = 0; i < n; i++) {  // 1 ns , every round i++ is executed\n        System.out.println(0);     // 5 ns\n    }\n}\n
// Under a particular operating platform\nvoid Algorithm(int n) {\n    int a = 2;  // 1 ns\n    a = a + 1;  // 1 ns\n    a = a * 2;  // 10 ns\n    // Loop n times\n    for (int i = 0; i < n; i++) {  // 1 ns , every round i++ is executed\n        Console.WriteLine(0);      // 5 ns\n    }\n}\n
// Under a particular operating platform\nfunc algorithm(n int) {\n    a := 2     // 1 ns\n    a = a + 1  // 1 ns\n    a = a * 2  // 10 ns\n    // Loop n times\n    for i := 0; i < n; i++ {  // 1 ns\n        fmt.Println(a)        // 5 ns\n    }\n}\n
// Under a particular operating platform\nfunc algorithm(n: Int) {\n    var a = 2 // 1 ns\n    a = a + 1 // 1 ns\n    a = a * 2 // 10 ns\n    // Loop n times\n    for _ in 0 ..< n { // 1 ns\n        print(0) // 5 ns\n    }\n}\n
// Under a particular operating platform\nfunction algorithm(n) {\n    var a = 2; // 1 ns\n    a = a + 1; // 1 ns\n    a = a * 2; // 10 ns\n    // Loop n times\n    for(let i = 0; i < n; i++) { // 1 ns , every round i++ is executed\n        console.log(0); // 5 ns\n    }\n}\n
// Under a particular operating platform\nfunction algorithm(n: number): void {\n    var a: number = 2; // 1 ns\n    a = a + 1; // 1 ns\n    a = a * 2; // 10 ns\n    // Loop n times\n    for(let i = 0; i < n; i++) { // 1 ns , every round i++ is executed\n        console.log(0); // 5 ns\n    }\n}\n
// Under a particular operating platform\nvoid algorithm(int n) {\n  int a = 2; // 1 ns\n  a = a + 1; // 1 ns\n  a = a * 2; // 10 ns\n  // Loop n times\n  for (int i = 0; i < n; i++) { // 1 ns , every round i++ is executed\n    print(0); // 5 ns\n  }\n}\n
// Under a particular operating platform\nfn algorithm(n: i32) {\n    let mut a = 2;      // 1 ns\n    a = a + 1;          // 1 ns\n    a = a * 2;          // 10 ns\n    // Loop n times\n    for _ in 0..n {     // 1 ns for each round i++\n        println!(\"{}\", 0);  // 5 ns\n    }\n}\n
// Under a particular operating platform\nvoid algorithm(int n) {\n    int a = 2;  // 1 ns\n    a = a + 1;  // 1 ns\n    a = a * 2;  // 10 ns\n    // Loop n times\n    for (int i = 0; i < n; i++) {   // 1 ns , every round i++ is executed\n        printf(\"%d\", 0);            // 5 ns\n    }\n}\n
// Under a particular operating platform\nfn algorithm(n: usize) void {\n    var a: i32 = 2; // 1 ns\n    a += 1; // 1 ns\n    a *= 2; // 10 ns\n    // Loop n times\n    for (0..n) |_| { // 1 ns\n        std.debug.print(\"{}\\n\", .{0}); // 5 ns\n    }\n}\n

Using the above method, the run time of the algorithm can be calculated as \\((6n + 12)\\) ns:

\\[ 1 + 1 + 10 + (1 + 5) \\times n = 6n + 12 \\]

However, in practice, counting the run time of an algorithm is neither practical nor reasonable. First, we don't want to tie the estimated time to the running platform, as algorithms need to run on various platforms. Second, it's challenging to know the run time for each type of operation, making the estimation process difficult.

"},{"location":"chapter_computational_complexity/time_complexity/#231-assessing-time-growth-trend","title":"2.3.1 \u00a0 Assessing Time Growth Trend","text":"

Time complexity analysis does not count the algorithm's run time, but rather the growth trend of the run time as the data volume increases.

Let's understand this concept of \"time growth trend\" with an example. Assume the input data size is \\(n\\), and consider three algorithms A, B, and C:

PythonC++JavaC#GoSwiftJSTSDartRustCZig
# Time complexity of algorithm A: constant order\ndef algorithm_A(n: int):\n    print(0)\n# Time complexity of algorithm B: linear order\ndef algorithm_B(n: int):\n    for _ in range(n):\n        print(0)\n# Time complexity of algorithm C: constant order\ndef algorithm_C(n: int):\n    for _ in range(1000000):\n        print(0)\n
// Time complexity of algorithm A: constant order\nvoid algorithm_A(int n) {\n    cout << 0 << endl;\n}\n// Time complexity of algorithm B: linear order\nvoid algorithm_B(int n) {\n    for (int i = 0; i < n; i++) {\n        cout << 0 << endl;\n    }\n}\n// Time complexity of algorithm C: constant order\nvoid algorithm_C(int n) {\n    for (int i = 0; i < 1000000; i++) {\n        cout << 0 << endl;\n    }\n}\n
// Time complexity of algorithm A: constant order\nvoid algorithm_A(int n) {\n    System.out.println(0);\n}\n// Time complexity of algorithm B: linear order\nvoid algorithm_B(int n) {\n    for (int i = 0; i < n; i++) {\n        System.out.println(0);\n    }\n}\n// Time complexity of algorithm C: constant order\nvoid algorithm_C(int n) {\n    for (int i = 0; i < 1000000; i++) {\n        System.out.println(0);\n    }\n}\n
// Time complexity of algorithm A: constant order\nvoid AlgorithmA(int n) {\n    Console.WriteLine(0);\n}\n// Time complexity of algorithm B: linear order\nvoid AlgorithmB(int n) {\n    for (int i = 0; i < n; i++) {\n        Console.WriteLine(0);\n    }\n}\n// Time complexity of algorithm C: constant order\nvoid AlgorithmC(int n) {\n    for (int i = 0; i < 1000000; i++) {\n        Console.WriteLine(0);\n    }\n}\n
// Time complexity of algorithm A: constant order\nfunc algorithm_A(n int) {\n    fmt.Println(0)\n}\n// Time complexity of algorithm B: linear order\nfunc algorithm_B(n int) {\n    for i := 0; i < n; i++ {\n        fmt.Println(0)\n    }\n}\n// Time complexity of algorithm C: constant order\nfunc algorithm_C(n int) {\n    for i := 0; i < 1000000; i++ {\n        fmt.Println(0)\n    }\n}\n
// Time complexity of algorithm A: constant order\nfunc algorithmA(n: Int) {\n    print(0)\n}\n\n// Time complexity of algorithm B: linear order\nfunc algorithmB(n: Int) {\n    for _ in 0 ..< n {\n        print(0)\n    }\n}\n\n// Time complexity of algorithm C: constant order\nfunc algorithmC(n: Int) {\n    for _ in 0 ..< 1_000_000 {\n        print(0)\n    }\n}\n
// Time complexity of algorithm A: constant order\nfunction algorithm_A(n) {\n    console.log(0);\n}\n// Time complexity of algorithm B: linear order\nfunction algorithm_B(n) {\n    for (let i = 0; i < n; i++) {\n        console.log(0);\n    }\n}\n// Time complexity of algorithm C: constant order\nfunction algorithm_C(n) {\n    for (let i = 0; i < 1000000; i++) {\n        console.log(0);\n    }\n}\n
// Time complexity of algorithm A: constant order\nfunction algorithm_A(n: number): void {\n    console.log(0);\n}\n// Time complexity of algorithm B: linear order\nfunction algorithm_B(n: number): void {\n    for (let i = 0; i < n; i++) {\n        console.log(0);\n    }\n}\n// Time complexity of algorithm C: constant order\nfunction algorithm_C(n: number): void {\n    for (let i = 0; i < 1000000; i++) {\n        console.log(0);\n    }\n}\n
// Time complexity of algorithm A: constant order\nvoid algorithmA(int n) {\n  print(0);\n}\n// Time complexity of algorithm B: linear order\nvoid algorithmB(int n) {\n  for (int i = 0; i < n; i++) {\n    print(0);\n  }\n}\n// Time complexity of algorithm C: constant order\nvoid algorithmC(int n) {\n  for (int i = 0; i < 1000000; i++) {\n    print(0);\n  }\n}\n
// Time complexity of algorithm A: constant order\nfn algorithm_A(n: i32) {\n    println!(\"{}\", 0);\n}\n// Time complexity of algorithm B: linear order\nfn algorithm_B(n: i32) {\n    for _ in 0..n {\n        println!(\"{}\", 0);\n    }\n}\n// Time complexity of algorithm C: constant order\nfn algorithm_C(n: i32) {\n    for _ in 0..1000000 {\n        println!(\"{}\", 0);\n    }\n}\n
// Time complexity of algorithm A: constant order\nvoid algorithm_A(int n) {\n    printf(\"%d\", 0);\n}\n// Time complexity of algorithm B: linear order\nvoid algorithm_B(int n) {\n    for (int i = 0; i < n; i++) {\n        printf(\"%d\", 0);\n    }\n}\n// Time complexity of algorithm C: constant order\nvoid algorithm_C(int n) {\n    for (int i = 0; i < 1000000; i++) {\n        printf(\"%d\", 0);\n    }\n}\n
// Time complexity of algorithm A: constant order\nfn algorithm_A(n: usize) void {\n    _ = n;\n    std.debug.print(\"{}\\n\", .{0});\n}\n// Time complexity of algorithm B: linear order\nfn algorithm_B(n: i32) void {\n    for (0..n) |_| {\n        std.debug.print(\"{}\\n\", .{0});\n    }\n}\n// Time complexity of algorithm C: constant order\nfn algorithm_C(n: i32) void {\n    _ = n;\n    for (0..1000000) |_| {\n        std.debug.print(\"{}\\n\", .{0});\n    }\n}\n

The following figure shows the time complexities of these three algorithms.

  • Algorithm A has just one print operation, and its run time does not grow with \\(n\\). Its time complexity is considered \"constant order.\"
  • Algorithm B involves a print operation looping \\(n\\) times, and its run time grows linearly with \\(n\\). Its time complexity is \"linear order.\"
  • Algorithm C has a print operation looping 1,000,000 times. Although it takes a long time, it is independent of the input data size \\(n\\). Therefore, the time complexity of C is the same as A, which is \"constant order.\"

Figure 2-7 \u00a0 Time Growth Trend of Algorithms A, B, and C

Compared to directly counting the run time of an algorithm, what are the characteristics of time complexity analysis?

  • Time complexity effectively assesses algorithm efficiency. For instance, algorithm B has linearly growing run time, which is slower than algorithm A when \\(n > 1\\) and slower than C when \\(n > 1,000,000\\). In fact, as long as the input data size \\(n\\) is sufficiently large, a \"constant order\" complexity algorithm will always be better than a \"linear order\" one, demonstrating the essence of time growth trend.
  • Time complexity analysis is more straightforward. Obviously, the running platform and the types of computational operations are irrelevant to the trend of run time growth. Therefore, in time complexity analysis, we can simply treat the execution time of all computational operations as the same \"unit time,\" simplifying the \"computational operation run time count\" to a \"computational operation count.\" This significantly reduces the complexity of estimation.
  • Time complexity has its limitations. For example, although algorithms A and C have the same time complexity, their actual run times can be quite different. Similarly, even though algorithm B has a higher time complexity than C, it is clearly superior when the input data size \\(n\\) is small. In these cases, it's difficult to judge the efficiency of algorithms based solely on time complexity. Nonetheless, despite these issues, complexity analysis remains the most effective and commonly used method for evaluating algorithm efficiency.
"},{"location":"chapter_computational_complexity/time_complexity/#232-asymptotic-upper-bound","title":"2.3.2 \u00a0 Asymptotic Upper Bound","text":"

Consider a function with an input size of \\(n\\):

PythonC++JavaC#GoSwiftJSTSDartRustCZig
def algorithm(n: int):\n    a = 1      # +1\n    a = a + 1  # +1\n    a = a * 2  # +1\n    # Cycle n times\n    for i in range(n):  # +1\n        print(0)        # +1\n
void algorithm(int n) {\n    int a = 1;  // +1\n    a = a + 1;  // +1\n    a = a * 2;  // +1\n    // Loop n times\n    for (int i = 0; i < n; i++) { // +1 (execute i ++ every round)\n        cout << 0 << endl;    // +1\n    }\n}\n
void algorithm(int n) {\n    int a = 1;  // +1\n    a = a + 1;  // +1\n    a = a * 2;  // +1\n    // Loop n times\n    for (int i = 0; i < n; i++) { // +1 (execute i ++ every round)\n        System.out.println(0);    // +1\n    }\n}\n
void Algorithm(int n) {\n    int a = 1;  // +1\n    a = a + 1;  // +1\n    a = a * 2;  // +1\n    // Loop n times\n    for (int i = 0; i < n; i++) {   // +1 (execute i ++ every round)\n        Console.WriteLine(0);   // +1\n    }\n}\n
func algorithm(n int) {\n    a := 1      // +1\n    a = a + 1   // +1\n    a = a * 2   // +1\n    // Loop n times\n    for i := 0; i < n; i++ {   // +1\n        fmt.Println(a)         // +1\n    }\n}\n
func algorithm(n: Int) {\n    var a = 1 // +1\n    a = a + 1 // +1\n    a = a * 2 // +1\n    // Loop n times\n    for _ in 0 ..< n { // +1\n        print(0) // +1\n    }\n}\n
function algorithm(n) {\n    var a = 1; // +1\n    a += 1; // +1\n    a *= 2; // +1\n    // Loop n times\n    for(let i = 0; i < n; i++){ // +1 (execute i ++ every round)\n        console.log(0); // +1\n    }\n}\n
function algorithm(n: number): void{\n    var a: number = 1; // +1\n    a += 1; // +1\n    a *= 2; // +1\n    // Loop n times\n    for(let i = 0; i < n; i++){ // +1 (execute i ++ every round)\n        console.log(0); // +1\n    }\n}\n
void algorithm(int n) {\n  int a = 1; // +1\n  a = a + 1; // +1\n  a = a * 2; // +1\n  // Loop n times\n  for (int i = 0; i < n; i++) { // +1 (execute i ++ every round)\n    print(0); // +1\n  }\n}\n
fn algorithm(n: i32) {\n    let mut a = 1;   // +1\n    a = a + 1;      // +1\n    a = a * 2;      // +1\n\n    // Loop n times\n    for _ in 0..n { // +1 (execute i ++ every round)\n        println!(\"{}\", 0); // +1\n    }\n}\n
void algorithm(int n) {\n    int a = 1;  // +1\n    a = a + 1;  // +1\n    a = a * 2;  // +1\n    // Loop n times\n    for (int i = 0; i < n; i++) {   // +1 (execute i ++ every round)\n        printf(\"%d\", 0);            // +1\n    }\n} \n
fn algorithm(n: usize) void {\n    var a: i32 = 1; // +1\n    a += 1; // +1\n    a *= 2; // +1\n    // Loop n times\n    for (0..n) |_| { // +1 (execute i ++ every round)\n        std.debug.print(\"{}\\n\", .{0}); // +1\n    }\n}\n

Given a function that represents the number of operations of an algorithm as a function of the input size \\(n\\), denoted as \\(T(n)\\), consider the following example:

\\[ T(n) = 3 + 2n \\]

Since \\(T(n)\\) is a linear function, its growth trend is linear, and therefore, its time complexity is of linear order, denoted as \\(O(n)\\). This mathematical notation, known as \"big-O notation,\" represents the \"asymptotic upper bound\" of the function \\(T(n)\\).

In essence, time complexity analysis is about finding the asymptotic upper bound of the \"number of operations \\(T(n)\\)\". It has a precise mathematical definition.

Asymptotic Upper Bound

If there exist positive real numbers \\(c\\) and \\(n_0\\) such that for all \\(n > n_0\\), \\(T(n) \\leq c \\cdot f(n)\\), then \\(f(n)\\) is considered an asymptotic upper bound of \\(T(n)\\), denoted as \\(T(n) = O(f(n))\\).

As illustrated below, calculating the asymptotic upper bound involves finding a function \\(f(n)\\) such that, as \\(n\\) approaches infinity, \\(T(n)\\) and \\(f(n)\\) have the same growth order, differing only by a constant factor \\(c\\).

Figure 2-8 \u00a0 Asymptotic Upper Bound of a Function

"},{"location":"chapter_computational_complexity/time_complexity/#233-calculation-method","title":"2.3.3 \u00a0 Calculation Method","text":"

While the concept of asymptotic upper bound might seem mathematically dense, you don't need to fully grasp it right away. Let's first understand the method of calculation, which can be practiced and comprehended over time.

Once \\(f(n)\\) is determined, we obtain the time complexity \\(O(f(n))\\). But how do we determine the asymptotic upper bound \\(f(n)\\)? This process generally involves two steps: counting the number of operations and determining the asymptotic upper bound.

"},{"location":"chapter_computational_complexity/time_complexity/#1-step-1-counting-the-number-of-operations","title":"1. \u00a0 Step 1: Counting the Number of Operations","text":"

This step involves going through the code line by line. However, due to the presence of the constant \\(c\\) in \\(c \\cdot f(n)\\), all coefficients and constant terms in \\(T(n)\\) can be ignored. This principle allows for simplification techniques in counting operations.

  1. Ignore constant terms in \\(T(n)\\), as they do not affect the time complexity being independent of \\(n\\).
  2. Omit all coefficients. For example, looping \\(2n\\), \\(5n + 1\\) times, etc., can be simplified to \\(n\\) times since the coefficient before \\(n\\) does not impact the time complexity.
  3. Use multiplication for nested loops. The total number of operations equals the product of the number of operations in each loop, applying the simplification techniques from points 1 and 2 for each loop level.

Given a function, we can use these techniques to count operations:

PythonC++JavaC#GoSwiftJSTSDartRustCZig
def algorithm(n: int):\n    a = 1      # +0 (trick 1)\n    a = a + n  # +0 (trick 1)\n    # +n (technique 2)\n    for i in range(5 * n + 1):\n        print(0)\n    # +n*n (technique 3)\n    for i in range(2 * n):\n        for j in range(n + 1):\n            print(0)\n
void algorithm(int n) {\n    int a = 1;  // +0 (trick 1)\n    a = a + n;  // +0 (trick 1)\n    // +n (technique 2)\n    for (int i = 0; i < 5 * n + 1; i++) {\n        cout << 0 << endl;\n    }\n    // +n*n (technique 3)\n    for (int i = 0; i < 2 * n; i++) {\n        for (int j = 0; j < n + 1; j++) {\n            cout << 0 << endl;\n        }\n    }\n}\n
void algorithm(int n) {\n    int a = 1;  // +0 (trick 1)\n    a = a + n;  // +0 (trick 1)\n    // +n (technique 2)\n    for (int i = 0; i < 5 * n + 1; i++) {\n        System.out.println(0);\n    }\n    // +n*n (technique 3)\n    for (int i = 0; i < 2 * n; i++) {\n        for (int j = 0; j < n + 1; j++) {\n            System.out.println(0);\n        }\n    }\n}\n
void Algorithm(int n) {\n    int a = 1;  // +0 (trick 1)\n    a = a + n;  // +0 (trick 1)\n    // +n (technique 2)\n    for (int i = 0; i < 5 * n + 1; i++) {\n        Console.WriteLine(0);\n    }\n    // +n*n (technique 3)\n    for (int i = 0; i < 2 * n; i++) {\n        for (int j = 0; j < n + 1; j++) {\n            Console.WriteLine(0);\n        }\n    }\n}\n
func algorithm(n int) {\n    a := 1     // +0 (trick 1)\n    a = a + n  // +0 (trick 1)\n    // +n (technique 2)\n    for i := 0; i < 5 * n + 1; i++ {\n        fmt.Println(0)\n    }\n    // +n*n (technique 3)\n    for i := 0; i < 2 * n; i++ {\n        for j := 0; j < n + 1; j++ {\n            fmt.Println(0)\n        }\n    }\n}\n
func algorithm(n: Int) {\n    var a = 1 // +0 (trick 1)\n    a = a + n // +0 (trick 1)\n    // +n (technique 2)\n    for _ in 0 ..< (5 * n + 1) {\n        print(0)\n    }\n    // +n*n (technique 3)\n    for _ in 0 ..< (2 * n) {\n        for _ in 0 ..< (n + 1) {\n            print(0)\n        }\n    }\n}\n
function algorithm(n) {\n    let a = 1;  // +0 (trick 1)\n    a = a + n;  // +0 (trick 1)\n    // +n (technique 2)\n    for (let i = 0; i < 5 * n + 1; i++) {\n        console.log(0);\n    }\n    // +n*n (technique 3)\n    for (let i = 0; i < 2 * n; i++) {\n        for (let j = 0; j < n + 1; j++) {\n            console.log(0);\n        }\n    }\n}\n
function algorithm(n: number): void {\n    let a = 1;  // +0 (trick 1)\n    a = a + n;  // +0 (trick 1)\n    // +n (technique 2)\n    for (let i = 0; i < 5 * n + 1; i++) {\n        console.log(0);\n    }\n    // +n*n (technique 3)\n    for (let i = 0; i < 2 * n; i++) {\n        for (let j = 0; j < n + 1; j++) {\n            console.log(0);\n        }\n    }\n}\n
void algorithm(int n) {\n  int a = 1; // +0 (trick 1)\n  a = a + n; // +0 (trick 1)\n  // +n (technique 2)\n  for (int i = 0; i < 5 * n + 1; i++) {\n    print(0);\n  }\n  // +n*n (technique 3)\n  for (int i = 0; i < 2 * n; i++) {\n    for (int j = 0; j < n + 1; j++) {\n      print(0);\n    }\n  }\n}\n
fn algorithm(n: i32) {\n    let mut a = 1;     // +0 (trick 1)\n    a = a + n;        // +0 (trick 1)\n\n    // +n (technique 2)\n    for i in 0..(5 * n + 1) {\n        println!(\"{}\", 0);\n    }\n\n    // +n*n (technique 3)\n    for i in 0..(2 * n) {\n        for j in 0..(n + 1) {\n            println!(\"{}\", 0);\n        }\n    }\n}\n
void algorithm(int n) {\n    int a = 1;  // +0 (trick 1)\n    a = a + n;  // +0 (trick 1)\n    // +n (technique 2)\n    for (int i = 0; i < 5 * n + 1; i++) {\n        printf(\"%d\", 0);\n    }\n    // +n*n (technique 3)\n    for (int i = 0; i < 2 * n; i++) {\n        for (int j = 0; j < n + 1; j++) {\n            printf(\"%d\", 0);\n        }\n    }\n}\n
fn algorithm(n: usize) void {\n    var a: i32 = 1;     // +0 (trick 1)\n    a = a + @as(i32, @intCast(n));        // +0 (trick 1)\n\n    // +n (technique 2)\n    for(0..(5 * n + 1)) |_| {\n        std.debug.print(\"{}\\n\", .{0});\n    }\n\n    // +n*n (technique 3)\n    for(0..(2 * n)) |_| {\n        for(0..(n + 1)) |_| {\n            std.debug.print(\"{}\\n\", .{0});\n        }\n    }\n}\n

The formula below shows the counting results before and after simplification, both leading to a time complexity of \\(O(n^2)\\):

\\[ \\begin{aligned} T(n) & = 2n(n + 1) + (5n + 1) + 2 & \\text{Complete Count (-.-|||)} \\newline & = 2n^2 + 7n + 3 \\newline T(n) & = n^2 + n & \\text{Simplified Count (o.O)} \\end{aligned} \\]"},{"location":"chapter_computational_complexity/time_complexity/#2-step-2-determining-the-asymptotic-upper-bound","title":"2. \u00a0 Step 2: Determining the Asymptotic Upper Bound","text":"

The time complexity is determined by the highest order term in \\(T(n)\\). This is because, as \\(n\\) approaches infinity, the highest order term dominates, rendering the influence of other terms negligible.

The following table illustrates examples of different operation counts and their corresponding time complexities. Some exaggerated values are used to emphasize that coefficients cannot alter the order of growth. When \\(n\\) becomes very large, these constants become insignificant.

Table: Time Complexity for Different Operation Counts

Operation Count \\(T(n)\\) Time Complexity \\(O(f(n))\\) \\(100000\\) \\(O(1)\\) \\(3n + 2\\) \\(O(n)\\) \\(2n^2 + 3n + 2\\) \\(O(n^2)\\) \\(n^3 + 10000n^2\\) \\(O(n^3)\\) \\(2^n + 10000n^{10000}\\) \\(O(2^n)\\)"},{"location":"chapter_computational_complexity/time_complexity/#234-common-types-of-time-complexity","title":"2.3.4 \u00a0 Common Types of Time Complexity","text":"

Let's consider the input data size as \\(n\\). The common types of time complexities are illustrated below, arranged from lowest to highest:

\\[ \\begin{aligned} O(1) < O(\\log n) < O(n) < O(n \\log n) < O(n^2) < O(2^n) < O(n!) \\newline \\text{Constant Order} < \\text{Logarithmic Order} < \\text{Linear Order} < \\text{Linear-Logarithmic Order} < \\text{Quadratic Order} < \\text{Exponential Order} < \\text{Factorial Order} \\end{aligned} \\]

Figure 2-9 \u00a0 Common Types of Time Complexity

"},{"location":"chapter_computational_complexity/time_complexity/#1-constant-order-o1","title":"1. \u00a0 Constant Order \\(O(1)\\)","text":"

Constant order means the number of operations is independent of the input data size \\(n\\). In the following function, although the number of operations size might be large, the time complexity remains \\(O(1)\\) as it's unrelated to \\(n\\):

PythonC++JavaC#GoSwiftJSTSDartRustCZig time_complexity.py
def constant(n: int) -> int:\n    \"\"\"\u5e38\u6570\u9636\"\"\"\n    count = 0\n    size = 100000\n    for _ in range(size):\n        count += 1\n    return count\n
time_complexity.cpp
/* \u5e38\u6570\u9636 */\nint constant(int n) {\n    int count = 0;\n    int size = 100000;\n    for (int i = 0; i < size; i++)\n        count++;\n    return count;\n}\n
time_complexity.java
/* \u5e38\u6570\u9636 */\nint constant(int n) {\n    int count = 0;\n    int size = 100000;\n    for (int i = 0; i < size; i++)\n        count++;\n    return count;\n}\n
time_complexity.cs
/* \u5e38\u6570\u9636 */\nint Constant(int n) {\n    int count = 0;\n    int size = 100000;\n    for (int i = 0; i < size; i++)\n        count++;\n    return count;\n}\n
time_complexity.go
/* \u5e38\u6570\u9636 */\nfunc constant(n int) int {\n    count := 0\n    size := 100000\n    for i := 0; i < size; i++ {\n        count++\n    }\n    return count\n}\n
time_complexity.swift
/* \u5e38\u6570\u9636 */\nfunc constant(n: Int) -> Int {\n    var count = 0\n    let size = 100_000\n    for _ in 0 ..< size {\n        count += 1\n    }\n    return count\n}\n
time_complexity.js
/* \u5e38\u6570\u9636 */\nfunction constant(n) {\n    let count = 0;\n    const size = 100000;\n    for (let i = 0; i < size; i++) count++;\n    return count;\n}\n
time_complexity.ts
/* \u5e38\u6570\u9636 */\nfunction constant(n: number): number {\n    let count = 0;\n    const size = 100000;\n    for (let i = 0; i < size; i++) count++;\n    return count;\n}\n
time_complexity.dart
/* \u5e38\u6570\u9636 */\nint constant(int n) {\n  int count = 0;\n  int size = 100000;\n  for (var i = 0; i < size; i++) {\n    count++;\n  }\n  return count;\n}\n
time_complexity.rs
/* \u5e38\u6570\u9636 */\nfn constant(n: i32) -> i32 {\n    _ = n;\n    let mut count = 0;\n    let size = 100_000;\n    for _ in 0..size {\n        count += 1;\n    }\n    count\n}\n
time_complexity.c
/* \u5e38\u6570\u9636 */\nint constant(int n) {\n    int count = 0;\n    int size = 100000;\n    int i = 0;\n    for (int i = 0; i < size; i++) {\n        count++;\n    }\n    return count;\n}\n
time_complexity.zig
// \u5e38\u6570\u9636\nfn constant(n: i32) i32 {\n    _ = n;\n    var count: i32 = 0;\n    const size: i32 = 100_000;\n    var i: i32 = 0;\n    while(i<size) : (i += 1) {\n        count += 1;\n    }\n    return count;\n}\n
Code Visualization

Full Screen >

"},{"location":"chapter_computational_complexity/time_complexity/#2-linear-order-on","title":"2. \u00a0 Linear Order \\(O(n)\\)","text":"

Linear order indicates the number of operations grows linearly with the input data size \\(n\\). Linear order commonly appears in single-loop structures:

PythonC++JavaC#GoSwiftJSTSDartRustCZig time_complexity.py
def linear(n: int) -> int:\n    \"\"\"\u7ebf\u6027\u9636\"\"\"\n    count = 0\n    for _ in range(n):\n        count += 1\n    return count\n
time_complexity.cpp
/* \u7ebf\u6027\u9636 */\nint linear(int n) {\n    int count = 0;\n    for (int i = 0; i < n; i++)\n        count++;\n    return count;\n}\n
time_complexity.java
/* \u7ebf\u6027\u9636 */\nint linear(int n) {\n    int count = 0;\n    for (int i = 0; i < n; i++)\n        count++;\n    return count;\n}\n
time_complexity.cs
/* \u7ebf\u6027\u9636 */\nint Linear(int n) {\n    int count = 0;\n    for (int i = 0; i < n; i++)\n        count++;\n    return count;\n}\n
time_complexity.go
/* \u7ebf\u6027\u9636 */\nfunc linear(n int) int {\n    count := 0\n    for i := 0; i < n; i++ {\n        count++\n    }\n    return count\n}\n
time_complexity.swift
/* \u7ebf\u6027\u9636 */\nfunc linear(n: Int) -> Int {\n    var count = 0\n    for _ in 0 ..< n {\n        count += 1\n    }\n    return count\n}\n
time_complexity.js
/* \u7ebf\u6027\u9636 */\nfunction linear(n) {\n    let count = 0;\n    for (let i = 0; i < n; i++) count++;\n    return count;\n}\n
time_complexity.ts
/* \u7ebf\u6027\u9636 */\nfunction linear(n: number): number {\n    let count = 0;\n    for (let i = 0; i < n; i++) count++;\n    return count;\n}\n
time_complexity.dart
/* \u7ebf\u6027\u9636 */\nint linear(int n) {\n  int count = 0;\n  for (var i = 0; i < n; i++) {\n    count++;\n  }\n  return count;\n}\n
time_complexity.rs
/* \u7ebf\u6027\u9636 */\nfn linear(n: i32) -> i32 {\n    let mut count = 0;\n    for _ in 0..n {\n        count += 1;\n    }\n    count\n}\n
time_complexity.c
/* \u7ebf\u6027\u9636 */\nint linear(int n) {\n    int count = 0;\n    for (int i = 0; i < n; i++) {\n        count++;\n    }\n    return count;\n}\n
time_complexity.zig
// \u7ebf\u6027\u9636\nfn linear(n: i32) i32 {\n    var count: i32 = 0;\n    var i: i32 = 0;\n    while (i < n) : (i += 1) {\n        count += 1;\n    }\n    return count;\n}\n
Code Visualization

Full Screen >

Operations like array traversal and linked list traversal have a time complexity of \\(O(n)\\), where \\(n\\) is the length of the array or list:

PythonC++JavaC#GoSwiftJSTSDartRustCZig time_complexity.py
def array_traversal(nums: list[int]) -> int:\n    \"\"\"\u7ebf\u6027\u9636\uff08\u904d\u5386\u6570\u7ec4\uff09\"\"\"\n    count = 0\n    # \u5faa\u73af\u6b21\u6570\u4e0e\u6570\u7ec4\u957f\u5ea6\u6210\u6b63\u6bd4\n    for num in nums:\n        count += 1\n    return count\n
time_complexity.cpp
/* \u7ebf\u6027\u9636\uff08\u904d\u5386\u6570\u7ec4\uff09 */\nint arrayTraversal(vector<int> &nums) {\n    int count = 0;\n    // \u5faa\u73af\u6b21\u6570\u4e0e\u6570\u7ec4\u957f\u5ea6\u6210\u6b63\u6bd4\n    for (int num : nums) {\n        count++;\n    }\n    return count;\n}\n
time_complexity.java
/* \u7ebf\u6027\u9636\uff08\u904d\u5386\u6570\u7ec4\uff09 */\nint arrayTraversal(int[] nums) {\n    int count = 0;\n    // \u5faa\u73af\u6b21\u6570\u4e0e\u6570\u7ec4\u957f\u5ea6\u6210\u6b63\u6bd4\n    for (int num : nums) {\n        count++;\n    }\n    return count;\n}\n
time_complexity.cs
/* \u7ebf\u6027\u9636\uff08\u904d\u5386\u6570\u7ec4\uff09 */\nint ArrayTraversal(int[] nums) {\n    int count = 0;\n    // \u5faa\u73af\u6b21\u6570\u4e0e\u6570\u7ec4\u957f\u5ea6\u6210\u6b63\u6bd4\n    foreach (int num in nums) {\n        count++;\n    }\n    return count;\n}\n
time_complexity.go
/* \u7ebf\u6027\u9636\uff08\u904d\u5386\u6570\u7ec4\uff09 */\nfunc arrayTraversal(nums []int) int {\n    count := 0\n    // \u5faa\u73af\u6b21\u6570\u4e0e\u6570\u7ec4\u957f\u5ea6\u6210\u6b63\u6bd4\n    for range nums {\n        count++\n    }\n    return count\n}\n
time_complexity.swift
/* \u7ebf\u6027\u9636\uff08\u904d\u5386\u6570\u7ec4\uff09 */\nfunc arrayTraversal(nums: [Int]) -> Int {\n    var count = 0\n    // \u5faa\u73af\u6b21\u6570\u4e0e\u6570\u7ec4\u957f\u5ea6\u6210\u6b63\u6bd4\n    for _ in nums {\n        count += 1\n    }\n    return count\n}\n
time_complexity.js
/* \u7ebf\u6027\u9636\uff08\u904d\u5386\u6570\u7ec4\uff09 */\nfunction arrayTraversal(nums) {\n    let count = 0;\n    // \u5faa\u73af\u6b21\u6570\u4e0e\u6570\u7ec4\u957f\u5ea6\u6210\u6b63\u6bd4\n    for (let i = 0; i < nums.length; i++) {\n        count++;\n    }\n    return count;\n}\n
time_complexity.ts
/* \u7ebf\u6027\u9636\uff08\u904d\u5386\u6570\u7ec4\uff09 */\nfunction arrayTraversal(nums: number[]): number {\n    let count = 0;\n    // \u5faa\u73af\u6b21\u6570\u4e0e\u6570\u7ec4\u957f\u5ea6\u6210\u6b63\u6bd4\n    for (let i = 0; i < nums.length; i++) {\n        count++;\n    }\n    return count;\n}\n
time_complexity.dart
/* \u7ebf\u6027\u9636\uff08\u904d\u5386\u6570\u7ec4\uff09 */\nint arrayTraversal(List<int> nums) {\n  int count = 0;\n  // \u5faa\u73af\u6b21\u6570\u4e0e\u6570\u7ec4\u957f\u5ea6\u6210\u6b63\u6bd4\n  for (var _num in nums) {\n    count++;\n  }\n  return count;\n}\n
time_complexity.rs
/* \u7ebf\u6027\u9636\uff08\u904d\u5386\u6570\u7ec4\uff09 */\nfn array_traversal(nums: &[i32]) -> i32 {\n    let mut count = 0;\n    // \u5faa\u73af\u6b21\u6570\u4e0e\u6570\u7ec4\u957f\u5ea6\u6210\u6b63\u6bd4\n    for _ in nums {\n        count += 1;\n    }\n    count\n}\n
time_complexity.c
/* \u7ebf\u6027\u9636\uff08\u904d\u5386\u6570\u7ec4\uff09 */\nint arrayTraversal(int *nums, int n) {\n    int count = 0;\n    // \u5faa\u73af\u6b21\u6570\u4e0e\u6570\u7ec4\u957f\u5ea6\u6210\u6b63\u6bd4\n    for (int i = 0; i < n; i++) {\n        count++;\n    }\n    return count;\n}\n
time_complexity.zig
// \u7ebf\u6027\u9636\uff08\u904d\u5386\u6570\u7ec4\uff09\nfn arrayTraversal(nums: []i32) i32 {\n    var count: i32 = 0;\n    // \u5faa\u73af\u6b21\u6570\u4e0e\u6570\u7ec4\u957f\u5ea6\u6210\u6b63\u6bd4\n    for (nums) |_| {\n        count += 1;\n    }\n    return count;\n}\n
Code Visualization

Full Screen >

It's important to note that the input data size \\(n\\) should be determined based on the type of input data. For example, in the first example, \\(n\\) represents the input data size, while in the second example, the length of the array \\(n\\) is the data size.

"},{"location":"chapter_computational_complexity/time_complexity/#3-quadratic-order-on2","title":"3. \u00a0 Quadratic Order \\(O(n^2)\\)","text":"

Quadratic order means the number of operations grows quadratically with the input data size \\(n\\). Quadratic order typically appears in nested loops, where both the outer and inner loops have a time complexity of \\(O(n)\\), resulting in an overall complexity of \\(O(n^2)\\):

PythonC++JavaC#GoSwiftJSTSDartRustCZig time_complexity.py
def quadratic(n: int) -> int:\n    \"\"\"\u5e73\u65b9\u9636\"\"\"\n    count = 0\n    # \u5faa\u73af\u6b21\u6570\u4e0e\u6570\u636e\u5927\u5c0f n \u6210\u5e73\u65b9\u5173\u7cfb\n    for i in range(n):\n        for j in range(n):\n            count += 1\n    return count\n
time_complexity.cpp
/* \u5e73\u65b9\u9636 */\nint quadratic(int n) {\n    int count = 0;\n    // \u5faa\u73af\u6b21\u6570\u4e0e\u6570\u636e\u5927\u5c0f n \u6210\u5e73\u65b9\u5173\u7cfb\n    for (int i = 0; i < n; i++) {\n        for (int j = 0; j < n; j++) {\n            count++;\n        }\n    }\n    return count;\n}\n
time_complexity.java
/* \u5e73\u65b9\u9636 */\nint quadratic(int n) {\n    int count = 0;\n    // \u5faa\u73af\u6b21\u6570\u4e0e\u6570\u636e\u5927\u5c0f n \u6210\u5e73\u65b9\u5173\u7cfb\n    for (int i = 0; i < n; i++) {\n        for (int j = 0; j < n; j++) {\n            count++;\n        }\n    }\n    return count;\n}\n
time_complexity.cs
/* \u5e73\u65b9\u9636 */\nint Quadratic(int n) {\n    int count = 0;\n    // \u5faa\u73af\u6b21\u6570\u4e0e\u6570\u636e\u5927\u5c0f n \u6210\u5e73\u65b9\u5173\u7cfb\n    for (int i = 0; i < n; i++) {\n        for (int j = 0; j < n; j++) {\n            count++;\n        }\n    }\n    return count;\n}\n
time_complexity.go
/* \u5e73\u65b9\u9636 */\nfunc quadratic(n int) int {\n    count := 0\n    // \u5faa\u73af\u6b21\u6570\u4e0e\u6570\u636e\u5927\u5c0f n \u6210\u5e73\u65b9\u5173\u7cfb\n    for i := 0; i < n; i++ {\n        for j := 0; j < n; j++ {\n            count++\n        }\n    }\n    return count\n}\n
time_complexity.swift
/* \u5e73\u65b9\u9636 */\nfunc quadratic(n: Int) -> Int {\n    var count = 0\n    // \u5faa\u73af\u6b21\u6570\u4e0e\u6570\u636e\u5927\u5c0f n \u6210\u5e73\u65b9\u5173\u7cfb\n    for _ in 0 ..< n {\n        for _ in 0 ..< n {\n            count += 1\n        }\n    }\n    return count\n}\n
time_complexity.js
/* \u5e73\u65b9\u9636 */\nfunction quadratic(n) {\n    let count = 0;\n    // \u5faa\u73af\u6b21\u6570\u4e0e\u6570\u636e\u5927\u5c0f n \u6210\u5e73\u65b9\u5173\u7cfb\n    for (let i = 0; i < n; i++) {\n        for (let j = 0; j < n; j++) {\n            count++;\n        }\n    }\n    return count;\n}\n
time_complexity.ts
/* \u5e73\u65b9\u9636 */\nfunction quadratic(n: number): number {\n    let count = 0;\n    // \u5faa\u73af\u6b21\u6570\u4e0e\u6570\u636e\u5927\u5c0f n \u6210\u5e73\u65b9\u5173\u7cfb\n    for (let i = 0; i < n; i++) {\n        for (let j = 0; j < n; j++) {\n            count++;\n        }\n    }\n    return count;\n}\n
time_complexity.dart
/* \u5e73\u65b9\u9636 */\nint quadratic(int n) {\n  int count = 0;\n  // \u5faa\u73af\u6b21\u6570\u4e0e\u6570\u636e\u5927\u5c0f n \u6210\u5e73\u65b9\u5173\u7cfb\n  for (int i = 0; i < n; i++) {\n    for (int j = 0; j < n; j++) {\n      count++;\n    }\n  }\n  return count;\n}\n
time_complexity.rs
/* \u5e73\u65b9\u9636 */\nfn quadratic(n: i32) -> i32 {\n    let mut count = 0;\n    // \u5faa\u73af\u6b21\u6570\u4e0e\u6570\u636e\u5927\u5c0f n \u6210\u5e73\u65b9\u5173\u7cfb\n    for _ in 0..n {\n        for _ in 0..n {\n            count += 1;\n        }\n    }\n    count\n}\n
time_complexity.c
/* \u5e73\u65b9\u9636 */\nint quadratic(int n) {\n    int count = 0;\n    // \u5faa\u73af\u6b21\u6570\u4e0e\u6570\u636e\u5927\u5c0f n \u6210\u5e73\u65b9\u5173\u7cfb\n    for (int i = 0; i < n; i++) {\n        for (int j = 0; j < n; j++) {\n            count++;\n        }\n    }\n    return count;\n}\n
time_complexity.zig
// \u5e73\u65b9\u9636\nfn quadratic(n: i32) i32 {\n    var count: i32 = 0;\n    var i: i32 = 0;\n    // \u5faa\u73af\u6b21\u6570\u4e0e\u6570\u636e\u5927\u5c0f n \u6210\u5e73\u65b9\u5173\u7cfb\n    while (i < n) : (i += 1) {\n        var j: i32 = 0;\n        while (j < n) : (j += 1) {\n            count += 1;\n        }\n    }\n    return count;\n}\n
Code Visualization

Full Screen >

The following image compares constant order, linear order, and quadratic order time complexities.

Figure 2-10 \u00a0 Constant, Linear, and Quadratic Order Time Complexities

For instance, in bubble sort, the outer loop runs \\(n - 1\\) times, and the inner loop runs \\(n-1\\), \\(n-2\\), ..., \\(2\\), \\(1\\) times, averaging \\(n / 2\\) times, resulting in a time complexity of \\(O((n - 1) n / 2) = O(n^2)\\):

PythonC++JavaC#GoSwiftJSTSDartRustCZig time_complexity.py
def bubble_sort(nums: list[int]) -> int:\n    \"\"\"\u5e73\u65b9\u9636\uff08\u5192\u6ce1\u6392\u5e8f\uff09\"\"\"\n    count = 0  # \u8ba1\u6570\u5668\n    # \u5916\u5faa\u73af\uff1a\u672a\u6392\u5e8f\u533a\u95f4\u4e3a [0, i]\n    for i in range(len(nums) - 1, 0, -1):\n        # \u5185\u5faa\u73af\uff1a\u5c06\u672a\u6392\u5e8f\u533a\u95f4 [0, i] \u4e2d\u7684\u6700\u5927\u5143\u7d20\u4ea4\u6362\u81f3\u8be5\u533a\u95f4\u7684\u6700\u53f3\u7aef\n        for j in range(i):\n            if nums[j] > nums[j + 1]:\n                # \u4ea4\u6362 nums[j] \u4e0e nums[j + 1]\n                tmp: int = nums[j]\n                nums[j] = nums[j + 1]\n                nums[j + 1] = tmp\n                count += 3  # \u5143\u7d20\u4ea4\u6362\u5305\u542b 3 \u4e2a\u5355\u5143\u64cd\u4f5c\n    return count\n
time_complexity.cpp
/* \u5e73\u65b9\u9636\uff08\u5192\u6ce1\u6392\u5e8f\uff09 */\nint bubbleSort(vector<int> &nums) {\n    int count = 0; // \u8ba1\u6570\u5668\n    // \u5916\u5faa\u73af\uff1a\u672a\u6392\u5e8f\u533a\u95f4\u4e3a [0, i]\n    for (int i = nums.size() - 1; i > 0; i--) {\n        // \u5185\u5faa\u73af\uff1a\u5c06\u672a\u6392\u5e8f\u533a\u95f4 [0, i] \u4e2d\u7684\u6700\u5927\u5143\u7d20\u4ea4\u6362\u81f3\u8be5\u533a\u95f4\u7684\u6700\u53f3\u7aef\n        for (int j = 0; j < i; j++) {\n            if (nums[j] > nums[j + 1]) {\n                // \u4ea4\u6362 nums[j] \u4e0e nums[j + 1]\n                int tmp = nums[j];\n                nums[j] = nums[j + 1];\n                nums[j + 1] = tmp;\n                count += 3; // \u5143\u7d20\u4ea4\u6362\u5305\u542b 3 \u4e2a\u5355\u5143\u64cd\u4f5c\n            }\n        }\n    }\n    return count;\n}\n
time_complexity.java
/* \u5e73\u65b9\u9636\uff08\u5192\u6ce1\u6392\u5e8f\uff09 */\nint bubbleSort(int[] nums) {\n    int count = 0; // \u8ba1\u6570\u5668\n    // \u5916\u5faa\u73af\uff1a\u672a\u6392\u5e8f\u533a\u95f4\u4e3a [0, i]\n    for (int i = nums.length - 1; i > 0; i--) {\n        // \u5185\u5faa\u73af\uff1a\u5c06\u672a\u6392\u5e8f\u533a\u95f4 [0, i] \u4e2d\u7684\u6700\u5927\u5143\u7d20\u4ea4\u6362\u81f3\u8be5\u533a\u95f4\u7684\u6700\u53f3\u7aef\n        for (int j = 0; j < i; j++) {\n            if (nums[j] > nums[j + 1]) {\n                // \u4ea4\u6362 nums[j] \u4e0e nums[j + 1]\n                int tmp = nums[j];\n                nums[j] = nums[j + 1];\n                nums[j + 1] = tmp;\n                count += 3; // \u5143\u7d20\u4ea4\u6362\u5305\u542b 3 \u4e2a\u5355\u5143\u64cd\u4f5c\n            }\n        }\n    }\n    return count;\n}\n
time_complexity.cs
/* \u5e73\u65b9\u9636\uff08\u5192\u6ce1\u6392\u5e8f\uff09 */\nint BubbleSort(int[] nums) {\n    int count = 0;  // \u8ba1\u6570\u5668\n    // \u5916\u5faa\u73af\uff1a\u672a\u6392\u5e8f\u533a\u95f4\u4e3a [0, i]\n    for (int i = nums.Length - 1; i > 0; i--) {\n        // \u5185\u5faa\u73af\uff1a\u5c06\u672a\u6392\u5e8f\u533a\u95f4 [0, i] \u4e2d\u7684\u6700\u5927\u5143\u7d20\u4ea4\u6362\u81f3\u8be5\u533a\u95f4\u7684\u6700\u53f3\u7aef\n        for (int j = 0; j < i; j++) {\n            if (nums[j] > nums[j + 1]) {\n                // \u4ea4\u6362 nums[j] \u4e0e nums[j + 1]\n                (nums[j + 1], nums[j]) = (nums[j], nums[j + 1]);\n                count += 3;  // \u5143\u7d20\u4ea4\u6362\u5305\u542b 3 \u4e2a\u5355\u5143\u64cd\u4f5c\n            }\n        }\n    }\n    return count;\n}\n
time_complexity.go
/* \u5e73\u65b9\u9636\uff08\u5192\u6ce1\u6392\u5e8f\uff09 */\nfunc bubbleSort(nums []int) int {\n    count := 0 // \u8ba1\u6570\u5668\n    // \u5916\u5faa\u73af\uff1a\u672a\u6392\u5e8f\u533a\u95f4\u4e3a [0, i]\n    for i := len(nums) - 1; i > 0; i-- {\n        // \u5185\u5faa\u73af\uff1a\u5c06\u672a\u6392\u5e8f\u533a\u95f4 [0, i] \u4e2d\u7684\u6700\u5927\u5143\u7d20\u4ea4\u6362\u81f3\u8be5\u533a\u95f4\u7684\u6700\u53f3\u7aef\n        for j := 0; j < i; j++ {\n            if nums[j] > nums[j+1] {\n                // \u4ea4\u6362 nums[j] \u4e0e nums[j + 1]\n                tmp := nums[j]\n                nums[j] = nums[j+1]\n                nums[j+1] = tmp\n                count += 3 // \u5143\u7d20\u4ea4\u6362\u5305\u542b 3 \u4e2a\u5355\u5143\u64cd\u4f5c\n            }\n        }\n    }\n    return count\n}\n
time_complexity.swift
/* \u5e73\u65b9\u9636\uff08\u5192\u6ce1\u6392\u5e8f\uff09 */\nfunc bubbleSort(nums: inout [Int]) -> Int {\n    var count = 0 // \u8ba1\u6570\u5668\n    // \u5916\u5faa\u73af\uff1a\u672a\u6392\u5e8f\u533a\u95f4\u4e3a [0, i]\n    for i in nums.indices.dropFirst().reversed() {\n        // \u5185\u5faa\u73af\uff1a\u5c06\u672a\u6392\u5e8f\u533a\u95f4 [0, i] \u4e2d\u7684\u6700\u5927\u5143\u7d20\u4ea4\u6362\u81f3\u8be5\u533a\u95f4\u7684\u6700\u53f3\u7aef\n        for j in 0 ..< i {\n            if nums[j] > nums[j + 1] {\n                // \u4ea4\u6362 nums[j] \u4e0e nums[j + 1]\n                let tmp = nums[j]\n                nums[j] = nums[j + 1]\n                nums[j + 1] = tmp\n                count += 3 // \u5143\u7d20\u4ea4\u6362\u5305\u542b 3 \u4e2a\u5355\u5143\u64cd\u4f5c\n            }\n        }\n    }\n    return count\n}\n
time_complexity.js
/* \u5e73\u65b9\u9636\uff08\u5192\u6ce1\u6392\u5e8f\uff09 */\nfunction bubbleSort(nums) {\n    let count = 0; // \u8ba1\u6570\u5668\n    // \u5916\u5faa\u73af\uff1a\u672a\u6392\u5e8f\u533a\u95f4\u4e3a [0, i]\n    for (let i = nums.length - 1; i > 0; i--) {\n        // \u5185\u5faa\u73af\uff1a\u5c06\u672a\u6392\u5e8f\u533a\u95f4 [0, i] \u4e2d\u7684\u6700\u5927\u5143\u7d20\u4ea4\u6362\u81f3\u8be5\u533a\u95f4\u7684\u6700\u53f3\u7aef\n        for (let j = 0; j < i; j++) {\n            if (nums[j] > nums[j + 1]) {\n                // \u4ea4\u6362 nums[j] \u4e0e nums[j + 1]\n                let tmp = nums[j];\n                nums[j] = nums[j + 1];\n                nums[j + 1] = tmp;\n                count += 3; // \u5143\u7d20\u4ea4\u6362\u5305\u542b 3 \u4e2a\u5355\u5143\u64cd\u4f5c\n            }\n        }\n    }\n    return count;\n}\n
time_complexity.ts
/* \u5e73\u65b9\u9636\uff08\u5192\u6ce1\u6392\u5e8f\uff09 */\nfunction bubbleSort(nums: number[]): number {\n    let count = 0; // \u8ba1\u6570\u5668\n    // \u5916\u5faa\u73af\uff1a\u672a\u6392\u5e8f\u533a\u95f4\u4e3a [0, i]\n    for (let i = nums.length - 1; i > 0; i--) {\n        // \u5185\u5faa\u73af\uff1a\u5c06\u672a\u6392\u5e8f\u533a\u95f4 [0, i] \u4e2d\u7684\u6700\u5927\u5143\u7d20\u4ea4\u6362\u81f3\u8be5\u533a\u95f4\u7684\u6700\u53f3\u7aef\n        for (let j = 0; j < i; j++) {\n            if (nums[j] > nums[j + 1]) {\n                // \u4ea4\u6362 nums[j] \u4e0e nums[j + 1]\n                let tmp = nums[j];\n                nums[j] = nums[j + 1];\n                nums[j + 1] = tmp;\n                count += 3; // \u5143\u7d20\u4ea4\u6362\u5305\u542b 3 \u4e2a\u5355\u5143\u64cd\u4f5c\n            }\n        }\n    }\n    return count;\n}\n
time_complexity.dart
/* \u5e73\u65b9\u9636\uff08\u5192\u6ce1\u6392\u5e8f\uff09 */\nint bubbleSort(List<int> nums) {\n  int count = 0; // \u8ba1\u6570\u5668\n  // \u5916\u5faa\u73af\uff1a\u672a\u6392\u5e8f\u533a\u95f4\u4e3a [0, i]\n  for (var i = nums.length - 1; i > 0; i--) {\n    // \u5185\u5faa\u73af\uff1a\u5c06\u672a\u6392\u5e8f\u533a\u95f4 [0, i] \u4e2d\u7684\u6700\u5927\u5143\u7d20\u4ea4\u6362\u81f3\u8be5\u533a\u95f4\u7684\u6700\u53f3\u7aef\n    for (var j = 0; j < i; j++) {\n      if (nums[j] > nums[j + 1]) {\n        // \u4ea4\u6362 nums[j] \u4e0e nums[j + 1]\n        int tmp = nums[j];\n        nums[j] = nums[j + 1];\n        nums[j + 1] = tmp;\n        count += 3; // \u5143\u7d20\u4ea4\u6362\u5305\u542b 3 \u4e2a\u5355\u5143\u64cd\u4f5c\n      }\n    }\n  }\n  return count;\n}\n
time_complexity.rs
/* \u5e73\u65b9\u9636\uff08\u5192\u6ce1\u6392\u5e8f\uff09 */\nfn bubble_sort(nums: &mut [i32]) -> i32 {\n    let mut count = 0; // \u8ba1\u6570\u5668\n\n    // \u5916\u5faa\u73af\uff1a\u672a\u6392\u5e8f\u533a\u95f4\u4e3a [0, i]\n    for i in (1..nums.len()).rev() {\n        // \u5185\u5faa\u73af\uff1a\u5c06\u672a\u6392\u5e8f\u533a\u95f4 [0, i] \u4e2d\u7684\u6700\u5927\u5143\u7d20\u4ea4\u6362\u81f3\u8be5\u533a\u95f4\u7684\u6700\u53f3\u7aef\n        for j in 0..i {\n            if nums[j] > nums[j + 1] {\n                // \u4ea4\u6362 nums[j] \u4e0e nums[j + 1]\n                let tmp = nums[j];\n                nums[j] = nums[j + 1];\n                nums[j + 1] = tmp;\n                count += 3; // \u5143\u7d20\u4ea4\u6362\u5305\u542b 3 \u4e2a\u5355\u5143\u64cd\u4f5c\n            }\n        }\n    }\n    count\n}\n
time_complexity.c
/* \u5e73\u65b9\u9636\uff08\u5192\u6ce1\u6392\u5e8f\uff09 */\nint bubbleSort(int *nums, int n) {\n    int count = 0; // \u8ba1\u6570\u5668\n    // \u5916\u5faa\u73af\uff1a\u672a\u6392\u5e8f\u533a\u95f4\u4e3a [0, i]\n    for (int i = n - 1; i > 0; i--) {\n        // \u5185\u5faa\u73af\uff1a\u5c06\u672a\u6392\u5e8f\u533a\u95f4 [0, i] \u4e2d\u7684\u6700\u5927\u5143\u7d20\u4ea4\u6362\u81f3\u8be5\u533a\u95f4\u7684\u6700\u53f3\u7aef\n        for (int j = 0; j < i; j++) {\n            if (nums[j] > nums[j + 1]) {\n                // \u4ea4\u6362 nums[j] \u4e0e nums[j + 1]\n                int tmp = nums[j];\n                nums[j] = nums[j + 1];\n                nums[j + 1] = tmp;\n                count += 3; // \u5143\u7d20\u4ea4\u6362\u5305\u542b 3 \u4e2a\u5355\u5143\u64cd\u4f5c\n            }\n        }\n    }\n    return count;\n}\n
time_complexity.zig
// \u5e73\u65b9\u9636\uff08\u5192\u6ce1\u6392\u5e8f\uff09\nfn bubbleSort(nums: []i32) i32 {\n    var count: i32 = 0;  // \u8ba1\u6570\u5668 \n    // \u5916\u5faa\u73af\uff1a\u672a\u6392\u5e8f\u533a\u95f4\u4e3a [0, i]\n    var i: i32 = @as(i32, @intCast(nums.len)) - 1;\n    while (i > 0) : (i -= 1) {\n        var j: usize = 0;\n        // \u5185\u5faa\u73af\uff1a\u5c06\u672a\u6392\u5e8f\u533a\u95f4 [0, i] \u4e2d\u7684\u6700\u5927\u5143\u7d20\u4ea4\u6362\u81f3\u8be5\u533a\u95f4\u7684\u6700\u53f3\u7aef\n        while (j < i) : (j += 1) {\n            if (nums[j] > nums[j + 1]) {\n                // \u4ea4\u6362 nums[j] \u4e0e nums[j + 1]\n                var tmp = nums[j];\n                nums[j] = nums[j + 1];\n                nums[j + 1] = tmp;\n                count += 3;  // \u5143\u7d20\u4ea4\u6362\u5305\u542b 3 \u4e2a\u5355\u5143\u64cd\u4f5c\n            }\n        }\n    }\n    return count;\n}\n
Code Visualization

Full Screen >

"},{"location":"chapter_computational_complexity/time_complexity/#4-exponential-order-o2n","title":"4. \u00a0 Exponential Order \\(O(2^n)\\)","text":"

Biological \"cell division\" is a classic example of exponential order growth: starting with one cell, it becomes two after one division, four after two divisions, and so on, resulting in \\(2^n\\) cells after \\(n\\) divisions.

The following image and code simulate the cell division process, with a time complexity of \\(O(2^n)\\):

PythonC++JavaC#GoSwiftJSTSDartRustCZig time_complexity.py
def exponential(n: int) -> int:\n    \"\"\"\u6307\u6570\u9636\uff08\u5faa\u73af\u5b9e\u73b0\uff09\"\"\"\n    count = 0\n    base = 1\n    # \u7ec6\u80de\u6bcf\u8f6e\u4e00\u5206\u4e3a\u4e8c\uff0c\u5f62\u6210\u6570\u5217 1, 2, 4, 8, ..., 2^(n-1)\n    for _ in range(n):\n        for _ in range(base):\n            count += 1\n        base *= 2\n    # count = 1 + 2 + 4 + 8 + .. + 2^(n-1) = 2^n - 1\n    return count\n
time_complexity.cpp
/* \u6307\u6570\u9636\uff08\u5faa\u73af\u5b9e\u73b0\uff09 */\nint exponential(int n) {\n    int count = 0, base = 1;\n    // \u7ec6\u80de\u6bcf\u8f6e\u4e00\u5206\u4e3a\u4e8c\uff0c\u5f62\u6210\u6570\u5217 1, 2, 4, 8, ..., 2^(n-1)\n    for (int i = 0; i < n; i++) {\n        for (int j = 0; j < base; j++) {\n            count++;\n        }\n        base *= 2;\n    }\n    // count = 1 + 2 + 4 + 8 + .. + 2^(n-1) = 2^n - 1\n    return count;\n}\n
time_complexity.java
/* \u6307\u6570\u9636\uff08\u5faa\u73af\u5b9e\u73b0\uff09 */\nint exponential(int n) {\n    int count = 0, base = 1;\n    // \u7ec6\u80de\u6bcf\u8f6e\u4e00\u5206\u4e3a\u4e8c\uff0c\u5f62\u6210\u6570\u5217 1, 2, 4, 8, ..., 2^(n-1)\n    for (int i = 0; i < n; i++) {\n        for (int j = 0; j < base; j++) {\n            count++;\n        }\n        base *= 2;\n    }\n    // count = 1 + 2 + 4 + 8 + .. + 2^(n-1) = 2^n - 1\n    return count;\n}\n
time_complexity.cs
/* \u6307\u6570\u9636\uff08\u5faa\u73af\u5b9e\u73b0\uff09 */\nint Exponential(int n) {\n    int count = 0, bas = 1;\n    // \u7ec6\u80de\u6bcf\u8f6e\u4e00\u5206\u4e3a\u4e8c\uff0c\u5f62\u6210\u6570\u5217 1, 2, 4, 8, ..., 2^(n-1)\n    for (int i = 0; i < n; i++) {\n        for (int j = 0; j < bas; j++) {\n            count++;\n        }\n        bas *= 2;\n    }\n    // count = 1 + 2 + 4 + 8 + .. + 2^(n-1) = 2^n - 1\n    return count;\n}\n
time_complexity.go
/* \u6307\u6570\u9636\uff08\u5faa\u73af\u5b9e\u73b0\uff09*/\nfunc exponential(n int) int {\n    count, base := 0, 1\n    // \u7ec6\u80de\u6bcf\u8f6e\u4e00\u5206\u4e3a\u4e8c\uff0c\u5f62\u6210\u6570\u5217 1, 2, 4, 8, ..., 2^(n-1)\n    for i := 0; i < n; i++ {\n        for j := 0; j < base; j++ {\n            count++\n        }\n        base *= 2\n    }\n    // count = 1 + 2 + 4 + 8 + .. + 2^(n-1) = 2^n - 1\n    return count\n}\n
time_complexity.swift
/* \u6307\u6570\u9636\uff08\u5faa\u73af\u5b9e\u73b0\uff09 */\nfunc exponential(n: Int) -> Int {\n    var count = 0\n    var base = 1\n    // \u7ec6\u80de\u6bcf\u8f6e\u4e00\u5206\u4e3a\u4e8c\uff0c\u5f62\u6210\u6570\u5217 1, 2, 4, 8, ..., 2^(n-1)\n    for _ in 0 ..< n {\n        for _ in 0 ..< base {\n            count += 1\n        }\n        base *= 2\n    }\n    // count = 1 + 2 + 4 + 8 + .. + 2^(n-1) = 2^n - 1\n    return count\n}\n
time_complexity.js
/* \u6307\u6570\u9636\uff08\u5faa\u73af\u5b9e\u73b0\uff09 */\nfunction exponential(n) {\n    let count = 0,\n        base = 1;\n    // \u7ec6\u80de\u6bcf\u8f6e\u4e00\u5206\u4e3a\u4e8c\uff0c\u5f62\u6210\u6570\u5217 1, 2, 4, 8, ..., 2^(n-1)\n    for (let i = 0; i < n; i++) {\n        for (let j = 0; j < base; j++) {\n            count++;\n        }\n        base *= 2;\n    }\n    // count = 1 + 2 + 4 + 8 + .. + 2^(n-1) = 2^n - 1\n    return count;\n}\n
time_complexity.ts
/* \u6307\u6570\u9636\uff08\u5faa\u73af\u5b9e\u73b0\uff09 */\nfunction exponential(n: number): number {\n    let count = 0,\n        base = 1;\n    // \u7ec6\u80de\u6bcf\u8f6e\u4e00\u5206\u4e3a\u4e8c\uff0c\u5f62\u6210\u6570\u5217 1, 2, 4, 8, ..., 2^(n-1)\n    for (let i = 0; i < n; i++) {\n        for (let j = 0; j < base; j++) {\n            count++;\n        }\n        base *= 2;\n    }\n    // count = 1 + 2 + 4 + 8 + .. + 2^(n-1) = 2^n - 1\n    return count;\n}\n
time_complexity.dart
/* \u6307\u6570\u9636\uff08\u5faa\u73af\u5b9e\u73b0\uff09 */\nint exponential(int n) {\n  int count = 0, base = 1;\n  // \u7ec6\u80de\u6bcf\u8f6e\u4e00\u5206\u4e3a\u4e8c\uff0c\u5f62\u6210\u6570\u5217 1, 2, 4, 8, ..., 2^(n-1)\n  for (var i = 0; i < n; i++) {\n    for (var j = 0; j < base; j++) {\n      count++;\n    }\n    base *= 2;\n  }\n  // count = 1 + 2 + 4 + 8 + .. + 2^(n-1) = 2^n - 1\n  return count;\n}\n
time_complexity.rs
/* \u6307\u6570\u9636\uff08\u5faa\u73af\u5b9e\u73b0\uff09 */\nfn exponential(n: i32) -> i32 {\n    let mut count = 0;\n    let mut base = 1;\n    // \u7ec6\u80de\u6bcf\u8f6e\u4e00\u5206\u4e3a\u4e8c\uff0c\u5f62\u6210\u6570\u5217 1, 2, 4, 8, ..., 2^(n-1)\n    for _ in 0..n {\n        for _ in 0..base {\n            count += 1\n        }\n        base *= 2;\n    }\n    // count = 1 + 2 + 4 + 8 + .. + 2^(n-1) = 2^n - 1\n    count\n}\n
time_complexity.c
/* \u6307\u6570\u9636\uff08\u5faa\u73af\u5b9e\u73b0\uff09 */\nint exponential(int n) {\n    int count = 0;\n    int bas = 1;\n    // \u7ec6\u80de\u6bcf\u8f6e\u4e00\u5206\u4e3a\u4e8c\uff0c\u5f62\u6210\u6570\u5217 1, 2, 4, 8, ..., 2^(n-1)\n    for (int i = 0; i < n; i++) {\n        for (int j = 0; j < bas; j++) {\n            count++;\n        }\n        bas *= 2;\n    }\n    // count = 1 + 2 + 4 + 8 + .. + 2^(n-1) = 2^n - 1\n    return count;\n}\n
time_complexity.zig
// \u6307\u6570\u9636\uff08\u5faa\u73af\u5b9e\u73b0\uff09\nfn exponential(n: i32) i32 {\n    var count: i32 = 0;\n    var bas: i32 = 1;\n    var i: i32 = 0;\n    // \u7ec6\u80de\u6bcf\u8f6e\u4e00\u5206\u4e3a\u4e8c\uff0c\u5f62\u6210\u6570\u5217 1, 2, 4, 8, ..., 2^(n-1)\n    while (i < n) : (i += 1) {\n        var j: i32 = 0;\n        while (j < bas) : (j += 1) {\n            count += 1;\n        }\n        bas *= 2;\n    }\n    // count = 1 + 2 + 4 + 8 + .. + 2^(n-1) = 2^n - 1\n    return count;\n}\n
Code Visualization

Full Screen >

Figure 2-11 \u00a0 Exponential Order Time Complexity

In practice, exponential order often appears in recursive functions. For example, in the code below, it recursively splits into two halves, stopping after \\(n\\) divisions:

PythonC++JavaC#GoSwiftJSTSDartRustCZig time_complexity.py
def exp_recur(n: int) -> int:\n    \"\"\"\u6307\u6570\u9636\uff08\u9012\u5f52\u5b9e\u73b0\uff09\"\"\"\n    if n == 1:\n        return 1\n    return exp_recur(n - 1) + exp_recur(n - 1) + 1\n
time_complexity.cpp
/* \u6307\u6570\u9636\uff08\u9012\u5f52\u5b9e\u73b0\uff09 */\nint expRecur(int n) {\n    if (n == 1)\n        return 1;\n    return expRecur(n - 1) + expRecur(n - 1) + 1;\n}\n
time_complexity.java
/* \u6307\u6570\u9636\uff08\u9012\u5f52\u5b9e\u73b0\uff09 */\nint expRecur(int n) {\n    if (n == 1)\n        return 1;\n    return expRecur(n - 1) + expRecur(n - 1) + 1;\n}\n
time_complexity.cs
/* \u6307\u6570\u9636\uff08\u9012\u5f52\u5b9e\u73b0\uff09 */\nint ExpRecur(int n) {\n    if (n == 1) return 1;\n    return ExpRecur(n - 1) + ExpRecur(n - 1) + 1;\n}\n
time_complexity.go
/* \u6307\u6570\u9636\uff08\u9012\u5f52\u5b9e\u73b0\uff09*/\nfunc expRecur(n int) int {\n    if n == 1 {\n        return 1\n    }\n    return expRecur(n-1) + expRecur(n-1) + 1\n}\n
time_complexity.swift
/* \u6307\u6570\u9636\uff08\u9012\u5f52\u5b9e\u73b0\uff09 */\nfunc expRecur(n: Int) -> Int {\n    if n == 1 {\n        return 1\n    }\n    return expRecur(n: n - 1) + expRecur(n: n - 1) + 1\n}\n
time_complexity.js
/* \u6307\u6570\u9636\uff08\u9012\u5f52\u5b9e\u73b0\uff09 */\nfunction expRecur(n) {\n    if (n === 1) return 1;\n    return expRecur(n - 1) + expRecur(n - 1) + 1;\n}\n
time_complexity.ts
/* \u6307\u6570\u9636\uff08\u9012\u5f52\u5b9e\u73b0\uff09 */\nfunction expRecur(n: number): number {\n    if (n === 1) return 1;\n    return expRecur(n - 1) + expRecur(n - 1) + 1;\n}\n
time_complexity.dart
/* \u6307\u6570\u9636\uff08\u9012\u5f52\u5b9e\u73b0\uff09 */\nint expRecur(int n) {\n  if (n == 1) return 1;\n  return expRecur(n - 1) + expRecur(n - 1) + 1;\n}\n
time_complexity.rs
/* \u6307\u6570\u9636\uff08\u9012\u5f52\u5b9e\u73b0\uff09 */\nfn exp_recur(n: i32) -> i32 {\n    if n == 1 {\n        return 1;\n    }\n    exp_recur(n - 1) + exp_recur(n - 1) + 1\n}\n
time_complexity.c
/* \u6307\u6570\u9636\uff08\u9012\u5f52\u5b9e\u73b0\uff09 */\nint expRecur(int n) {\n    if (n == 1)\n        return 1;\n    return expRecur(n - 1) + expRecur(n - 1) + 1;\n}\n
time_complexity.zig
// \u6307\u6570\u9636\uff08\u9012\u5f52\u5b9e\u73b0\uff09\nfn expRecur(n: i32) i32 {\n    if (n == 1) return 1;\n    return expRecur(n - 1) + expRecur(n - 1) + 1;\n}\n
Code Visualization

Full Screen >

Exponential order growth is extremely rapid and is commonly seen in exhaustive search methods (brute force, backtracking, etc.). For large-scale problems, exponential order is unacceptable, often requiring dynamic programming or greedy algorithms as solutions.

"},{"location":"chapter_computational_complexity/time_complexity/#5-logarithmic-order-olog-n","title":"5. \u00a0 Logarithmic Order \\(O(\\log n)\\)","text":"

In contrast to exponential order, logarithmic order reflects situations where \"the size is halved each round.\" Given an input data size \\(n\\), since the size is halved each round, the number of iterations is \\(\\log_2 n\\), the inverse function of \\(2^n\\).

The following image and code simulate the \"halving each round\" process, with a time complexity of \\(O(\\log_2 n)\\), commonly abbreviated as \\(O(\\log n)\\):

PythonC++JavaC#GoSwiftJSTSDartRustCZig time_complexity.py
def logarithmic(n: int) -> int:\n    \"\"\"\u5bf9\u6570\u9636\uff08\u5faa\u73af\u5b9e\u73b0\uff09\"\"\"\n    count = 0\n    while n > 1:\n        n = n / 2\n        count += 1\n    return count\n
time_complexity.cpp
/* \u5bf9\u6570\u9636\uff08\u5faa\u73af\u5b9e\u73b0\uff09 */\nint logarithmic(int n) {\n    int count = 0;\n    while (n > 1) {\n        n = n / 2;\n        count++;\n    }\n    return count;\n}\n
time_complexity.java
/* \u5bf9\u6570\u9636\uff08\u5faa\u73af\u5b9e\u73b0\uff09 */\nint logarithmic(int n) {\n    int count = 0;\n    while (n > 1) {\n        n = n / 2;\n        count++;\n    }\n    return count;\n}\n
time_complexity.cs
/* \u5bf9\u6570\u9636\uff08\u5faa\u73af\u5b9e\u73b0\uff09 */\nint Logarithmic(int n) {\n    int count = 0;\n    while (n > 1) {\n        n /= 2;\n        count++;\n    }\n    return count;\n}\n
time_complexity.go
/* \u5bf9\u6570\u9636\uff08\u5faa\u73af\u5b9e\u73b0\uff09*/\nfunc logarithmic(n int) int {\n    count := 0\n    for n > 1 {\n        n = n / 2\n        count++\n    }\n    return count\n}\n
time_complexity.swift
/* \u5bf9\u6570\u9636\uff08\u5faa\u73af\u5b9e\u73b0\uff09 */\nfunc logarithmic(n: Int) -> Int {\n    var count = 0\n    var n = n\n    while n > 1 {\n        n = n / 2\n        count += 1\n    }\n    return count\n}\n
time_complexity.js
/* \u5bf9\u6570\u9636\uff08\u5faa\u73af\u5b9e\u73b0\uff09 */\nfunction logarithmic(n) {\n    let count = 0;\n    while (n > 1) {\n        n = n / 2;\n        count++;\n    }\n    return count;\n}\n
time_complexity.ts
/* \u5bf9\u6570\u9636\uff08\u5faa\u73af\u5b9e\u73b0\uff09 */\nfunction logarithmic(n: number): number {\n    let count = 0;\n    while (n > 1) {\n        n = n / 2;\n        count++;\n    }\n    return count;\n}\n
time_complexity.dart
/* \u5bf9\u6570\u9636\uff08\u5faa\u73af\u5b9e\u73b0\uff09 */\nint logarithmic(int n) {\n  int count = 0;\n  while (n > 1) {\n    n = n ~/ 2;\n    count++;\n  }\n  return count;\n}\n
time_complexity.rs
/* \u5bf9\u6570\u9636\uff08\u5faa\u73af\u5b9e\u73b0\uff09 */\nfn logarithmic(mut n: i32) -> i32 {\n    let mut count = 0;\n    while n > 1 {\n        n = n / 2;\n        count += 1;\n    }\n    count\n}\n
time_complexity.c
/* \u5bf9\u6570\u9636\uff08\u5faa\u73af\u5b9e\u73b0\uff09 */\nint logarithmic(int n) {\n    int count = 0;\n    while (n > 1) {\n        n = n / 2;\n        count++;\n    }\n    return count;\n}\n
time_complexity.zig
// \u5bf9\u6570\u9636\uff08\u5faa\u73af\u5b9e\u73b0\uff09\nfn logarithmic(n: i32) i32 {\n    var count: i32 = 0;\n    var n_var = n;\n    while (n_var > 1)\n    {\n        n_var = n_var / 2;\n        count +=1;\n    }\n    return count;\n}\n
Code Visualization

Full Screen >

Figure 2-12 \u00a0 Logarithmic Order Time Complexity

Like exponential order, logarithmic order also frequently appears in recursive functions. The code below forms a recursive tree of height \\(\\log_2 n\\):

PythonC++JavaC#GoSwiftJSTSDartRustCZig time_complexity.py
def log_recur(n: int) -> int:\n    \"\"\"\u5bf9\u6570\u9636\uff08\u9012\u5f52\u5b9e\u73b0\uff09\"\"\"\n    if n <= 1:\n        return 0\n    return log_recur(n / 2) + 1\n
time_complexity.cpp
/* \u5bf9\u6570\u9636\uff08\u9012\u5f52\u5b9e\u73b0\uff09 */\nint logRecur(int n) {\n    if (n <= 1)\n        return 0;\n    return logRecur(n / 2) + 1;\n}\n
time_complexity.java
/* \u5bf9\u6570\u9636\uff08\u9012\u5f52\u5b9e\u73b0\uff09 */\nint logRecur(int n) {\n    if (n <= 1)\n        return 0;\n    return logRecur(n / 2) + 1;\n}\n
time_complexity.cs
/* \u5bf9\u6570\u9636\uff08\u9012\u5f52\u5b9e\u73b0\uff09 */\nint LogRecur(int n) {\n    if (n <= 1) return 0;\n    return LogRecur(n / 2) + 1;\n}\n
time_complexity.go
/* \u5bf9\u6570\u9636\uff08\u9012\u5f52\u5b9e\u73b0\uff09*/\nfunc logRecur(n int) int {\n    if n <= 1 {\n        return 0\n    }\n    return logRecur(n/2) + 1\n}\n
time_complexity.swift
/* \u5bf9\u6570\u9636\uff08\u9012\u5f52\u5b9e\u73b0\uff09 */\nfunc logRecur(n: Int) -> Int {\n    if n <= 1 {\n        return 0\n    }\n    return logRecur(n: n / 2) + 1\n}\n
time_complexity.js
/* \u5bf9\u6570\u9636\uff08\u9012\u5f52\u5b9e\u73b0\uff09 */\nfunction logRecur(n) {\n    if (n <= 1) return 0;\n    return logRecur(n / 2) + 1;\n}\n
time_complexity.ts
/* \u5bf9\u6570\u9636\uff08\u9012\u5f52\u5b9e\u73b0\uff09 */\nfunction logRecur(n: number): number {\n    if (n <= 1) return 0;\n    return logRecur(n / 2) + 1;\n}\n
time_complexity.dart
/* \u5bf9\u6570\u9636\uff08\u9012\u5f52\u5b9e\u73b0\uff09 */\nint logRecur(int n) {\n  if (n <= 1) return 0;\n  return logRecur(n ~/ 2) + 1;\n}\n
time_complexity.rs
/* \u5bf9\u6570\u9636\uff08\u9012\u5f52\u5b9e\u73b0\uff09 */\nfn log_recur(n: i32) -> i32 {\n    if n <= 1 {\n        return 0;\n    }\n    log_recur(n / 2) + 1\n}\n
time_complexity.c
/* \u5bf9\u6570\u9636\uff08\u9012\u5f52\u5b9e\u73b0\uff09 */\nint logRecur(int n) {\n    if (n <= 1)\n        return 0;\n    return logRecur(n / 2) + 1;\n}\n
time_complexity.zig
// \u5bf9\u6570\u9636\uff08\u9012\u5f52\u5b9e\u73b0\uff09\nfn logRecur(n: i32) i32 {\n    if (n <= 1) return 0;\n    return logRecur(n / 2) + 1;\n}\n
Code Visualization

Full Screen >

Logarithmic order is typical in algorithms based on the divide-and-conquer strategy, embodying the \"split into many\" and \"simplify complex problems\" approach. It's slow-growing and is the most ideal time complexity after constant order.

What is the base of \\(O(\\log n)\\)?

Technically, \"splitting into \\(m\\)\" corresponds to a time complexity of \\(O(\\log_m n)\\). Using the logarithm base change formula, we can equate different logarithmic complexities:

\\[ O(\\log_m n) = O(\\log_k n / \\log_k m) = O(\\log_k n) \\]

This means the base \\(m\\) can be changed without affecting the complexity. Therefore, we often omit the base \\(m\\) and simply denote logarithmic order as \\(O(\\log n)\\).

"},{"location":"chapter_computational_complexity/time_complexity/#6-linear-logarithmic-order-on-log-n","title":"6. \u00a0 Linear-Logarithmic Order \\(O(n \\log n)\\)","text":"

Linear-logarithmic order often appears in nested loops, with the complexities of the two loops being \\(O(\\log n)\\) and \\(O(n)\\) respectively. The related code is as follows:

PythonC++JavaC#GoSwiftJSTSDartRustCZig time_complexity.py
def linear_log_recur(n: int) -> int:\n    \"\"\"\u7ebf\u6027\u5bf9\u6570\u9636\"\"\"\n    if n <= 1:\n        return 1\n    count: int = linear_log_recur(n // 2) + linear_log_recur(n // 2)\n    for _ in range(n):\n        count += 1\n    return count\n
time_complexity.cpp
/* \u7ebf\u6027\u5bf9\u6570\u9636 */\nint linearLogRecur(int n) {\n    if (n <= 1)\n        return 1;\n    int count = linearLogRecur(n / 2) + linearLogRecur(n / 2);\n    for (int i = 0; i < n; i++) {\n        count++;\n    }\n    return count;\n}\n
time_complexity.java
/* \u7ebf\u6027\u5bf9\u6570\u9636 */\nint linearLogRecur(int n) {\n    if (n <= 1)\n        return 1;\n    int count = linearLogRecur(n / 2) + linearLogRecur(n / 2);\n    for (int i = 0; i < n; i++) {\n        count++;\n    }\n    return count;\n}\n
time_complexity.cs
/* \u7ebf\u6027\u5bf9\u6570\u9636 */\nint LinearLogRecur(int n) {\n    if (n <= 1) return 1;\n    int count = LinearLogRecur(n / 2) + LinearLogRecur(n / 2);\n    for (int i = 0; i < n; i++) {\n        count++;\n    }\n    return count;\n}\n
time_complexity.go
/* \u7ebf\u6027\u5bf9\u6570\u9636 */\nfunc linearLogRecur(n int) int {\n    if n <= 1 {\n        return 1\n    }\n    count := linearLogRecur(n/2) + linearLogRecur(n/2)\n    for i := 0; i < n; i++ {\n        count++\n    }\n    return count\n}\n
time_complexity.swift
/* \u7ebf\u6027\u5bf9\u6570\u9636 */\nfunc linearLogRecur(n: Int) -> Int {\n    if n <= 1 {\n        return 1\n    }\n    var count = linearLogRecur(n: n / 2) + linearLogRecur(n: n / 2)\n    for _ in stride(from: 0, to: n, by: 1) {\n        count += 1\n    }\n    return count\n}\n
time_complexity.js
/* \u7ebf\u6027\u5bf9\u6570\u9636 */\nfunction linearLogRecur(n) {\n    if (n <= 1) return 1;\n    let count = linearLogRecur(n / 2) + linearLogRecur(n / 2);\n    for (let i = 0; i < n; i++) {\n        count++;\n    }\n    return count;\n}\n
time_complexity.ts
/* \u7ebf\u6027\u5bf9\u6570\u9636 */\nfunction linearLogRecur(n: number): number {\n    if (n <= 1) return 1;\n    let count = linearLogRecur(n / 2) + linearLogRecur(n / 2);\n    for (let i = 0; i < n; i++) {\n        count++;\n    }\n    return count;\n}\n
time_complexity.dart
/* \u7ebf\u6027\u5bf9\u6570\u9636 */\nint linearLogRecur(int n) {\n  if (n <= 1) return 1;\n  int count = linearLogRecur(n ~/ 2) + linearLogRecur(n ~/ 2);\n  for (var i = 0; i < n; i++) {\n    count++;\n  }\n  return count;\n}\n
time_complexity.rs
/* \u7ebf\u6027\u5bf9\u6570\u9636 */\nfn linear_log_recur(n: i32) -> i32 {\n    if n <= 1 {\n        return 1;\n    }\n    let mut count = linear_log_recur(n / 2) + linear_log_recur(n / 2);\n    for _ in 0..n as i32 {\n        count += 1;\n    }\n    return count;\n}\n
time_complexity.c
/* \u7ebf\u6027\u5bf9\u6570\u9636 */\nint linearLogRecur(int n) {\n    if (n <= 1)\n        return 1;\n    int count = linearLogRecur(n / 2) + linearLogRecur(n / 2);\n    for (int i = 0; i < n; i++) {\n        count++;\n    }\n    return count;\n}\n
time_complexity.zig
// \u7ebf\u6027\u5bf9\u6570\u9636\nfn linearLogRecur(n: i32) i32 {\n    if (n <= 1) return 1;\n    var count: i32 = linearLogRecur(n / 2) + linearLogRecur(n / 2);\n    var i: i32 = 0;\n    while (i < n) : (i += 1) {\n        count += 1;\n    }\n    return count;\n}\n
Code Visualization

Full Screen >

The image below demonstrates how linear-logarithmic order is generated. Each level of a binary tree has \\(n\\) operations, and the tree has \\(\\log_2 n + 1\\) levels, resulting in a time complexity of \\(O(n \\log n)\\).

Figure 2-13 \u00a0 Linear-Logarithmic Order Time Complexity

Mainstream sorting algorithms typically have a time complexity of \\(O(n \\log n)\\), such as quicksort, mergesort, and heapsort.

"},{"location":"chapter_computational_complexity/time_complexity/#7-factorial-order-on","title":"7. \u00a0 Factorial Order \\(O(n!)\\)","text":"

Factorial order corresponds to the mathematical problem of \"full permutation.\" Given \\(n\\) distinct elements, the total number of possible permutations is:

\\[ n! = n \\times (n - 1) \\times (n - 2) \\times \\dots \\times 2 \\times 1 \\]

Factorials are typically implemented using recursion. As shown in the image and code below, the first level splits into \\(n\\) branches, the second level into \\(n - 1\\) branches, and so on, stopping after the \\(n\\)th level:

PythonC++JavaC#GoSwiftJSTSDartRustCZig time_complexity.py
def factorial_recur(n: int) -> int:\n    \"\"\"\u9636\u4e58\u9636\uff08\u9012\u5f52\u5b9e\u73b0\uff09\"\"\"\n    if n == 0:\n        return 1\n    count = 0\n    # \u4ece 1 \u4e2a\u5206\u88c2\u51fa n \u4e2a\n    for _ in range(n):\n        count += factorial_recur(n - 1)\n    return count\n
time_complexity.cpp
/* \u9636\u4e58\u9636\uff08\u9012\u5f52\u5b9e\u73b0\uff09 */\nint factorialRecur(int n) {\n    if (n == 0)\n        return 1;\n    int count = 0;\n    // \u4ece 1 \u4e2a\u5206\u88c2\u51fa n \u4e2a\n    for (int i = 0; i < n; i++) {\n        count += factorialRecur(n - 1);\n    }\n    return count;\n}\n
time_complexity.java
/* \u9636\u4e58\u9636\uff08\u9012\u5f52\u5b9e\u73b0\uff09 */\nint factorialRecur(int n) {\n    if (n == 0)\n        return 1;\n    int count = 0;\n    // \u4ece 1 \u4e2a\u5206\u88c2\u51fa n \u4e2a\n    for (int i = 0; i < n; i++) {\n        count += factorialRecur(n - 1);\n    }\n    return count;\n}\n
time_complexity.cs
/* \u9636\u4e58\u9636\uff08\u9012\u5f52\u5b9e\u73b0\uff09 */\nint FactorialRecur(int n) {\n    if (n == 0) return 1;\n    int count = 0;\n    // \u4ece 1 \u4e2a\u5206\u88c2\u51fa n \u4e2a\n    for (int i = 0; i < n; i++) {\n        count += FactorialRecur(n - 1);\n    }\n    return count;\n}\n
time_complexity.go
/* \u9636\u4e58\u9636\uff08\u9012\u5f52\u5b9e\u73b0\uff09 */\nfunc factorialRecur(n int) int {\n    if n == 0 {\n        return 1\n    }\n    count := 0\n    // \u4ece 1 \u4e2a\u5206\u88c2\u51fa n \u4e2a\n    for i := 0; i < n; i++ {\n        count += factorialRecur(n - 1)\n    }\n    return count\n}\n
time_complexity.swift
/* \u9636\u4e58\u9636\uff08\u9012\u5f52\u5b9e\u73b0\uff09 */\nfunc factorialRecur(n: Int) -> Int {\n    if n == 0 {\n        return 1\n    }\n    var count = 0\n    // \u4ece 1 \u4e2a\u5206\u88c2\u51fa n \u4e2a\n    for _ in 0 ..< n {\n        count += factorialRecur(n: n - 1)\n    }\n    return count\n}\n
time_complexity.js
/* \u9636\u4e58\u9636\uff08\u9012\u5f52\u5b9e\u73b0\uff09 */\nfunction factorialRecur(n) {\n    if (n === 0) return 1;\n    let count = 0;\n    // \u4ece 1 \u4e2a\u5206\u88c2\u51fa n \u4e2a\n    for (let i = 0; i < n; i++) {\n        count += factorialRecur(n - 1);\n    }\n    return count;\n}\n
time_complexity.ts
/* \u9636\u4e58\u9636\uff08\u9012\u5f52\u5b9e\u73b0\uff09 */\nfunction factorialRecur(n: number): number {\n    if (n === 0) return 1;\n    let count = 0;\n    // \u4ece 1 \u4e2a\u5206\u88c2\u51fa n \u4e2a\n    for (let i = 0; i < n; i++) {\n        count += factorialRecur(n - 1);\n    }\n    return count;\n}\n
time_complexity.dart
/* \u9636\u4e58\u9636\uff08\u9012\u5f52\u5b9e\u73b0\uff09 */\nint factorialRecur(int n) {\n  if (n == 0) return 1;\n  int count = 0;\n  // \u4ece 1 \u4e2a\u5206\u88c2\u51fa n \u4e2a\n  for (var i = 0; i < n; i++) {\n    count += factorialRecur(n - 1);\n  }\n  return count;\n}\n
time_complexity.rs
/* \u9636\u4e58\u9636\uff08\u9012\u5f52\u5b9e\u73b0\uff09 */\nfn factorial_recur(n: i32) -> i32 {\n    if n == 0 {\n        return 1;\n    }\n    let mut count = 0;\n    // \u4ece 1 \u4e2a\u5206\u88c2\u51fa n \u4e2a\n    for _ in 0..n {\n        count += factorial_recur(n - 1);\n    }\n    count\n}\n
time_complexity.c
/* \u9636\u4e58\u9636\uff08\u9012\u5f52\u5b9e\u73b0\uff09 */\nint factorialRecur(int n) {\n    if (n == 0)\n        return 1;\n    int count = 0;\n    for (int i = 0; i < n; i++) {\n        count += factorialRecur(n - 1);\n    }\n    return count;\n}\n
time_complexity.zig
// \u9636\u4e58\u9636\uff08\u9012\u5f52\u5b9e\u73b0\uff09\nfn factorialRecur(n: i32) i32 {\n    if (n == 0) return 1;\n    var count: i32 = 0;\n    var i: i32 = 0;\n    // \u4ece 1 \u4e2a\u5206\u88c2\u51fa n \u4e2a\n    while (i < n) : (i += 1) {\n        count += factorialRecur(n - 1);\n    }\n    return count;\n}\n
Code Visualization

Full Screen >

Figure 2-14 \u00a0 Factorial Order Time Complexity

Note that factorial order grows even faster than exponential order; it's unacceptable for larger \\(n\\) values.

"},{"location":"chapter_computational_complexity/time_complexity/#235-worst-best-and-average-time-complexities","title":"2.3.5 \u00a0 Worst, Best, and Average Time Complexities","text":"

The time efficiency of an algorithm is often not fixed but depends on the distribution of the input data. Assume we have an array nums of length \\(n\\), consisting of numbers from \\(1\\) to \\(n\\), each appearing only once, but in a randomly shuffled order. The task is to return the index of the element \\(1\\). We can draw the following conclusions:

  • When nums = [?, ?, ..., 1], that is, when the last element is \\(1\\), it requires a complete traversal of the array, achieving the worst-case time complexity of \\(O(n)\\).
  • When nums = [1, ?, ?, ...], that is, when the first element is \\(1\\), no matter the length of the array, no further traversal is needed, achieving the best-case time complexity of \\(\\Omega(1)\\).

The \"worst-case time complexity\" corresponds to the asymptotic upper bound, denoted by the big \\(O\\) notation. Correspondingly, the \"best-case time complexity\" corresponds to the asymptotic lower bound, denoted by \\(\\Omega\\):

PythonC++JavaC#GoSwiftJSTSDartRustCZig worst_best_time_complexity.py
def random_numbers(n: int) -> list[int]:\n    \"\"\"\u751f\u6210\u4e00\u4e2a\u6570\u7ec4\uff0c\u5143\u7d20\u4e3a: 1, 2, ..., n \uff0c\u987a\u5e8f\u88ab\u6253\u4e71\"\"\"\n    # \u751f\u6210\u6570\u7ec4 nums =: 1, 2, 3, ..., n\n    nums = [i for i in range(1, n + 1)]\n    # \u968f\u673a\u6253\u4e71\u6570\u7ec4\u5143\u7d20\n    random.shuffle(nums)\n    return nums\n\ndef find_one(nums: list[int]) -> int:\n    \"\"\"\u67e5\u627e\u6570\u7ec4 nums \u4e2d\u6570\u5b57 1 \u6240\u5728\u7d22\u5f15\"\"\"\n    for i in range(len(nums)):\n        # \u5f53\u5143\u7d20 1 \u5728\u6570\u7ec4\u5934\u90e8\u65f6\uff0c\u8fbe\u5230\u6700\u4f73\u65f6\u95f4\u590d\u6742\u5ea6 O(1)\n        # \u5f53\u5143\u7d20 1 \u5728\u6570\u7ec4\u5c3e\u90e8\u65f6\uff0c\u8fbe\u5230\u6700\u5dee\u65f6\u95f4\u590d\u6742\u5ea6 O(n)\n        if nums[i] == 1:\n            return i\n    return -1\n
worst_best_time_complexity.cpp
/* \u751f\u6210\u4e00\u4e2a\u6570\u7ec4\uff0c\u5143\u7d20\u4e3a { 1, 2, ..., n }\uff0c\u987a\u5e8f\u88ab\u6253\u4e71 */\nvector<int> randomNumbers(int n) {\n    vector<int> nums(n);\n    // \u751f\u6210\u6570\u7ec4 nums = { 1, 2, 3, ..., n }\n    for (int i = 0; i < n; i++) {\n        nums[i] = i + 1;\n    }\n    // \u4f7f\u7528\u7cfb\u7edf\u65f6\u95f4\u751f\u6210\u968f\u673a\u79cd\u5b50\n    unsigned seed = chrono::system_clock::now().time_since_epoch().count();\n    // \u968f\u673a\u6253\u4e71\u6570\u7ec4\u5143\u7d20\n    shuffle(nums.begin(), nums.end(), default_random_engine(seed));\n    return nums;\n}\n\n/* \u67e5\u627e\u6570\u7ec4 nums \u4e2d\u6570\u5b57 1 \u6240\u5728\u7d22\u5f15 */\nint findOne(vector<int> &nums) {\n    for (int i = 0; i < nums.size(); i++) {\n        // \u5f53\u5143\u7d20 1 \u5728\u6570\u7ec4\u5934\u90e8\u65f6\uff0c\u8fbe\u5230\u6700\u4f73\u65f6\u95f4\u590d\u6742\u5ea6 O(1)\n        // \u5f53\u5143\u7d20 1 \u5728\u6570\u7ec4\u5c3e\u90e8\u65f6\uff0c\u8fbe\u5230\u6700\u5dee\u65f6\u95f4\u590d\u6742\u5ea6 O(n)\n        if (nums[i] == 1)\n            return i;\n    }\n    return -1;\n}\n
worst_best_time_complexity.java
/* \u751f\u6210\u4e00\u4e2a\u6570\u7ec4\uff0c\u5143\u7d20\u4e3a { 1, 2, ..., n }\uff0c\u987a\u5e8f\u88ab\u6253\u4e71 */\nint[] randomNumbers(int n) {\n    Integer[] nums = new Integer[n];\n    // \u751f\u6210\u6570\u7ec4 nums = { 1, 2, 3, ..., n }\n    for (int i = 0; i < n; i++) {\n        nums[i] = i + 1;\n    }\n    // \u968f\u673a\u6253\u4e71\u6570\u7ec4\u5143\u7d20\n    Collections.shuffle(Arrays.asList(nums));\n    // Integer[] -> int[]\n    int[] res = new int[n];\n    for (int i = 0; i < n; i++) {\n        res[i] = nums[i];\n    }\n    return res;\n}\n\n/* \u67e5\u627e\u6570\u7ec4 nums \u4e2d\u6570\u5b57 1 \u6240\u5728\u7d22\u5f15 */\nint findOne(int[] nums) {\n    for (int i = 0; i < nums.length; i++) {\n        // \u5f53\u5143\u7d20 1 \u5728\u6570\u7ec4\u5934\u90e8\u65f6\uff0c\u8fbe\u5230\u6700\u4f73\u65f6\u95f4\u590d\u6742\u5ea6 O(1)\n        // \u5f53\u5143\u7d20 1 \u5728\u6570\u7ec4\u5c3e\u90e8\u65f6\uff0c\u8fbe\u5230\u6700\u5dee\u65f6\u95f4\u590d\u6742\u5ea6 O(n)\n        if (nums[i] == 1)\n            return i;\n    }\n    return -1;\n}\n
worst_best_time_complexity.cs
/* \u751f\u6210\u4e00\u4e2a\u6570\u7ec4\uff0c\u5143\u7d20\u4e3a { 1, 2, ..., n }\uff0c\u987a\u5e8f\u88ab\u6253\u4e71 */\nint[] RandomNumbers(int n) {\n    int[] nums = new int[n];\n    // \u751f\u6210\u6570\u7ec4 nums = { 1, 2, 3, ..., n }\n    for (int i = 0; i < n; i++) {\n        nums[i] = i + 1;\n    }\n\n    // \u968f\u673a\u6253\u4e71\u6570\u7ec4\u5143\u7d20\n    for (int i = 0; i < nums.Length; i++) {\n        int index = new Random().Next(i, nums.Length);\n        (nums[i], nums[index]) = (nums[index], nums[i]);\n    }\n    return nums;\n}\n\n/* \u67e5\u627e\u6570\u7ec4 nums \u4e2d\u6570\u5b57 1 \u6240\u5728\u7d22\u5f15 */\nint FindOne(int[] nums) {\n    for (int i = 0; i < nums.Length; i++) {\n        // \u5f53\u5143\u7d20 1 \u5728\u6570\u7ec4\u5934\u90e8\u65f6\uff0c\u8fbe\u5230\u6700\u4f73\u65f6\u95f4\u590d\u6742\u5ea6 O(1)\n        // \u5f53\u5143\u7d20 1 \u5728\u6570\u7ec4\u5c3e\u90e8\u65f6\uff0c\u8fbe\u5230\u6700\u5dee\u65f6\u95f4\u590d\u6742\u5ea6 O(n)\n        if (nums[i] == 1)\n            return i;\n    }\n    return -1;\n}\n
worst_best_time_complexity.go
/* \u751f\u6210\u4e00\u4e2a\u6570\u7ec4\uff0c\u5143\u7d20\u4e3a { 1, 2, ..., n }\uff0c\u987a\u5e8f\u88ab\u6253\u4e71 */\nfunc randomNumbers(n int) []int {\n    nums := make([]int, n)\n    // \u751f\u6210\u6570\u7ec4 nums = { 1, 2, 3, ..., n }\n    for i := 0; i < n; i++ {\n        nums[i] = i + 1\n    }\n    // \u968f\u673a\u6253\u4e71\u6570\u7ec4\u5143\u7d20\n    rand.Shuffle(len(nums), func(i, j int) {\n        nums[i], nums[j] = nums[j], nums[i]\n    })\n    return nums\n}\n\n/* \u67e5\u627e\u6570\u7ec4 nums \u4e2d\u6570\u5b57 1 \u6240\u5728\u7d22\u5f15 */\nfunc findOne(nums []int) int {\n    for i := 0; i < len(nums); i++ {\n        // \u5f53\u5143\u7d20 1 \u5728\u6570\u7ec4\u5934\u90e8\u65f6\uff0c\u8fbe\u5230\u6700\u4f73\u65f6\u95f4\u590d\u6742\u5ea6 O(1)\n        // \u5f53\u5143\u7d20 1 \u5728\u6570\u7ec4\u5c3e\u90e8\u65f6\uff0c\u8fbe\u5230\u6700\u5dee\u65f6\u95f4\u590d\u6742\u5ea6 O(n)\n        if nums[i] == 1 {\n            return i\n        }\n    }\n    return -1\n}\n
worst_best_time_complexity.swift
/* \u751f\u6210\u4e00\u4e2a\u6570\u7ec4\uff0c\u5143\u7d20\u4e3a { 1, 2, ..., n }\uff0c\u987a\u5e8f\u88ab\u6253\u4e71 */\nfunc randomNumbers(n: Int) -> [Int] {\n    // \u751f\u6210\u6570\u7ec4 nums = { 1, 2, 3, ..., n }\n    var nums = Array(1 ... n)\n    // \u968f\u673a\u6253\u4e71\u6570\u7ec4\u5143\u7d20\n    nums.shuffle()\n    return nums\n}\n\n/* \u67e5\u627e\u6570\u7ec4 nums \u4e2d\u6570\u5b57 1 \u6240\u5728\u7d22\u5f15 */\nfunc findOne(nums: [Int]) -> Int {\n    for i in nums.indices {\n        // \u5f53\u5143\u7d20 1 \u5728\u6570\u7ec4\u5934\u90e8\u65f6\uff0c\u8fbe\u5230\u6700\u4f73\u65f6\u95f4\u590d\u6742\u5ea6 O(1)\n        // \u5f53\u5143\u7d20 1 \u5728\u6570\u7ec4\u5c3e\u90e8\u65f6\uff0c\u8fbe\u5230\u6700\u5dee\u65f6\u95f4\u590d\u6742\u5ea6 O(n)\n        if nums[i] == 1 {\n            return i\n        }\n    }\n    return -1\n}\n
worst_best_time_complexity.js
/* \u751f\u6210\u4e00\u4e2a\u6570\u7ec4\uff0c\u5143\u7d20\u4e3a { 1, 2, ..., n }\uff0c\u987a\u5e8f\u88ab\u6253\u4e71 */\nfunction randomNumbers(n) {\n    const nums = Array(n);\n    // \u751f\u6210\u6570\u7ec4 nums = { 1, 2, 3, ..., n }\n    for (let i = 0; i < n; i++) {\n        nums[i] = i + 1;\n    }\n    // \u968f\u673a\u6253\u4e71\u6570\u7ec4\u5143\u7d20\n    for (let i = 0; i < n; i++) {\n        const r = Math.floor(Math.random() * (i + 1));\n        const temp = nums[i];\n        nums[i] = nums[r];\n        nums[r] = temp;\n    }\n    return nums;\n}\n\n/* \u67e5\u627e\u6570\u7ec4 nums \u4e2d\u6570\u5b57 1 \u6240\u5728\u7d22\u5f15 */\nfunction findOne(nums) {\n    for (let i = 0; i < nums.length; i++) {\n        // \u5f53\u5143\u7d20 1 \u5728\u6570\u7ec4\u5934\u90e8\u65f6\uff0c\u8fbe\u5230\u6700\u4f73\u65f6\u95f4\u590d\u6742\u5ea6 O(1)\n        // \u5f53\u5143\u7d20 1 \u5728\u6570\u7ec4\u5c3e\u90e8\u65f6\uff0c\u8fbe\u5230\u6700\u5dee\u65f6\u95f4\u590d\u6742\u5ea6 O(n)\n        if (nums[i] === 1) {\n            return i;\n        }\n    }\n    return -1;\n}\n
worst_best_time_complexity.ts
/* \u751f\u6210\u4e00\u4e2a\u6570\u7ec4\uff0c\u5143\u7d20\u4e3a { 1, 2, ..., n }\uff0c\u987a\u5e8f\u88ab\u6253\u4e71 */\nfunction randomNumbers(n: number): number[] {\n    const nums = Array(n);\n    // \u751f\u6210\u6570\u7ec4 nums = { 1, 2, 3, ..., n }\n    for (let i = 0; i < n; i++) {\n        nums[i] = i + 1;\n    }\n    // \u968f\u673a\u6253\u4e71\u6570\u7ec4\u5143\u7d20\n    for (let i = 0; i < n; i++) {\n        const r = Math.floor(Math.random() * (i + 1));\n        const temp = nums[i];\n        nums[i] = nums[r];\n        nums[r] = temp;\n    }\n    return nums;\n}\n\n/* \u67e5\u627e\u6570\u7ec4 nums \u4e2d\u6570\u5b57 1 \u6240\u5728\u7d22\u5f15 */\nfunction findOne(nums: number[]): number {\n    for (let i = 0; i < nums.length; i++) {\n        // \u5f53\u5143\u7d20 1 \u5728\u6570\u7ec4\u5934\u90e8\u65f6\uff0c\u8fbe\u5230\u6700\u4f73\u65f6\u95f4\u590d\u6742\u5ea6 O(1)\n        // \u5f53\u5143\u7d20 1 \u5728\u6570\u7ec4\u5c3e\u90e8\u65f6\uff0c\u8fbe\u5230\u6700\u5dee\u65f6\u95f4\u590d\u6742\u5ea6 O(n)\n        if (nums[i] === 1) {\n            return i;\n        }\n    }\n    return -1;\n}\n
worst_best_time_complexity.dart
/* \u751f\u6210\u4e00\u4e2a\u6570\u7ec4\uff0c\u5143\u7d20\u4e3a { 1, 2, ..., n }\uff0c\u987a\u5e8f\u88ab\u6253\u4e71 */\nList<int> randomNumbers(int n) {\n  final nums = List.filled(n, 0);\n  // \u751f\u6210\u6570\u7ec4 nums = { 1, 2, 3, ..., n }\n  for (var i = 0; i < n; i++) {\n    nums[i] = i + 1;\n  }\n  // \u968f\u673a\u6253\u4e71\u6570\u7ec4\u5143\u7d20\n  nums.shuffle();\n\n  return nums;\n}\n\n/* \u67e5\u627e\u6570\u7ec4 nums \u4e2d\u6570\u5b57 1 \u6240\u5728\u7d22\u5f15 */\nint findOne(List<int> nums) {\n  for (var i = 0; i < nums.length; i++) {\n    // \u5f53\u5143\u7d20 1 \u5728\u6570\u7ec4\u5934\u90e8\u65f6\uff0c\u8fbe\u5230\u6700\u4f73\u65f6\u95f4\u590d\u6742\u5ea6 O(1)\n    // \u5f53\u5143\u7d20 1 \u5728\u6570\u7ec4\u5c3e\u90e8\u65f6\uff0c\u8fbe\u5230\u6700\u5dee\u65f6\u95f4\u590d\u6742\u5ea6 O(n)\n    if (nums[i] == 1) return i;\n  }\n\n  return -1;\n}\n
worst_best_time_complexity.rs
/* \u751f\u6210\u4e00\u4e2a\u6570\u7ec4\uff0c\u5143\u7d20\u4e3a { 1, 2, ..., n }\uff0c\u987a\u5e8f\u88ab\u6253\u4e71 */\nfn random_numbers(n: i32) -> Vec<i32> {\n    // \u751f\u6210\u6570\u7ec4 nums = { 1, 2, 3, ..., n }\n    let mut nums = (1..=n).collect::<Vec<i32>>();\n    // \u968f\u673a\u6253\u4e71\u6570\u7ec4\u5143\u7d20\n    nums.shuffle(&mut thread_rng());\n    nums\n}\n\n/* \u67e5\u627e\u6570\u7ec4 nums \u4e2d\u6570\u5b57 1 \u6240\u5728\u7d22\u5f15 */\nfn find_one(nums: &[i32]) -> Option<usize> {\n    for i in 0..nums.len() {\n        // \u5f53\u5143\u7d20 1 \u5728\u6570\u7ec4\u5934\u90e8\u65f6\uff0c\u8fbe\u5230\u6700\u4f73\u65f6\u95f4\u590d\u6742\u5ea6 O(1)\n        // \u5f53\u5143\u7d20 1 \u5728\u6570\u7ec4\u5c3e\u90e8\u65f6\uff0c\u8fbe\u5230\u6700\u5dee\u65f6\u95f4\u590d\u6742\u5ea6 O(n)\n        if nums[i] == 1 {\n            return Some(i);\n        }\n    }\n    None\n}\n
worst_best_time_complexity.c
/* \u751f\u6210\u4e00\u4e2a\u6570\u7ec4\uff0c\u5143\u7d20\u4e3a { 1, 2, ..., n }\uff0c\u987a\u5e8f\u88ab\u6253\u4e71 */\nint *randomNumbers(int n) {\n    // \u5206\u914d\u5806\u533a\u5185\u5b58\uff08\u521b\u5efa\u4e00\u7ef4\u53ef\u53d8\u957f\u6570\u7ec4\uff1a\u6570\u7ec4\u4e2d\u5143\u7d20\u6570\u91cf\u4e3a n \uff0c\u5143\u7d20\u7c7b\u578b\u4e3a int \uff09\n    int *nums = (int *)malloc(n * sizeof(int));\n    // \u751f\u6210\u6570\u7ec4 nums = { 1, 2, 3, ..., n }\n    for (int i = 0; i < n; i++) {\n        nums[i] = i + 1;\n    }\n    // \u968f\u673a\u6253\u4e71\u6570\u7ec4\u5143\u7d20\n    for (int i = n - 1; i > 0; i--) {\n        int j = rand() % (i + 1);\n        int temp = nums[i];\n        nums[i] = nums[j];\n        nums[j] = temp;\n    }\n    return nums;\n}\n\n/* \u67e5\u627e\u6570\u7ec4 nums \u4e2d\u6570\u5b57 1 \u6240\u5728\u7d22\u5f15 */\nint findOne(int *nums, int n) {\n    for (int i = 0; i < n; i++) {\n        // \u5f53\u5143\u7d20 1 \u5728\u6570\u7ec4\u5934\u90e8\u65f6\uff0c\u8fbe\u5230\u6700\u4f73\u65f6\u95f4\u590d\u6742\u5ea6 O(1)\n        // \u5f53\u5143\u7d20 1 \u5728\u6570\u7ec4\u5c3e\u90e8\u65f6\uff0c\u8fbe\u5230\u6700\u5dee\u65f6\u95f4\u590d\u6742\u5ea6 O(n)\n        if (nums[i] == 1)\n            return i;\n    }\n    return -1;\n}\n
worst_best_time_complexity.zig
// \u751f\u6210\u4e00\u4e2a\u6570\u7ec4\uff0c\u5143\u7d20\u4e3a { 1, 2, ..., n }\uff0c\u987a\u5e8f\u88ab\u6253\u4e71\nfn randomNumbers(comptime n: usize) [n]i32 {\n    var nums: [n]i32 = undefined;\n    // \u751f\u6210\u6570\u7ec4 nums = { 1, 2, 3, ..., n }\n    for (&nums, 0..) |*num, i| {\n        num.* = @as(i32, @intCast(i)) + 1;\n    }\n    // \u968f\u673a\u6253\u4e71\u6570\u7ec4\u5143\u7d20\n    const rand = std.crypto.random;\n    rand.shuffle(i32, &nums);\n    return nums;\n}\n\n// \u67e5\u627e\u6570\u7ec4 nums \u4e2d\u6570\u5b57 1 \u6240\u5728\u7d22\u5f15\nfn findOne(nums: []i32) i32 {\n    for (nums, 0..) |num, i| {\n        // \u5f53\u5143\u7d20 1 \u5728\u6570\u7ec4\u5934\u90e8\u65f6\uff0c\u8fbe\u5230\u6700\u4f73\u65f6\u95f4\u590d\u6742\u5ea6 O(1)\n        // \u5f53\u5143\u7d20 1 \u5728\u6570\u7ec4\u5c3e\u90e8\u65f6\uff0c\u8fbe\u5230\u6700\u5dee\u65f6\u95f4\u590d\u6742\u5ea6 O(n)\n        if (num == 1) return @intCast(i);\n    }\n    return -1;\n}\n
Code Visualization

Full Screen >

It's important to note that the best-case time complexity is rarely used in practice, as it is usually only achievable under very low probabilities and might be misleading. The worst-case time complexity is more practical as it provides a safety value for efficiency, allowing us to confidently use the algorithm.

From the above example, it's clear that both the worst-case and best-case time complexities only occur under \"special data distributions,\" which may have a small probability of occurrence and may not accurately reflect the algorithm's run efficiency. In contrast, the average time complexity can reflect the algorithm's efficiency under random input data, denoted by the \\(\\Theta\\) notation.

For some algorithms, we can simply estimate the average case under a random data distribution. For example, in the aforementioned example, since the input array is shuffled, the probability of element \\(1\\) appearing at any index is equal. Therefore, the average number of loops for the algorithm is half the length of the array \\(n / 2\\), giving an average time complexity of \\(\\Theta(n / 2) = \\Theta(n)\\).

However, calculating the average time complexity for more complex algorithms can be quite difficult, as it's challenging to analyze the overall mathematical expectation under the data distribution. In such cases, we usually use the worst-case time complexity as the standard for judging the efficiency of the algorithm.

Why is the \\(\\Theta\\) symbol rarely seen?

Possibly because the \\(O\\) notation is more commonly spoken, it is often used to represent the average time complexity. However, strictly speaking, this practice is not accurate. In this book and other materials, if you encounter statements like \"average time complexity \\(O(n)\\)\", please understand it directly as \\(\\Theta(n)\\).

"},{"location":"chapter_data_structure/","title":"Chapter 3. \u00a0 Data Structures","text":"

Abstract

Data structures serve as a robust and diverse framework.

They offer a blueprint for the orderly organization of data, upon which algorithms come to life.

"},{"location":"chapter_data_structure/#chapter-contents","title":"Chapter Contents","text":"
  • 3.1 \u00a0 Classification of Data Structures
  • 3.2 \u00a0 Fundamental Data Types
  • 3.3 \u00a0 Number Encoding *
  • 3.4 \u00a0 Character Encoding *
  • 3.5 \u00a0 Summary
"},{"location":"chapter_data_structure/basic_data_types/","title":"3.2 \u00a0 Basic Data Types","text":"

When discussing data in computers, various forms like text, images, videos, voice and 3D models comes to mind. Despite their different organizational forms, they are all composed of various basic data types.

Basic data types are those that the CPU can directly operate on and are directly used in algorithms, mainly including the following.

  • Integer types: byte, short, int, long.
  • Floating-point types: float, double, used to represent decimals.
  • Character type: char, used to represent letters, punctuation, and even emojis in various languages.
  • Boolean type: bool, used to represent \"yes\" or \"no\" decisions.

Basic data types are stored in computers in binary form. One binary digit is 1 bit. In most modern operating systems, 1 byte consists of 8 bits.

The range of values for basic data types depends on the size of the space they occupy. Below, we take Java as an example.

  • The integer type byte occupies 1 byte = 8 bits and can represent \\(2^8\\) numbers.
  • The integer type int occupies 4 bytes = 32 bits and can represent \\(2^{32}\\) numbers.

The following table lists the space occupied, value range, and default values of various basic data types in Java. While memorizing this table isn't necessary, having a general understanding of it and referencing it when required is recommended.

Table 3-1 \u00a0 Space Occupied and Value Range of Basic Data Types

Type Symbol Space Occupied Minimum Value Maximum Value Default Value Integer byte 1 byte \\(-2^7\\) (\\(-128\\)) \\(2^7 - 1\\) (\\(127\\)) 0 short 2 bytes \\(-2^{15}\\) \\(2^{15} - 1\\) 0 int 4 bytes \\(-2^{31}\\) \\(2^{31} - 1\\) 0 long 8 bytes \\(-2^{63}\\) \\(2^{63} - 1\\) 0 Float float 4 bytes \\(1.175 \\times 10^{-38}\\) \\(3.403 \\times 10^{38}\\) \\(0.0\\text{f}\\) double 8 bytes \\(2.225 \\times 10^{-308}\\) \\(1.798 \\times 10^{308}\\) 0.0 Char char 2 bytes 0 \\(2^{16} - 1\\) 0 Boolean bool 1 byte \\(\\text{false}\\) \\(\\text{true}\\) \\(\\text{false}\\)

Please note that the above table is specific to Java's basic data types. Every programming language has its own data type definitions, which might differ in space occupied, value ranges, and default values.

  • In Python, the integer type int can be of any size, limited only by available memory; the floating-point float is double precision 64-bit; there is no char type, as a single character is actually a string str of length 1.
  • C and C++ do not specify the size of basic data types, it varies with implementation and platform. The above table follows the LP64 data model, used for Unix 64-bit operating systems including Linux and macOS.
  • The size of char in C and C++ is 1 byte, while in most programming languages, it depends on the specific character encoding method, as detailed in the \"Character Encoding\" chapter.
  • Even though representing a boolean only requires 1 bit (0 or 1), it is usually stored in memory as 1 byte. This is because modern computer CPUs typically use 1 byte as the smallest addressable memory unit.

So, what is the connection between basic data types and data structures? We know that data structures are ways to organize and store data in computers. The focus here is on \"structure\" rather than \"data\".

If we want to represent \"a row of numbers\", we naturally think of using an array. This is because the linear structure of an array can represent the adjacency and the ordering of the numbers, but whether the stored content is an integer int, a decimal float, or a character char, is irrelevant to the \"data structure\".

In other words, basic data types provide the \"content type\" of data, while data structures provide the \"way of organizing\" data. For example, in the following code, we use the same data structure (array) to store and represent different basic data types, including int, float, char, bool, etc.

PythonC++JavaC#GoSwiftJSTSDartRustCZig
# Using various basic data types to initialize arrays\nnumbers: list[int] = [0] * 5\ndecimals: list[float] = [0.0] * 5\n# Python's characters are actually strings of length 1\ncharacters: list[str] = ['0'] * 5\nbools: list[bool] = [False] * 5\n# Python's lists can freely store various basic data types and object references\ndata = [0, 0.0, 'a', False, ListNode(0)]\n
// Using various basic data types to initialize arrays\nint numbers[5];\nfloat decimals[5];\nchar characters[5];\nbool bools[5];\n
// Using various basic data types to initialize arrays\nint[] numbers = new int[5];\nfloat[] decimals = new float[5];\nchar[] characters = new char[5];\nboolean[] bools = new boolean[5];\n
// Using various basic data types to initialize arrays\nint[] numbers = new int[5];\nfloat[] decimals = new float[5];\nchar[] characters = new char[5];\nbool[] bools = new bool[5];\n
// Using various basic data types to initialize arrays\nvar numbers = [5]int{}\nvar decimals = [5]float64{}\nvar characters = [5]byte{}\nvar bools = [5]bool{}\n
// Using various basic data types to initialize arrays\nlet numbers = Array(repeating: 0, count: 5)\nlet decimals = Array(repeating: 0.0, count: 5)\nlet characters: [Character] = Array(repeating: \"a\", count: 5)\nlet bools = Array(repeating: false, count: 5)\n
// JavaScript's arrays can freely store various basic data types and objects\nconst array = [0, 0.0, 'a', false];\n
// Using various basic data types to initialize arrays\nconst numbers: number[] = [];\nconst characters: string[] = [];\nconst bools: boolean[] = [];\n
// Using various basic data types to initialize arrays\nList<int> numbers = List.filled(5, 0);\nList<double> decimals = List.filled(5, 0.0);\nList<String> characters = List.filled(5, 'a');\nList<bool> bools = List.filled(5, false);\n
// Using various basic data types to initialize arrays\nlet numbers: Vec<i32> = vec![0; 5];\nlet decimals: Vec<f32> = vec![0.0, 5];\nlet characters: Vec<char> = vec!['0'; 5];\nlet bools: Vec<bool> = vec![false; 5];\n
// Using various basic data types to initialize arrays\nint numbers[10];\nfloat decimals[10];\nchar characters[10];\nbool bools[10];\n
// Using various basic data types to initialize arrays\nvar numbers: [5]i32 = undefined;\nvar decimals: [5]f32 = undefined;\nvar characters: [5]u8 = undefined;\nvar bools: [5]bool = undefined;\n
"},{"location":"chapter_data_structure/character_encoding/","title":"3.4 \u00a0 Character Encoding *","text":"

In the computer system, all data is stored in binary form, and characters (represented by char) are no exception. To represent characters, we need to develop a \"character set\" that defines a one-to-one mapping between each character and binary numbers. With the character set, computers can convert binary numbers to characters by looking up the table.

"},{"location":"chapter_data_structure/character_encoding/#341-ascii-character-set","title":"3.4.1 \u00a0 ASCII Character Set","text":"

The \"ASCII code\" is one of the earliest character sets, officially known as the American Standard Code for Information Interchange. It uses 7 binary digits (the lower 7 bits of a byte) to represent a character, allowing for a maximum of 128 different characters. As shown in the Figure 3-6 , ASCII includes uppercase and lowercase English letters, numbers 0 ~ 9, various punctuation marks, and certain control characters (such as newline and tab).

Figure 3-6 \u00a0 ASCII Code

However, ASCII can only represent English characters. With the globalization of computers, a character set called \"EASCII\" was developed to represent more languages. It expands from the 7-bit structure of ASCII to 8 bits, enabling the representation of 256 characters.

Globally, various region-specific EASCII character sets have been introduced. The first 128 characters of these sets are consistent with the ASCII, while the remaining 128 characters are defined differently to accommodate the requirements of different languages.

"},{"location":"chapter_data_structure/character_encoding/#342-gbk-character-set","title":"3.4.2 \u00a0 GBK Character Set","text":"

Later, it was found that EASCII still could not meet the character requirements of many languages. For instance, there are nearly a hundred thousand Chinese characters, with several thousand used regularly. In 1980, the Standardization Administration of China released the \"GB2312\" character set, which included 6763 Chinese characters, essentially fulfilling the computer processing needs for the Chinese language.

However, GB2312 could not handle some rare and traditional characters. The \"GBK\" character set expands GB2312 and includes 21886 Chinese characters. In the GBK encoding scheme, ASCII characters are represented with one byte, while Chinese characters use two bytes.

"},{"location":"chapter_data_structure/character_encoding/#343-unicode-character-set","title":"3.4.3 \u00a0 Unicode Character Set","text":"

With the rapid evolution of computer technology and a plethora of character sets and encoding standards, numerous problems arose. On the one hand, these character sets generally only defined characters for specific languages and could not function properly in multilingual environments. On the other hand, the existence of multiple character set standards for the same language caused garbled text when information was exchanged between computers using different encoding standards.

Researchers of that era thought: What if a comprehensive character set encompassing all global languages and symbols was developed? Wouldn't this resolve the issues associated with cross-linguistic environments and garbled text? Inspired by this idea, the extensive character set, Unicode, was born.

\"Unicode\" is referred to as \"\u7edf\u4e00\u7801\" (Unified Code) in Chinese, theoretically capable of accommodating over a million characters. It aims to incorporate characters from all over the world into a single set, providing a universal character set for processing and displaying various languages and reducing the issues of garbled text due to different encoding standards.

Since its release in 1991, Unicode has continually expanded to include new languages and characters. As of September 2022, Unicode contains 149,186 characters, including characters, symbols, and even emojis from various languages. In the vast Unicode character set, commonly used characters occupy 2 bytes, while some rare characters may occupy 3 or even 4 bytes.

Unicode is a universal character set that assigns a number (called a \"code point\") to each character, but it does not specify how these character code points should be stored in a computer system. One might ask: How does a system interpret Unicode code points of varying lengths within a text? For example, given a 2-byte code, how does the system determine if it represents a single 2-byte character or two 1-byte characters?

A straightforward solution to this problem is to store all characters as equal-length encodings. As shown in the Figure 3-7 , each character in \"Hello\" occupies 1 byte, while each character in \"\u7b97\u6cd5\" (algorithm) occupies 2 bytes. We could encode all characters in \"Hello \u7b97\u6cd5\" as 2 bytes by padding the higher bits with zeros. This method would enable the system to interpret a character every 2 bytes, recovering the content of the phrase.

Figure 3-7 \u00a0 Unicode Encoding Example

However, as ASCII has shown us, encoding English only requires 1 byte. Using the above approach would double the space occupied by English text compared to ASCII encoding, which is a waste of memory space. Therefore, a more efficient Unicode encoding method is needed.

"},{"location":"chapter_data_structure/character_encoding/#344-utf-8-encoding","title":"3.4.4 \u00a0 UTF-8 Encoding","text":"

Currently, UTF-8 has become the most widely used Unicode encoding method internationally. It is a variable-length encoding, using 1 to 4 bytes to represent a character, depending on the complexity of the character. ASCII characters need only 1 byte, Latin and Greek letters require 2 bytes, commonly used Chinese characters need 3 bytes, and some other rare characters need 4 bytes.

The encoding rules for UTF-8 are not complex and can be divided into two cases:

  • For 1-byte characters, set the highest bit to \\(0\\), and the remaining 7 bits to the Unicode code point. Notably, ASCII characters occupy the first 128 code points in the Unicode set. This means that UTF-8 encoding is backward compatible with ASCII. This implies that UTF-8 can be used to parse ancient ASCII text.
  • For characters of length \\(n\\) bytes (where \\(n > 1\\)), set the highest \\(n\\) bits of the first byte to \\(1\\), and the \\((n + 1)^{\\text{th}}\\) bit to \\(0\\); starting from the second byte, set the highest 2 bits of each byte to \\(10\\); the rest of the bits are used to fill the Unicode code point.

The Figure 3-8 shows the UTF-8 encoding for \"Hello\u7b97\u6cd5\". It can be observed that since the highest \\(n\\) bits are set to \\(1\\), the system can determine the length of the character as \\(n\\) by counting the number of highest bits set to \\(1\\).

But why set the highest 2 bits of the remaining bytes to \\(10\\)? Actually, this \\(10\\) serves as a kind of checksum. If the system starts parsing text from an incorrect byte, the \\(10\\) at the beginning of the byte can help the system quickly detect anomalies.

The reason for using \\(10\\) as a checksum is that, under UTF-8 encoding rules, it's impossible for the highest two bits of a character to be \\(10\\). This can be proven by contradiction: If the highest two bits of a character are \\(10\\), it indicates that the character's length is \\(1\\), corresponding to ASCII. However, the highest bit of an ASCII character should be \\(0\\), which contradicts the assumption.

Figure 3-8 \u00a0 UTF-8 Encoding Example

Apart from UTF-8, other common encoding methods include:

  • UTF-16 Encoding: Uses 2 or 4 bytes to represent a character. All ASCII characters and commonly used non-English characters are represented with 2 bytes; a few characters require 4 bytes. For 2-byte characters, the UTF-16 encoding equals the Unicode code point.
  • UTF-32 Encoding: Every character uses 4 bytes. This means UTF-32 occupies more space than UTF-8 and UTF-16, especially for texts with a high proportion of ASCII characters.

From the perspective of storage space, using UTF-8 to represent English characters is very efficient because it only requires 1 byte; using UTF-16 to encode some non-English characters (such as Chinese) can be more efficient because it only requires 2 bytes, while UTF-8 might need 3 bytes.

From a compatibility perspective, UTF-8 is the most versatile, with many tools and libraries supporting UTF-8 as a priority.

"},{"location":"chapter_data_structure/character_encoding/#345-character-encoding-in-programming-languages","title":"3.4.5 \u00a0 Character Encoding in Programming Languages","text":"

Historically, many programming languages utilized fixed-length encodings such as UTF-16 or UTF-32 for processing strings during program execution. This allows strings to be handled as arrays, offering several advantages:

  • Random Access: Strings encoded in UTF-16 can be accessed randomly with ease. For UTF-8, which is a variable-length encoding, locating the \\(i^{th}\\) character requires traversing the string from the start to the \\(i^{th}\\) position, taking \\(O(n)\\) time.
  • Character Counting: Similar to random access, counting the number of characters in a UTF-16 encoded string is an \\(O(1)\\) operation. However, counting characters in a UTF-8 encoded string requires traversing the entire string.
  • String Operations: Many string operations like splitting, concatenating, inserting, and deleting are easier on UTF-16 encoded strings. These operations generally require additional computation on UTF-8 encoded strings to ensure the validity of the UTF-8 encoding.

The design of character encoding schemes in programming languages is an interesting topic involving various factors:

  • Java\u2019s String type uses UTF-16 encoding, with each character occupying 2 bytes. This was based on the initial belief that 16 bits were sufficient to represent all possible characters and proven incorrect later. As the Unicode standard expanded beyond 16 bits, characters in Java may now be represented by a pair of 16-bit values, known as \u201csurrogate pairs.\u201d
  • JavaScript and TypeScript use UTF-16 encoding for similar reasons as Java. When JavaScript was first introduced by Netscape in 1995, Unicode was still in its early stages, and 16-bit encoding was sufficient to represent all Unicode characters.
  • C# uses UTF-16 encoding, largely because the .NET platform, designed by Microsoft, and many Microsoft technologies, including the Windows operating system, extensively use UTF-16 encoding.

Due to the underestimation of character counts, these languages had to use \"surrogate pairs\" to represent Unicode characters exceeding 16 bits. This approach has its drawbacks: strings containing surrogate pairs may have characters occupying 2 or 4 bytes, losing the advantage of fixed-length encoding. Additionally, handling surrogate pairs adds complexity and debugging difficulty to programming.

Addressing these challenges, some languages have adopted alternative encoding strategies:

  • Python\u2019s str type uses Unicode encoding with a flexible representation where the storage length of characters depends on the largest Unicode code point in the string. If all characters are ASCII, each character occupies 1 byte, 2 bytes for characters within the Basic Multilingual Plane (BMP), and 4 bytes for characters beyond the BMP.
  • Go\u2019s string type internally uses UTF-8 encoding. Go also provides the rune type for representing individual Unicode code points.
  • Rust\u2019s str and String types use UTF-8 encoding internally. Rust also offers the char type for individual Unicode code points.

It\u2019s important to note that the above discussion pertains to how strings are stored in programming languages, which is different from how strings are stored in files or transmitted over networks. For file storage or network transmission, strings are usually encoded in UTF-8 format for optimal compatibility and space efficiency.

"},{"location":"chapter_data_structure/classification_of_data_structure/","title":"3.1 \u00a0 Classification of Data Structures","text":"

Common data structures include arrays, linked lists, stacks, queues, hash tables, trees, heaps, and graphs. They can be classified into \"logical structure\" and \"physical structure\".

"},{"location":"chapter_data_structure/classification_of_data_structure/#311-logical-structure-linear-and-non-linear","title":"3.1.1 \u00a0 Logical Structure: Linear and Non-Linear","text":"

The logical structures reveal the logical relationships between data elements. In arrays and linked lists, data are arranged in a specific sequence, demonstrating the linear relationship between data; while in trees, data are arranged hierarchically from the top down, showing the derived relationship between \"ancestors\" and \"descendants\"; and graphs are composed of nodes and edges, reflecting the intricate network relationship.

As shown in the Figure 3-1 , logical structures can be divided into two major categories: \"linear\" and \"non-linear\". Linear structures are more intuitive, indicating data is arranged linearly in logical relationships; non-linear structures, conversely, are arranged non-linearly.

  • Linear Data Structures: Arrays, Linked Lists, Stacks, Queues, Hash Tables.
  • Non-Linear Data Structures: Trees, Heaps, Graphs, Hash Tables.

Figure 3-1 \u00a0 Linear and Non-Linear Data Structures

Non-linear data structures can be further divided into tree structures and network structures.

  • Linear Structures: Arrays, linked lists, queues, stacks, and hash tables, where elements have a one-to-one sequential relationship.
  • Tree Structures: Trees, Heaps, Hash Tables, where elements have a one-to-many relationship.
  • Network Structures: Graphs, where elements have a many-to-many relationships.
"},{"location":"chapter_data_structure/classification_of_data_structure/#312-physical-structure-contiguous-and-dispersed","title":"3.1.2 \u00a0 Physical Structure: Contiguous and Dispersed","text":"

During the execution of an algorithm, the data being processed is stored in memory. The Figure 3-2 shows a computer memory stick where each black square is a physical memory space. We can think of memory as a vast Excel spreadsheet, with each cell capable of storing a certain amount of data.

The system accesses the data at the target location by means of a memory address. As shown in the Figure 3-2 , the computer assigns a unique identifier to each cell in the table according to specific rules, ensuring that each memory space has a unique memory address. With these addresses, the program can access the data stored in memory.

Figure 3-2 \u00a0 Memory Stick, Memory Spaces, Memory Addresses

Tip

It's worth noting that comparing memory to an Excel spreadsheet is a simplified analogy. The actual working mechanism of memory is more complex, involving concepts like address space, memory management, cache mechanisms, virtual memory, and physical memory.

Memory is a shared resource for all programs. When a block of memory is occupied by one program, it cannot be simultaneously used by other programs. Therefore, considering memory resources is crucial in designing data structures and algorithms. For instance, the algorithm's peak memory usage should not exceed the remaining free memory of the system; if there is a lack of contiguous memory blocks, then the data structure chosen must be able to be stored in non-contiguous memory blocks.

As illustrated in the Figure 3-3 , the physical structure reflects the way data is stored in computer memory and it can be divided into contiguous space storage (arrays) and non-contiguous space storage (linked lists). The two types of physical structures exhibit complementary characteristics in terms of time efficiency and space efficiency.

Figure 3-3 \u00a0 Contiguous Space Storage and Dispersed Space Storage

It is worth noting that all data structures are implemented based on arrays, linked lists, or a combination of both. For example, stacks and queues can be implemented using either arrays or linked lists; while implementations of hash tables may involve both arrays and linked lists. - Array-based implementations: Stacks, Queues, Hash Tables, Trees, Heaps, Graphs, Matrices, Tensors (arrays with dimensions \\(\\geq 3\\)). - Linked-list-based implementations: Stacks, Queues, Hash Tables, Trees, Heaps, Graphs, etc.

Data structures implemented based on arrays are also called \u201cStatic Data Structures,\u201d meaning their length cannot be changed after initialization. Conversely, those based on linked lists are called \u201cDynamic Data Structures,\u201d which can still adjust their size during program execution.

Tip

If you find it challenging to comprehend the physical structure, it is recommended that you read the next chapter, \"Arrays and Linked Lists,\" and revisit this section later.

"},{"location":"chapter_data_structure/number_encoding/","title":"3.3 \u00a0 Number Encoding *","text":"

Note

In this book, chapters marked with an asterisk '*' are optional readings. If you are short on time or find them challenging, you may skip these initially and return to them after completing the essential chapters.

"},{"location":"chapter_data_structure/number_encoding/#331-integer-encoding","title":"3.3.1 \u00a0 Integer Encoding","text":"

In the table from the previous section, we observed that all integer types can represent one more negative number than positive numbers, such as the byte range of \\([-128, 127]\\). This phenomenon seems counterintuitive, and its underlying reason involves knowledge of sign-magnitude, one's complement, and two's complement encoding.

Firstly, it's important to note that numbers are stored in computers using the two's complement form. Before analyzing why this is the case, let's define these three encoding methods:

  • Sign-magnitude: The highest bit of a binary representation of a number is considered the sign bit, where \\(0\\) represents a positive number and \\(1\\) represents a negative number. The remaining bits represent the value of the number.
  • One's complement: The one's complement of a positive number is the same as its sign-magnitude. For negative numbers, it's obtained by inverting all bits except the sign bit.
  • Two's complement: The two's complement of a positive number is the same as its sign-magnitude. For negative numbers, it's obtained by adding \\(1\\) to their one's complement.

The following diagram illustrates the conversions among sign-magnitude, one's complement, and two's complement:

Figure 3-4 \u00a0 Conversions between Sign-Magnitude, One's Complement, and Two's Complement

Although sign-magnitude is the most intuitive, it has limitations. For one, negative numbers in sign-magnitude cannot be directly used in calculations. For example, in sign-magnitude, calculating \\(1 + (-2)\\) results in \\(-3\\), which is incorrect.

\\[ \\begin{aligned} & 1 + (-2) \\newline & \\rightarrow 0000 \\; 0001 + 1000 \\; 0010 \\newline & = 1000 \\; 0011 \\newline & \\rightarrow -3 \\end{aligned} \\]

To address this, computers introduced the one's complement. If we convert to one's complement and calculate \\(1 + (-2)\\), then convert the result back to sign-magnitude, we get the correct result of \\(-1\\).

\\[ \\begin{aligned} & 1 + (-2) \\newline & \\rightarrow 0000 \\; 0001 \\; \\text{(Sign-magnitude)} + 1000 \\; 0010 \\; \\text{(Sign-magnitude)} \\newline & = 0000 \\; 0001 \\; \\text{(One's complement)} + 1111 \\; 1101 \\; \\text{(One's complement)} \\newline & = 1111 \\; 1110 \\; \\text{(One's complement)} \\newline & = 1000 \\; 0001 \\; \\text{(Sign-magnitude)} \\newline & \\rightarrow -1 \\end{aligned} \\]

Additionally, there are two representations of zero in sign-magnitude: \\(+0\\) and \\(-0\\). This means two different binary encodings for zero, which could lead to ambiguity. For example, in conditional checks, not differentiating between positive and negative zero might result in incorrect outcomes. Addressing this ambiguity would require additional checks, potentially reducing computational efficiency.

\\[ \\begin{aligned} +0 & \\rightarrow 0000 \\; 0000 \\newline -0 & \\rightarrow 1000 \\; 0000 \\end{aligned} \\]

Like sign-magnitude, one's complement also suffers from the positive and negative zero ambiguity. Therefore, computers further introduced the two's complement. Let's observe the conversion process for negative zero in sign-magnitude, one's complement, and two's complement:

\\[ \\begin{aligned} -0 \\rightarrow \\; & 1000 \\; 0000 \\; \\text{(Sign-magnitude)} \\newline = \\; & 1111 \\; 1111 \\; \\text{(One's complement)} \\newline = 1 \\; & 0000 \\; 0000 \\; \\text{(Two's complement)} \\newline \\end{aligned} \\]

Adding \\(1\\) to the one's complement of negative zero produces a carry, but with byte length being only 8 bits, the carried-over \\(1\\) to the 9th bit is discarded. Therefore, the two's complement of negative zero is \\(0000 \\; 0000\\), the same as positive zero, thus resolving the ambiguity.

One last puzzle is the \\([-128, 127]\\) range for byte, with an additional negative number, \\(-128\\). We observe that for the interval \\([-127, +127]\\), all integers have corresponding sign-magnitude, one's complement, and two's complement, allowing for mutual conversion between them.

However, the two's complement \\(1000 \\; 0000\\) is an exception without a corresponding sign-magnitude. According to the conversion method, its sign-magnitude would be \\(0000 \\; 0000\\), indicating zero. This presents a contradiction because its two's complement should represent itself. Computers designate this special two's complement \\(1000 \\; 0000\\) as representing \\(-128\\). In fact, the calculation of \\((-1) + (-127)\\) in two's complement results in \\(-128\\).

\\[ \\begin{aligned} & (-127) + (-1) \\newline & \\rightarrow 1111 \\; 1111 \\; \\text{(Sign-magnitude)} + 1000 \\; 0001 \\; \\text{(Sign-magnitude)} \\newline & = 1000 \\; 0000 \\; \\text{(One's complement)} + 1111 \\; 1110 \\; \\text{(One's complement)} \\newline & = 1000 \\; 0001 \\; \\text{(Two's complement)} + 1111 \\; 1111 \\; \\text{(Two's complement)} \\newline & = 1000 \\; 0000 \\; \\text{(Two's complement)} \\newline & \\rightarrow -128 \\end{aligned} \\]

As you might have noticed, all these calculations are additions, hinting at an important fact: computers' internal hardware circuits are primarily designed around addition operations. This is because addition is simpler to implement in hardware compared to other operations like multiplication, division, and subtraction, allowing for easier parallelization and faster computation.

It's important to note that this doesn't mean computers can only perform addition. By combining addition with basic logical operations, computers can execute a variety of other mathematical operations. For example, the subtraction \\(a - b\\) can be translated into \\(a + (-b)\\); multiplication and division can be translated into multiple additions or subtractions.

We can now summarize the reason for using two's complement in computers: with two's complement representation, computers can use the same circuits and operations to handle both positive and negative number addition, eliminating the need for special hardware circuits for subtraction and avoiding the ambiguity of positive and negative zero. This greatly simplifies hardware design and enhances computational efficiency.

The design of two's complement is quite ingenious, and due to space constraints, we'll stop here. Interested readers are encouraged to explore further.

"},{"location":"chapter_data_structure/number_encoding/#332-floating-point-number-encoding","title":"3.3.2 \u00a0 Floating-Point Number Encoding","text":"

You might have noticed something intriguing: despite having the same length of 4 bytes, why does a float have a much larger range of values compared to an int? This seems counterintuitive, as one would expect the range to shrink for float since it needs to represent fractions.

In fact, this is due to the different representation method used by floating-point numbers (float). Let's consider a 32-bit binary number as:

\\[ b_{31} b_{30} b_{29} \\ldots b_2 b_1 b_0 \\]

According to the IEEE 754 standard, a 32-bit float consists of the following three parts:

  • Sign bit \\(\\mathrm{S}\\): Occupies 1 bit, corresponding to \\(b_{31}\\).
  • Exponent bit \\(\\mathrm{E}\\): Occupies 8 bits, corresponding to \\(b_{30} b_{29} \\ldots b_{23}\\).
  • Fraction bit \\(\\mathrm{N}\\): Occupies 23 bits, corresponding to \\(b_{22} b_{21} \\ldots b_0\\).

The value of a binary float number is calculated as:

\\[ \\text{val} = (-1)^{b_{31}} \\times 2^{\\left(b_{30} b_{29} \\ldots b_{23}\\right)_2 - 127} \\times \\left(1 . b_{22} b_{21} \\ldots b_0\\right)_2 \\]

Converted to a decimal formula, this becomes:

\\[ \\text{val} = (-1)^{\\mathrm{S}} \\times 2^{\\mathrm{E} - 127} \\times (1 + \\mathrm{N}) \\]

The range of each component is:

\\[ \\begin{aligned} \\mathrm{S} \\in & \\{ 0, 1\\}, \\quad \\mathrm{E} \\in \\{ 1, 2, \\dots, 254 \\} \\newline (1 + \\mathrm{N}) = & (1 + \\sum_{i=1}^{23} b_{23-i} \\times 2^{-i}) \\subset [1, 2 - 2^{-23}] \\end{aligned} \\]

Figure 3-5 \u00a0 Example Calculation of a float in IEEE 754 Standard

Observing the diagram, given an example data \\(\\mathrm{S} = 0\\), \\(\\mathrm{E} = 124\\), \\(\\mathrm{N} = 2^{-2} + 2^{-3} = 0.375\\), we have:

\\[ \\text{val} = (-1)^0 \\times 2^{124 - 127} \\times (1 + 0.375) = 0.171875 \\]

Now we can answer the initial question: The representation of float includes an exponent bit, leading to a much larger range than int. Based on the above calculation, the maximum positive number representable by float is approximately \\(2^{254 - 127} \\times (2 - 2^{-23}) \\approx 3.4 \\times 10^{38}\\), and the minimum negative number is obtained by switching the sign bit.

However, the trade-off for float's expanded range is a sacrifice in precision. The integer type int uses all 32 bits to represent the number, with values evenly distributed; but due to the exponent bit, the larger the value of a float, the greater the difference between adjacent numbers.

As shown in the Table 3-2 , exponent bits \\(E = 0\\) and \\(E = 255\\) have special meanings, used to represent zero, infinity, \\(\\mathrm{NaN}\\), etc.

Table 3-2 \u00a0 Meaning of Exponent Bits

Exponent Bit E Fraction Bit \\(\\mathrm{N} = 0\\) Fraction Bit \\(\\mathrm{N} \\ne 0\\) Calculation Formula \\(0\\) \\(\\pm 0\\) Subnormal Numbers \\((-1)^{\\mathrm{S}} \\times 2^{-126} \\times (0.\\mathrm{N})\\) \\(1, 2, \\dots, 254\\) Normal Numbers Normal Numbers \\((-1)^{\\mathrm{S}} \\times 2^{(\\mathrm{E} -127)} \\times (1.\\mathrm{N})\\) \\(255\\) \\(\\pm \\infty\\) \\(\\mathrm{NaN}\\)

It's worth noting that subnormal numbers significantly improve the precision of floating-point numbers. The smallest positive normal number is \\(2^{-126}\\), and the smallest positive subnormal number is \\(2^{-126} \\times 2^{-23}\\).

Double-precision double also uses a similar representation method to float, which is not elaborated here for brevity.

"},{"location":"chapter_data_structure/summary/","title":"3.5 \u00a0 Summary","text":""},{"location":"chapter_data_structure/summary/#1-key-review","title":"1. \u00a0 Key Review","text":"
  • Data structures can be categorized from two perspectives: logical structure and physical structure. Logical structure describes the logical relationships between data elements, while physical structure describes how data is stored in computer memory.
  • Common logical structures include linear, tree-like, and network structures. We generally classify data structures into linear (arrays, linked lists, stacks, queues) and non-linear (trees, graphs, heaps) based on their logical structure. The implementation of hash tables may involve both linear and non-linear data structures.
  • When a program runs, data is stored in computer memory. Each memory space has a corresponding memory address, and the program accesses data through these addresses.
  • Physical structures are primarily divided into contiguous space storage (arrays) and dispersed space storage (linked lists). All data structures are implemented using arrays, linked lists, or a combination of both.
  • Basic data types in computers include integers (byte, short, int, long), floating-point numbers (float, double), characters (char), and booleans (boolean). Their range depends on the size of the space occupied and the representation method.
  • Original code, complement code, and two's complement code are three methods of encoding numbers in computers, and they can be converted into each other. The highest bit of the original code of an integer is the sign bit, and the remaining bits represent the value of the number.
  • Integers are stored in computers in the form of two's complement. In this representation, the computer can treat the addition of positive and negative numbers uniformly, without the need for special hardware circuits for subtraction, and there is no ambiguity of positive and negative zero.
  • The encoding of floating-point numbers consists of 1 sign bit, 8 exponent bits, and 23 fraction bits. Due to the presence of the exponent bit, the range of floating-point numbers is much greater than that of integers, but at the cost of sacrificing precision.
  • ASCII is the earliest English character set, 1 byte in length, and includes 127 characters. The GBK character set is a commonly used Chinese character set, including more than 20,000 Chinese characters. Unicode strives to provide a complete character set standard, including characters from various languages worldwide, thus solving the problem of garbled characters caused by inconsistent character encoding methods.
  • UTF-8 is the most popular Unicode encoding method, with excellent universality. It is a variable-length encoding method with good scalability and effectively improves the efficiency of space usage. UTF-16 and UTF-32 are fixed-length encoding methods. When encoding Chinese characters, UTF-16 occupies less space than UTF-8. Programming languages like Java and C# use UTF-16 encoding by default.
"},{"location":"chapter_data_structure/summary/#2-q-a","title":"2. \u00a0 Q & A","text":"

Q: Why does a hash table contain both linear and non-linear data structures?

The underlying structure of a hash table is an array. To resolve hash collisions, we may use \"chaining\": each bucket in the array points to a linked list, which, when exceeding a certain threshold, might be transformed into a tree (usually a red-black tree). From a storage perspective, the foundation of a hash table is an array, where each bucket slot might contain a value, a linked list, or a tree. Therefore, hash tables may contain both linear data structures (arrays, linked lists) and non-linear data structures (trees).

Q: Is the length of the char type 1 byte?

The length of the char type is determined by the encoding method used by the programming language. For example, Java, JavaScript, TypeScript, and C# all use UTF-16 encoding (to save Unicode code points), so the length of the char type is 2 bytes.

Q: Is there ambiguity in calling data structures based on arrays \"static data structures\"? Because operations like push and pop on stacks are \"dynamic\".

While stacks indeed allow for dynamic data operations, the data structure itself remains \"static\" (with unchangeable length). Even though data structures based on arrays can dynamically add or remove elements, their capacity is fixed. If the data volume exceeds the pre-allocated size, a new, larger array needs to be created, and the contents of the old array copied into it.

Q: When building stacks (queues) without specifying their size, why are they considered \"static data structures\"?

In high-level programming languages, we don't need to manually specify the initial capacity of stacks (queues); this task is automatically handled internally by the class. For example, the initial capacity of Java's ArrayList is usually 10. Furthermore, the expansion operation is also implemented automatically. See the subsequent \"List\" chapter for details.

"},{"location":"chapter_hashing/","title":"Chapter 6. \u00a0 Hash Table","text":"

Abstract

In the world of computing, a hash table is akin to an intelligent librarian.

It understands how to compute index numbers, enabling swift retrieval of the desired book.

"},{"location":"chapter_hashing/#chapter-contents","title":"Chapter Contents","text":"
  • 6.1 \u00a0 Hash Table
  • 6.2 \u00a0 Hash Collision
  • 6.3 \u00a0 Hash Algorithm
  • 6.4 \u00a0 Summary
"},{"location":"chapter_hashing/hash_algorithm/","title":"6.3 \u00a0 Hash Algorithms","text":"

The previous two sections introduced the working principle of hash tables and the methods to handle hash collisions. However, both open addressing and chaining can only ensure that the hash table functions normally when collisions occur, but cannot reduce the frequency of hash collisions.

If hash collisions occur too frequently, the performance of the hash table will deteriorate drastically. As shown in the Figure 6-8 , for a chaining hash table, in the ideal case, the key-value pairs are evenly distributed across the buckets, achieving optimal query efficiency; in the worst case, all key-value pairs are stored in the same bucket, degrading the time complexity to \\(O(n)\\).

Figure 6-8 \u00a0 Ideal and Worst Cases of Hash Collisions

The distribution of key-value pairs is determined by the hash function. Recalling the steps of calculating a hash function, first compute the hash value, then modulo it by the array length:

index = hash(key) % capacity\n

Observing the above formula, when the hash table capacity capacity is fixed, the hash algorithm hash() determines the output value, thereby determining the distribution of key-value pairs in the hash table.

This means that, to reduce the probability of hash collisions, we should focus on the design of the hash algorithm hash().

"},{"location":"chapter_hashing/hash_algorithm/#631-goals-of-hash-algorithms","title":"6.3.1 \u00a0 Goals of Hash Algorithms","text":"

To achieve a \"fast and stable\" hash table data structure, hash algorithms should have the following characteristics:

  • Determinism: For the same input, the hash algorithm should always produce the same output. Only then can the hash table be reliable.
  • High Efficiency: The process of computing the hash value should be fast enough. The smaller the computational overhead, the more practical the hash table.
  • Uniform Distribution: The hash algorithm should ensure that key-value pairs are evenly distributed in the hash table. The more uniform the distribution, the lower the probability of hash collisions.

In fact, hash algorithms are not only used to implement hash tables but are also widely applied in other fields.

  • Password Storage: To protect the security of user passwords, systems usually do not store the plaintext passwords but rather the hash values of the passwords. When a user enters a password, the system calculates the hash value of the input and compares it with the stored hash value. If they match, the password is considered correct.
  • Data Integrity Check: The data sender can calculate the hash value of the data and send it along; the receiver can recalculate the hash value of the received data and compare it with the received hash value. If they match, the data is considered intact.

For cryptographic applications, to prevent reverse engineering such as deducing the original password from the hash value, hash algorithms need higher-level security features.

  • Unidirectionality: It should be impossible to deduce any information about the input data from the hash value.
  • Collision Resistance: It should be extremely difficult to find two different inputs that produce the same hash value.
  • Avalanche Effect: Minor changes in the input should lead to significant and unpredictable changes in the output.

Note that \"Uniform Distribution\" and \"Collision Resistance\" are two separate concepts. Satisfying uniform distribution does not necessarily mean collision resistance. For example, under random input key, the hash function key % 100 can produce a uniformly distributed output. However, this hash algorithm is too simple, and all key with the same last two digits will have the same output, making it easy to deduce a usable key from the hash value, thereby cracking the password.

"},{"location":"chapter_hashing/hash_algorithm/#632-design-of-hash-algorithms","title":"6.3.2 \u00a0 Design of Hash Algorithms","text":"

The design of hash algorithms is a complex issue that requires consideration of many factors. However, for some less demanding scenarios, we can also design some simple hash algorithms.

  • Additive Hash: Add up the ASCII codes of each character in the input and use the total sum as the hash value.
  • Multiplicative Hash: Utilize the non-correlation of multiplication, multiplying each round by a constant, accumulating the ASCII codes of each character into the hash value.
  • XOR Hash: Accumulate the hash value by XORing each element of the input data.
  • Rotating Hash: Accumulate the ASCII code of each character into a hash value, performing a rotation operation on the hash value before each accumulation.
PythonC++JavaC#GoSwiftJSTSDartRustCZig simple_hash.py
def add_hash(key: str) -> int:\n    \"\"\"\u52a0\u6cd5\u54c8\u5e0c\"\"\"\n    hash = 0\n    modulus = 1000000007\n    for c in key:\n        hash += ord(c)\n    return hash % modulus\n\ndef mul_hash(key: str) -> int:\n    \"\"\"\u4e58\u6cd5\u54c8\u5e0c\"\"\"\n    hash = 0\n    modulus = 1000000007\n    for c in key:\n        hash = 31 * hash + ord(c)\n    return hash % modulus\n\ndef xor_hash(key: str) -> int:\n    \"\"\"\u5f02\u6216\u54c8\u5e0c\"\"\"\n    hash = 0\n    modulus = 1000000007\n    for c in key:\n        hash ^= ord(c)\n    return hash % modulus\n\ndef rot_hash(key: str) -> int:\n    \"\"\"\u65cb\u8f6c\u54c8\u5e0c\"\"\"\n    hash = 0\n    modulus = 1000000007\n    for c in key:\n        hash = (hash << 4) ^ (hash >> 28) ^ ord(c)\n    return hash % modulus\n
simple_hash.cpp
/* \u52a0\u6cd5\u54c8\u5e0c */\nint addHash(string key) {\n    long long hash = 0;\n    const int MODULUS = 1000000007;\n    for (unsigned char c : key) {\n        hash = (hash + (int)c) % MODULUS;\n    }\n    return (int)hash;\n}\n\n/* \u4e58\u6cd5\u54c8\u5e0c */\nint mulHash(string key) {\n    long long hash = 0;\n    const int MODULUS = 1000000007;\n    for (unsigned char c : key) {\n        hash = (31 * hash + (int)c) % MODULUS;\n    }\n    return (int)hash;\n}\n\n/* \u5f02\u6216\u54c8\u5e0c */\nint xorHash(string key) {\n    int hash = 0;\n    const int MODULUS = 1000000007;\n    for (unsigned char c : key) {\n        hash ^= (int)c;\n    }\n    return hash & MODULUS;\n}\n\n/* \u65cb\u8f6c\u54c8\u5e0c */\nint rotHash(string key) {\n    long long hash = 0;\n    const int MODULUS = 1000000007;\n    for (unsigned char c : key) {\n        hash = ((hash << 4) ^ (hash >> 28) ^ (int)c) % MODULUS;\n    }\n    return (int)hash;\n}\n
simple_hash.java
/* \u52a0\u6cd5\u54c8\u5e0c */\nint addHash(String key) {\n    long hash = 0;\n    final int MODULUS = 1000000007;\n    for (char c : key.toCharArray()) {\n        hash = (hash + (int) c) % MODULUS;\n    }\n    return (int) hash;\n}\n\n/* \u4e58\u6cd5\u54c8\u5e0c */\nint mulHash(String key) {\n    long hash = 0;\n    final int MODULUS = 1000000007;\n    for (char c : key.toCharArray()) {\n        hash = (31 * hash + (int) c) % MODULUS;\n    }\n    return (int) hash;\n}\n\n/* \u5f02\u6216\u54c8\u5e0c */\nint xorHash(String key) {\n    int hash = 0;\n    final int MODULUS = 1000000007;\n    for (char c : key.toCharArray()) {\n        hash ^= (int) c;\n    }\n    return hash & MODULUS;\n}\n\n/* \u65cb\u8f6c\u54c8\u5e0c */\nint rotHash(String key) {\n    long hash = 0;\n    final int MODULUS = 1000000007;\n    for (char c : key.toCharArray()) {\n        hash = ((hash << 4) ^ (hash >> 28) ^ (int) c) % MODULUS;\n    }\n    return (int) hash;\n}\n
simple_hash.cs
/* \u52a0\u6cd5\u54c8\u5e0c */\nint AddHash(string key) {\n    long hash = 0;\n    const int MODULUS = 1000000007;\n    foreach (char c in key) {\n        hash = (hash + c) % MODULUS;\n    }\n    return (int)hash;\n}\n\n/* \u4e58\u6cd5\u54c8\u5e0c */\nint MulHash(string key) {\n    long hash = 0;\n    const int MODULUS = 1000000007;\n    foreach (char c in key) {\n        hash = (31 * hash + c) % MODULUS;\n    }\n    return (int)hash;\n}\n\n/* \u5f02\u6216\u54c8\u5e0c */\nint XorHash(string key) {\n    int hash = 0;\n    const int MODULUS = 1000000007;\n    foreach (char c in key) {\n        hash ^= c;\n    }\n    return hash & MODULUS;\n}\n\n/* \u65cb\u8f6c\u54c8\u5e0c */\nint RotHash(string key) {\n    long hash = 0;\n    const int MODULUS = 1000000007;\n    foreach (char c in key) {\n        hash = ((hash << 4) ^ (hash >> 28) ^ c) % MODULUS;\n    }\n    return (int)hash;\n}\n
simple_hash.go
/* \u52a0\u6cd5\u54c8\u5e0c */\nfunc addHash(key string) int {\n    var hash int64\n    var modulus int64\n\n    modulus = 1000000007\n    for _, b := range []byte(key) {\n        hash = (hash + int64(b)) % modulus\n    }\n    return int(hash)\n}\n\n/* \u4e58\u6cd5\u54c8\u5e0c */\nfunc mulHash(key string) int {\n    var hash int64\n    var modulus int64\n\n    modulus = 1000000007\n    for _, b := range []byte(key) {\n        hash = (31*hash + int64(b)) % modulus\n    }\n    return int(hash)\n}\n\n/* \u5f02\u6216\u54c8\u5e0c */\nfunc xorHash(key string) int {\n    hash := 0\n    modulus := 1000000007\n    for _, b := range []byte(key) {\n        fmt.Println(int(b))\n        hash ^= int(b)\n        hash = (31*hash + int(b)) % modulus\n    }\n    return hash & modulus\n}\n\n/* \u65cb\u8f6c\u54c8\u5e0c */\nfunc rotHash(key string) int {\n    var hash int64\n    var modulus int64\n\n    modulus = 1000000007\n    for _, b := range []byte(key) {\n        hash = ((hash << 4) ^ (hash >> 28) ^ int64(b)) % modulus\n    }\n    return int(hash)\n}\n
simple_hash.swift
/* \u52a0\u6cd5\u54c8\u5e0c */\nfunc addHash(key: String) -> Int {\n    var hash = 0\n    let MODULUS = 1_000_000_007\n    for c in key {\n        for scalar in c.unicodeScalars {\n            hash = (hash + Int(scalar.value)) % MODULUS\n        }\n    }\n    return hash\n}\n\n/* \u4e58\u6cd5\u54c8\u5e0c */\nfunc mulHash(key: String) -> Int {\n    var hash = 0\n    let MODULUS = 1_000_000_007\n    for c in key {\n        for scalar in c.unicodeScalars {\n            hash = (31 * hash + Int(scalar.value)) % MODULUS\n        }\n    }\n    return hash\n}\n\n/* \u5f02\u6216\u54c8\u5e0c */\nfunc xorHash(key: String) -> Int {\n    var hash = 0\n    let MODULUS = 1_000_000_007\n    for c in key {\n        for scalar in c.unicodeScalars {\n            hash ^= Int(scalar.value)\n        }\n    }\n    return hash & MODULUS\n}\n\n/* \u65cb\u8f6c\u54c8\u5e0c */\nfunc rotHash(key: String) -> Int {\n    var hash = 0\n    let MODULUS = 1_000_000_007\n    for c in key {\n        for scalar in c.unicodeScalars {\n            hash = ((hash << 4) ^ (hash >> 28) ^ Int(scalar.value)) % MODULUS\n        }\n    }\n    return hash\n}\n
simple_hash.js
/* \u52a0\u6cd5\u54c8\u5e0c */\nfunction addHash(key) {\n    let hash = 0;\n    const MODULUS = 1000000007;\n    for (const c of key) {\n        hash = (hash + c.charCodeAt(0)) % MODULUS;\n    }\n    return hash;\n}\n\n/* \u4e58\u6cd5\u54c8\u5e0c */\nfunction mulHash(key) {\n    let hash = 0;\n    const MODULUS = 1000000007;\n    for (const c of key) {\n        hash = (31 * hash + c.charCodeAt(0)) % MODULUS;\n    }\n    return hash;\n}\n\n/* \u5f02\u6216\u54c8\u5e0c */\nfunction xorHash(key) {\n    let hash = 0;\n    const MODULUS = 1000000007;\n    for (const c of key) {\n        hash ^= c.charCodeAt(0);\n    }\n    return hash & MODULUS;\n}\n\n/* \u65cb\u8f6c\u54c8\u5e0c */\nfunction rotHash(key) {\n    let hash = 0;\n    const MODULUS = 1000000007;\n    for (const c of key) {\n        hash = ((hash << 4) ^ (hash >> 28) ^ c.charCodeAt(0)) % MODULUS;\n    }\n    return hash;\n}\n
simple_hash.ts
/* \u52a0\u6cd5\u54c8\u5e0c */\nfunction addHash(key: string): number {\n    let hash = 0;\n    const MODULUS = 1000000007;\n    for (const c of key) {\n        hash = (hash + c.charCodeAt(0)) % MODULUS;\n    }\n    return hash;\n}\n\n/* \u4e58\u6cd5\u54c8\u5e0c */\nfunction mulHash(key: string): number {\n    let hash = 0;\n    const MODULUS = 1000000007;\n    for (const c of key) {\n        hash = (31 * hash + c.charCodeAt(0)) % MODULUS;\n    }\n    return hash;\n}\n\n/* \u5f02\u6216\u54c8\u5e0c */\nfunction xorHash(key: string): number {\n    let hash = 0;\n    const MODULUS = 1000000007;\n    for (const c of key) {\n        hash ^= c.charCodeAt(0);\n    }\n    return hash & MODULUS;\n}\n\n/* \u65cb\u8f6c\u54c8\u5e0c */\nfunction rotHash(key: string): number {\n    let hash = 0;\n    const MODULUS = 1000000007;\n    for (const c of key) {\n        hash = ((hash << 4) ^ (hash >> 28) ^ c.charCodeAt(0)) % MODULUS;\n    }\n    return hash;\n}\n
simple_hash.dart
/* \u52a0\u6cd5\u54c8\u5e0c */\nint addHash(String key) {\n  int hash = 0;\n  final int MODULUS = 1000000007;\n  for (int i = 0; i < key.length; i++) {\n    hash = (hash + key.codeUnitAt(i)) % MODULUS;\n  }\n  return hash;\n}\n\n/* \u4e58\u6cd5\u54c8\u5e0c */\nint mulHash(String key) {\n  int hash = 0;\n  final int MODULUS = 1000000007;\n  for (int i = 0; i < key.length; i++) {\n    hash = (31 * hash + key.codeUnitAt(i)) % MODULUS;\n  }\n  return hash;\n}\n\n/* \u5f02\u6216\u54c8\u5e0c */\nint xorHash(String key) {\n  int hash = 0;\n  final int MODULUS = 1000000007;\n  for (int i = 0; i < key.length; i++) {\n    hash ^= key.codeUnitAt(i);\n  }\n  return hash & MODULUS;\n}\n\n/* \u65cb\u8f6c\u54c8\u5e0c */\nint rotHash(String key) {\n  int hash = 0;\n  final int MODULUS = 1000000007;\n  for (int i = 0; i < key.length; i++) {\n    hash = ((hash << 4) ^ (hash >> 28) ^ key.codeUnitAt(i)) % MODULUS;\n  }\n  return hash;\n}\n
simple_hash.rs
/* \u52a0\u6cd5\u54c8\u5e0c */\nfn add_hash(key: &str) -> i32 {\n    let mut hash = 0_i64;\n    const MODULUS: i64 = 1000000007;\n\n    for c in key.chars() {\n        hash = (hash + c as i64) % MODULUS;\n    }\n\n    hash as i32\n}\n\n/* \u4e58\u6cd5\u54c8\u5e0c */\nfn mul_hash(key: &str) -> i32 {\n    let mut hash = 0_i64;\n    const MODULUS: i64 = 1000000007;\n\n    for c in key.chars() {\n        hash = (31 * hash + c as i64) % MODULUS;\n    }\n\n    hash as i32\n}\n\n/* \u5f02\u6216\u54c8\u5e0c */\nfn xor_hash(key: &str) -> i32 {\n    let mut hash = 0_i64;\n    const MODULUS: i64 = 1000000007;\n\n    for c in key.chars() {\n        hash ^= c as i64;\n    }\n\n    (hash & MODULUS) as i32\n}\n\n/* \u65cb\u8f6c\u54c8\u5e0c */\nfn rot_hash(key: &str) -> i32 {\n    let mut hash = 0_i64;\n    const MODULUS: i64 = 1000000007;\n\n    for c in key.chars() {\n        hash = ((hash << 4) ^ (hash >> 28) ^ c as i64) % MODULUS;\n    }\n\n    hash as i32\n}\n
simple_hash.c
/* \u52a0\u6cd5\u54c8\u5e0c */\nint addHash(char *key) {\n    long long hash = 0;\n    const int MODULUS = 1000000007;\n    for (int i = 0; i < strlen(key); i++) {\n        hash = (hash + (unsigned char)key[i]) % MODULUS;\n    }\n    return (int)hash;\n}\n\n/* \u4e58\u6cd5\u54c8\u5e0c */\nint mulHash(char *key) {\n    long long hash = 0;\n    const int MODULUS = 1000000007;\n    for (int i = 0; i < strlen(key); i++) {\n        hash = (31 * hash + (unsigned char)key[i]) % MODULUS;\n    }\n    return (int)hash;\n}\n\n/* \u5f02\u6216\u54c8\u5e0c */\nint xorHash(char *key) {\n    int hash = 0;\n    const int MODULUS = 1000000007;\n\n    for (int i = 0; i < strlen(key); i++) {\n        hash ^= (unsigned char)key[i];\n    }\n    return hash & MODULUS;\n}\n\n/* \u65cb\u8f6c\u54c8\u5e0c */\nint rotHash(char *key) {\n    long long hash = 0;\n    const int MODULUS = 1000000007;\n    for (int i = 0; i < strlen(key); i++) {\n        hash = ((hash << 4) ^ (hash >> 28) ^ (unsigned char)key[i]) % MODULUS;\n    }\n\n    return (int)hash;\n}\n
simple_hash.zig
[class]{}-[func]{addHash}\n\n[class]{}-[func]{mulHash}\n\n[class]{}-[func]{xorHash}\n\n[class]{}-[func]{rotHash}\n
Code Visualization

Full Screen >

It is observed that the last step of each hash algorithm is to take the modulus of the large prime number \\(1000000007\\) to ensure that the hash value is within an appropriate range. It is worth pondering why emphasis is placed on modulo a prime number, or what are the disadvantages of modulo a composite number? This is an interesting question.

To conclude: Using a large prime number as the modulus can maximize the uniform distribution of hash values. Since a prime number does not share common factors with other numbers, it can reduce the periodic patterns caused by the modulo operation, thus avoiding hash collisions.

For example, suppose we choose the composite number \\(9\\) as the modulus, which can be divided by \\(3\\), then all key divisible by \\(3\\) will be mapped to hash values \\(0\\), \\(3\\), \\(6\\).

\\[ \\begin{aligned} \\text{modulus} & = 9 \\newline \\text{key} & = \\{ 0, 3, 6, 9, 12, 15, 18, 21, 24, 27, 30, 33, \\dots \\} \\newline \\text{hash} & = \\{ 0, 3, 6, 0, 3, 6, 0, 3, 6, 0, 3, 6,\\dots \\} \\end{aligned} \\]

If the input key happens to have this kind of arithmetic sequence distribution, then the hash values will cluster, thereby exacerbating hash collisions. Now, suppose we replace modulus with the prime number \\(13\\), since there are no common factors between key and modulus, the uniformity of the output hash values will be significantly improved.

\\[ \\begin{aligned} \\text{modulus} & = 13 \\newline \\text{key} & = \\{ 0, 3, 6, 9, 12, 15, 18, 21, 24, 27, 30, 33, \\dots \\} \\newline \\text{hash} & = \\{ 0, 3, 6, 9, 12, 2, 5, 8, 11, 1, 4, 7, \\dots \\} \\end{aligned} \\]

It is worth noting that if the key is guaranteed to be randomly and uniformly distributed, then choosing a prime number or a composite number as the modulus can both produce uniformly distributed hash values. However, when the distribution of key has some periodicity, modulo a composite number is more likely to result in clustering.

In summary, we usually choose a prime number as the modulus, and this prime number should be large enough to eliminate periodic patterns as much as possible, enhancing the robustness of the hash algorithm.

"},{"location":"chapter_hashing/hash_algorithm/#633-common-hash-algorithms","title":"6.3.3 \u00a0 Common Hash Algorithms","text":"

It is not hard to see that the simple hash algorithms mentioned above are quite \"fragile\" and far from reaching the design goals of hash algorithms. For example, since addition and XOR obey the commutative law, additive hash and XOR hash cannot distinguish strings with the same content but in different order, which may exacerbate hash collisions and cause security issues.

In practice, we usually use some standard hash algorithms, such as MD5, SHA-1, SHA-2, and SHA-3. They can map input data of any length to a fixed-length hash value.

Over the past century, hash algorithms have been in a continuous process of upgrading and optimization. Some researchers strive to improve the performance of hash algorithms, while others, including hackers, are dedicated to finding security issues in hash algorithms. The Table 6-2 shows hash algorithms commonly used in practical applications.

  • MD5 and SHA-1 have been successfully attacked multiple times and are thus abandoned in various security applications.
  • SHA-2 series, especially SHA-256, is one of the most secure hash algorithms to date, with no successful attacks reported, hence commonly used in various security applications and protocols.
  • SHA-3 has lower implementation costs and higher computational efficiency compared to SHA-2, but its current usage coverage is not as extensive as the SHA-2 series.

Table 6-2 \u00a0 Common Hash Algorithms

MD5 SHA-1 SHA-2 SHA-3 Release Year 1992 1995 2002 2008 Output Length 128 bit 160 bit 256/512 bit 224/256/384/512 bit Hash Collisions Frequent Frequent Rare Rare Security Level Low, has been successfully attacked Low, has been successfully attacked High High Applications Abandoned, still used for data integrity checks Abandoned Cryptocurrency transaction verification, digital signatures, etc. Can be used to replace SHA-2"},{"location":"chapter_hashing/hash_algorithm/#hash-values-in-data-structures","title":"Hash Values in Data Structures","text":"

We know that the keys in a hash table can be of various data types such as integers, decimals, or strings. Programming languages usually provide built-in hash algorithms for these data types to calculate the bucket indices in the hash table. Taking Python as an example, we can use the hash() function to compute the hash values for various data types.

  • The hash values of integers and booleans are their own values.
  • The calculation of hash values for floating-point numbers and strings is more complex, and interested readers are encouraged to study this on their own.
  • The hash value of a tuple is a combination of the hash values of each of its elements, resulting in a single hash value.
  • The hash value of an object is generated based on its memory address. By overriding the hash method of an object, hash values can be generated based on content.

Tip

Be aware that the definition and methods of the built-in hash value calculation functions in different programming languages vary.

PythonC++JavaC#GoSwiftJSTSDartRustCZig built_in_hash.py
num = 3\nhash_num = hash(num)\n# Hash value of integer 3 is 3\n\nbol = True\nhash_bol = hash(bol)\n# Hash value of boolean True is 1\n\ndec = 3.14159\nhash_dec = hash(dec)\n# Hash value of decimal 3.14159 is 326484311674566659\n\nstr = \"Hello \u7b97\u6cd5\"\nhash_str = hash(str)\n# Hash value of string \"Hello \u7b97\u6cd5\" is 4617003410720528961\n\ntup = (12836, \"\u5c0f\u54c8\")\nhash_tup = hash(tup)\n# Hash value of tuple (12836, '\u5c0f\u54c8') is 1029005403108185979\n\nobj = ListNode(0)\nhash_obj = hash(obj)\n# Hash value of ListNode object at 0x1058fd810 is 274267521\n
built_in_hash.cpp
int num = 3;\nsize_t hashNum = hash<int>()(num);\n// Hash value of integer 3 is 3\n\nbool bol = true;\nsize_t hashBol = hash<bool>()(bol);\n// Hash value of boolean 1 is 1\n\ndouble dec = 3.14159;\nsize_t hashDec = hash<double>()(dec);\n// Hash value of decimal 3.14159 is 4614256650576692846\n\nstring str = \"Hello \u7b97\u6cd5\";\nsize_t hashStr = hash<string>()(str);\n// Hash value of string \"Hello \u7b97\u6cd5\" is 15466937326284535026\n\n// In C++, built-in std::hash() only provides hash values for basic data types\n// Hash values for arrays and objects need to be implemented separately\n
built_in_hash.java
int num = 3;\nint hashNum = Integer.hashCode(num);\n// Hash value of integer 3 is 3\n\nboolean bol = true;\nint hashBol = Boolean.hashCode(bol);\n// Hash value of boolean true is 1231\n\ndouble dec = 3.14159;\nint hashDec = Double.hashCode(dec);\n// Hash value of decimal 3.14159 is -1340954729\n\nString str = \"Hello \u7b97\u6cd5\";\nint hashStr = str.hashCode();\n// Hash value of string \"Hello \u7b97\u6cd5\" is -727081396\n\nObject[] arr = { 12836, \"\u5c0f\u54c8\" };\nint hashTup = Arrays.hashCode(arr);\n// Hash value of array [12836, \u5c0f\u54c8] is 1151158\n\nListNode obj = new ListNode(0);\nint hashObj = obj.hashCode();\n// Hash value of ListNode object utils.ListNode@7dc5e7b4 is 2110121908\n
built_in_hash.cs
int num = 3;\nint hashNum = num.GetHashCode();\n// Hash value of integer 3 is 3;\n\nbool bol = true;\nint hashBol = bol.GetHashCode();\n// Hash value of boolean true is 1;\n\ndouble dec = 3.14159;\nint hashDec = dec.GetHashCode();\n// Hash value of decimal 3.14159 is -1340954729;\n\nstring str = \"Hello \u7b97\u6cd5\";\nint hashStr = str.GetHashCode();\n// Hash value of string \"Hello \u7b97\u6cd5\" is -586107568;\n\nobject[] arr = [12836, \"\u5c0f\u54c8\"];\nint hashTup = arr.GetHashCode();\n// Hash value of array [12836, \u5c0f\u54c8] is 42931033;\n\nListNode obj = new(0);\nint hashObj = obj.GetHashCode();\n// Hash value of ListNode object 0 is 39053774;\n
built_in_hash.go
// Go does not provide built-in hash code functions\n
built_in_hash.swift
let num = 3\nlet hashNum = num.hashValue\n// Hash value of integer 3 is 9047044699613009734\n\nlet bol = true\nlet hashBol = bol.hashValue\n// Hash value of boolean true is -4431640247352757451\n\nlet dec = 3.14159\nlet hashDec = dec.hashValue\n// Hash value of decimal 3.14159 is -2465384235396674631\n\nlet str = \"Hello \u7b97\u6cd5\"\nlet hashStr = str.hashValue\n// Hash value of string \"Hello \u7b97\u6cd5\" is -7850626797806988787\n\nlet arr = [AnyHashable(12836), AnyHashable(\"\u5c0f\u54c8\")]\nlet hashTup = arr.hashValue\n// Hash value of array [AnyHashable(12836), AnyHashable(\"\u5c0f\u54c8\")] is -2308633508154532996\n\nlet obj = ListNode(x: 0)\nlet hashObj = obj.hashValue\n// Hash value of ListNode object utils.ListNode is -2434780518035996159\n
built_in_hash.js
// JavaScript does not provide built-in hash code functions\n
built_in_hash.ts
// TypeScript does not provide built-in hash code functions\n
built_in_hash.dart
int num = 3;\nint hashNum = num.hashCode;\n// Hash value of integer 3 is 34803\n\nbool bol = true;\nint hashBol = bol.hashCode;\n// Hash value of boolean true is 1231\n\ndouble dec = 3.14159;\nint hashDec = dec.hashCode;\n// Hash value of decimal 3.14159 is 2570631074981783\n\nString str = \"Hello \u7b97\u6cd5\";\nint hashStr = str.hashCode;\n// Hash value of string \"Hello \u7b97\u6cd5\" is 468167534\n\nList arr = [12836, \"\u5c0f\u54c8\"];\nint hashArr = arr.hashCode;\n// Hash value of array [12836, \u5c0f\u54c8] is 976512528\n\nListNode obj = new ListNode(0);\nint hashObj = obj.hashCode;\n// Hash value of ListNode object Instance of 'ListNode' is 1033450432\n
built_in_hash.rs
use std::collections::hash_map::DefaultHasher;\nuse std::hash::{Hash, Hasher};\n\nlet num = 3;\nlet mut num_hasher = DefaultHasher::new();\nnum.hash(&mut num_hasher);\nlet hash_num = num_hasher.finish();\n// Hash value of integer 3 is 568126464209439262\n\nlet bol = true;\nlet mut bol_hasher = DefaultHasher::new();\nbol.hash(&mut bol_hasher);\nlet hash_bol = bol_hasher.finish();\n// Hash value of boolean true is 4952851536318644461\n\nlet dec: f32 = 3.14159;\nlet mut dec_hasher = DefaultHasher::new();\ndec.to_bits().hash(&mut dec_hasher);\nlet hash_dec = dec_hasher.finish();\n// Hash value of decimal 3.14159 is 2566941990314602357\n\nlet str = \"Hello \u7b97\u6cd5\";\nlet mut str_hasher = DefaultHasher::new();\nstr.hash(&mut str_hasher);\nlet hash_str = str_hasher.finish();\n// Hash value of string \"Hello \u7b97\u6cd5\" is 16092673739211250988\n\nlet arr = (&12836, &\"\u5c0f\u54c8\");\nlet mut tup_hasher = DefaultHasher::new();\narr.hash(&mut tup_hasher);\nlet hash_tup = tup_hasher.finish();\n// Hash value of tuple (12836, \"\u5c0f\u54c8\") is 1885128010422702749\n\nlet node = ListNode::new(42);\nlet mut hasher = DefaultHasher::new();\nnode.borrow().val.hash(&mut hasher);\nlet hash = hasher.finish();\n// Hash value of ListNode object RefCell { value: ListNode { val: 42, next: None } } is 15387811073369036852\n
built_in_hash.c
// C does not provide built-in hash code functions\n
built_in_hash.zig
\n
Code Visualization

Full Screen >

In many programming languages, only immutable objects can serve as the key in a hash table. If we use a list (dynamic array) as a key, when the contents of the list change, its hash value also changes, and we would no longer be able to find the original value in the hash table.

Although the member variables of a custom object (such as a linked list node) are mutable, it is hashable. This is because the hash value of an object is usually generated based on its memory address, and even if the contents of the object change, the memory address remains the same, so the hash value remains unchanged.

You might have noticed that the hash values output in different consoles are different. This is because the Python interpreter adds a random salt to the string hash function each time it starts up. This approach effectively prevents HashDoS attacks and enhances the security of the hash algorithm.

"},{"location":"chapter_hashing/hash_collision/","title":"6.2 \u00a0 Hash Collision","text":"

As mentioned in the previous section, usually the input space of a hash function is much larger than its output space, making hash collisions theoretically inevitable. For example, if the input space consists of all integers and the output space is the size of the array capacity, multiple integers will inevitably map to the same bucket index.

Hash collisions can lead to incorrect query results, severely affecting the usability of hash tables. To solve this problem, we expand the hash table whenever a hash collision occurs, until the collision is resolved. This method is simple and effective but inefficient due to the extensive data transfer and hash value computation involved in resizing the hash table. To improve efficiency, we can adopt the following strategies:

  1. Improve the data structure of the hash table, allowing it to function normally in the event of a hash collision.
  2. Only perform resizing when necessary, i.e., when hash collisions are severe.

There are mainly two methods for improving the structure of hash tables: \"Separate Chaining\" and \"Open Addressing\".

"},{"location":"chapter_hashing/hash_collision/#621-separate-chaining","title":"6.2.1 \u00a0 Separate Chaining","text":"

In the original hash table, each bucket can store only one key-value pair. \"Separate chaining\" transforms individual elements into a linked list, with key-value pairs as list nodes, storing all colliding key-value pairs in the same list. The Figure 6-5 shows an example of a hash table with separate chaining.

Figure 6-5 \u00a0 Separate Chaining Hash Table

The operations of a hash table implemented with separate chaining have changed as follows:

  • Querying Elements: Input key, pass through the hash function to obtain the bucket index, access the head node of the list, then traverse the list and compare key to find the target key-value pair.
  • Adding Elements: First access the list head node via the hash function, then add the node (key-value pair) to the list.
  • Deleting Elements: Access the list head based on the hash function's result, then traverse the list to find and remove the target node.

Separate chaining has the following limitations:

  • Increased Space Usage: The linked list contains node pointers, which consume more memory space than arrays.
  • Reduced Query Efficiency: Due to the need for linear traversal of the list to find the corresponding element.

The code below provides a simple implementation of a separate chaining hash table, with two things to note:

  • Lists (dynamic arrays) are used instead of linked lists for simplicity. In this setup, the hash table (array) contains multiple buckets, each of which is a list.
  • This implementation includes a method for resizing the hash table. When the load factor exceeds \\(\\frac{2}{3}\\), we resize the hash table to twice its original size.
PythonC++JavaC#GoSwiftJSTSDartRustCZig hash_map_chaining.py
class HashMapChaining:\n    \"\"\"\u94fe\u5f0f\u5730\u5740\u54c8\u5e0c\u8868\"\"\"\n\n    def __init__(self):\n        \"\"\"\u6784\u9020\u65b9\u6cd5\"\"\"\n        self.size = 0  # \u952e\u503c\u5bf9\u6570\u91cf\n        self.capacity = 4  # \u54c8\u5e0c\u8868\u5bb9\u91cf\n        self.load_thres = 2.0 / 3.0  # \u89e6\u53d1\u6269\u5bb9\u7684\u8d1f\u8f7d\u56e0\u5b50\u9608\u503c\n        self.extend_ratio = 2  # \u6269\u5bb9\u500d\u6570\n        self.buckets = [[] for _ in range(self.capacity)]  # \u6876\u6570\u7ec4\n\n    def hash_func(self, key: int) -> int:\n        \"\"\"\u54c8\u5e0c\u51fd\u6570\"\"\"\n        return key % self.capacity\n\n    def load_factor(self) -> float:\n        \"\"\"\u8d1f\u8f7d\u56e0\u5b50\"\"\"\n        return self.size / self.capacity\n\n    def get(self, key: int) -> str | None:\n        \"\"\"\u67e5\u8be2\u64cd\u4f5c\"\"\"\n        index = self.hash_func(key)\n        bucket = self.buckets[index]\n        # \u904d\u5386\u6876\uff0c\u82e5\u627e\u5230 key \uff0c\u5219\u8fd4\u56de\u5bf9\u5e94 val\n        for pair in bucket:\n            if pair.key == key:\n                return pair.val\n        # \u82e5\u672a\u627e\u5230 key \uff0c\u5219\u8fd4\u56de None\n        return None\n\n    def put(self, key: int, val: str):\n        \"\"\"\u6dfb\u52a0\u64cd\u4f5c\"\"\"\n        # \u5f53\u8d1f\u8f7d\u56e0\u5b50\u8d85\u8fc7\u9608\u503c\u65f6\uff0c\u6267\u884c\u6269\u5bb9\n        if self.load_factor() > self.load_thres:\n            self.extend()\n        index = self.hash_func(key)\n        bucket = self.buckets[index]\n        # \u904d\u5386\u6876\uff0c\u82e5\u9047\u5230\u6307\u5b9a key \uff0c\u5219\u66f4\u65b0\u5bf9\u5e94 val \u5e76\u8fd4\u56de\n        for pair in bucket:\n            if pair.key == key:\n                pair.val = val\n                return\n        # \u82e5\u65e0\u8be5 key \uff0c\u5219\u5c06\u952e\u503c\u5bf9\u6dfb\u52a0\u81f3\u5c3e\u90e8\n        pair = Pair(key, val)\n        bucket.append(pair)\n        self.size += 1\n\n    def remove(self, key: int):\n        \"\"\"\u5220\u9664\u64cd\u4f5c\"\"\"\n        index = self.hash_func(key)\n        bucket = self.buckets[index]\n        # \u904d\u5386\u6876\uff0c\u4ece\u4e2d\u5220\u9664\u952e\u503c\u5bf9\n        for pair in bucket:\n            if pair.key == key:\n                bucket.remove(pair)\n                self.size -= 1\n                break\n\n    def extend(self):\n        \"\"\"\u6269\u5bb9\u54c8\u5e0c\u8868\"\"\"\n        # \u6682\u5b58\u539f\u54c8\u5e0c\u8868\n        buckets = self.buckets\n        # \u521d\u59cb\u5316\u6269\u5bb9\u540e\u7684\u65b0\u54c8\u5e0c\u8868\n        self.capacity *= self.extend_ratio\n        self.buckets = [[] for _ in range(self.capacity)]\n        self.size = 0\n        # \u5c06\u952e\u503c\u5bf9\u4ece\u539f\u54c8\u5e0c\u8868\u642c\u8fd0\u81f3\u65b0\u54c8\u5e0c\u8868\n        for bucket in buckets:\n            for pair in bucket:\n                self.put(pair.key, pair.val)\n\n    def print(self):\n        \"\"\"\u6253\u5370\u54c8\u5e0c\u8868\"\"\"\n        for bucket in self.buckets:\n            res = []\n            for pair in bucket:\n                res.append(str(pair.key) + \" -> \" + pair.val)\n            print(res)\n
hash_map_chaining.cpp
/* \u94fe\u5f0f\u5730\u5740\u54c8\u5e0c\u8868 */\nclass HashMapChaining {\n  private:\n    int size;                       // \u952e\u503c\u5bf9\u6570\u91cf\n    int capacity;                   // \u54c8\u5e0c\u8868\u5bb9\u91cf\n    double loadThres;               // \u89e6\u53d1\u6269\u5bb9\u7684\u8d1f\u8f7d\u56e0\u5b50\u9608\u503c\n    int extendRatio;                // \u6269\u5bb9\u500d\u6570\n    vector<vector<Pair *>> buckets; // \u6876\u6570\u7ec4\n\n  public:\n    /* \u6784\u9020\u65b9\u6cd5 */\n    HashMapChaining() : size(0), capacity(4), loadThres(2.0 / 3.0), extendRatio(2) {\n        buckets.resize(capacity);\n    }\n\n    /* \u6790\u6784\u65b9\u6cd5 */\n    ~HashMapChaining() {\n        for (auto &bucket : buckets) {\n            for (Pair *pair : bucket) {\n                // \u91ca\u653e\u5185\u5b58\n                delete pair;\n            }\n        }\n    }\n\n    /* \u54c8\u5e0c\u51fd\u6570 */\n    int hashFunc(int key) {\n        return key % capacity;\n    }\n\n    /* \u8d1f\u8f7d\u56e0\u5b50 */\n    double loadFactor() {\n        return (double)size / (double)capacity;\n    }\n\n    /* \u67e5\u8be2\u64cd\u4f5c */\n    string get(int key) {\n        int index = hashFunc(key);\n        // \u904d\u5386\u6876\uff0c\u82e5\u627e\u5230 key \uff0c\u5219\u8fd4\u56de\u5bf9\u5e94 val\n        for (Pair *pair : buckets[index]) {\n            if (pair->key == key) {\n                return pair->val;\n            }\n        }\n        // \u82e5\u672a\u627e\u5230 key \uff0c\u5219\u8fd4\u56de\u7a7a\u5b57\u7b26\u4e32\n        return \"\";\n    }\n\n    /* \u6dfb\u52a0\u64cd\u4f5c */\n    void put(int key, string val) {\n        // \u5f53\u8d1f\u8f7d\u56e0\u5b50\u8d85\u8fc7\u9608\u503c\u65f6\uff0c\u6267\u884c\u6269\u5bb9\n        if (loadFactor() > loadThres) {\n            extend();\n        }\n        int index = hashFunc(key);\n        // \u904d\u5386\u6876\uff0c\u82e5\u9047\u5230\u6307\u5b9a key \uff0c\u5219\u66f4\u65b0\u5bf9\u5e94 val \u5e76\u8fd4\u56de\n        for (Pair *pair : buckets[index]) {\n            if (pair->key == key) {\n                pair->val = val;\n                return;\n            }\n        }\n        // \u82e5\u65e0\u8be5 key \uff0c\u5219\u5c06\u952e\u503c\u5bf9\u6dfb\u52a0\u81f3\u5c3e\u90e8\n        buckets[index].push_back(new Pair(key, val));\n        size++;\n    }\n\n    /* \u5220\u9664\u64cd\u4f5c */\n    void remove(int key) {\n        int index = hashFunc(key);\n        auto &bucket = buckets[index];\n        // \u904d\u5386\u6876\uff0c\u4ece\u4e2d\u5220\u9664\u952e\u503c\u5bf9\n        for (int i = 0; i < bucket.size(); i++) {\n            if (bucket[i]->key == key) {\n                Pair *tmp = bucket[i];\n                bucket.erase(bucket.begin() + i); // \u4ece\u4e2d\u5220\u9664\u952e\u503c\u5bf9\n                delete tmp;                       // \u91ca\u653e\u5185\u5b58\n                size--;\n                return;\n            }\n        }\n    }\n\n    /* \u6269\u5bb9\u54c8\u5e0c\u8868 */\n    void extend() {\n        // \u6682\u5b58\u539f\u54c8\u5e0c\u8868\n        vector<vector<Pair *>> bucketsTmp = buckets;\n        // \u521d\u59cb\u5316\u6269\u5bb9\u540e\u7684\u65b0\u54c8\u5e0c\u8868\n        capacity *= extendRatio;\n        buckets.clear();\n        buckets.resize(capacity);\n        size = 0;\n        // \u5c06\u952e\u503c\u5bf9\u4ece\u539f\u54c8\u5e0c\u8868\u642c\u8fd0\u81f3\u65b0\u54c8\u5e0c\u8868\n        for (auto &bucket : bucketsTmp) {\n            for (Pair *pair : bucket) {\n                put(pair->key, pair->val);\n                // \u91ca\u653e\u5185\u5b58\n                delete pair;\n            }\n        }\n    }\n\n    /* \u6253\u5370\u54c8\u5e0c\u8868 */\n    void print() {\n        for (auto &bucket : buckets) {\n            cout << \"[\";\n            for (Pair *pair : bucket) {\n                cout << pair->key << \" -> \" << pair->val << \", \";\n            }\n            cout << \"]\\n\";\n        }\n    }\n};\n
hash_map_chaining.java
/* \u94fe\u5f0f\u5730\u5740\u54c8\u5e0c\u8868 */\nclass HashMapChaining {\n    int size; // \u952e\u503c\u5bf9\u6570\u91cf\n    int capacity; // \u54c8\u5e0c\u8868\u5bb9\u91cf\n    double loadThres; // \u89e6\u53d1\u6269\u5bb9\u7684\u8d1f\u8f7d\u56e0\u5b50\u9608\u503c\n    int extendRatio; // \u6269\u5bb9\u500d\u6570\n    List<List<Pair>> buckets; // \u6876\u6570\u7ec4\n\n    /* \u6784\u9020\u65b9\u6cd5 */\n    public HashMapChaining() {\n        size = 0;\n        capacity = 4;\n        loadThres = 2.0 / 3.0;\n        extendRatio = 2;\n        buckets = new ArrayList<>(capacity);\n        for (int i = 0; i < capacity; i++) {\n            buckets.add(new ArrayList<>());\n        }\n    }\n\n    /* \u54c8\u5e0c\u51fd\u6570 */\n    int hashFunc(int key) {\n        return key % capacity;\n    }\n\n    /* \u8d1f\u8f7d\u56e0\u5b50 */\n    double loadFactor() {\n        return (double) size / capacity;\n    }\n\n    /* \u67e5\u8be2\u64cd\u4f5c */\n    String get(int key) {\n        int index = hashFunc(key);\n        List<Pair> bucket = buckets.get(index);\n        // \u904d\u5386\u6876\uff0c\u82e5\u627e\u5230 key \uff0c\u5219\u8fd4\u56de\u5bf9\u5e94 val\n        for (Pair pair : bucket) {\n            if (pair.key == key) {\n                return pair.val;\n            }\n        }\n        // \u82e5\u672a\u627e\u5230 key \uff0c\u5219\u8fd4\u56de null\n        return null;\n    }\n\n    /* \u6dfb\u52a0\u64cd\u4f5c */\n    void put(int key, String val) {\n        // \u5f53\u8d1f\u8f7d\u56e0\u5b50\u8d85\u8fc7\u9608\u503c\u65f6\uff0c\u6267\u884c\u6269\u5bb9\n        if (loadFactor() > loadThres) {\n            extend();\n        }\n        int index = hashFunc(key);\n        List<Pair> bucket = buckets.get(index);\n        // \u904d\u5386\u6876\uff0c\u82e5\u9047\u5230\u6307\u5b9a key \uff0c\u5219\u66f4\u65b0\u5bf9\u5e94 val \u5e76\u8fd4\u56de\n        for (Pair pair : bucket) {\n            if (pair.key == key) {\n                pair.val = val;\n                return;\n            }\n        }\n        // \u82e5\u65e0\u8be5 key \uff0c\u5219\u5c06\u952e\u503c\u5bf9\u6dfb\u52a0\u81f3\u5c3e\u90e8\n        Pair pair = new Pair(key, val);\n        bucket.add(pair);\n        size++;\n    }\n\n    /* \u5220\u9664\u64cd\u4f5c */\n    void remove(int key) {\n        int index = hashFunc(key);\n        List<Pair> bucket = buckets.get(index);\n        // \u904d\u5386\u6876\uff0c\u4ece\u4e2d\u5220\u9664\u952e\u503c\u5bf9\n        for (Pair pair : bucket) {\n            if (pair.key == key) {\n                bucket.remove(pair);\n                size--;\n                break;\n            }\n        }\n    }\n\n    /* \u6269\u5bb9\u54c8\u5e0c\u8868 */\n    void extend() {\n        // \u6682\u5b58\u539f\u54c8\u5e0c\u8868\n        List<List<Pair>> bucketsTmp = buckets;\n        // \u521d\u59cb\u5316\u6269\u5bb9\u540e\u7684\u65b0\u54c8\u5e0c\u8868\n        capacity *= extendRatio;\n        buckets = new ArrayList<>(capacity);\n        for (int i = 0; i < capacity; i++) {\n            buckets.add(new ArrayList<>());\n        }\n        size = 0;\n        // \u5c06\u952e\u503c\u5bf9\u4ece\u539f\u54c8\u5e0c\u8868\u642c\u8fd0\u81f3\u65b0\u54c8\u5e0c\u8868\n        for (List<Pair> bucket : bucketsTmp) {\n            for (Pair pair : bucket) {\n                put(pair.key, pair.val);\n            }\n        }\n    }\n\n    /* \u6253\u5370\u54c8\u5e0c\u8868 */\n    void print() {\n        for (List<Pair> bucket : buckets) {\n            List<String> res = new ArrayList<>();\n            for (Pair pair : bucket) {\n                res.add(pair.key + \" -> \" + pair.val);\n            }\n            System.out.println(res);\n        }\n    }\n}\n
hash_map_chaining.cs
/* \u94fe\u5f0f\u5730\u5740\u54c8\u5e0c\u8868 */\nclass HashMapChaining {\n    int size; // \u952e\u503c\u5bf9\u6570\u91cf\n    int capacity; // \u54c8\u5e0c\u8868\u5bb9\u91cf\n    double loadThres; // \u89e6\u53d1\u6269\u5bb9\u7684\u8d1f\u8f7d\u56e0\u5b50\u9608\u503c\n    int extendRatio; // \u6269\u5bb9\u500d\u6570\n    List<List<Pair>> buckets; // \u6876\u6570\u7ec4\n\n    /* \u6784\u9020\u65b9\u6cd5 */\n    public HashMapChaining() {\n        size = 0;\n        capacity = 4;\n        loadThres = 2.0 / 3.0;\n        extendRatio = 2;\n        buckets = new List<List<Pair>>(capacity);\n        for (int i = 0; i < capacity; i++) {\n            buckets.Add([]);\n        }\n    }\n\n    /* \u54c8\u5e0c\u51fd\u6570 */\n    int HashFunc(int key) {\n        return key % capacity;\n    }\n\n    /* \u8d1f\u8f7d\u56e0\u5b50 */\n    double LoadFactor() {\n        return (double)size / capacity;\n    }\n\n    /* \u67e5\u8be2\u64cd\u4f5c */\n    public string? Get(int key) {\n        int index = HashFunc(key);\n        // \u904d\u5386\u6876\uff0c\u82e5\u627e\u5230 key \uff0c\u5219\u8fd4\u56de\u5bf9\u5e94 val\n        foreach (Pair pair in buckets[index]) {\n            if (pair.key == key) {\n                return pair.val;\n            }\n        }\n        // \u82e5\u672a\u627e\u5230 key \uff0c\u5219\u8fd4\u56de null\n        return null;\n    }\n\n    /* \u6dfb\u52a0\u64cd\u4f5c */\n    public void Put(int key, string val) {\n        // \u5f53\u8d1f\u8f7d\u56e0\u5b50\u8d85\u8fc7\u9608\u503c\u65f6\uff0c\u6267\u884c\u6269\u5bb9\n        if (LoadFactor() > loadThres) {\n            Extend();\n        }\n        int index = HashFunc(key);\n        // \u904d\u5386\u6876\uff0c\u82e5\u9047\u5230\u6307\u5b9a key \uff0c\u5219\u66f4\u65b0\u5bf9\u5e94 val \u5e76\u8fd4\u56de\n        foreach (Pair pair in buckets[index]) {\n            if (pair.key == key) {\n                pair.val = val;\n                return;\n            }\n        }\n        // \u82e5\u65e0\u8be5 key \uff0c\u5219\u5c06\u952e\u503c\u5bf9\u6dfb\u52a0\u81f3\u5c3e\u90e8\n        buckets[index].Add(new Pair(key, val));\n        size++;\n    }\n\n    /* \u5220\u9664\u64cd\u4f5c */\n    public void Remove(int key) {\n        int index = HashFunc(key);\n        // \u904d\u5386\u6876\uff0c\u4ece\u4e2d\u5220\u9664\u952e\u503c\u5bf9\n        foreach (Pair pair in buckets[index].ToList()) {\n            if (pair.key == key) {\n                buckets[index].Remove(pair);\n                size--;\n                break;\n            }\n        }\n    }\n\n    /* \u6269\u5bb9\u54c8\u5e0c\u8868 */\n    void Extend() {\n        // \u6682\u5b58\u539f\u54c8\u5e0c\u8868\n        List<List<Pair>> bucketsTmp = buckets;\n        // \u521d\u59cb\u5316\u6269\u5bb9\u540e\u7684\u65b0\u54c8\u5e0c\u8868\n        capacity *= extendRatio;\n        buckets = new List<List<Pair>>(capacity);\n        for (int i = 0; i < capacity; i++) {\n            buckets.Add([]);\n        }\n        size = 0;\n        // \u5c06\u952e\u503c\u5bf9\u4ece\u539f\u54c8\u5e0c\u8868\u642c\u8fd0\u81f3\u65b0\u54c8\u5e0c\u8868\n        foreach (List<Pair> bucket in bucketsTmp) {\n            foreach (Pair pair in bucket) {\n                Put(pair.key, pair.val);\n            }\n        }\n    }\n\n    /* \u6253\u5370\u54c8\u5e0c\u8868 */\n    public void Print() {\n        foreach (List<Pair> bucket in buckets) {\n            List<string> res = [];\n            foreach (Pair pair in bucket) {\n                res.Add(pair.key + \" -> \" + pair.val);\n            }\n            foreach (string kv in res) {\n                Console.WriteLine(kv);\n            }\n        }\n    }\n}\n
hash_map_chaining.go
/* \u94fe\u5f0f\u5730\u5740\u54c8\u5e0c\u8868 */\ntype hashMapChaining struct {\n    size        int      // \u952e\u503c\u5bf9\u6570\u91cf\n    capacity    int      // \u54c8\u5e0c\u8868\u5bb9\u91cf\n    loadThres   float64  // \u89e6\u53d1\u6269\u5bb9\u7684\u8d1f\u8f7d\u56e0\u5b50\u9608\u503c\n    extendRatio int      // \u6269\u5bb9\u500d\u6570\n    buckets     [][]pair // \u6876\u6570\u7ec4\n}\n\n/* \u6784\u9020\u65b9\u6cd5 */\nfunc newHashMapChaining() *hashMapChaining {\n    buckets := make([][]pair, 4)\n    for i := 0; i < 4; i++ {\n        buckets[i] = make([]pair, 0)\n    }\n    return &hashMapChaining{\n        size:        0,\n        capacity:    4,\n        loadThres:   2.0 / 3.0,\n        extendRatio: 2,\n        buckets:     buckets,\n    }\n}\n\n/* \u54c8\u5e0c\u51fd\u6570 */\nfunc (m *hashMapChaining) hashFunc(key int) int {\n    return key % m.capacity\n}\n\n/* \u8d1f\u8f7d\u56e0\u5b50 */\nfunc (m *hashMapChaining) loadFactor() float64 {\n    return float64(m.size) / float64(m.capacity)\n}\n\n/* \u67e5\u8be2\u64cd\u4f5c */\nfunc (m *hashMapChaining) get(key int) string {\n    idx := m.hashFunc(key)\n    bucket := m.buckets[idx]\n    // \u904d\u5386\u6876\uff0c\u82e5\u627e\u5230 key \uff0c\u5219\u8fd4\u56de\u5bf9\u5e94 val\n    for _, p := range bucket {\n        if p.key == key {\n            return p.val\n        }\n    }\n    // \u82e5\u672a\u627e\u5230 key \uff0c\u5219\u8fd4\u56de\u7a7a\u5b57\u7b26\u4e32\n    return \"\"\n}\n\n/* \u6dfb\u52a0\u64cd\u4f5c */\nfunc (m *hashMapChaining) put(key int, val string) {\n    // \u5f53\u8d1f\u8f7d\u56e0\u5b50\u8d85\u8fc7\u9608\u503c\u65f6\uff0c\u6267\u884c\u6269\u5bb9\n    if m.loadFactor() > m.loadThres {\n        m.extend()\n    }\n    idx := m.hashFunc(key)\n    // \u904d\u5386\u6876\uff0c\u82e5\u9047\u5230\u6307\u5b9a key \uff0c\u5219\u66f4\u65b0\u5bf9\u5e94 val \u5e76\u8fd4\u56de\n    for i := range m.buckets[idx] {\n        if m.buckets[idx][i].key == key {\n            m.buckets[idx][i].val = val\n            return\n        }\n    }\n    // \u82e5\u65e0\u8be5 key \uff0c\u5219\u5c06\u952e\u503c\u5bf9\u6dfb\u52a0\u81f3\u5c3e\u90e8\n    p := pair{\n        key: key,\n        val: val,\n    }\n    m.buckets[idx] = append(m.buckets[idx], p)\n    m.size += 1\n}\n\n/* \u5220\u9664\u64cd\u4f5c */\nfunc (m *hashMapChaining) remove(key int) {\n    idx := m.hashFunc(key)\n    // \u904d\u5386\u6876\uff0c\u4ece\u4e2d\u5220\u9664\u952e\u503c\u5bf9\n    for i, p := range m.buckets[idx] {\n        if p.key == key {\n            // \u5207\u7247\u5220\u9664\n            m.buckets[idx] = append(m.buckets[idx][:i], m.buckets[idx][i+1:]...)\n            m.size -= 1\n            break\n        }\n    }\n}\n\n/* \u6269\u5bb9\u54c8\u5e0c\u8868 */\nfunc (m *hashMapChaining) extend() {\n    // \u6682\u5b58\u539f\u54c8\u5e0c\u8868\n    tmpBuckets := make([][]pair, len(m.buckets))\n    for i := 0; i < len(m.buckets); i++ {\n        tmpBuckets[i] = make([]pair, len(m.buckets[i]))\n        copy(tmpBuckets[i], m.buckets[i])\n    }\n    // \u521d\u59cb\u5316\u6269\u5bb9\u540e\u7684\u65b0\u54c8\u5e0c\u8868\n    m.capacity *= m.extendRatio\n    m.buckets = make([][]pair, m.capacity)\n    for i := 0; i < m.capacity; i++ {\n        m.buckets[i] = make([]pair, 0)\n    }\n    m.size = 0\n    // \u5c06\u952e\u503c\u5bf9\u4ece\u539f\u54c8\u5e0c\u8868\u642c\u8fd0\u81f3\u65b0\u54c8\u5e0c\u8868\n    for _, bucket := range tmpBuckets {\n        for _, p := range bucket {\n            m.put(p.key, p.val)\n        }\n    }\n}\n\n/* \u6253\u5370\u54c8\u5e0c\u8868 */\nfunc (m *hashMapChaining) print() {\n    var builder strings.Builder\n\n    for _, bucket := range m.buckets {\n        builder.WriteString(\"[\")\n        for _, p := range bucket {\n            builder.WriteString(strconv.Itoa(p.key) + \" -> \" + p.val + \" \")\n        }\n        builder.WriteString(\"]\")\n        fmt.Println(builder.String())\n        builder.Reset()\n    }\n}\n
hash_map_chaining.swift
/* \u94fe\u5f0f\u5730\u5740\u54c8\u5e0c\u8868 */\nclass HashMapChaining {\n    var size: Int // \u952e\u503c\u5bf9\u6570\u91cf\n    var capacity: Int // \u54c8\u5e0c\u8868\u5bb9\u91cf\n    var loadThres: Double // \u89e6\u53d1\u6269\u5bb9\u7684\u8d1f\u8f7d\u56e0\u5b50\u9608\u503c\n    var extendRatio: Int // \u6269\u5bb9\u500d\u6570\n    var buckets: [[Pair]] // \u6876\u6570\u7ec4\n\n    /* \u6784\u9020\u65b9\u6cd5 */\n    init() {\n        size = 0\n        capacity = 4\n        loadThres = 2.0 / 3.0\n        extendRatio = 2\n        buckets = Array(repeating: [], count: capacity)\n    }\n\n    /* \u54c8\u5e0c\u51fd\u6570 */\n    func hashFunc(key: Int) -> Int {\n        key % capacity\n    }\n\n    /* \u8d1f\u8f7d\u56e0\u5b50 */\n    func loadFactor() -> Double {\n        Double(size) / Double(capacity)\n    }\n\n    /* \u67e5\u8be2\u64cd\u4f5c */\n    func get(key: Int) -> String? {\n        let index = hashFunc(key: key)\n        let bucket = buckets[index]\n        // \u904d\u5386\u6876\uff0c\u82e5\u627e\u5230 key \uff0c\u5219\u8fd4\u56de\u5bf9\u5e94 val\n        for pair in bucket {\n            if pair.key == key {\n                return pair.val\n            }\n        }\n        // \u82e5\u672a\u627e\u5230 key \uff0c\u5219\u8fd4\u56de nil\n        return nil\n    }\n\n    /* \u6dfb\u52a0\u64cd\u4f5c */\n    func put(key: Int, val: String) {\n        // \u5f53\u8d1f\u8f7d\u56e0\u5b50\u8d85\u8fc7\u9608\u503c\u65f6\uff0c\u6267\u884c\u6269\u5bb9\n        if loadFactor() > loadThres {\n            extend()\n        }\n        let index = hashFunc(key: key)\n        let bucket = buckets[index]\n        // \u904d\u5386\u6876\uff0c\u82e5\u9047\u5230\u6307\u5b9a key \uff0c\u5219\u66f4\u65b0\u5bf9\u5e94 val \u5e76\u8fd4\u56de\n        for pair in bucket {\n            if pair.key == key {\n                pair.val = val\n                return\n            }\n        }\n        // \u82e5\u65e0\u8be5 key \uff0c\u5219\u5c06\u952e\u503c\u5bf9\u6dfb\u52a0\u81f3\u5c3e\u90e8\n        let pair = Pair(key: key, val: val)\n        buckets[index].append(pair)\n        size += 1\n    }\n\n    /* \u5220\u9664\u64cd\u4f5c */\n    func remove(key: Int) {\n        let index = hashFunc(key: key)\n        let bucket = buckets[index]\n        // \u904d\u5386\u6876\uff0c\u4ece\u4e2d\u5220\u9664\u952e\u503c\u5bf9\n        for (pairIndex, pair) in bucket.enumerated() {\n            if pair.key == key {\n                buckets[index].remove(at: pairIndex)\n                size -= 1\n                break\n            }\n        }\n    }\n\n    /* \u6269\u5bb9\u54c8\u5e0c\u8868 */\n    func extend() {\n        // \u6682\u5b58\u539f\u54c8\u5e0c\u8868\n        let bucketsTmp = buckets\n        // \u521d\u59cb\u5316\u6269\u5bb9\u540e\u7684\u65b0\u54c8\u5e0c\u8868\n        capacity *= extendRatio\n        buckets = Array(repeating: [], count: capacity)\n        size = 0\n        // \u5c06\u952e\u503c\u5bf9\u4ece\u539f\u54c8\u5e0c\u8868\u642c\u8fd0\u81f3\u65b0\u54c8\u5e0c\u8868\n        for bucket in bucketsTmp {\n            for pair in bucket {\n                put(key: pair.key, val: pair.val)\n            }\n        }\n    }\n\n    /* \u6253\u5370\u54c8\u5e0c\u8868 */\n    func print() {\n        for bucket in buckets {\n            let res = bucket.map { \"\\($0.key) -> \\($0.val)\" }\n            Swift.print(res)\n        }\n    }\n}\n
hash_map_chaining.js
/* \u94fe\u5f0f\u5730\u5740\u54c8\u5e0c\u8868 */\nclass HashMapChaining {\n    #size; // \u952e\u503c\u5bf9\u6570\u91cf\n    #capacity; // \u54c8\u5e0c\u8868\u5bb9\u91cf\n    #loadThres; // \u89e6\u53d1\u6269\u5bb9\u7684\u8d1f\u8f7d\u56e0\u5b50\u9608\u503c\n    #extendRatio; // \u6269\u5bb9\u500d\u6570\n    #buckets; // \u6876\u6570\u7ec4\n\n    /* \u6784\u9020\u65b9\u6cd5 */\n    constructor() {\n        this.#size = 0;\n        this.#capacity = 4;\n        this.#loadThres = 2.0 / 3.0;\n        this.#extendRatio = 2;\n        this.#buckets = new Array(this.#capacity).fill(null).map((x) => []);\n    }\n\n    /* \u54c8\u5e0c\u51fd\u6570 */\n    #hashFunc(key) {\n        return key % this.#capacity;\n    }\n\n    /* \u8d1f\u8f7d\u56e0\u5b50 */\n    #loadFactor() {\n        return this.#size / this.#capacity;\n    }\n\n    /* \u67e5\u8be2\u64cd\u4f5c */\n    get(key) {\n        const index = this.#hashFunc(key);\n        const bucket = this.#buckets[index];\n        // \u904d\u5386\u6876\uff0c\u82e5\u627e\u5230 key \uff0c\u5219\u8fd4\u56de\u5bf9\u5e94 val\n        for (const pair of bucket) {\n            if (pair.key === key) {\n                return pair.val;\n            }\n        }\n        // \u82e5\u672a\u627e\u5230 key \uff0c\u5219\u8fd4\u56de null\n        return null;\n    }\n\n    /* \u6dfb\u52a0\u64cd\u4f5c */\n    put(key, val) {\n        // \u5f53\u8d1f\u8f7d\u56e0\u5b50\u8d85\u8fc7\u9608\u503c\u65f6\uff0c\u6267\u884c\u6269\u5bb9\n        if (this.#loadFactor() > this.#loadThres) {\n            this.#extend();\n        }\n        const index = this.#hashFunc(key);\n        const bucket = this.#buckets[index];\n        // \u904d\u5386\u6876\uff0c\u82e5\u9047\u5230\u6307\u5b9a key \uff0c\u5219\u66f4\u65b0\u5bf9\u5e94 val \u5e76\u8fd4\u56de\n        for (const pair of bucket) {\n            if (pair.key === key) {\n                pair.val = val;\n                return;\n            }\n        }\n        // \u82e5\u65e0\u8be5 key \uff0c\u5219\u5c06\u952e\u503c\u5bf9\u6dfb\u52a0\u81f3\u5c3e\u90e8\n        const pair = new Pair(key, val);\n        bucket.push(pair);\n        this.#size++;\n    }\n\n    /* \u5220\u9664\u64cd\u4f5c */\n    remove(key) {\n        const index = this.#hashFunc(key);\n        let bucket = this.#buckets[index];\n        // \u904d\u5386\u6876\uff0c\u4ece\u4e2d\u5220\u9664\u952e\u503c\u5bf9\n        for (let i = 0; i < bucket.length; i++) {\n            if (bucket[i].key === key) {\n                bucket.splice(i, 1);\n                this.#size--;\n                break;\n            }\n        }\n    }\n\n    /* \u6269\u5bb9\u54c8\u5e0c\u8868 */\n    #extend() {\n        // \u6682\u5b58\u539f\u54c8\u5e0c\u8868\n        const bucketsTmp = this.#buckets;\n        // \u521d\u59cb\u5316\u6269\u5bb9\u540e\u7684\u65b0\u54c8\u5e0c\u8868\n        this.#capacity *= this.#extendRatio;\n        this.#buckets = new Array(this.#capacity).fill(null).map((x) => []);\n        this.#size = 0;\n        // \u5c06\u952e\u503c\u5bf9\u4ece\u539f\u54c8\u5e0c\u8868\u642c\u8fd0\u81f3\u65b0\u54c8\u5e0c\u8868\n        for (const bucket of bucketsTmp) {\n            for (const pair of bucket) {\n                this.put(pair.key, pair.val);\n            }\n        }\n    }\n\n    /* \u6253\u5370\u54c8\u5e0c\u8868 */\n    print() {\n        for (const bucket of this.#buckets) {\n            let res = [];\n            for (const pair of bucket) {\n                res.push(pair.key + ' -> ' + pair.val);\n            }\n            console.log(res);\n        }\n    }\n}\n
hash_map_chaining.ts
/* \u94fe\u5f0f\u5730\u5740\u54c8\u5e0c\u8868 */\nclass HashMapChaining {\n    #size: number; // \u952e\u503c\u5bf9\u6570\u91cf\n    #capacity: number; // \u54c8\u5e0c\u8868\u5bb9\u91cf\n    #loadThres: number; // \u89e6\u53d1\u6269\u5bb9\u7684\u8d1f\u8f7d\u56e0\u5b50\u9608\u503c\n    #extendRatio: number; // \u6269\u5bb9\u500d\u6570\n    #buckets: Pair[][]; // \u6876\u6570\u7ec4\n\n    /* \u6784\u9020\u65b9\u6cd5 */\n    constructor() {\n        this.#size = 0;\n        this.#capacity = 4;\n        this.#loadThres = 2.0 / 3.0;\n        this.#extendRatio = 2;\n        this.#buckets = new Array(this.#capacity).fill(null).map((x) => []);\n    }\n\n    /* \u54c8\u5e0c\u51fd\u6570 */\n    #hashFunc(key: number): number {\n        return key % this.#capacity;\n    }\n\n    /* \u8d1f\u8f7d\u56e0\u5b50 */\n    #loadFactor(): number {\n        return this.#size / this.#capacity;\n    }\n\n    /* \u67e5\u8be2\u64cd\u4f5c */\n    get(key: number): string | null {\n        const index = this.#hashFunc(key);\n        const bucket = this.#buckets[index];\n        // \u904d\u5386\u6876\uff0c\u82e5\u627e\u5230 key \uff0c\u5219\u8fd4\u56de\u5bf9\u5e94 val\n        for (const pair of bucket) {\n            if (pair.key === key) {\n                return pair.val;\n            }\n        }\n        // \u82e5\u672a\u627e\u5230 key \uff0c\u5219\u8fd4\u56de null\n        return null;\n    }\n\n    /* \u6dfb\u52a0\u64cd\u4f5c */\n    put(key: number, val: string): void {\n        // \u5f53\u8d1f\u8f7d\u56e0\u5b50\u8d85\u8fc7\u9608\u503c\u65f6\uff0c\u6267\u884c\u6269\u5bb9\n        if (this.#loadFactor() > this.#loadThres) {\n            this.#extend();\n        }\n        const index = this.#hashFunc(key);\n        const bucket = this.#buckets[index];\n        // \u904d\u5386\u6876\uff0c\u82e5\u9047\u5230\u6307\u5b9a key \uff0c\u5219\u66f4\u65b0\u5bf9\u5e94 val \u5e76\u8fd4\u56de\n        for (const pair of bucket) {\n            if (pair.key === key) {\n                pair.val = val;\n                return;\n            }\n        }\n        // \u82e5\u65e0\u8be5 key \uff0c\u5219\u5c06\u952e\u503c\u5bf9\u6dfb\u52a0\u81f3\u5c3e\u90e8\n        const pair = new Pair(key, val);\n        bucket.push(pair);\n        this.#size++;\n    }\n\n    /* \u5220\u9664\u64cd\u4f5c */\n    remove(key: number): void {\n        const index = this.#hashFunc(key);\n        let bucket = this.#buckets[index];\n        // \u904d\u5386\u6876\uff0c\u4ece\u4e2d\u5220\u9664\u952e\u503c\u5bf9\n        for (let i = 0; i < bucket.length; i++) {\n            if (bucket[i].key === key) {\n                bucket.splice(i, 1);\n                this.#size--;\n                break;\n            }\n        }\n    }\n\n    /* \u6269\u5bb9\u54c8\u5e0c\u8868 */\n    #extend(): void {\n        // \u6682\u5b58\u539f\u54c8\u5e0c\u8868\n        const bucketsTmp = this.#buckets;\n        // \u521d\u59cb\u5316\u6269\u5bb9\u540e\u7684\u65b0\u54c8\u5e0c\u8868\n        this.#capacity *= this.#extendRatio;\n        this.#buckets = new Array(this.#capacity).fill(null).map((x) => []);\n        this.#size = 0;\n        // \u5c06\u952e\u503c\u5bf9\u4ece\u539f\u54c8\u5e0c\u8868\u642c\u8fd0\u81f3\u65b0\u54c8\u5e0c\u8868\n        for (const bucket of bucketsTmp) {\n            for (const pair of bucket) {\n                this.put(pair.key, pair.val);\n            }\n        }\n    }\n\n    /* \u6253\u5370\u54c8\u5e0c\u8868 */\n    print(): void {\n        for (const bucket of this.#buckets) {\n            let res = [];\n            for (const pair of bucket) {\n                res.push(pair.key + ' -> ' + pair.val);\n            }\n            console.log(res);\n        }\n    }\n}\n
hash_map_chaining.dart
/* \u94fe\u5f0f\u5730\u5740\u54c8\u5e0c\u8868 */\nclass HashMapChaining {\n  late int size; // \u952e\u503c\u5bf9\u6570\u91cf\n  late int capacity; // \u54c8\u5e0c\u8868\u5bb9\u91cf\n  late double loadThres; // \u89e6\u53d1\u6269\u5bb9\u7684\u8d1f\u8f7d\u56e0\u5b50\u9608\u503c\n  late int extendRatio; // \u6269\u5bb9\u500d\u6570\n  late List<List<Pair>> buckets; // \u6876\u6570\u7ec4\n\n  /* \u6784\u9020\u65b9\u6cd5 */\n  HashMapChaining() {\n    size = 0;\n    capacity = 4;\n    loadThres = 2.0 / 3.0;\n    extendRatio = 2;\n    buckets = List.generate(capacity, (_) => []);\n  }\n\n  /* \u54c8\u5e0c\u51fd\u6570 */\n  int hashFunc(int key) {\n    return key % capacity;\n  }\n\n  /* \u8d1f\u8f7d\u56e0\u5b50 */\n  double loadFactor() {\n    return size / capacity;\n  }\n\n  /* \u67e5\u8be2\u64cd\u4f5c */\n  String? get(int key) {\n    int index = hashFunc(key);\n    List<Pair> bucket = buckets[index];\n    // \u904d\u5386\u6876\uff0c\u82e5\u627e\u5230 key \uff0c\u5219\u8fd4\u56de\u5bf9\u5e94 val\n    for (Pair pair in bucket) {\n      if (pair.key == key) {\n        return pair.val;\n      }\n    }\n    // \u82e5\u672a\u627e\u5230 key \uff0c\u5219\u8fd4\u56de null\n    return null;\n  }\n\n  /* \u6dfb\u52a0\u64cd\u4f5c */\n  void put(int key, String val) {\n    // \u5f53\u8d1f\u8f7d\u56e0\u5b50\u8d85\u8fc7\u9608\u503c\u65f6\uff0c\u6267\u884c\u6269\u5bb9\n    if (loadFactor() > loadThres) {\n      extend();\n    }\n    int index = hashFunc(key);\n    List<Pair> bucket = buckets[index];\n    // \u904d\u5386\u6876\uff0c\u82e5\u9047\u5230\u6307\u5b9a key \uff0c\u5219\u66f4\u65b0\u5bf9\u5e94 val \u5e76\u8fd4\u56de\n    for (Pair pair in bucket) {\n      if (pair.key == key) {\n        pair.val = val;\n        return;\n      }\n    }\n    // \u82e5\u65e0\u8be5 key \uff0c\u5219\u5c06\u952e\u503c\u5bf9\u6dfb\u52a0\u81f3\u5c3e\u90e8\n    Pair pair = Pair(key, val);\n    bucket.add(pair);\n    size++;\n  }\n\n  /* \u5220\u9664\u64cd\u4f5c */\n  void remove(int key) {\n    int index = hashFunc(key);\n    List<Pair> bucket = buckets[index];\n    // \u904d\u5386\u6876\uff0c\u4ece\u4e2d\u5220\u9664\u952e\u503c\u5bf9\n    for (Pair pair in bucket) {\n      if (pair.key == key) {\n        bucket.remove(pair);\n        size--;\n        break;\n      }\n    }\n  }\n\n  /* \u6269\u5bb9\u54c8\u5e0c\u8868 */\n  void extend() {\n    // \u6682\u5b58\u539f\u54c8\u5e0c\u8868\n    List<List<Pair>> bucketsTmp = buckets;\n    // \u521d\u59cb\u5316\u6269\u5bb9\u540e\u7684\u65b0\u54c8\u5e0c\u8868\n    capacity *= extendRatio;\n    buckets = List.generate(capacity, (_) => []);\n    size = 0;\n    // \u5c06\u952e\u503c\u5bf9\u4ece\u539f\u54c8\u5e0c\u8868\u642c\u8fd0\u81f3\u65b0\u54c8\u5e0c\u8868\n    for (List<Pair> bucket in bucketsTmp) {\n      for (Pair pair in bucket) {\n        put(pair.key, pair.val);\n      }\n    }\n  }\n\n  /* \u6253\u5370\u54c8\u5e0c\u8868 */\n  void printHashMap() {\n    for (List<Pair> bucket in buckets) {\n      List<String> res = [];\n      for (Pair pair in bucket) {\n        res.add(\"${pair.key} -> ${pair.val}\");\n      }\n      print(res);\n    }\n  }\n}\n
hash_map_chaining.rs
/* \u94fe\u5f0f\u5730\u5740\u54c8\u5e0c\u8868 */\nstruct HashMapChaining {\n    size: i32,\n    capacity: i32,\n    load_thres: f32,\n    extend_ratio: i32,\n    buckets: Vec<Vec<Pair>>,\n}\n\nimpl HashMapChaining {\n    /* \u6784\u9020\u65b9\u6cd5 */\n    fn new() -> Self {\n        Self {\n            size: 0,\n            capacity: 4,\n            load_thres: 2.0 / 3.0,\n            extend_ratio: 2,\n            buckets: vec![vec![]; 4],\n        }\n    }\n\n    /* \u54c8\u5e0c\u51fd\u6570 */\n    fn hash_func(&self, key: i32) -> usize {\n        key as usize % self.capacity as usize\n    }\n\n    /* \u8d1f\u8f7d\u56e0\u5b50 */\n    fn load_factor(&self) -> f32 {\n        self.size as f32 / self.capacity as f32\n    }\n\n    /* \u5220\u9664\u64cd\u4f5c */\n    fn remove(&mut self, key: i32) -> Option<String> {\n        let index = self.hash_func(key);\n        let bucket = &mut self.buckets[index];\n\n        // \u904d\u5386\u6876\uff0c\u4ece\u4e2d\u5220\u9664\u952e\u503c\u5bf9\n        for i in 0..bucket.len() {\n            if bucket[i].key == key {\n                let pair = bucket.remove(i);\n                self.size -= 1;\n                return Some(pair.val);\n            }\n        }\n\n        // \u82e5\u672a\u627e\u5230 key \uff0c\u5219\u8fd4\u56de None\n        None\n    }\n\n    /* \u6269\u5bb9\u54c8\u5e0c\u8868 */\n    fn extend(&mut self) {\n        // \u6682\u5b58\u539f\u54c8\u5e0c\u8868\n        let buckets_tmp = std::mem::replace(&mut self.buckets, vec![]);\n\n        // \u521d\u59cb\u5316\u6269\u5bb9\u540e\u7684\u65b0\u54c8\u5e0c\u8868\n        self.capacity *= self.extend_ratio;\n        self.buckets = vec![Vec::new(); self.capacity as usize];\n        self.size = 0;\n\n        // \u5c06\u952e\u503c\u5bf9\u4ece\u539f\u54c8\u5e0c\u8868\u642c\u8fd0\u81f3\u65b0\u54c8\u5e0c\u8868\n        for bucket in buckets_tmp {\n            for pair in bucket {\n                self.put(pair.key, pair.val);\n            }\n        }\n    }\n\n    /* \u6253\u5370\u54c8\u5e0c\u8868 */\n    fn print(&self) {\n        for bucket in &self.buckets {\n            let mut res = Vec::new();\n            for pair in bucket {\n                res.push(format!(\"{} -> {}\", pair.key, pair.val));\n            }\n            println!(\"{:?}\", res);\n        }\n    }\n\n    /* \u6dfb\u52a0\u64cd\u4f5c */\n    fn put(&mut self, key: i32, val: String) {\n        // \u5f53\u8d1f\u8f7d\u56e0\u5b50\u8d85\u8fc7\u9608\u503c\u65f6\uff0c\u6267\u884c\u6269\u5bb9\n        if self.load_factor() > self.load_thres {\n            self.extend();\n        }\n\n        let index = self.hash_func(key);\n        let bucket = &mut self.buckets[index];\n\n        // \u904d\u5386\u6876\uff0c\u82e5\u9047\u5230\u6307\u5b9a key \uff0c\u5219\u66f4\u65b0\u5bf9\u5e94 val \u5e76\u8fd4\u56de\n        for pair in bucket {\n            if pair.key == key {\n                pair.val = val.clone();\n                return;\n            }\n        }\n        let bucket = &mut self.buckets[index];\n\n        // \u82e5\u65e0\u8be5 key \uff0c\u5219\u5c06\u952e\u503c\u5bf9\u6dfb\u52a0\u81f3\u5c3e\u90e8\n        let pair = Pair {\n            key,\n            val: val.clone(),\n        };\n        bucket.push(pair);\n        self.size += 1;\n    }\n\n    /* \u67e5\u8be2\u64cd\u4f5c */\n    fn get(&self, key: i32) -> Option<&str> {\n        let index = self.hash_func(key);\n        let bucket = &self.buckets[index];\n\n        // \u904d\u5386\u6876\uff0c\u82e5\u627e\u5230 key \uff0c\u5219\u8fd4\u56de\u5bf9\u5e94 val\n        for pair in bucket {\n            if pair.key == key {\n                return Some(&pair.val);\n            }\n        }\n\n        // \u82e5\u672a\u627e\u5230 key \uff0c\u5219\u8fd4\u56de None\n        None\n    }\n}\n
hash_map_chaining.c
/* \u94fe\u8868\u8282\u70b9 */\ntypedef struct Node {\n    Pair *pair;\n    struct Node *next;\n} Node;\n\n/* \u94fe\u5f0f\u5730\u5740\u54c8\u5e0c\u8868 */\ntypedef struct {\n    int size;         // \u952e\u503c\u5bf9\u6570\u91cf\n    int capacity;     // \u54c8\u5e0c\u8868\u5bb9\u91cf\n    double loadThres; // \u89e6\u53d1\u6269\u5bb9\u7684\u8d1f\u8f7d\u56e0\u5b50\u9608\u503c\n    int extendRatio;  // \u6269\u5bb9\u500d\u6570\n    Node **buckets;   // \u6876\u6570\u7ec4\n} HashMapChaining;\n\n/* \u6784\u9020\u51fd\u6570 */\nHashMapChaining *newHashMapChaining() {\n    HashMapChaining *hashMap = (HashMapChaining *)malloc(sizeof(HashMapChaining));\n    hashMap->size = 0;\n    hashMap->capacity = 4;\n    hashMap->loadThres = 2.0 / 3.0;\n    hashMap->extendRatio = 2;\n    hashMap->buckets = (Node **)malloc(hashMap->capacity * sizeof(Node *));\n    for (int i = 0; i < hashMap->capacity; i++) {\n        hashMap->buckets[i] = NULL;\n    }\n    return hashMap;\n}\n\n/* \u6790\u6784\u51fd\u6570 */\nvoid delHashMapChaining(HashMapChaining *hashMap) {\n    for (int i = 0; i < hashMap->capacity; i++) {\n        Node *cur = hashMap->buckets[i];\n        while (cur) {\n            Node *tmp = cur;\n            cur = cur->next;\n            free(tmp->pair);\n            free(tmp);\n        }\n    }\n    free(hashMap->buckets);\n    free(hashMap);\n}\n\n/* \u54c8\u5e0c\u51fd\u6570 */\nint hashFunc(HashMapChaining *hashMap, int key) {\n    return key % hashMap->capacity;\n}\n\n/* \u8d1f\u8f7d\u56e0\u5b50 */\ndouble loadFactor(HashMapChaining *hashMap) {\n    return (double)hashMap->size / (double)hashMap->capacity;\n}\n\n/* \u67e5\u8be2\u64cd\u4f5c */\nchar *get(HashMapChaining *hashMap, int key) {\n    int index = hashFunc(hashMap, key);\n    // \u904d\u5386\u6876\uff0c\u82e5\u627e\u5230 key \uff0c\u5219\u8fd4\u56de\u5bf9\u5e94 val\n    Node *cur = hashMap->buckets[index];\n    while (cur) {\n        if (cur->pair->key == key) {\n            return cur->pair->val;\n        }\n        cur = cur->next;\n    }\n    return \"\"; // \u82e5\u672a\u627e\u5230 key \uff0c\u5219\u8fd4\u56de\u7a7a\u5b57\u7b26\u4e32\n}\n\n/* \u6dfb\u52a0\u64cd\u4f5c */\nvoid put(HashMapChaining *hashMap, int key, const char *val) {\n    // \u5f53\u8d1f\u8f7d\u56e0\u5b50\u8d85\u8fc7\u9608\u503c\u65f6\uff0c\u6267\u884c\u6269\u5bb9\n    if (loadFactor(hashMap) > hashMap->loadThres) {\n        extend(hashMap);\n    }\n    int index = hashFunc(hashMap, key);\n    // \u904d\u5386\u6876\uff0c\u82e5\u9047\u5230\u6307\u5b9a key \uff0c\u5219\u66f4\u65b0\u5bf9\u5e94 val \u5e76\u8fd4\u56de\n    Node *cur = hashMap->buckets[index];\n    while (cur) {\n        if (cur->pair->key == key) {\n            strcpy(cur->pair->val, val); // \u82e5\u9047\u5230\u6307\u5b9a key \uff0c\u5219\u66f4\u65b0\u5bf9\u5e94 val \u5e76\u8fd4\u56de\n            return;\n        }\n        cur = cur->next;\n    }\n    // \u82e5\u65e0\u8be5 key \uff0c\u5219\u5c06\u952e\u503c\u5bf9\u6dfb\u52a0\u81f3\u94fe\u8868\u5934\u90e8\n    Pair *newPair = (Pair *)malloc(sizeof(Pair));\n    newPair->key = key;\n    strcpy(newPair->val, val);\n    Node *newNode = (Node *)malloc(sizeof(Node));\n    newNode->pair = newPair;\n    newNode->next = hashMap->buckets[index];\n    hashMap->buckets[index] = newNode;\n    hashMap->size++;\n}\n\n/* \u6269\u5bb9\u54c8\u5e0c\u8868 */\nvoid extend(HashMapChaining *hashMap) {\n    // \u6682\u5b58\u539f\u54c8\u5e0c\u8868\n    int oldCapacity = hashMap->capacity;\n    Node **oldBuckets = hashMap->buckets;\n    // \u521d\u59cb\u5316\u6269\u5bb9\u540e\u7684\u65b0\u54c8\u5e0c\u8868\n    hashMap->capacity *= hashMap->extendRatio;\n    hashMap->buckets = (Node **)malloc(hashMap->capacity * sizeof(Node *));\n    for (int i = 0; i < hashMap->capacity; i++) {\n        hashMap->buckets[i] = NULL;\n    }\n    hashMap->size = 0;\n    // \u5c06\u952e\u503c\u5bf9\u4ece\u539f\u54c8\u5e0c\u8868\u642c\u8fd0\u81f3\u65b0\u54c8\u5e0c\u8868\n    for (int i = 0; i < oldCapacity; i++) {\n        Node *cur = oldBuckets[i];\n        while (cur) {\n            put(hashMap, cur->pair->key, cur->pair->val);\n            Node *temp = cur;\n            cur = cur->next;\n            // \u91ca\u653e\u5185\u5b58\n            free(temp->pair);\n            free(temp);\n        }\n    }\n\n    free(oldBuckets);\n}\n\n/* \u5220\u9664\u64cd\u4f5c */\nvoid removeItem(HashMapChaining *hashMap, int key) {\n    int index = hashFunc(hashMap, key);\n    Node *cur = hashMap->buckets[index];\n    Node *pre = NULL;\n    while (cur) {\n        if (cur->pair->key == key) {\n            // \u4ece\u4e2d\u5220\u9664\u952e\u503c\u5bf9\n            if (pre) {\n                pre->next = cur->next;\n            } else {\n                hashMap->buckets[index] = cur->next;\n            }\n            // \u91ca\u653e\u5185\u5b58\n            free(cur->pair);\n            free(cur);\n            hashMap->size--;\n            return;\n        }\n        pre = cur;\n        cur = cur->next;\n    }\n}\n\n/* \u6253\u5370\u54c8\u5e0c\u8868 */\nvoid print(HashMapChaining *hashMap) {\n    for (int i = 0; i < hashMap->capacity; i++) {\n        Node *cur = hashMap->buckets[i];\n        printf(\"[\");\n        while (cur) {\n            printf(\"%d -> %s, \", cur->pair->key, cur->pair->val);\n            cur = cur->next;\n        }\n        printf(\"]\\n\");\n    }\n}\n
hash_map_chaining.zig
[class]{HashMapChaining}-[func]{}\n
Code Visualization

Full Screen >

It's worth noting that when the list is very long, the query efficiency \\(O(n)\\) is poor. At this point, the list can be converted to an \"AVL tree\" or \"Red-Black tree\" to optimize the time complexity of the query operation to \\(O(\\log n)\\).

"},{"location":"chapter_hashing/hash_collision/#622-open-addressing","title":"6.2.2 \u00a0 Open Addressing","text":"

\"Open addressing\" does not introduce additional data structures but uses \"multiple probes\" to handle hash collisions. The probing methods mainly include linear probing, quadratic probing, and double hashing.

Let's use linear probing as an example to introduce the mechanism of open addressing hash tables.

"},{"location":"chapter_hashing/hash_collision/#1-linear-probing","title":"1. \u00a0 Linear Probing","text":"

Linear probing uses a fixed-step linear search for probing, differing from ordinary hash tables.

  • Inserting Elements: Calculate the bucket index using the hash function. If the bucket already contains an element, linearly traverse forward from the conflict position (usually with a step size of \\(1\\)) until an empty bucket is found, then insert the element.
  • Searching for Elements: If a hash collision is found, use the same step size to linearly traverse forward until the corresponding element is found and return value; if an empty bucket is encountered, it means the target element is not in the hash table, so return None.

The Figure 6-6 shows the distribution of key-value pairs in an open addressing (linear probing) hash table. According to this hash function, keys with the same last two digits will be mapped to the same bucket. Through linear probing, they are stored consecutively in that bucket and the buckets below it.

Figure 6-6 \u00a0 Distribution of Key-Value Pairs in Open Addressing (Linear Probing) Hash Table

However, linear probing tends to create \"clustering\". Specifically, the longer a continuous position in the array is occupied, the more likely these positions are to encounter hash collisions, further promoting the growth of these clusters and eventually leading to deterioration in the efficiency of operations.

It's important to note that we cannot directly delete elements in an open addressing hash table. Deleting an element creates an empty bucket None in the array. When searching for elements, if linear probing encounters this empty bucket, it will return, making the elements below this bucket inaccessible. The program may incorrectly assume these elements do not exist, as shown in the Figure 6-7 .

Figure 6-7 \u00a0 Query Issues Caused by Deletion in Open Addressing

To solve this problem, we can use a \"lazy deletion\" mechanism: instead of directly removing elements from the hash table, use a constant TOMBSTONE to mark the bucket. In this mechanism, both None and TOMBSTONE represent empty buckets and can hold key-value pairs. However, when linear probing encounters TOMBSTONE, it should continue traversing since there may still be key-value pairs below it.

However, lazy deletion may accelerate the degradation of hash table performance. Every deletion operation produces a delete mark, and as TOMBSTONE increases, so does the search time, as linear probing may have to skip multiple TOMBSTONE to find the target element.

Therefore, consider recording the index of the first TOMBSTONE encountered during linear probing and swapping the target element found with this TOMBSTONE. The advantage of this is that each time a query or addition is performed, the element is moved to a bucket closer to the ideal position (starting point of probing), thereby optimizing the query efficiency.

The code below implements an open addressing (linear probing) hash table with lazy deletion. To make fuller use of the hash table space, we treat the hash table as a \"circular array,\" continuing to traverse from the beginning when the end of the array is passed.

PythonC++JavaC#GoSwiftJSTSDartRustCZig hash_map_open_addressing.py
class HashMapOpenAddressing:\n    \"\"\"\u5f00\u653e\u5bfb\u5740\u54c8\u5e0c\u8868\"\"\"\n\n    def __init__(self):\n        \"\"\"\u6784\u9020\u65b9\u6cd5\"\"\"\n        self.size = 0  # \u952e\u503c\u5bf9\u6570\u91cf\n        self.capacity = 4  # \u54c8\u5e0c\u8868\u5bb9\u91cf\n        self.load_thres = 2.0 / 3.0  # \u89e6\u53d1\u6269\u5bb9\u7684\u8d1f\u8f7d\u56e0\u5b50\u9608\u503c\n        self.extend_ratio = 2  # \u6269\u5bb9\u500d\u6570\n        self.buckets: list[Pair | None] = [None] * self.capacity  # \u6876\u6570\u7ec4\n        self.TOMBSTONE = Pair(-1, \"-1\")  # \u5220\u9664\u6807\u8bb0\n\n    def hash_func(self, key: int) -> int:\n        \"\"\"\u54c8\u5e0c\u51fd\u6570\"\"\"\n        return key % self.capacity\n\n    def load_factor(self) -> float:\n        \"\"\"\u8d1f\u8f7d\u56e0\u5b50\"\"\"\n        return self.size / self.capacity\n\n    def find_bucket(self, key: int) -> int:\n        \"\"\"\u641c\u7d22 key \u5bf9\u5e94\u7684\u6876\u7d22\u5f15\"\"\"\n        index = self.hash_func(key)\n        first_tombstone = -1\n        # \u7ebf\u6027\u63a2\u6d4b\uff0c\u5f53\u9047\u5230\u7a7a\u6876\u65f6\u8df3\u51fa\n        while self.buckets[index] is not None:\n            # \u82e5\u9047\u5230 key \uff0c\u8fd4\u56de\u5bf9\u5e94\u7684\u6876\u7d22\u5f15\n            if self.buckets[index].key == key:\n                # \u82e5\u4e4b\u524d\u9047\u5230\u4e86\u5220\u9664\u6807\u8bb0\uff0c\u5219\u5c06\u952e\u503c\u5bf9\u79fb\u52a8\u81f3\u8be5\u7d22\u5f15\u5904\n                if first_tombstone != -1:\n                    self.buckets[first_tombstone] = self.buckets[index]\n                    self.buckets[index] = self.TOMBSTONE\n                    return first_tombstone  # \u8fd4\u56de\u79fb\u52a8\u540e\u7684\u6876\u7d22\u5f15\n                return index  # \u8fd4\u56de\u6876\u7d22\u5f15\n            # \u8bb0\u5f55\u9047\u5230\u7684\u9996\u4e2a\u5220\u9664\u6807\u8bb0\n            if first_tombstone == -1 and self.buckets[index] is self.TOMBSTONE:\n                first_tombstone = index\n            # \u8ba1\u7b97\u6876\u7d22\u5f15\uff0c\u8d8a\u8fc7\u5c3e\u90e8\u5219\u8fd4\u56de\u5934\u90e8\n            index = (index + 1) % self.capacity\n        # \u82e5 key \u4e0d\u5b58\u5728\uff0c\u5219\u8fd4\u56de\u6dfb\u52a0\u70b9\u7684\u7d22\u5f15\n        return index if first_tombstone == -1 else first_tombstone\n\n    def get(self, key: int) -> str:\n        \"\"\"\u67e5\u8be2\u64cd\u4f5c\"\"\"\n        # \u641c\u7d22 key \u5bf9\u5e94\u7684\u6876\u7d22\u5f15\n        index = self.find_bucket(key)\n        # \u82e5\u627e\u5230\u952e\u503c\u5bf9\uff0c\u5219\u8fd4\u56de\u5bf9\u5e94 val\n        if self.buckets[index] not in [None, self.TOMBSTONE]:\n            return self.buckets[index].val\n        # \u82e5\u952e\u503c\u5bf9\u4e0d\u5b58\u5728\uff0c\u5219\u8fd4\u56de None\n        return None\n\n    def put(self, key: int, val: str):\n        \"\"\"\u6dfb\u52a0\u64cd\u4f5c\"\"\"\n        # \u5f53\u8d1f\u8f7d\u56e0\u5b50\u8d85\u8fc7\u9608\u503c\u65f6\uff0c\u6267\u884c\u6269\u5bb9\n        if self.load_factor() > self.load_thres:\n            self.extend()\n        # \u641c\u7d22 key \u5bf9\u5e94\u7684\u6876\u7d22\u5f15\n        index = self.find_bucket(key)\n        # \u82e5\u627e\u5230\u952e\u503c\u5bf9\uff0c\u5219\u8986\u76d6 val \u5e76\u8fd4\u56de\n        if self.buckets[index] not in [None, self.TOMBSTONE]:\n            self.buckets[index].val = val\n            return\n        # \u82e5\u952e\u503c\u5bf9\u4e0d\u5b58\u5728\uff0c\u5219\u6dfb\u52a0\u8be5\u952e\u503c\u5bf9\n        self.buckets[index] = Pair(key, val)\n        self.size += 1\n\n    def remove(self, key: int):\n        \"\"\"\u5220\u9664\u64cd\u4f5c\"\"\"\n        # \u641c\u7d22 key \u5bf9\u5e94\u7684\u6876\u7d22\u5f15\n        index = self.find_bucket(key)\n        # \u82e5\u627e\u5230\u952e\u503c\u5bf9\uff0c\u5219\u7528\u5220\u9664\u6807\u8bb0\u8986\u76d6\u5b83\n        if self.buckets[index] not in [None, self.TOMBSTONE]:\n            self.buckets[index] = self.TOMBSTONE\n            self.size -= 1\n\n    def extend(self):\n        \"\"\"\u6269\u5bb9\u54c8\u5e0c\u8868\"\"\"\n        # \u6682\u5b58\u539f\u54c8\u5e0c\u8868\n        buckets_tmp = self.buckets\n        # \u521d\u59cb\u5316\u6269\u5bb9\u540e\u7684\u65b0\u54c8\u5e0c\u8868\n        self.capacity *= self.extend_ratio\n        self.buckets = [None] * self.capacity\n        self.size = 0\n        # \u5c06\u952e\u503c\u5bf9\u4ece\u539f\u54c8\u5e0c\u8868\u642c\u8fd0\u81f3\u65b0\u54c8\u5e0c\u8868\n        for pair in buckets_tmp:\n            if pair not in [None, self.TOMBSTONE]:\n                self.put(pair.key, pair.val)\n\n    def print(self):\n        \"\"\"\u6253\u5370\u54c8\u5e0c\u8868\"\"\"\n        for pair in self.buckets:\n            if pair is None:\n                print(\"None\")\n            elif pair is self.TOMBSTONE:\n                print(\"TOMBSTONE\")\n            else:\n                print(pair.key, \"->\", pair.val)\n
hash_map_open_addressing.cpp
/* \u5f00\u653e\u5bfb\u5740\u54c8\u5e0c\u8868 */\nclass HashMapOpenAddressing {\n  private:\n    int size;                             // \u952e\u503c\u5bf9\u6570\u91cf\n    int capacity = 4;                     // \u54c8\u5e0c\u8868\u5bb9\u91cf\n    const double loadThres = 2.0 / 3.0;     // \u89e6\u53d1\u6269\u5bb9\u7684\u8d1f\u8f7d\u56e0\u5b50\u9608\u503c\n    const int extendRatio = 2;            // \u6269\u5bb9\u500d\u6570\n    vector<Pair *> buckets;               // \u6876\u6570\u7ec4\n    Pair *TOMBSTONE = new Pair(-1, \"-1\"); // \u5220\u9664\u6807\u8bb0\n\n  public:\n    /* \u6784\u9020\u65b9\u6cd5 */\n    HashMapOpenAddressing() : size(0), buckets(capacity, nullptr) {\n    }\n\n    /* \u6790\u6784\u65b9\u6cd5 */\n    ~HashMapOpenAddressing() {\n        for (Pair *pair : buckets) {\n            if (pair != nullptr && pair != TOMBSTONE) {\n                delete pair;\n            }\n        }\n        delete TOMBSTONE;\n    }\n\n    /* \u54c8\u5e0c\u51fd\u6570 */\n    int hashFunc(int key) {\n        return key % capacity;\n    }\n\n    /* \u8d1f\u8f7d\u56e0\u5b50 */\n    double loadFactor() {\n        return (double)size / capacity;\n    }\n\n    /* \u641c\u7d22 key \u5bf9\u5e94\u7684\u6876\u7d22\u5f15 */\n    int findBucket(int key) {\n        int index = hashFunc(key);\n        int firstTombstone = -1;\n        // \u7ebf\u6027\u63a2\u6d4b\uff0c\u5f53\u9047\u5230\u7a7a\u6876\u65f6\u8df3\u51fa\n        while (buckets[index] != nullptr) {\n            // \u82e5\u9047\u5230 key \uff0c\u8fd4\u56de\u5bf9\u5e94\u7684\u6876\u7d22\u5f15\n            if (buckets[index]->key == key) {\n                // \u82e5\u4e4b\u524d\u9047\u5230\u4e86\u5220\u9664\u6807\u8bb0\uff0c\u5219\u5c06\u952e\u503c\u5bf9\u79fb\u52a8\u81f3\u8be5\u7d22\u5f15\u5904\n                if (firstTombstone != -1) {\n                    buckets[firstTombstone] = buckets[index];\n                    buckets[index] = TOMBSTONE;\n                    return firstTombstone; // \u8fd4\u56de\u79fb\u52a8\u540e\u7684\u6876\u7d22\u5f15\n                }\n                return index; // \u8fd4\u56de\u6876\u7d22\u5f15\n            }\n            // \u8bb0\u5f55\u9047\u5230\u7684\u9996\u4e2a\u5220\u9664\u6807\u8bb0\n            if (firstTombstone == -1 && buckets[index] == TOMBSTONE) {\n                firstTombstone = index;\n            }\n            // \u8ba1\u7b97\u6876\u7d22\u5f15\uff0c\u8d8a\u8fc7\u5c3e\u90e8\u5219\u8fd4\u56de\u5934\u90e8\n            index = (index + 1) % capacity;\n        }\n        // \u82e5 key \u4e0d\u5b58\u5728\uff0c\u5219\u8fd4\u56de\u6dfb\u52a0\u70b9\u7684\u7d22\u5f15\n        return firstTombstone == -1 ? index : firstTombstone;\n    }\n\n    /* \u67e5\u8be2\u64cd\u4f5c */\n    string get(int key) {\n        // \u641c\u7d22 key \u5bf9\u5e94\u7684\u6876\u7d22\u5f15\n        int index = findBucket(key);\n        // \u82e5\u627e\u5230\u952e\u503c\u5bf9\uff0c\u5219\u8fd4\u56de\u5bf9\u5e94 val\n        if (buckets[index] != nullptr && buckets[index] != TOMBSTONE) {\n            return buckets[index]->val;\n        }\n        // \u82e5\u952e\u503c\u5bf9\u4e0d\u5b58\u5728\uff0c\u5219\u8fd4\u56de\u7a7a\u5b57\u7b26\u4e32\n        return \"\";\n    }\n\n    /* \u6dfb\u52a0\u64cd\u4f5c */\n    void put(int key, string val) {\n        // \u5f53\u8d1f\u8f7d\u56e0\u5b50\u8d85\u8fc7\u9608\u503c\u65f6\uff0c\u6267\u884c\u6269\u5bb9\n        if (loadFactor() > loadThres) {\n            extend();\n        }\n        // \u641c\u7d22 key \u5bf9\u5e94\u7684\u6876\u7d22\u5f15\n        int index = findBucket(key);\n        // \u82e5\u627e\u5230\u952e\u503c\u5bf9\uff0c\u5219\u8986\u76d6 val \u5e76\u8fd4\u56de\n        if (buckets[index] != nullptr && buckets[index] != TOMBSTONE) {\n            buckets[index]->val = val;\n            return;\n        }\n        // \u82e5\u952e\u503c\u5bf9\u4e0d\u5b58\u5728\uff0c\u5219\u6dfb\u52a0\u8be5\u952e\u503c\u5bf9\n        buckets[index] = new Pair(key, val);\n        size++;\n    }\n\n    /* \u5220\u9664\u64cd\u4f5c */\n    void remove(int key) {\n        // \u641c\u7d22 key \u5bf9\u5e94\u7684\u6876\u7d22\u5f15\n        int index = findBucket(key);\n        // \u82e5\u627e\u5230\u952e\u503c\u5bf9\uff0c\u5219\u7528\u5220\u9664\u6807\u8bb0\u8986\u76d6\u5b83\n        if (buckets[index] != nullptr && buckets[index] != TOMBSTONE) {\n            delete buckets[index];\n            buckets[index] = TOMBSTONE;\n            size--;\n        }\n    }\n\n    /* \u6269\u5bb9\u54c8\u5e0c\u8868 */\n    void extend() {\n        // \u6682\u5b58\u539f\u54c8\u5e0c\u8868\n        vector<Pair *> bucketsTmp = buckets;\n        // \u521d\u59cb\u5316\u6269\u5bb9\u540e\u7684\u65b0\u54c8\u5e0c\u8868\n        capacity *= extendRatio;\n        buckets = vector<Pair *>(capacity, nullptr);\n        size = 0;\n        // \u5c06\u952e\u503c\u5bf9\u4ece\u539f\u54c8\u5e0c\u8868\u642c\u8fd0\u81f3\u65b0\u54c8\u5e0c\u8868\n        for (Pair *pair : bucketsTmp) {\n            if (pair != nullptr && pair != TOMBSTONE) {\n                put(pair->key, pair->val);\n                delete pair;\n            }\n        }\n    }\n\n    /* \u6253\u5370\u54c8\u5e0c\u8868 */\n    void print() {\n        for (Pair *pair : buckets) {\n            if (pair == nullptr) {\n                cout << \"nullptr\" << endl;\n            } else if (pair == TOMBSTONE) {\n                cout << \"TOMBSTONE\" << endl;\n            } else {\n                cout << pair->key << \" -> \" << pair->val << endl;\n            }\n        }\n    }\n};\n
hash_map_open_addressing.java
/* \u5f00\u653e\u5bfb\u5740\u54c8\u5e0c\u8868 */\nclass HashMapOpenAddressing {\n    private int size; // \u952e\u503c\u5bf9\u6570\u91cf\n    private int capacity = 4; // \u54c8\u5e0c\u8868\u5bb9\u91cf\n    private final double loadThres = 2.0 / 3.0; // \u89e6\u53d1\u6269\u5bb9\u7684\u8d1f\u8f7d\u56e0\u5b50\u9608\u503c\n    private final int extendRatio = 2; // \u6269\u5bb9\u500d\u6570\n    private Pair[] buckets; // \u6876\u6570\u7ec4\n    private final Pair TOMBSTONE = new Pair(-1, \"-1\"); // \u5220\u9664\u6807\u8bb0\n\n    /* \u6784\u9020\u65b9\u6cd5 */\n    public HashMapOpenAddressing() {\n        size = 0;\n        buckets = new Pair[capacity];\n    }\n\n    /* \u54c8\u5e0c\u51fd\u6570 */\n    private int hashFunc(int key) {\n        return key % capacity;\n    }\n\n    /* \u8d1f\u8f7d\u56e0\u5b50 */\n    private double loadFactor() {\n        return (double) size / capacity;\n    }\n\n    /* \u641c\u7d22 key \u5bf9\u5e94\u7684\u6876\u7d22\u5f15 */\n    private int findBucket(int key) {\n        int index = hashFunc(key);\n        int firstTombstone = -1;\n        // \u7ebf\u6027\u63a2\u6d4b\uff0c\u5f53\u9047\u5230\u7a7a\u6876\u65f6\u8df3\u51fa\n        while (buckets[index] != null) {\n            // \u82e5\u9047\u5230 key \uff0c\u8fd4\u56de\u5bf9\u5e94\u7684\u6876\u7d22\u5f15\n            if (buckets[index].key == key) {\n                // \u82e5\u4e4b\u524d\u9047\u5230\u4e86\u5220\u9664\u6807\u8bb0\uff0c\u5219\u5c06\u952e\u503c\u5bf9\u79fb\u52a8\u81f3\u8be5\u7d22\u5f15\u5904\n                if (firstTombstone != -1) {\n                    buckets[firstTombstone] = buckets[index];\n                    buckets[index] = TOMBSTONE;\n                    return firstTombstone; // \u8fd4\u56de\u79fb\u52a8\u540e\u7684\u6876\u7d22\u5f15\n                }\n                return index; // \u8fd4\u56de\u6876\u7d22\u5f15\n            }\n            // \u8bb0\u5f55\u9047\u5230\u7684\u9996\u4e2a\u5220\u9664\u6807\u8bb0\n            if (firstTombstone == -1 && buckets[index] == TOMBSTONE) {\n                firstTombstone = index;\n            }\n            // \u8ba1\u7b97\u6876\u7d22\u5f15\uff0c\u8d8a\u8fc7\u5c3e\u90e8\u5219\u8fd4\u56de\u5934\u90e8\n            index = (index + 1) % capacity;\n        }\n        // \u82e5 key \u4e0d\u5b58\u5728\uff0c\u5219\u8fd4\u56de\u6dfb\u52a0\u70b9\u7684\u7d22\u5f15\n        return firstTombstone == -1 ? index : firstTombstone;\n    }\n\n    /* \u67e5\u8be2\u64cd\u4f5c */\n    public String get(int key) {\n        // \u641c\u7d22 key \u5bf9\u5e94\u7684\u6876\u7d22\u5f15\n        int index = findBucket(key);\n        // \u82e5\u627e\u5230\u952e\u503c\u5bf9\uff0c\u5219\u8fd4\u56de\u5bf9\u5e94 val\n        if (buckets[index] != null && buckets[index] != TOMBSTONE) {\n            return buckets[index].val;\n        }\n        // \u82e5\u952e\u503c\u5bf9\u4e0d\u5b58\u5728\uff0c\u5219\u8fd4\u56de null\n        return null;\n    }\n\n    /* \u6dfb\u52a0\u64cd\u4f5c */\n    public void put(int key, String val) {\n        // \u5f53\u8d1f\u8f7d\u56e0\u5b50\u8d85\u8fc7\u9608\u503c\u65f6\uff0c\u6267\u884c\u6269\u5bb9\n        if (loadFactor() > loadThres) {\n            extend();\n        }\n        // \u641c\u7d22 key \u5bf9\u5e94\u7684\u6876\u7d22\u5f15\n        int index = findBucket(key);\n        // \u82e5\u627e\u5230\u952e\u503c\u5bf9\uff0c\u5219\u8986\u76d6 val \u5e76\u8fd4\u56de\n        if (buckets[index] != null && buckets[index] != TOMBSTONE) {\n            buckets[index].val = val;\n            return;\n        }\n        // \u82e5\u952e\u503c\u5bf9\u4e0d\u5b58\u5728\uff0c\u5219\u6dfb\u52a0\u8be5\u952e\u503c\u5bf9\n        buckets[index] = new Pair(key, val);\n        size++;\n    }\n\n    /* \u5220\u9664\u64cd\u4f5c */\n    public void remove(int key) {\n        // \u641c\u7d22 key \u5bf9\u5e94\u7684\u6876\u7d22\u5f15\n        int index = findBucket(key);\n        // \u82e5\u627e\u5230\u952e\u503c\u5bf9\uff0c\u5219\u7528\u5220\u9664\u6807\u8bb0\u8986\u76d6\u5b83\n        if (buckets[index] != null && buckets[index] != TOMBSTONE) {\n            buckets[index] = TOMBSTONE;\n            size--;\n        }\n    }\n\n    /* \u6269\u5bb9\u54c8\u5e0c\u8868 */\n    private void extend() {\n        // \u6682\u5b58\u539f\u54c8\u5e0c\u8868\n        Pair[] bucketsTmp = buckets;\n        // \u521d\u59cb\u5316\u6269\u5bb9\u540e\u7684\u65b0\u54c8\u5e0c\u8868\n        capacity *= extendRatio;\n        buckets = new Pair[capacity];\n        size = 0;\n        // \u5c06\u952e\u503c\u5bf9\u4ece\u539f\u54c8\u5e0c\u8868\u642c\u8fd0\u81f3\u65b0\u54c8\u5e0c\u8868\n        for (Pair pair : bucketsTmp) {\n            if (pair != null && pair != TOMBSTONE) {\n                put(pair.key, pair.val);\n            }\n        }\n    }\n\n    /* \u6253\u5370\u54c8\u5e0c\u8868 */\n    public void print() {\n        for (Pair pair : buckets) {\n            if (pair == null) {\n                System.out.println(\"null\");\n            } else if (pair == TOMBSTONE) {\n                System.out.println(\"TOMBSTONE\");\n            } else {\n                System.out.println(pair.key + \" -> \" + pair.val);\n            }\n        }\n    }\n}\n
hash_map_open_addressing.cs
/* \u5f00\u653e\u5bfb\u5740\u54c8\u5e0c\u8868 */\nclass HashMapOpenAddressing {\n    int size; // \u952e\u503c\u5bf9\u6570\u91cf\n    int capacity = 4; // \u54c8\u5e0c\u8868\u5bb9\u91cf\n    double loadThres = 2.0 / 3.0; // \u89e6\u53d1\u6269\u5bb9\u7684\u8d1f\u8f7d\u56e0\u5b50\u9608\u503c\n    int extendRatio = 2; // \u6269\u5bb9\u500d\u6570\n    Pair[] buckets; // \u6876\u6570\u7ec4\n    Pair TOMBSTONE = new(-1, \"-1\"); // \u5220\u9664\u6807\u8bb0\n\n    /* \u6784\u9020\u65b9\u6cd5 */\n    public HashMapOpenAddressing() {\n        size = 0;\n        buckets = new Pair[capacity];\n    }\n\n    /* \u54c8\u5e0c\u51fd\u6570 */\n    int HashFunc(int key) {\n        return key % capacity;\n    }\n\n    /* \u8d1f\u8f7d\u56e0\u5b50 */\n    double LoadFactor() {\n        return (double)size / capacity;\n    }\n\n    /* \u641c\u7d22 key \u5bf9\u5e94\u7684\u6876\u7d22\u5f15 */\n    int FindBucket(int key) {\n        int index = HashFunc(key);\n        int firstTombstone = -1;\n        // \u7ebf\u6027\u63a2\u6d4b\uff0c\u5f53\u9047\u5230\u7a7a\u6876\u65f6\u8df3\u51fa\n        while (buckets[index] != null) {\n            // \u82e5\u9047\u5230 key \uff0c\u8fd4\u56de\u5bf9\u5e94\u7684\u6876\u7d22\u5f15\n            if (buckets[index].key == key) {\n                // \u82e5\u4e4b\u524d\u9047\u5230\u4e86\u5220\u9664\u6807\u8bb0\uff0c\u5219\u5c06\u952e\u503c\u5bf9\u79fb\u52a8\u81f3\u8be5\u7d22\u5f15\u5904\n                if (firstTombstone != -1) {\n                    buckets[firstTombstone] = buckets[index];\n                    buckets[index] = TOMBSTONE;\n                    return firstTombstone; // \u8fd4\u56de\u79fb\u52a8\u540e\u7684\u6876\u7d22\u5f15\n                }\n                return index; // \u8fd4\u56de\u6876\u7d22\u5f15\n            }\n            // \u8bb0\u5f55\u9047\u5230\u7684\u9996\u4e2a\u5220\u9664\u6807\u8bb0\n            if (firstTombstone == -1 && buckets[index] == TOMBSTONE) {\n                firstTombstone = index;\n            }\n            // \u8ba1\u7b97\u6876\u7d22\u5f15\uff0c\u8d8a\u8fc7\u5c3e\u90e8\u5219\u8fd4\u56de\u5934\u90e8\n            index = (index + 1) % capacity;\n        }\n        // \u82e5 key \u4e0d\u5b58\u5728\uff0c\u5219\u8fd4\u56de\u6dfb\u52a0\u70b9\u7684\u7d22\u5f15\n        return firstTombstone == -1 ? index : firstTombstone;\n    }\n\n    /* \u67e5\u8be2\u64cd\u4f5c */\n    public string? Get(int key) {\n        // \u641c\u7d22 key \u5bf9\u5e94\u7684\u6876\u7d22\u5f15\n        int index = FindBucket(key);\n        // \u82e5\u627e\u5230\u952e\u503c\u5bf9\uff0c\u5219\u8fd4\u56de\u5bf9\u5e94 val\n        if (buckets[index] != null && buckets[index] != TOMBSTONE) {\n            return buckets[index].val;\n        }\n        // \u82e5\u952e\u503c\u5bf9\u4e0d\u5b58\u5728\uff0c\u5219\u8fd4\u56de null\n        return null;\n    }\n\n    /* \u6dfb\u52a0\u64cd\u4f5c */\n    public void Put(int key, string val) {\n        // \u5f53\u8d1f\u8f7d\u56e0\u5b50\u8d85\u8fc7\u9608\u503c\u65f6\uff0c\u6267\u884c\u6269\u5bb9\n        if (LoadFactor() > loadThres) {\n            Extend();\n        }\n        // \u641c\u7d22 key \u5bf9\u5e94\u7684\u6876\u7d22\u5f15\n        int index = FindBucket(key);\n        // \u82e5\u627e\u5230\u952e\u503c\u5bf9\uff0c\u5219\u8986\u76d6 val \u5e76\u8fd4\u56de\n        if (buckets[index] != null && buckets[index] != TOMBSTONE) {\n            buckets[index].val = val;\n            return;\n        }\n        // \u82e5\u952e\u503c\u5bf9\u4e0d\u5b58\u5728\uff0c\u5219\u6dfb\u52a0\u8be5\u952e\u503c\u5bf9\n        buckets[index] = new Pair(key, val);\n        size++;\n    }\n\n    /* \u5220\u9664\u64cd\u4f5c */\n    public void Remove(int key) {\n        // \u641c\u7d22 key \u5bf9\u5e94\u7684\u6876\u7d22\u5f15\n        int index = FindBucket(key);\n        // \u82e5\u627e\u5230\u952e\u503c\u5bf9\uff0c\u5219\u7528\u5220\u9664\u6807\u8bb0\u8986\u76d6\u5b83\n        if (buckets[index] != null && buckets[index] != TOMBSTONE) {\n            buckets[index] = TOMBSTONE;\n            size--;\n        }\n    }\n\n    /* \u6269\u5bb9\u54c8\u5e0c\u8868 */\n    void Extend() {\n        // \u6682\u5b58\u539f\u54c8\u5e0c\u8868\n        Pair[] bucketsTmp = buckets;\n        // \u521d\u59cb\u5316\u6269\u5bb9\u540e\u7684\u65b0\u54c8\u5e0c\u8868\n        capacity *= extendRatio;\n        buckets = new Pair[capacity];\n        size = 0;\n        // \u5c06\u952e\u503c\u5bf9\u4ece\u539f\u54c8\u5e0c\u8868\u642c\u8fd0\u81f3\u65b0\u54c8\u5e0c\u8868\n        foreach (Pair pair in bucketsTmp) {\n            if (pair != null && pair != TOMBSTONE) {\n                Put(pair.key, pair.val);\n            }\n        }\n    }\n\n    /* \u6253\u5370\u54c8\u5e0c\u8868 */\n    public void Print() {\n        foreach (Pair pair in buckets) {\n            if (pair == null) {\n                Console.WriteLine(\"null\");\n            } else if (pair == TOMBSTONE) {\n                Console.WriteLine(\"TOMBSTONE\");\n            } else {\n                Console.WriteLine(pair.key + \" -> \" + pair.val);\n            }\n        }\n    }\n}\n
hash_map_open_addressing.go
/* \u5f00\u653e\u5bfb\u5740\u54c8\u5e0c\u8868 */\ntype hashMapOpenAddressing struct {\n    size        int     // \u952e\u503c\u5bf9\u6570\u91cf\n    capacity    int     // \u54c8\u5e0c\u8868\u5bb9\u91cf\n    loadThres   float64 // \u89e6\u53d1\u6269\u5bb9\u7684\u8d1f\u8f7d\u56e0\u5b50\u9608\u503c\n    extendRatio int     // \u6269\u5bb9\u500d\u6570\n    buckets     []*pair // \u6876\u6570\u7ec4\n    TOMBSTONE   *pair   // \u5220\u9664\u6807\u8bb0\n}\n\n/* \u6784\u9020\u65b9\u6cd5 */\nfunc newHashMapOpenAddressing() *hashMapOpenAddressing {\n    return &hashMapOpenAddressing{\n        size:        0,\n        capacity:    4,\n        loadThres:   2.0 / 3.0,\n        extendRatio: 2,\n        buckets:     make([]*pair, 4),\n        TOMBSTONE:   &pair{-1, \"-1\"},\n    }\n}\n\n/* \u54c8\u5e0c\u51fd\u6570 */\nfunc (h *hashMapOpenAddressing) hashFunc(key int) int {\n    return key % h.capacity // \u6839\u636e\u952e\u8ba1\u7b97\u54c8\u5e0c\u503c\n}\n\n/* \u8d1f\u8f7d\u56e0\u5b50 */\nfunc (h *hashMapOpenAddressing) loadFactor() float64 {\n    return float64(h.size) / float64(h.capacity) // \u8ba1\u7b97\u5f53\u524d\u8d1f\u8f7d\u56e0\u5b50\n}\n\n/* \u641c\u7d22 key \u5bf9\u5e94\u7684\u6876\u7d22\u5f15 */\nfunc (h *hashMapOpenAddressing) findBucket(key int) int {\n    index := h.hashFunc(key) // \u83b7\u53d6\u521d\u59cb\u7d22\u5f15\n    firstTombstone := -1     // \u8bb0\u5f55\u9047\u5230\u7684\u7b2c\u4e00\u4e2aTOMBSTONE\u7684\u4f4d\u7f6e\n    for h.buckets[index] != nil {\n        if h.buckets[index].key == key {\n            if firstTombstone != -1 {\n                // \u82e5\u4e4b\u524d\u9047\u5230\u4e86\u5220\u9664\u6807\u8bb0\uff0c\u5219\u5c06\u952e\u503c\u5bf9\u79fb\u52a8\u81f3\u8be5\u7d22\u5f15\u5904\n                h.buckets[firstTombstone] = h.buckets[index]\n                h.buckets[index] = h.TOMBSTONE\n                return firstTombstone // \u8fd4\u56de\u79fb\u52a8\u540e\u7684\u6876\u7d22\u5f15\n            }\n            return index // \u8fd4\u56de\u627e\u5230\u7684\u7d22\u5f15\n        }\n        if firstTombstone == -1 && h.buckets[index] == h.TOMBSTONE {\n            firstTombstone = index // \u8bb0\u5f55\u9047\u5230\u7684\u9996\u4e2a\u5220\u9664\u6807\u8bb0\u7684\u4f4d\u7f6e\n        }\n        index = (index + 1) % h.capacity // \u7ebf\u6027\u63a2\u6d4b\uff0c\u8d8a\u8fc7\u5c3e\u90e8\u5219\u8fd4\u56de\u5934\u90e8\n    }\n    // \u82e5 key \u4e0d\u5b58\u5728\uff0c\u5219\u8fd4\u56de\u6dfb\u52a0\u70b9\u7684\u7d22\u5f15\n    if firstTombstone != -1 {\n        return firstTombstone\n    }\n    return index\n}\n\n/* \u67e5\u8be2\u64cd\u4f5c */\nfunc (h *hashMapOpenAddressing) get(key int) string {\n    index := h.findBucket(key) // \u641c\u7d22 key \u5bf9\u5e94\u7684\u6876\u7d22\u5f15\n    if h.buckets[index] != nil && h.buckets[index] != h.TOMBSTONE {\n        return h.buckets[index].val // \u82e5\u627e\u5230\u952e\u503c\u5bf9\uff0c\u5219\u8fd4\u56de\u5bf9\u5e94 val\n    }\n    return \"\" // \u82e5\u952e\u503c\u5bf9\u4e0d\u5b58\u5728\uff0c\u5219\u8fd4\u56de \"\"\n}\n\n/* \u6dfb\u52a0\u64cd\u4f5c */\nfunc (h *hashMapOpenAddressing) put(key int, val string) {\n    if h.loadFactor() > h.loadThres {\n        h.extend() // \u5f53\u8d1f\u8f7d\u56e0\u5b50\u8d85\u8fc7\u9608\u503c\u65f6\uff0c\u6267\u884c\u6269\u5bb9\n    }\n    index := h.findBucket(key) // \u641c\u7d22 key \u5bf9\u5e94\u7684\u6876\u7d22\u5f15\n    if h.buckets[index] == nil || h.buckets[index] == h.TOMBSTONE {\n        h.buckets[index] = &pair{key, val} // \u82e5\u952e\u503c\u5bf9\u4e0d\u5b58\u5728\uff0c\u5219\u6dfb\u52a0\u8be5\u952e\u503c\u5bf9\n        h.size++\n    } else {\n        h.buckets[index].val = val // \u82e5\u627e\u5230\u952e\u503c\u5bf9\uff0c\u5219\u8986\u76d6 val\n    }\n}\n\n/* \u5220\u9664\u64cd\u4f5c */\nfunc (h *hashMapOpenAddressing) remove(key int) {\n    index := h.findBucket(key) // \u641c\u7d22 key \u5bf9\u5e94\u7684\u6876\u7d22\u5f15\n    if h.buckets[index] != nil && h.buckets[index] != h.TOMBSTONE {\n        h.buckets[index] = h.TOMBSTONE // \u82e5\u627e\u5230\u952e\u503c\u5bf9\uff0c\u5219\u7528\u5220\u9664\u6807\u8bb0\u8986\u76d6\u5b83\n        h.size--\n    }\n}\n\n/* \u6269\u5bb9\u54c8\u5e0c\u8868 */\nfunc (h *hashMapOpenAddressing) extend() {\n    oldBuckets := h.buckets               // \u6682\u5b58\u539f\u54c8\u5e0c\u8868\n    h.capacity *= h.extendRatio           // \u66f4\u65b0\u5bb9\u91cf\n    h.buckets = make([]*pair, h.capacity) // \u521d\u59cb\u5316\u6269\u5bb9\u540e\u7684\u65b0\u54c8\u5e0c\u8868\n    h.size = 0                            // \u91cd\u7f6e\u5927\u5c0f\n    // \u5c06\u952e\u503c\u5bf9\u4ece\u539f\u54c8\u5e0c\u8868\u642c\u8fd0\u81f3\u65b0\u54c8\u5e0c\u8868\n    for _, pair := range oldBuckets {\n        if pair != nil && pair != h.TOMBSTONE {\n            h.put(pair.key, pair.val)\n        }\n    }\n}\n\n/* \u6253\u5370\u54c8\u5e0c\u8868 */\nfunc (h *hashMapOpenAddressing) print() {\n    for _, pair := range h.buckets {\n        if pair == nil {\n            fmt.Println(\"nil\")\n        } else if pair == h.TOMBSTONE {\n            fmt.Println(\"TOMBSTONE\")\n        } else {\n            fmt.Printf(\"%d -> %s\\n\", pair.key, pair.val)\n        }\n    }\n}\n
hash_map_open_addressing.swift
/* \u5f00\u653e\u5bfb\u5740\u54c8\u5e0c\u8868 */\nclass HashMapOpenAddressing {\n    var size: Int // \u952e\u503c\u5bf9\u6570\u91cf\n    var capacity: Int // \u54c8\u5e0c\u8868\u5bb9\u91cf\n    var loadThres: Double // \u89e6\u53d1\u6269\u5bb9\u7684\u8d1f\u8f7d\u56e0\u5b50\u9608\u503c\n    var extendRatio: Int // \u6269\u5bb9\u500d\u6570\n    var buckets: [Pair?] // \u6876\u6570\u7ec4\n    var TOMBSTONE: Pair // \u5220\u9664\u6807\u8bb0\n\n    /* \u6784\u9020\u65b9\u6cd5 */\n    init() {\n        size = 0\n        capacity = 4\n        loadThres = 2.0 / 3.0\n        extendRatio = 2\n        buckets = Array(repeating: nil, count: capacity)\n        TOMBSTONE = Pair(key: -1, val: \"-1\")\n    }\n\n    /* \u54c8\u5e0c\u51fd\u6570 */\n    func hashFunc(key: Int) -> Int {\n        key % capacity\n    }\n\n    /* \u8d1f\u8f7d\u56e0\u5b50 */\n    func loadFactor() -> Double {\n        Double(size) / Double(capacity)\n    }\n\n    /* \u641c\u7d22 key \u5bf9\u5e94\u7684\u6876\u7d22\u5f15 */\n    func findBucket(key: Int) -> Int {\n        var index = hashFunc(key: key)\n        var firstTombstone = -1\n        // \u7ebf\u6027\u63a2\u6d4b\uff0c\u5f53\u9047\u5230\u7a7a\u6876\u65f6\u8df3\u51fa\n        while buckets[index] != nil {\n            // \u82e5\u9047\u5230 key \uff0c\u8fd4\u56de\u5bf9\u5e94\u7684\u6876\u7d22\u5f15\n            if buckets[index]!.key == key {\n                // \u82e5\u4e4b\u524d\u9047\u5230\u4e86\u5220\u9664\u6807\u8bb0\uff0c\u5219\u5c06\u952e\u503c\u5bf9\u79fb\u52a8\u81f3\u8be5\u7d22\u5f15\u5904\n                if firstTombstone != -1 {\n                    buckets[firstTombstone] = buckets[index]\n                    buckets[index] = TOMBSTONE\n                    return firstTombstone // \u8fd4\u56de\u79fb\u52a8\u540e\u7684\u6876\u7d22\u5f15\n                }\n                return index // \u8fd4\u56de\u6876\u7d22\u5f15\n            }\n            // \u8bb0\u5f55\u9047\u5230\u7684\u9996\u4e2a\u5220\u9664\u6807\u8bb0\n            if firstTombstone == -1 && buckets[index] == TOMBSTONE {\n                firstTombstone = index\n            }\n            // \u8ba1\u7b97\u6876\u7d22\u5f15\uff0c\u8d8a\u8fc7\u5c3e\u90e8\u5219\u8fd4\u56de\u5934\u90e8\n            index = (index + 1) % capacity\n        }\n        // \u82e5 key \u4e0d\u5b58\u5728\uff0c\u5219\u8fd4\u56de\u6dfb\u52a0\u70b9\u7684\u7d22\u5f15\n        return firstTombstone == -1 ? index : firstTombstone\n    }\n\n    /* \u67e5\u8be2\u64cd\u4f5c */\n    func get(key: Int) -> String? {\n        // \u641c\u7d22 key \u5bf9\u5e94\u7684\u6876\u7d22\u5f15\n        let index = findBucket(key: key)\n        // \u82e5\u627e\u5230\u952e\u503c\u5bf9\uff0c\u5219\u8fd4\u56de\u5bf9\u5e94 val\n        if buckets[index] != nil, buckets[index] != TOMBSTONE {\n            return buckets[index]!.val\n        }\n        // \u82e5\u952e\u503c\u5bf9\u4e0d\u5b58\u5728\uff0c\u5219\u8fd4\u56de null\n        return nil\n    }\n\n    /* \u6dfb\u52a0\u64cd\u4f5c */\n    func put(key: Int, val: String) {\n        // \u5f53\u8d1f\u8f7d\u56e0\u5b50\u8d85\u8fc7\u9608\u503c\u65f6\uff0c\u6267\u884c\u6269\u5bb9\n        if loadFactor() > loadThres {\n            extend()\n        }\n        // \u641c\u7d22 key \u5bf9\u5e94\u7684\u6876\u7d22\u5f15\n        let index = findBucket(key: key)\n        // \u82e5\u627e\u5230\u952e\u503c\u5bf9\uff0c\u5219\u8986\u76d6 val \u5e76\u8fd4\u56de\n        if buckets[index] != nil, buckets[index] != TOMBSTONE {\n            buckets[index]!.val = val\n            return\n        }\n        // \u82e5\u952e\u503c\u5bf9\u4e0d\u5b58\u5728\uff0c\u5219\u6dfb\u52a0\u8be5\u952e\u503c\u5bf9\n        buckets[index] = Pair(key: key, val: val)\n        size += 1\n    }\n\n    /* \u5220\u9664\u64cd\u4f5c */\n    func remove(key: Int) {\n        // \u641c\u7d22 key \u5bf9\u5e94\u7684\u6876\u7d22\u5f15\n        let index = findBucket(key: key)\n        // \u82e5\u627e\u5230\u952e\u503c\u5bf9\uff0c\u5219\u7528\u5220\u9664\u6807\u8bb0\u8986\u76d6\u5b83\n        if buckets[index] != nil, buckets[index] != TOMBSTONE {\n            buckets[index] = TOMBSTONE\n            size -= 1\n        }\n    }\n\n    /* \u6269\u5bb9\u54c8\u5e0c\u8868 */\n    func extend() {\n        // \u6682\u5b58\u539f\u54c8\u5e0c\u8868\n        let bucketsTmp = buckets\n        // \u521d\u59cb\u5316\u6269\u5bb9\u540e\u7684\u65b0\u54c8\u5e0c\u8868\n        capacity *= extendRatio\n        buckets = Array(repeating: nil, count: capacity)\n        size = 0\n        // \u5c06\u952e\u503c\u5bf9\u4ece\u539f\u54c8\u5e0c\u8868\u642c\u8fd0\u81f3\u65b0\u54c8\u5e0c\u8868\n        for pair in bucketsTmp {\n            if let pair, pair != TOMBSTONE {\n                put(key: pair.key, val: pair.val)\n            }\n        }\n    }\n\n    /* \u6253\u5370\u54c8\u5e0c\u8868 */\n    func print() {\n        for pair in buckets {\n            if pair == nil {\n                Swift.print(\"null\")\n            } else if pair == TOMBSTONE {\n                Swift.print(\"TOMBSTONE\")\n            } else {\n                Swift.print(\"\\(pair!.key) -> \\(pair!.val)\")\n            }\n        }\n    }\n}\n
hash_map_open_addressing.js
/* \u5f00\u653e\u5bfb\u5740\u54c8\u5e0c\u8868 */\nclass HashMapOpenAddressing {\n    #size; // \u952e\u503c\u5bf9\u6570\u91cf\n    #capacity; // \u54c8\u5e0c\u8868\u5bb9\u91cf\n    #loadThres; // \u89e6\u53d1\u6269\u5bb9\u7684\u8d1f\u8f7d\u56e0\u5b50\u9608\u503c\n    #extendRatio; // \u6269\u5bb9\u500d\u6570\n    #buckets; // \u6876\u6570\u7ec4\n    #TOMBSTONE; // \u5220\u9664\u6807\u8bb0\n\n    /* \u6784\u9020\u65b9\u6cd5 */\n    constructor() {\n        this.#size = 0; // \u952e\u503c\u5bf9\u6570\u91cf\n        this.#capacity = 4; // \u54c8\u5e0c\u8868\u5bb9\u91cf\n        this.#loadThres = 2.0 / 3.0; // \u89e6\u53d1\u6269\u5bb9\u7684\u8d1f\u8f7d\u56e0\u5b50\u9608\u503c\n        this.#extendRatio = 2; // \u6269\u5bb9\u500d\u6570\n        this.#buckets = Array(this.#capacity).fill(null); // \u6876\u6570\u7ec4\n        this.#TOMBSTONE = new Pair(-1, '-1'); // \u5220\u9664\u6807\u8bb0\n    }\n\n    /* \u54c8\u5e0c\u51fd\u6570 */\n    #hashFunc(key) {\n        return key % this.#capacity;\n    }\n\n    /* \u8d1f\u8f7d\u56e0\u5b50 */\n    #loadFactor() {\n        return this.#size / this.#capacity;\n    }\n\n    /* \u641c\u7d22 key \u5bf9\u5e94\u7684\u6876\u7d22\u5f15 */\n    #findBucket(key) {\n        let index = this.#hashFunc(key);\n        let firstTombstone = -1;\n        // \u7ebf\u6027\u63a2\u6d4b\uff0c\u5f53\u9047\u5230\u7a7a\u6876\u65f6\u8df3\u51fa\n        while (this.#buckets[index] !== null) {\n            // \u82e5\u9047\u5230 key \uff0c\u8fd4\u56de\u5bf9\u5e94\u7684\u6876\u7d22\u5f15\n            if (this.#buckets[index].key === key) {\n                // \u82e5\u4e4b\u524d\u9047\u5230\u4e86\u5220\u9664\u6807\u8bb0\uff0c\u5219\u5c06\u952e\u503c\u5bf9\u79fb\u52a8\u81f3\u8be5\u7d22\u5f15\u5904\n                if (firstTombstone !== -1) {\n                    this.#buckets[firstTombstone] = this.#buckets[index];\n                    this.#buckets[index] = this.#TOMBSTONE;\n                    return firstTombstone; // \u8fd4\u56de\u79fb\u52a8\u540e\u7684\u6876\u7d22\u5f15\n                }\n                return index; // \u8fd4\u56de\u6876\u7d22\u5f15\n            }\n            // \u8bb0\u5f55\u9047\u5230\u7684\u9996\u4e2a\u5220\u9664\u6807\u8bb0\n            if (\n                firstTombstone === -1 &&\n                this.#buckets[index] === this.#TOMBSTONE\n            ) {\n                firstTombstone = index;\n            }\n            // \u8ba1\u7b97\u6876\u7d22\u5f15\uff0c\u8d8a\u8fc7\u5c3e\u90e8\u5219\u8fd4\u56de\u5934\u90e8\n            index = (index + 1) % this.#capacity;\n        }\n        // \u82e5 key \u4e0d\u5b58\u5728\uff0c\u5219\u8fd4\u56de\u6dfb\u52a0\u70b9\u7684\u7d22\u5f15\n        return firstTombstone === -1 ? index : firstTombstone;\n    }\n\n    /* \u67e5\u8be2\u64cd\u4f5c */\n    get(key) {\n        // \u641c\u7d22 key \u5bf9\u5e94\u7684\u6876\u7d22\u5f15\n        const index = this.#findBucket(key);\n        // \u82e5\u627e\u5230\u952e\u503c\u5bf9\uff0c\u5219\u8fd4\u56de\u5bf9\u5e94 val\n        if (\n            this.#buckets[index] !== null &&\n            this.#buckets[index] !== this.#TOMBSTONE\n        ) {\n            return this.#buckets[index].val;\n        }\n        // \u82e5\u952e\u503c\u5bf9\u4e0d\u5b58\u5728\uff0c\u5219\u8fd4\u56de null\n        return null;\n    }\n\n    /* \u6dfb\u52a0\u64cd\u4f5c */\n    put(key, val) {\n        // \u5f53\u8d1f\u8f7d\u56e0\u5b50\u8d85\u8fc7\u9608\u503c\u65f6\uff0c\u6267\u884c\u6269\u5bb9\n        if (this.#loadFactor() > this.#loadThres) {\n            this.#extend();\n        }\n        // \u641c\u7d22 key \u5bf9\u5e94\u7684\u6876\u7d22\u5f15\n        const index = this.#findBucket(key);\n        // \u82e5\u627e\u5230\u952e\u503c\u5bf9\uff0c\u5219\u8986\u76d6 val \u5e76\u8fd4\u56de\n        if (\n            this.#buckets[index] !== null &&\n            this.#buckets[index] !== this.#TOMBSTONE\n        ) {\n            this.#buckets[index].val = val;\n            return;\n        }\n        // \u82e5\u952e\u503c\u5bf9\u4e0d\u5b58\u5728\uff0c\u5219\u6dfb\u52a0\u8be5\u952e\u503c\u5bf9\n        this.#buckets[index] = new Pair(key, val);\n        this.#size++;\n    }\n\n    /* \u5220\u9664\u64cd\u4f5c */\n    remove(key) {\n        // \u641c\u7d22 key \u5bf9\u5e94\u7684\u6876\u7d22\u5f15\n        const index = this.#findBucket(key);\n        // \u82e5\u627e\u5230\u952e\u503c\u5bf9\uff0c\u5219\u7528\u5220\u9664\u6807\u8bb0\u8986\u76d6\u5b83\n        if (\n            this.#buckets[index] !== null &&\n            this.#buckets[index] !== this.#TOMBSTONE\n        ) {\n            this.#buckets[index] = this.#TOMBSTONE;\n            this.#size--;\n        }\n    }\n\n    /* \u6269\u5bb9\u54c8\u5e0c\u8868 */\n    #extend() {\n        // \u6682\u5b58\u539f\u54c8\u5e0c\u8868\n        const bucketsTmp = this.#buckets;\n        // \u521d\u59cb\u5316\u6269\u5bb9\u540e\u7684\u65b0\u54c8\u5e0c\u8868\n        this.#capacity *= this.#extendRatio;\n        this.#buckets = Array(this.#capacity).fill(null);\n        this.#size = 0;\n        // \u5c06\u952e\u503c\u5bf9\u4ece\u539f\u54c8\u5e0c\u8868\u642c\u8fd0\u81f3\u65b0\u54c8\u5e0c\u8868\n        for (const pair of bucketsTmp) {\n            if (pair !== null && pair !== this.#TOMBSTONE) {\n                this.put(pair.key, pair.val);\n            }\n        }\n    }\n\n    /* \u6253\u5370\u54c8\u5e0c\u8868 */\n    print() {\n        for (const pair of this.#buckets) {\n            if (pair === null) {\n                console.log('null');\n            } else if (pair === this.#TOMBSTONE) {\n                console.log('TOMBSTONE');\n            } else {\n                console.log(pair.key + ' -> ' + pair.val);\n            }\n        }\n    }\n}\n
hash_map_open_addressing.ts
/* \u5f00\u653e\u5bfb\u5740\u54c8\u5e0c\u8868 */\nclass HashMapOpenAddressing {\n    private size: number; // \u952e\u503c\u5bf9\u6570\u91cf\n    private capacity: number; // \u54c8\u5e0c\u8868\u5bb9\u91cf\n    private loadThres: number; // \u89e6\u53d1\u6269\u5bb9\u7684\u8d1f\u8f7d\u56e0\u5b50\u9608\u503c\n    private extendRatio: number; // \u6269\u5bb9\u500d\u6570\n    private buckets: Array<Pair | null>; // \u6876\u6570\u7ec4\n    private TOMBSTONE: Pair; // \u5220\u9664\u6807\u8bb0\n\n    /* \u6784\u9020\u65b9\u6cd5 */\n    constructor() {\n        this.size = 0; // \u952e\u503c\u5bf9\u6570\u91cf\n        this.capacity = 4; // \u54c8\u5e0c\u8868\u5bb9\u91cf\n        this.loadThres = 2.0 / 3.0; // \u89e6\u53d1\u6269\u5bb9\u7684\u8d1f\u8f7d\u56e0\u5b50\u9608\u503c\n        this.extendRatio = 2; // \u6269\u5bb9\u500d\u6570\n        this.buckets = Array(this.capacity).fill(null); // \u6876\u6570\u7ec4\n        this.TOMBSTONE = new Pair(-1, '-1'); // \u5220\u9664\u6807\u8bb0\n    }\n\n    /* \u54c8\u5e0c\u51fd\u6570 */\n    private hashFunc(key: number): number {\n        return key % this.capacity;\n    }\n\n    /* \u8d1f\u8f7d\u56e0\u5b50 */\n    private loadFactor(): number {\n        return this.size / this.capacity;\n    }\n\n    /* \u641c\u7d22 key \u5bf9\u5e94\u7684\u6876\u7d22\u5f15 */\n    private findBucket(key: number): number {\n        let index = this.hashFunc(key);\n        let firstTombstone = -1;\n        // \u7ebf\u6027\u63a2\u6d4b\uff0c\u5f53\u9047\u5230\u7a7a\u6876\u65f6\u8df3\u51fa\n        while (this.buckets[index] !== null) {\n            // \u82e5\u9047\u5230 key \uff0c\u8fd4\u56de\u5bf9\u5e94\u7684\u6876\u7d22\u5f15\n            if (this.buckets[index]!.key === key) {\n                // \u82e5\u4e4b\u524d\u9047\u5230\u4e86\u5220\u9664\u6807\u8bb0\uff0c\u5219\u5c06\u952e\u503c\u5bf9\u79fb\u52a8\u81f3\u8be5\u7d22\u5f15\u5904\n                if (firstTombstone !== -1) {\n                    this.buckets[firstTombstone] = this.buckets[index];\n                    this.buckets[index] = this.TOMBSTONE;\n                    return firstTombstone; // \u8fd4\u56de\u79fb\u52a8\u540e\u7684\u6876\u7d22\u5f15\n                }\n                return index; // \u8fd4\u56de\u6876\u7d22\u5f15\n            }\n            // \u8bb0\u5f55\u9047\u5230\u7684\u9996\u4e2a\u5220\u9664\u6807\u8bb0\n            if (\n                firstTombstone === -1 &&\n                this.buckets[index] === this.TOMBSTONE\n            ) {\n                firstTombstone = index;\n            }\n            // \u8ba1\u7b97\u6876\u7d22\u5f15\uff0c\u8d8a\u8fc7\u5c3e\u90e8\u5219\u8fd4\u56de\u5934\u90e8\n            index = (index + 1) % this.capacity;\n        }\n        // \u82e5 key \u4e0d\u5b58\u5728\uff0c\u5219\u8fd4\u56de\u6dfb\u52a0\u70b9\u7684\u7d22\u5f15\n        return firstTombstone === -1 ? index : firstTombstone;\n    }\n\n    /* \u67e5\u8be2\u64cd\u4f5c */\n    get(key: number): string | null {\n        // \u641c\u7d22 key \u5bf9\u5e94\u7684\u6876\u7d22\u5f15\n        const index = this.findBucket(key);\n        // \u82e5\u627e\u5230\u952e\u503c\u5bf9\uff0c\u5219\u8fd4\u56de\u5bf9\u5e94 val\n        if (\n            this.buckets[index] !== null &&\n            this.buckets[index] !== this.TOMBSTONE\n        ) {\n            return this.buckets[index]!.val;\n        }\n        // \u82e5\u952e\u503c\u5bf9\u4e0d\u5b58\u5728\uff0c\u5219\u8fd4\u56de null\n        return null;\n    }\n\n    /* \u6dfb\u52a0\u64cd\u4f5c */\n    put(key: number, val: string): void {\n        // \u5f53\u8d1f\u8f7d\u56e0\u5b50\u8d85\u8fc7\u9608\u503c\u65f6\uff0c\u6267\u884c\u6269\u5bb9\n        if (this.loadFactor() > this.loadThres) {\n            this.extend();\n        }\n        // \u641c\u7d22 key \u5bf9\u5e94\u7684\u6876\u7d22\u5f15\n        const index = this.findBucket(key);\n        // \u82e5\u627e\u5230\u952e\u503c\u5bf9\uff0c\u5219\u8986\u76d6 val \u5e76\u8fd4\u56de\n        if (\n            this.buckets[index] !== null &&\n            this.buckets[index] !== this.TOMBSTONE\n        ) {\n            this.buckets[index]!.val = val;\n            return;\n        }\n        // \u82e5\u952e\u503c\u5bf9\u4e0d\u5b58\u5728\uff0c\u5219\u6dfb\u52a0\u8be5\u952e\u503c\u5bf9\n        this.buckets[index] = new Pair(key, val);\n        this.size++;\n    }\n\n    /* \u5220\u9664\u64cd\u4f5c */\n    remove(key: number): void {\n        // \u641c\u7d22 key \u5bf9\u5e94\u7684\u6876\u7d22\u5f15\n        const index = this.findBucket(key);\n        // \u82e5\u627e\u5230\u952e\u503c\u5bf9\uff0c\u5219\u7528\u5220\u9664\u6807\u8bb0\u8986\u76d6\u5b83\n        if (\n            this.buckets[index] !== null &&\n            this.buckets[index] !== this.TOMBSTONE\n        ) {\n            this.buckets[index] = this.TOMBSTONE;\n            this.size--;\n        }\n    }\n\n    /* \u6269\u5bb9\u54c8\u5e0c\u8868 */\n    private extend(): void {\n        // \u6682\u5b58\u539f\u54c8\u5e0c\u8868\n        const bucketsTmp = this.buckets;\n        // \u521d\u59cb\u5316\u6269\u5bb9\u540e\u7684\u65b0\u54c8\u5e0c\u8868\n        this.capacity *= this.extendRatio;\n        this.buckets = Array(this.capacity).fill(null);\n        this.size = 0;\n        // \u5c06\u952e\u503c\u5bf9\u4ece\u539f\u54c8\u5e0c\u8868\u642c\u8fd0\u81f3\u65b0\u54c8\u5e0c\u8868\n        for (const pair of bucketsTmp) {\n            if (pair !== null && pair !== this.TOMBSTONE) {\n                this.put(pair.key, pair.val);\n            }\n        }\n    }\n\n    /* \u6253\u5370\u54c8\u5e0c\u8868 */\n    print(): void {\n        for (const pair of this.buckets) {\n            if (pair === null) {\n                console.log('null');\n            } else if (pair === this.TOMBSTONE) {\n                console.log('TOMBSTONE');\n            } else {\n                console.log(pair.key + ' -> ' + pair.val);\n            }\n        }\n    }\n}\n
hash_map_open_addressing.dart
/* \u5f00\u653e\u5bfb\u5740\u54c8\u5e0c\u8868 */\nclass HashMapOpenAddressing {\n  late int _size; // \u952e\u503c\u5bf9\u6570\u91cf\n  int _capacity = 4; // \u54c8\u5e0c\u8868\u5bb9\u91cf\n  double _loadThres = 2.0 / 3.0; // \u89e6\u53d1\u6269\u5bb9\u7684\u8d1f\u8f7d\u56e0\u5b50\u9608\u503c\n  int _extendRatio = 2; // \u6269\u5bb9\u500d\u6570\n  late List<Pair?> _buckets; // \u6876\u6570\u7ec4\n  Pair _TOMBSTONE = Pair(-1, \"-1\"); // \u5220\u9664\u6807\u8bb0\n\n  /* \u6784\u9020\u65b9\u6cd5 */\n  HashMapOpenAddressing() {\n    _size = 0;\n    _buckets = List.generate(_capacity, (index) => null);\n  }\n\n  /* \u54c8\u5e0c\u51fd\u6570 */\n  int hashFunc(int key) {\n    return key % _capacity;\n  }\n\n  /* \u8d1f\u8f7d\u56e0\u5b50 */\n  double loadFactor() {\n    return _size / _capacity;\n  }\n\n  /* \u641c\u7d22 key \u5bf9\u5e94\u7684\u6876\u7d22\u5f15 */\n  int findBucket(int key) {\n    int index = hashFunc(key);\n    int firstTombstone = -1;\n    // \u7ebf\u6027\u63a2\u6d4b\uff0c\u5f53\u9047\u5230\u7a7a\u6876\u65f6\u8df3\u51fa\n    while (_buckets[index] != null) {\n      // \u82e5\u9047\u5230 key \uff0c\u8fd4\u56de\u5bf9\u5e94\u7684\u6876\u7d22\u5f15\n      if (_buckets[index]!.key == key) {\n        // \u82e5\u4e4b\u524d\u9047\u5230\u4e86\u5220\u9664\u6807\u8bb0\uff0c\u5219\u5c06\u952e\u503c\u5bf9\u79fb\u52a8\u81f3\u8be5\u7d22\u5f15\u5904\n        if (firstTombstone != -1) {\n          _buckets[firstTombstone] = _buckets[index];\n          _buckets[index] = _TOMBSTONE;\n          return firstTombstone; // \u8fd4\u56de\u79fb\u52a8\u540e\u7684\u6876\u7d22\u5f15\n        }\n        return index; // \u8fd4\u56de\u6876\u7d22\u5f15\n      }\n      // \u8bb0\u5f55\u9047\u5230\u7684\u9996\u4e2a\u5220\u9664\u6807\u8bb0\n      if (firstTombstone == -1 && _buckets[index] == _TOMBSTONE) {\n        firstTombstone = index;\n      }\n      // \u8ba1\u7b97\u6876\u7d22\u5f15\uff0c\u8d8a\u8fc7\u5c3e\u90e8\u5219\u8fd4\u56de\u5934\u90e8\n      index = (index + 1) % _capacity;\n    }\n    // \u82e5 key \u4e0d\u5b58\u5728\uff0c\u5219\u8fd4\u56de\u6dfb\u52a0\u70b9\u7684\u7d22\u5f15\n    return firstTombstone == -1 ? index : firstTombstone;\n  }\n\n  /* \u67e5\u8be2\u64cd\u4f5c */\n  String? get(int key) {\n    // \u641c\u7d22 key \u5bf9\u5e94\u7684\u6876\u7d22\u5f15\n    int index = findBucket(key);\n    // \u82e5\u627e\u5230\u952e\u503c\u5bf9\uff0c\u5219\u8fd4\u56de\u5bf9\u5e94 val\n    if (_buckets[index] != null && _buckets[index] != _TOMBSTONE) {\n      return _buckets[index]!.val;\n    }\n    // \u82e5\u952e\u503c\u5bf9\u4e0d\u5b58\u5728\uff0c\u5219\u8fd4\u56de null\n    return null;\n  }\n\n  /* \u6dfb\u52a0\u64cd\u4f5c */\n  void put(int key, String val) {\n    // \u5f53\u8d1f\u8f7d\u56e0\u5b50\u8d85\u8fc7\u9608\u503c\u65f6\uff0c\u6267\u884c\u6269\u5bb9\n    if (loadFactor() > _loadThres) {\n      extend();\n    }\n    // \u641c\u7d22 key \u5bf9\u5e94\u7684\u6876\u7d22\u5f15\n    int index = findBucket(key);\n    // \u82e5\u627e\u5230\u952e\u503c\u5bf9\uff0c\u5219\u8986\u76d6 val \u5e76\u8fd4\u56de\n    if (_buckets[index] != null && _buckets[index] != _TOMBSTONE) {\n      _buckets[index]!.val = val;\n      return;\n    }\n    // \u82e5\u952e\u503c\u5bf9\u4e0d\u5b58\u5728\uff0c\u5219\u6dfb\u52a0\u8be5\u952e\u503c\u5bf9\n    _buckets[index] = new Pair(key, val);\n    _size++;\n  }\n\n  /* \u5220\u9664\u64cd\u4f5c */\n  void remove(int key) {\n    // \u641c\u7d22 key \u5bf9\u5e94\u7684\u6876\u7d22\u5f15\n    int index = findBucket(key);\n    // \u82e5\u627e\u5230\u952e\u503c\u5bf9\uff0c\u5219\u7528\u5220\u9664\u6807\u8bb0\u8986\u76d6\u5b83\n    if (_buckets[index] != null && _buckets[index] != _TOMBSTONE) {\n      _buckets[index] = _TOMBSTONE;\n      _size--;\n    }\n  }\n\n  /* \u6269\u5bb9\u54c8\u5e0c\u8868 */\n  void extend() {\n    // \u6682\u5b58\u539f\u54c8\u5e0c\u8868\n    List<Pair?> bucketsTmp = _buckets;\n    // \u521d\u59cb\u5316\u6269\u5bb9\u540e\u7684\u65b0\u54c8\u5e0c\u8868\n    _capacity *= _extendRatio;\n    _buckets = List.generate(_capacity, (index) => null);\n    _size = 0;\n    // \u5c06\u952e\u503c\u5bf9\u4ece\u539f\u54c8\u5e0c\u8868\u642c\u8fd0\u81f3\u65b0\u54c8\u5e0c\u8868\n    for (Pair? pair in bucketsTmp) {\n      if (pair != null && pair != _TOMBSTONE) {\n        put(pair.key, pair.val);\n      }\n    }\n  }\n\n  /* \u6253\u5370\u54c8\u5e0c\u8868 */\n  void printHashMap() {\n    for (Pair? pair in _buckets) {\n      if (pair == null) {\n        print(\"null\");\n      } else if (pair == _TOMBSTONE) {\n        print(\"TOMBSTONE\");\n      } else {\n        print(\"${pair.key} -> ${pair.val}\");\n      }\n    }\n  }\n}\n
hash_map_open_addressing.rs
/* \u5f00\u653e\u5bfb\u5740\u54c8\u5e0c\u8868 */\nstruct HashMapOpenAddressing {\n    size: usize,                // \u952e\u503c\u5bf9\u6570\u91cf\n    capacity: usize,            // \u54c8\u5e0c\u8868\u5bb9\u91cf\n    load_thres: f64,            // \u89e6\u53d1\u6269\u5bb9\u7684\u8d1f\u8f7d\u56e0\u5b50\u9608\u503c\n    extend_ratio: usize,        // \u6269\u5bb9\u500d\u6570\n    buckets: Vec<Option<Pair>>, // \u6876\u6570\u7ec4\n    TOMBSTONE: Option<Pair>,    // \u5220\u9664\u6807\u8bb0\n}\n\nimpl HashMapOpenAddressing {\n    /* \u6784\u9020\u65b9\u6cd5 */\n    fn new() -> Self {\n        Self {\n            size: 0,\n            capacity: 4,\n            load_thres: 2.0 / 3.0,\n            extend_ratio: 2,\n            buckets: vec![None; 4],\n            TOMBSTONE: Some(Pair {\n                key: -1,\n                val: \"-1\".to_string(),\n            }),\n        }\n    }\n\n    /* \u54c8\u5e0c\u51fd\u6570 */\n    fn hash_func(&self, key: i32) -> usize {\n        (key % self.capacity as i32) as usize\n    }\n\n    /* \u8d1f\u8f7d\u56e0\u5b50 */\n    fn load_factor(&self) -> f64 {\n        self.size as f64 / self.capacity as f64\n    }\n\n    /* \u641c\u7d22 key \u5bf9\u5e94\u7684\u6876\u7d22\u5f15 */\n    fn find_bucket(&mut self, key: i32) -> usize {\n        let mut index = self.hash_func(key);\n        let mut first_tombstone = -1;\n        // \u7ebf\u6027\u63a2\u6d4b\uff0c\u5f53\u9047\u5230\u7a7a\u6876\u65f6\u8df3\u51fa\n        while self.buckets[index].is_some() {\n            // \u82e5\u9047\u5230 key\uff0c\u8fd4\u56de\u5bf9\u5e94\u7684\u6876\u7d22\u5f15\n            if self.buckets[index].as_ref().unwrap().key == key {\n                // \u82e5\u4e4b\u524d\u9047\u5230\u4e86\u5220\u9664\u6807\u8bb0\uff0c\u5219\u5c06\u5efa\u503c\u5bf9\u79fb\u52a8\u81f3\u8be5\u7d22\u5f15\n                if first_tombstone != -1 {\n                    self.buckets[first_tombstone as usize] = self.buckets[index].take();\n                    self.buckets[index] = self.TOMBSTONE.clone();\n                    return first_tombstone as usize; // \u8fd4\u56de\u79fb\u52a8\u540e\u7684\u6876\u7d22\u5f15\n                }\n                return index; // \u8fd4\u56de\u6876\u7d22\u5f15\n            }\n            // \u8bb0\u5f55\u9047\u5230\u7684\u9996\u4e2a\u5220\u9664\u6807\u8bb0\n            if first_tombstone == -1 && self.buckets[index] == self.TOMBSTONE {\n                first_tombstone = index as i32;\n            }\n            // \u8ba1\u7b97\u6876\u7d22\u5f15\uff0c\u8d8a\u8fc7\u5c3e\u90e8\u5219\u8fd4\u56de\u5934\u90e8\n            index = (index + 1) % self.capacity;\n        }\n        // \u82e5 key \u4e0d\u5b58\u5728\uff0c\u5219\u8fd4\u56de\u6dfb\u52a0\u70b9\u7684\u7d22\u5f15\n        if first_tombstone == -1 {\n            index\n        } else {\n            first_tombstone as usize\n        }\n    }\n\n    /* \u67e5\u8be2\u64cd\u4f5c */\n    fn get(&mut self, key: i32) -> Option<&str> {\n        // \u641c\u7d22 key \u5bf9\u5e94\u7684\u6876\u7d22\u5f15\n        let index = self.find_bucket(key);\n        // \u82e5\u627e\u5230\u952e\u503c\u5bf9\uff0c\u5219\u8fd4\u56de\u5bf9\u5e94 val\n        if self.buckets[index].is_some() && self.buckets[index] != self.TOMBSTONE {\n            return self.buckets[index].as_ref().map(|pair| &pair.val as &str);\n        }\n        // \u82e5\u952e\u503c\u5bf9\u4e0d\u5b58\u5728\uff0c\u5219\u8fd4\u56de null\n        None\n    }\n\n    /* \u6dfb\u52a0\u64cd\u4f5c */\n    fn put(&mut self, key: i32, val: String) {\n        // \u5f53\u8d1f\u8f7d\u56e0\u5b50\u8d85\u8fc7\u9608\u503c\u65f6\uff0c\u6267\u884c\u6269\u5bb9\n        if self.load_factor() > self.load_thres {\n            self.extend();\n        }\n        // \u641c\u7d22 key \u5bf9\u5e94\u7684\u6876\u7d22\u5f15\n        let index = self.find_bucket(key);\n        // \u82e5\u627e\u5230\u952e\u503c\u5bf9\uff0c\u5219\u8986\u76d6 val \u5e76\u8fd4\u56de\n        if self.buckets[index].is_some() && self.buckets[index] != self.TOMBSTONE {\n            self.buckets[index].as_mut().unwrap().val = val;\n            return;\n        }\n        // \u82e5\u952e\u503c\u5bf9\u4e0d\u5b58\u5728\uff0c\u5219\u6dfb\u52a0\u8be5\u952e\u503c\u5bf9\n        self.buckets[index] = Some(Pair { key, val });\n        self.size += 1;\n    }\n\n    /* \u5220\u9664\u64cd\u4f5c */\n    fn remove(&mut self, key: i32) {\n        // \u641c\u7d22 key \u5bf9\u5e94\u7684\u6876\u7d22\u5f15\n        let index = self.find_bucket(key);\n        // \u82e5\u627e\u5230\u952e\u503c\u5bf9\uff0c\u5219\u7528\u5220\u9664\u6807\u8bb0\u8986\u76d6\u5b83\n        if self.buckets[index].is_some() && self.buckets[index] != self.TOMBSTONE {\n            self.buckets[index] = self.TOMBSTONE.clone();\n            self.size -= 1;\n        }\n    }\n\n    /* \u6269\u5bb9\u54c8\u5e0c\u8868 */\n    fn extend(&mut self) {\n        // \u6682\u5b58\u539f\u54c8\u5e0c\u8868\n        let buckets_tmp = self.buckets.clone();\n        // \u521d\u59cb\u5316\u6269\u5bb9\u540e\u7684\u65b0\u54c8\u5e0c\u8868\n        self.capacity *= self.extend_ratio;\n        self.buckets = vec![None; self.capacity];\n        self.size = 0;\n\n        // \u5c06\u952e\u503c\u5bf9\u4ece\u539f\u54c8\u5e0c\u8868\u642c\u8fd0\u81f3\u65b0\u54c8\u5e0c\u8868\n        for pair in buckets_tmp {\n            if pair.is_none() || pair == self.TOMBSTONE {\n                continue;\n            }\n            let pair = pair.unwrap();\n\n            self.put(pair.key, pair.val);\n        }\n    }\n    /* \u6253\u5370\u54c8\u5e0c\u8868 */\n    fn print(&self) {\n        for pair in &self.buckets {\n            if pair.is_none() {\n                println!(\"null\");\n            } else if pair == &self.TOMBSTONE {\n                println!(\"TOMBSTONE\");\n            } else {\n                let pair = pair.as_ref().unwrap();\n                println!(\"{} -> {}\", pair.key, pair.val);\n            }\n        }\n    }\n}\n
hash_map_open_addressing.c
/* \u5f00\u653e\u5bfb\u5740\u54c8\u5e0c\u8868 */\ntypedef struct {\n    int size;         // \u952e\u503c\u5bf9\u6570\u91cf\n    int capacity;     // \u54c8\u5e0c\u8868\u5bb9\u91cf\n    double loadThres; // \u89e6\u53d1\u6269\u5bb9\u7684\u8d1f\u8f7d\u56e0\u5b50\u9608\u503c\n    int extendRatio;  // \u6269\u5bb9\u500d\u6570\n    Pair **buckets;   // \u6876\u6570\u7ec4\n    Pair *TOMBSTONE;  // \u5220\u9664\u6807\u8bb0\n} HashMapOpenAddressing;\n\n/* \u6784\u9020\u51fd\u6570 */\nHashMapOpenAddressing *newHashMapOpenAddressing() {\n    HashMapOpenAddressing *hashMap = (HashMapOpenAddressing *)malloc(sizeof(HashMapOpenAddressing));\n    hashMap->size = 0;\n    hashMap->capacity = 4;\n    hashMap->loadThres = 2.0 / 3.0;\n    hashMap->extendRatio = 2;\n    hashMap->buckets = (Pair **)malloc(sizeof(Pair *) * hashMap->capacity);\n    hashMap->TOMBSTONE = (Pair *)malloc(sizeof(Pair));\n    hashMap->TOMBSTONE->key = -1;\n    hashMap->TOMBSTONE->val = \"-1\";\n\n    return hashMap;\n}\n\n/* \u6790\u6784\u51fd\u6570 */\nvoid delHashMapOpenAddressing(HashMapOpenAddressing *hashMap) {\n    for (int i = 0; i < hashMap->capacity; i++) {\n        Pair *pair = hashMap->buckets[i];\n        if (pair != NULL && pair != hashMap->TOMBSTONE) {\n            free(pair->val);\n            free(pair);\n        }\n    }\n}\n\n/* \u54c8\u5e0c\u51fd\u6570 */\nint hashFunc(HashMapOpenAddressing *hashMap, int key) {\n    return key % hashMap->capacity;\n}\n\n/* \u8d1f\u8f7d\u56e0\u5b50 */\ndouble loadFactor(HashMapOpenAddressing *hashMap) {\n    return (double)hashMap->size / (double)hashMap->capacity;\n}\n\n/* \u641c\u7d22 key \u5bf9\u5e94\u7684\u6876\u7d22\u5f15 */\nint findBucket(HashMapOpenAddressing *hashMap, int key) {\n    int index = hashFunc(hashMap, key);\n    int firstTombstone = -1;\n    // \u7ebf\u6027\u63a2\u6d4b\uff0c\u5f53\u9047\u5230\u7a7a\u6876\u65f6\u8df3\u51fa\n    while (hashMap->buckets[index] != NULL) {\n        // \u82e5\u9047\u5230 key \uff0c\u8fd4\u56de\u5bf9\u5e94\u7684\u6876\u7d22\u5f15\n        if (hashMap->buckets[index]->key == key) {\n            // \u82e5\u4e4b\u524d\u9047\u5230\u4e86\u5220\u9664\u6807\u8bb0\uff0c\u5219\u5c06\u952e\u503c\u5bf9\u79fb\u52a8\u81f3\u8be5\u7d22\u5f15\u5904\n            if (firstTombstone != -1) {\n                hashMap->buckets[firstTombstone] = hashMap->buckets[index];\n                hashMap->buckets[index] = hashMap->TOMBSTONE;\n                return firstTombstone; // \u8fd4\u56de\u79fb\u52a8\u540e\u7684\u6876\u7d22\u5f15\n            }\n            return index; // \u8fd4\u56de\u6876\u7d22\u5f15\n        }\n        // \u8bb0\u5f55\u9047\u5230\u7684\u9996\u4e2a\u5220\u9664\u6807\u8bb0\n        if (firstTombstone == -1 && hashMap->buckets[index] == hashMap->TOMBSTONE) {\n            firstTombstone = index;\n        }\n        // \u8ba1\u7b97\u6876\u7d22\u5f15\uff0c\u8d8a\u8fc7\u5c3e\u90e8\u5219\u8fd4\u56de\u5934\u90e8\n        index = (index + 1) % hashMap->capacity;\n    }\n    // \u82e5 key \u4e0d\u5b58\u5728\uff0c\u5219\u8fd4\u56de\u6dfb\u52a0\u70b9\u7684\u7d22\u5f15\n    return firstTombstone == -1 ? index : firstTombstone;\n}\n\n/* \u67e5\u8be2\u64cd\u4f5c */\nchar *get(HashMapOpenAddressing *hashMap, int key) {\n    // \u641c\u7d22 key \u5bf9\u5e94\u7684\u6876\u7d22\u5f15\n    int index = findBucket(hashMap, key);\n    // \u82e5\u627e\u5230\u952e\u503c\u5bf9\uff0c\u5219\u8fd4\u56de\u5bf9\u5e94 val\n    if (hashMap->buckets[index] != NULL && hashMap->buckets[index] != hashMap->TOMBSTONE) {\n        return hashMap->buckets[index]->val;\n    }\n    // \u82e5\u952e\u503c\u5bf9\u4e0d\u5b58\u5728\uff0c\u5219\u8fd4\u56de\u7a7a\u5b57\u7b26\u4e32\n    return \"\";\n}\n\n/* \u6dfb\u52a0\u64cd\u4f5c */\nvoid put(HashMapOpenAddressing *hashMap, int key, char *val) {\n    // \u5f53\u8d1f\u8f7d\u56e0\u5b50\u8d85\u8fc7\u9608\u503c\u65f6\uff0c\u6267\u884c\u6269\u5bb9\n    if (loadFactor(hashMap) > hashMap->loadThres) {\n        extend(hashMap);\n    }\n    // \u641c\u7d22 key \u5bf9\u5e94\u7684\u6876\u7d22\u5f15\n    int index = findBucket(hashMap, key);\n    // \u82e5\u627e\u5230\u952e\u503c\u5bf9\uff0c\u5219\u8986\u76d6 val \u5e76\u8fd4\u56de\n    if (hashMap->buckets[index] != NULL && hashMap->buckets[index] != hashMap->TOMBSTONE) {\n        free(hashMap->buckets[index]->val);\n        hashMap->buckets[index]->val = (char *)malloc(sizeof(strlen(val) + 1));\n        strcpy(hashMap->buckets[index]->val, val);\n        hashMap->buckets[index]->val[strlen(val)] = '\\0';\n        return;\n    }\n    // \u82e5\u952e\u503c\u5bf9\u4e0d\u5b58\u5728\uff0c\u5219\u6dfb\u52a0\u8be5\u952e\u503c\u5bf9\n    Pair *pair = (Pair *)malloc(sizeof(Pair));\n    pair->key = key;\n    pair->val = (char *)malloc(sizeof(strlen(val) + 1));\n    strcpy(pair->val, val);\n    pair->val[strlen(val)] = '\\0';\n\n    hashMap->buckets[index] = pair;\n    hashMap->size++;\n}\n\n/* \u5220\u9664\u64cd\u4f5c */\nvoid removeItem(HashMapOpenAddressing *hashMap, int key) {\n    // \u641c\u7d22 key \u5bf9\u5e94\u7684\u6876\u7d22\u5f15\n    int index = findBucket(hashMap, key);\n    // \u82e5\u627e\u5230\u952e\u503c\u5bf9\uff0c\u5219\u7528\u5220\u9664\u6807\u8bb0\u8986\u76d6\u5b83\n    if (hashMap->buckets[index] != NULL && hashMap->buckets[index] != hashMap->TOMBSTONE) {\n        Pair *pair = hashMap->buckets[index];\n        free(pair->val);\n        free(pair);\n        hashMap->buckets[index] = hashMap->TOMBSTONE;\n        hashMap->size--;\n    }\n}\n\n/* \u6269\u5bb9\u54c8\u5e0c\u8868 */\nvoid extend(HashMapOpenAddressing *hashMap) {\n    // \u6682\u5b58\u539f\u54c8\u5e0c\u8868\n    Pair **bucketsTmp = hashMap->buckets;\n    int oldCapacity = hashMap->capacity;\n    // \u521d\u59cb\u5316\u6269\u5bb9\u540e\u7684\u65b0\u54c8\u5e0c\u8868\n    hashMap->capacity *= hashMap->extendRatio;\n    hashMap->buckets = (Pair **)malloc(sizeof(Pair *) * hashMap->capacity);\n    hashMap->size = 0;\n    // \u5c06\u952e\u503c\u5bf9\u4ece\u539f\u54c8\u5e0c\u8868\u642c\u8fd0\u81f3\u65b0\u54c8\u5e0c\u8868\n    for (int i = 0; i < oldCapacity; i++) {\n        Pair *pair = bucketsTmp[i];\n        if (pair != NULL && pair != hashMap->TOMBSTONE) {\n            put(hashMap, pair->key, pair->val);\n            free(pair->val);\n            free(pair);\n        }\n    }\n    free(bucketsTmp);\n}\n\n/* \u6253\u5370\u54c8\u5e0c\u8868 */\nvoid print(HashMapOpenAddressing *hashMap) {\n    for (int i = 0; i < hashMap->capacity; i++) {\n        Pair *pair = hashMap->buckets[i];\n        if (pair == NULL) {\n            printf(\"NULL\\n\");\n        } else if (pair == hashMap->TOMBSTONE) {\n            printf(\"TOMBSTONE\\n\");\n        } else {\n            printf(\"%d -> %s\\n\", pair->key, pair->val);\n        }\n    }\n}\n
hash_map_open_addressing.zig
[class]{HashMapOpenAddressing}-[func]{}\n
"},{"location":"chapter_hashing/hash_collision/#2-quadratic-probing","title":"2. \u00a0 Quadratic Probing","text":"

Quadratic probing is similar to linear probing and is one of the common strategies of open addressing. When a collision occurs, quadratic probing does not simply skip a fixed number of steps but skips \"the square of the number of probes,\" i.e., \\(1, 4, 9, \\dots\\) steps.

Quadratic probing has the following advantages:

  • Quadratic probing attempts to alleviate the clustering effect of linear probing by skipping the distance of the square of the number of probes.
  • Quadratic probing skips larger distances to find empty positions, helping to distribute data more evenly.

However, quadratic probing is not perfect:

  • Clustering still exists, i.e., some positions are more likely to be occupied than others.
  • Due to the growth of squares, quadratic probing may not probe the entire hash table, meaning it might not access empty buckets even if they exist in the hash table.
"},{"location":"chapter_hashing/hash_collision/#3-double-hashing","title":"3. \u00a0 Double Hashing","text":"

As the name suggests, the double hashing method uses multiple hash functions \\(f_1(x)\\), \\(f_2(x)\\), \\(f_3(x)\\), \\(\\dots\\) for probing.

  • Inserting Elements: If hash function \\(f_1(x)\\) encounters a conflict, try \\(f_2(x)\\), and so on, until an empty position is found and the element is inserted.
  • Searching for Elements: Search in the same order of hash functions until the target element is found and returned; if an empty position is encountered or all hash functions have been tried, it indicates the element is not in the hash table, then return None.

Compared to linear probing, double hashing is less prone to clustering but involves additional computation for multiple hash functions.

Tip

Please note that open addressing (linear probing, quadratic probing, and double hashing) hash tables all have the issue of \"not being able to directly delete elements.\"

"},{"location":"chapter_hashing/hash_collision/#623-choice-of-programming-languages","title":"6.2.3 \u00a0 Choice of Programming Languages","text":"

Various programming languages have adopted different hash table implementation strategies, here are a few examples:

  • Python uses open addressing. The dict dictionary uses pseudo-random numbers for probing.
  • Java uses separate chaining. Since JDK 1.8, when the array length in HashMap reaches 64 and the length of a linked list reaches 8, the linked list is converted to a red-black tree to improve search performance.
  • Go uses separate chaining. Go stipulates that each bucket can store up to 8 key-value pairs, and if the capacity is exceeded, an overflow bucket is connected; when there are too many overflow buckets, a special equal-size expansion operation is performed to ensure performance.
"},{"location":"chapter_hashing/hash_map/","title":"6.1 \u00a0 Hash Table","text":"

A \"hash table\", also known as a \"hash map\", achieves efficient element querying by establishing a mapping between keys and values. Specifically, when we input a key into the hash table, we can retrieve the corresponding value in \\(O(1)\\) time.

As shown in the Figure 6-1 , given \\(n\\) students, each with two pieces of data: \"name\" and \"student number\". If we want to implement a query feature that returns the corresponding name when given a student number, we can use the hash table shown in the Figure 6-1 .

Figure 6-1 \u00a0 Abstract representation of a hash table

Apart from hash tables, arrays and linked lists can also be used to implement querying functions. Their efficiency is compared in the Table 6-1 .

  • Adding Elements: Simply add the element to the end of the array (or linked list), using \\(O(1)\\) time.
  • Querying Elements: Since the array (or linked list) is unordered, it requires traversing all the elements, using \\(O(n)\\) time.
  • Deleting Elements: First, locate the element, then delete it from the array (or linked list), using \\(O(n)\\) time.

Table 6-1 \u00a0 Comparison of Element Query Efficiency

Array Linked List Hash Table Find Element \\(O(n)\\) \\(O(n)\\) \\(O(1)\\) Add Element \\(O(1)\\) \\(O(1)\\) \\(O(1)\\) Delete Element \\(O(n)\\) \\(O(n)\\) \\(O(1)\\)

Observations reveal that the time complexity for adding, deleting, and querying in a hash table is \\(O(1)\\), which is highly efficient.

"},{"location":"chapter_hashing/hash_map/#611-common-operations-of-hash-table","title":"6.1.1 \u00a0 Common Operations of Hash Table","text":"

Common operations of a hash table include initialization, querying, adding key-value pairs, and deleting key-value pairs, etc. Example code is as follows:

PythonC++JavaC#GoSwiftJSTSDartRustCZig hash_map.py
# Initialize hash table\nhmap: dict = {}\n\n# Add operation\n# Add key-value pair (key, value) to the hash table\nhmap[12836] = \"Xiao Ha\"\nhmap[15937] = \"Xiao Luo\"\nhmap[16750] = \"Xiao Suan\"\nhmap[13276] = \"Xiao Fa\"\nhmap[10583] = \"Xiao Ya\"\n\n# Query operation\n# Input key into hash table, get value\nname: str = hmap[15937]\n\n# Delete operation\n# Delete key-value pair (key, value) from hash table\nhmap.pop(10583)\n
hash_map.cpp
/* Initialize hash table */\nunordered_map<int, string> map;\n\n/* Add operation */\n// Add key-value pair (key, value) to the hash table\nmap[12836] = \"Xiao Ha\";\nmap[15937] = \"Xiao Luo\";\nmap[16750] = \"Xiao Suan\";\nmap[13276] = \"Xiao Fa\";\nmap[10583] = \"Xiao Ya\";\n\n/* Query operation */\n// Input key into hash table, get value\nstring name = map[15937];\n\n/* Delete operation */\n// Delete key-value pair (key, value) from hash table\nmap.erase(10583);\n
hash_map.java
/* Initialize hash table */\nMap<Integer, String> map = new HashMap<>();\n\n/* Add operation */\n// Add key-value pair (key, value) to the hash table\nmap.put(12836, \"Xiao Ha\");   \nmap.put(15937, \"Xiao Luo\");   \nmap.put(16750, \"Xiao Suan\");   \nmap.put(13276, \"Xiao Fa\");\nmap.put(10583, \"Xiao Ya\");\n\n/* Query operation */\n// Input key into hash table, get value\nString name = map.get(15937);\n\n/* Delete operation */\n// Delete key-value pair (key, value) from hash table\nmap.remove(10583);\n
hash_map.cs
/* Initialize hash table */\nDictionary<int, string> map = new() {\n    /* Add operation */\n    // Add key-value pair (key, value) to the hash table\n    { 12836, \"Xiao Ha\" },\n    { 15937, \"Xiao Luo\" },\n    { 16750, \"Xiao Suan\" },\n    { 13276, \"Xiao Fa\" },\n    { 10583, \"Xiao Ya\" }\n};\n\n/* Query operation */\n// Input key into hash table, get value\nstring name = map[15937];\n\n/* Delete operation */\n// Delete key-value pair (key, value) from hash table\nmap.Remove(10583);\n
hash_map_test.go
/* Initialize hash table */\nhmap := make(map[int]string)\n\n/* Add operation */\n// Add key-value pair (key, value) to the hash table\nhmap[12836] = \"Xiao Ha\"\nhmap[15937] = \"Xiao Luo\"\nhmap[16750] = \"Xiao Suan\"\nhmap[13276] = \"Xiao Fa\"\nhmap[10583] = \"Xiao Ya\"\n\n/* Query operation */\n// Input key into hash table, get value\nname := hmap[15937]\n\n/* Delete operation */\n// Delete key-value pair (key, value) from hash table\ndelete(hmap, 10583)\n
hash_map.swift
/* Initialize hash table */\nvar map: [Int: String] = [:]\n\n/* Add operation */\n// Add key-value pair (key, value) to the hash table\nmap[12836] = \"Xiao Ha\"\nmap[15937] = \"Xiao Luo\"\nmap[16750] = \"Xiao Suan\"\nmap[13276] = \"Xiao Fa\"\nmap[10583] = \"Xiao Ya\"\n\n/* Query operation */\n// Input key into hash table, get value\nlet name = map[15937]!\n\n/* Delete operation */\n// Delete key-value pair (key, value) from hash table\nmap.removeValue(forKey: 10583)\n
hash_map.js
/* Initialize hash table */\nconst map = new Map();\n/* Add operation */\n// Add key-value pair (key, value) to the hash table\nmap.set(12836, 'Xiao Ha');\nmap.set(15937, 'Xiao Luo');\nmap.set(16750, 'Xiao Suan');\nmap.set(13276, 'Xiao Fa');\nmap.set(10583, 'Xiao Ya');\n\n/* Query operation */\n// Input key into hash table, get value\nlet name = map.get(15937);\n\n/* Delete operation */\n// Delete key-value pair (key, value) from hash table\nmap.delete(10583);\n
hash_map.ts
/* Initialize hash table */\nconst map = new Map<number, string>();\n/* Add operation */\n// Add key-value pair (key, value) to the hash table\nmap.set(12836, 'Xiao Ha');\nmap.set(15937, 'Xiao Luo');\nmap.set(16750, 'Xiao Suan');\nmap.set(13276, 'Xiao Fa');\nmap.set(10583, 'Xiao Ya');\nconsole.info('\\nAfter adding, the hash table is\\nKey -> Value');\nconsole.info(map);\n\n/* Query operation */\n// Input key into hash table, get value\nlet name = map.get(15937);\nconsole.info('\\nInput student number 15937, query name ' + name);\n\n/* Delete operation */\n// Delete key-value pair (key, value) from hash table\nmap.delete(10583);\nconsole.info('\\nAfter deleting 10583, the hash table is\\nKey -> Value');\nconsole.info(map);\n
hash_map.dart
/* Initialize hash table */\nMap<int, String> map = {};\n\n/* Add operation */\n// Add key-value pair (key, value) to the hash table\nmap[12836] = \"Xiao Ha\";\nmap[15937] = \"Xiao Luo\";\nmap[16750] = \"Xiao Suan\";\nmap[13276] = \"Xiao Fa\";\nmap[10583] = \"Xiao Ya\";\n\n/* Query operation */\n// Input key into hash table, get value\nString name = map[15937];\n\n/* Delete operation */\n// Delete key-value pair (key, value) from hash table\nmap.remove(10583);\n
hash_map.rs
use std::collections::HashMap;\n\n/* Initialize hash table */\nlet mut map: HashMap<i32, String> = HashMap::new();\n\n/* Add operation */\n// Add key-value pair (key, value) to the hash table\nmap.insert(12836, \"Xiao Ha\".to_string());\nmap.insert(15937, \"Xiao Luo\".to_string());\nmap.insert(16750, \"Xiao Suan\".to_string());\nmap.insert(13279, \"Xiao Fa\".to_string());\nmap.insert(10583, \"Xiao Ya\".to_string());\n\n/* Query operation */\n// Input key into hash table, get value\nlet _name: Option<&String> = map.get(&15937);\n\n/* Delete operation */\n// Delete key-value pair (key, value) from hash table\nlet _removed_value: Option<String> = map.remove(&10583);\n
hash_map.c
// C does not provide a built-in hash table\n
hash_map.zig
\n
Code Visualization

Full Screen >

There are three common ways to traverse a hash table: traversing key-value pairs, keys, and values. Example code is as follows:

PythonC++JavaC#GoSwiftJSTSDartRustCZig hash_map.py
# Traverse hash table\n# Traverse key-value pairs key->value\nfor key, value in hmap.items():\n    print(key, \"->\", value)\n# Traverse keys only\nfor key in hmap.keys():\n    print(key)\n# Traverse values only\nfor value in hmap.values():\n    print(value)\n
hash_map.cpp
/* Traverse hash table */\n// Traverse key-value pairs key->value\nfor (auto kv: map) {\n    cout << kv.first << \" -> \" << kv.second << endl;\n}\n// Traverse using iterator key->value\nfor (auto iter = map.begin(); iter != map.end(); iter++) {\n    cout << iter->first << \"->\" << iter->second << endl;\n}\n
hash_map.java
/* Traverse hash table */\n// Traverse key-value pairs key->value\nfor (Map.Entry<Integer, String> kv: map.entrySet()) {\n    System.out.println(kv.getKey() + \" -> \" + kv.getValue());\n}\n// Traverse keys only\nfor (int key: map.keySet()) {\n    System.out.println(key);\n}\n// Traverse values only\nfor (String val: map.values()) {\n    System.out.println(val);\n}\n
hash_map.cs
/* Traverse hash table */\n// Traverse key-value pairs Key->Value\nforeach (var kv in map) {\n    Console.WriteLine(kv.Key + \" -> \" + kv.Value);\n}\n// Traverse keys only\nforeach (int key in map.Keys) {\n    Console.WriteLine(key);\n}\n// Traverse values only\nforeach (string val in map.Values) {\n    Console.WriteLine(val);\n}\n
hash_map_test.go
/* Traverse hash table */\n// Traverse key-value pairs key->value\nfor key, value := range hmap {\n    fmt.Println(key, \"->\", value)\n}\n// Traverse keys only\nfor key := range hmap {\n    fmt.Println(key)\n}\n// Traverse values only\nfor _, value := range hmap {\n    fmt.Println(value)\n}\n
hash_map.swift
/* Traverse hash table */\n// Traverse key-value pairs Key->Value\nfor (key, value) in map {\n    print(\"\\(key) -> \\(value)\")\n}\n// Traverse keys only\nfor key in map.keys {\n    print(key)\n}\n// Traverse values only\nfor value in map.values {\n    print(value)\n}\n
hash_map.js
/* Traverse hash table */\nconsole.info('\\nTraverse key-value pairs Key->Value');\nfor (const [k, v] of map.entries()) {\n    console.info(k + ' -> ' + v);\n}\nconsole.info('\\nTraverse keys only Key');\nfor (const k of map.keys()) {\n    console.info(k);\n}\nconsole.info('\\nTraverse values only Value');\nfor (const v of map.values()) {\n    console.info(v);\n}\n
hash_map.ts
/* Traverse hash table */\nconsole.info('\\nTraverse key-value pairs Key->Value');\nfor (const [k, v] of map.entries()) {\n    console.info(k + ' -> ' + v);\n}\nconsole.info('\\nTraverse keys only Key');\nfor (const k of map.keys()) {\n    console.info(k);\n}\nconsole.info('\\nTraverse values only Value');\nfor (const v of map.values()) {\n    console.info(v);\n}\n
hash_map.dart
/* Traverse hash table */\n// Traverse key-value pairs Key->Value\nmap.forEach((key, value) {\nprint('$key -> $value');\n});\n\n// Traverse keys only Key\nmap.keys.forEach((key) {\nprint(key);\n});\n\n// Traverse values only Value\nmap.values.forEach((value) {\nprint(value);\n});\n
hash_map.rs
/* Traverse hash table */\n// Traverse key-value pairs Key->Value\nfor (key, value) in &map {\n    println!(\"{key} -> {value}\");\n}\n\n// Traverse keys only Key\nfor key in map.keys() {\n    println!(\"{key}\"); \n}\n\n// Traverse values only Value\nfor value in map.values() {\n    println!(\"{value}\");\n}\n
hash_map.c
// C does not provide a built-in hash table\n
hash_map.zig
// Zig example is not provided\n
Code Visualization

Full Screen >

"},{"location":"chapter_hashing/hash_map/#612-simple-implementation-of-hash-table","title":"6.1.2 \u00a0 Simple Implementation of Hash Table","text":"

First, let's consider the simplest case: implementing a hash table using just an array. In the hash table, each empty slot in the array is called a \"bucket\", and each bucket can store one key-value pair. Therefore, the query operation involves finding the bucket corresponding to the key and retrieving the value from it.

So, how do we locate the appropriate bucket based on the key? This is achieved through a \"hash function\". The role of the hash function is to map a larger input space to a smaller output space. In a hash table, the input space is all possible keys, and the output space is all buckets (array indices). In other words, input a key, and we can use the hash function to determine the storage location of the corresponding key-value pair in the array.

The calculation process of the hash function for a given key is divided into the following two steps:

  1. Calculate the hash value using a certain hash algorithm hash().
  2. Take the modulus of the hash value with the number of buckets (array length) capacity to obtain the array index index.
index = hash(key) % capacity\n

Afterward, we can use index to access the corresponding bucket in the hash table and thereby retrieve the value.

Assuming array length capacity = 100 and hash algorithm hash(key) = key, the hash function is key % 100. The Figure 6-2 uses key as the student number and value as the name to demonstrate the working principle of the hash function.

Figure 6-2 \u00a0 Working principle of hash function

The following code implements a simple hash table. Here, we encapsulate key and value into a class Pair to represent the key-value pair.

PythonC++JavaC#GoSwiftJSTSDartRustCZig array_hash_map.py
class Pair:\n    \"\"\"\u952e\u503c\u5bf9\"\"\"\n\n    def __init__(self, key: int, val: str):\n        self.key = key\n        self.val = val\n\nclass ArrayHashMap:\n    \"\"\"\u57fa\u4e8e\u6570\u7ec4\u5b9e\u73b0\u7684\u54c8\u5e0c\u8868\"\"\"\n\n    def __init__(self):\n        \"\"\"\u6784\u9020\u65b9\u6cd5\"\"\"\n        # \u521d\u59cb\u5316\u6570\u7ec4\uff0c\u5305\u542b 100 \u4e2a\u6876\n        self.buckets: list[Pair | None] = [None] * 100\n\n    def hash_func(self, key: int) -> int:\n        \"\"\"\u54c8\u5e0c\u51fd\u6570\"\"\"\n        index = key % 100\n        return index\n\n    def get(self, key: int) -> str:\n        \"\"\"\u67e5\u8be2\u64cd\u4f5c\"\"\"\n        index: int = self.hash_func(key)\n        pair: Pair = self.buckets[index]\n        if pair is None:\n            return None\n        return pair.val\n\n    def put(self, key: int, val: str):\n        \"\"\"\u6dfb\u52a0\u64cd\u4f5c\"\"\"\n        pair = Pair(key, val)\n        index: int = self.hash_func(key)\n        self.buckets[index] = pair\n\n    def remove(self, key: int):\n        \"\"\"\u5220\u9664\u64cd\u4f5c\"\"\"\n        index: int = self.hash_func(key)\n        # \u7f6e\u4e3a None \uff0c\u4ee3\u8868\u5220\u9664\n        self.buckets[index] = None\n\n    def entry_set(self) -> list[Pair]:\n        \"\"\"\u83b7\u53d6\u6240\u6709\u952e\u503c\u5bf9\"\"\"\n        result: list[Pair] = []\n        for pair in self.buckets:\n            if pair is not None:\n                result.append(pair)\n        return result\n\n    def key_set(self) -> list[int]:\n        \"\"\"\u83b7\u53d6\u6240\u6709\u952e\"\"\"\n        result = []\n        for pair in self.buckets:\n            if pair is not None:\n                result.append(pair.key)\n        return result\n\n    def value_set(self) -> list[str]:\n        \"\"\"\u83b7\u53d6\u6240\u6709\u503c\"\"\"\n        result = []\n        for pair in self.buckets:\n            if pair is not None:\n                result.append(pair.val)\n        return result\n\n    def print(self):\n        \"\"\"\u6253\u5370\u54c8\u5e0c\u8868\"\"\"\n        for pair in self.buckets:\n            if pair is not None:\n                print(pair.key, \"->\", pair.val)\n
array_hash_map.cpp
/* \u952e\u503c\u5bf9 */\nstruct Pair {\n  public:\n    int key;\n    string val;\n    Pair(int key, string val) {\n        this->key = key;\n        this->val = val;\n    }\n};\n\n/* \u57fa\u4e8e\u6570\u7ec4\u5b9e\u73b0\u7684\u54c8\u5e0c\u8868 */\nclass ArrayHashMap {\n  private:\n    vector<Pair *> buckets;\n\n  public:\n    ArrayHashMap() {\n        // \u521d\u59cb\u5316\u6570\u7ec4\uff0c\u5305\u542b 100 \u4e2a\u6876\n        buckets = vector<Pair *>(100);\n    }\n\n    ~ArrayHashMap() {\n        // \u91ca\u653e\u5185\u5b58\n        for (const auto &bucket : buckets) {\n            delete bucket;\n        }\n        buckets.clear();\n    }\n\n    /* \u54c8\u5e0c\u51fd\u6570 */\n    int hashFunc(int key) {\n        int index = key % 100;\n        return index;\n    }\n\n    /* \u67e5\u8be2\u64cd\u4f5c */\n    string get(int key) {\n        int index = hashFunc(key);\n        Pair *pair = buckets[index];\n        if (pair == nullptr)\n            return \"\";\n        return pair->val;\n    }\n\n    /* \u6dfb\u52a0\u64cd\u4f5c */\n    void put(int key, string val) {\n        Pair *pair = new Pair(key, val);\n        int index = hashFunc(key);\n        buckets[index] = pair;\n    }\n\n    /* \u5220\u9664\u64cd\u4f5c */\n    void remove(int key) {\n        int index = hashFunc(key);\n        // \u91ca\u653e\u5185\u5b58\u5e76\u7f6e\u4e3a nullptr\n        delete buckets[index];\n        buckets[index] = nullptr;\n    }\n\n    /* \u83b7\u53d6\u6240\u6709\u952e\u503c\u5bf9 */\n    vector<Pair *> pairSet() {\n        vector<Pair *> pairSet;\n        for (Pair *pair : buckets) {\n            if (pair != nullptr) {\n                pairSet.push_back(pair);\n            }\n        }\n        return pairSet;\n    }\n\n    /* \u83b7\u53d6\u6240\u6709\u952e */\n    vector<int> keySet() {\n        vector<int> keySet;\n        for (Pair *pair : buckets) {\n            if (pair != nullptr) {\n                keySet.push_back(pair->key);\n            }\n        }\n        return keySet;\n    }\n\n    /* \u83b7\u53d6\u6240\u6709\u503c */\n    vector<string> valueSet() {\n        vector<string> valueSet;\n        for (Pair *pair : buckets) {\n            if (pair != nullptr) {\n                valueSet.push_back(pair->val);\n            }\n        }\n        return valueSet;\n    }\n\n    /* \u6253\u5370\u54c8\u5e0c\u8868 */\n    void print() {\n        for (Pair *kv : pairSet()) {\n            cout << kv->key << \" -> \" << kv->val << endl;\n        }\n    }\n};\n
array_hash_map.java
/* \u952e\u503c\u5bf9 */\nclass Pair {\n    public int key;\n    public String val;\n\n    public Pair(int key, String val) {\n        this.key = key;\n        this.val = val;\n    }\n}\n\n/* \u57fa\u4e8e\u6570\u7ec4\u5b9e\u73b0\u7684\u54c8\u5e0c\u8868 */\nclass ArrayHashMap {\n    private List<Pair> buckets;\n\n    public ArrayHashMap() {\n        // \u521d\u59cb\u5316\u6570\u7ec4\uff0c\u5305\u542b 100 \u4e2a\u6876\n        buckets = new ArrayList<>();\n        for (int i = 0; i < 100; i++) {\n            buckets.add(null);\n        }\n    }\n\n    /* \u54c8\u5e0c\u51fd\u6570 */\n    private int hashFunc(int key) {\n        int index = key % 100;\n        return index;\n    }\n\n    /* \u67e5\u8be2\u64cd\u4f5c */\n    public String get(int key) {\n        int index = hashFunc(key);\n        Pair pair = buckets.get(index);\n        if (pair == null)\n            return null;\n        return pair.val;\n    }\n\n    /* \u6dfb\u52a0\u64cd\u4f5c */\n    public void put(int key, String val) {\n        Pair pair = new Pair(key, val);\n        int index = hashFunc(key);\n        buckets.set(index, pair);\n    }\n\n    /* \u5220\u9664\u64cd\u4f5c */\n    public void remove(int key) {\n        int index = hashFunc(key);\n        // \u7f6e\u4e3a null \uff0c\u4ee3\u8868\u5220\u9664\n        buckets.set(index, null);\n    }\n\n    /* \u83b7\u53d6\u6240\u6709\u952e\u503c\u5bf9 */\n    public List<Pair> pairSet() {\n        List<Pair> pairSet = new ArrayList<>();\n        for (Pair pair : buckets) {\n            if (pair != null)\n                pairSet.add(pair);\n        }\n        return pairSet;\n    }\n\n    /* \u83b7\u53d6\u6240\u6709\u952e */\n    public List<Integer> keySet() {\n        List<Integer> keySet = new ArrayList<>();\n        for (Pair pair : buckets) {\n            if (pair != null)\n                keySet.add(pair.key);\n        }\n        return keySet;\n    }\n\n    /* \u83b7\u53d6\u6240\u6709\u503c */\n    public List<String> valueSet() {\n        List<String> valueSet = new ArrayList<>();\n        for (Pair pair : buckets) {\n            if (pair != null)\n                valueSet.add(pair.val);\n        }\n        return valueSet;\n    }\n\n    /* \u6253\u5370\u54c8\u5e0c\u8868 */\n    public void print() {\n        for (Pair kv : pairSet()) {\n            System.out.println(kv.key + \" -> \" + kv.val);\n        }\n    }\n}\n
array_hash_map.cs
/* \u952e\u503c\u5bf9 int->string */\nclass Pair(int key, string val) {\n    public int key = key;\n    public string val = val;\n}\n\n/* \u57fa\u4e8e\u6570\u7ec4\u5b9e\u73b0\u7684\u54c8\u5e0c\u8868 */\nclass ArrayHashMap {\n    List<Pair?> buckets;\n    public ArrayHashMap() {\n        // \u521d\u59cb\u5316\u6570\u7ec4\uff0c\u5305\u542b 100 \u4e2a\u6876\n        buckets = [];\n        for (int i = 0; i < 100; i++) {\n            buckets.Add(null);\n        }\n    }\n\n    /* \u54c8\u5e0c\u51fd\u6570 */\n    int HashFunc(int key) {\n        int index = key % 100;\n        return index;\n    }\n\n    /* \u67e5\u8be2\u64cd\u4f5c */\n    public string? Get(int key) {\n        int index = HashFunc(key);\n        Pair? pair = buckets[index];\n        if (pair == null) return null;\n        return pair.val;\n    }\n\n    /* \u6dfb\u52a0\u64cd\u4f5c */\n    public void Put(int key, string val) {\n        Pair pair = new(key, val);\n        int index = HashFunc(key);\n        buckets[index] = pair;\n    }\n\n    /* \u5220\u9664\u64cd\u4f5c */\n    public void Remove(int key) {\n        int index = HashFunc(key);\n        // \u7f6e\u4e3a null \uff0c\u4ee3\u8868\u5220\u9664\n        buckets[index] = null;\n    }\n\n    /* \u83b7\u53d6\u6240\u6709\u952e\u503c\u5bf9 */\n    public List<Pair> PairSet() {\n        List<Pair> pairSet = [];\n        foreach (Pair? pair in buckets) {\n            if (pair != null)\n                pairSet.Add(pair);\n        }\n        return pairSet;\n    }\n\n    /* \u83b7\u53d6\u6240\u6709\u952e */\n    public List<int> KeySet() {\n        List<int> keySet = [];\n        foreach (Pair? pair in buckets) {\n            if (pair != null)\n                keySet.Add(pair.key);\n        }\n        return keySet;\n    }\n\n    /* \u83b7\u53d6\u6240\u6709\u503c */\n    public List<string> ValueSet() {\n        List<string> valueSet = [];\n        foreach (Pair? pair in buckets) {\n            if (pair != null)\n                valueSet.Add(pair.val);\n        }\n        return valueSet;\n    }\n\n    /* \u6253\u5370\u54c8\u5e0c\u8868 */\n    public void Print() {\n        foreach (Pair kv in PairSet()) {\n            Console.WriteLine(kv.key + \" -> \" + kv.val);\n        }\n    }\n}\n
array_hash_map.go
/* \u952e\u503c\u5bf9 */\ntype pair struct {\n    key int\n    val string\n}\n\n/* \u57fa\u4e8e\u6570\u7ec4\u5b9e\u73b0\u7684\u54c8\u5e0c\u8868 */\ntype arrayHashMap struct {\n    buckets []*pair\n}\n\n/* \u521d\u59cb\u5316\u54c8\u5e0c\u8868 */\nfunc newArrayHashMap() *arrayHashMap {\n    // \u521d\u59cb\u5316\u6570\u7ec4\uff0c\u5305\u542b 100 \u4e2a\u6876\n    buckets := make([]*pair, 100)\n    return &arrayHashMap{buckets: buckets}\n}\n\n/* \u54c8\u5e0c\u51fd\u6570 */\nfunc (a *arrayHashMap) hashFunc(key int) int {\n    index := key % 100\n    return index\n}\n\n/* \u67e5\u8be2\u64cd\u4f5c */\nfunc (a *arrayHashMap) get(key int) string {\n    index := a.hashFunc(key)\n    pair := a.buckets[index]\n    if pair == nil {\n        return \"Not Found\"\n    }\n    return pair.val\n}\n\n/* \u6dfb\u52a0\u64cd\u4f5c */\nfunc (a *arrayHashMap) put(key int, val string) {\n    pair := &pair{key: key, val: val}\n    index := a.hashFunc(key)\n    a.buckets[index] = pair\n}\n\n/* \u5220\u9664\u64cd\u4f5c */\nfunc (a *arrayHashMap) remove(key int) {\n    index := a.hashFunc(key)\n    // \u7f6e\u4e3a nil \uff0c\u4ee3\u8868\u5220\u9664\n    a.buckets[index] = nil\n}\n\n/* \u83b7\u53d6\u6240\u6709\u952e\u5bf9 */\nfunc (a *arrayHashMap) pairSet() []*pair {\n    var pairs []*pair\n    for _, pair := range a.buckets {\n        if pair != nil {\n            pairs = append(pairs, pair)\n        }\n    }\n    return pairs\n}\n\n/* \u83b7\u53d6\u6240\u6709\u952e */\nfunc (a *arrayHashMap) keySet() []int {\n    var keys []int\n    for _, pair := range a.buckets {\n        if pair != nil {\n            keys = append(keys, pair.key)\n        }\n    }\n    return keys\n}\n\n/* \u83b7\u53d6\u6240\u6709\u503c */\nfunc (a *arrayHashMap) valueSet() []string {\n    var values []string\n    for _, pair := range a.buckets {\n        if pair != nil {\n            values = append(values, pair.val)\n        }\n    }\n    return values\n}\n\n/* \u6253\u5370\u54c8\u5e0c\u8868 */\nfunc (a *arrayHashMap) print() {\n    for _, pair := range a.buckets {\n        if pair != nil {\n            fmt.Println(pair.key, \"->\", pair.val)\n        }\n    }\n}\n
array_hash_map.swift
/* \u952e\u503c\u5bf9 */\nclass Pair: Equatable {\n    public var key: Int\n    public var val: String\n\n    public init(key: Int, val: String) {\n        self.key = key\n        self.val = val\n    }\n\n    public static func == (lhs: Pair, rhs: Pair) -> Bool {\n        lhs.key == rhs.key && lhs.val == rhs.val\n    }\n}\n\n/* \u57fa\u4e8e\u6570\u7ec4\u5b9e\u73b0\u7684\u54c8\u5e0c\u8868 */\nclass ArrayHashMap {\n    private var buckets: [Pair?]\n\n    init() {\n        // \u521d\u59cb\u5316\u6570\u7ec4\uff0c\u5305\u542b 100 \u4e2a\u6876\n        buckets = Array(repeating: nil, count: 100)\n    }\n\n    /* \u54c8\u5e0c\u51fd\u6570 */\n    private func hashFunc(key: Int) -> Int {\n        let index = key % 100\n        return index\n    }\n\n    /* \u67e5\u8be2\u64cd\u4f5c */\n    func get(key: Int) -> String? {\n        let index = hashFunc(key: key)\n        let pair = buckets[index]\n        return pair?.val\n    }\n\n    /* \u6dfb\u52a0\u64cd\u4f5c */\n    func put(key: Int, val: String) {\n        let pair = Pair(key: key, val: val)\n        let index = hashFunc(key: key)\n        buckets[index] = pair\n    }\n\n    /* \u5220\u9664\u64cd\u4f5c */\n    func remove(key: Int) {\n        let index = hashFunc(key: key)\n        // \u7f6e\u4e3a nil \uff0c\u4ee3\u8868\u5220\u9664\n        buckets[index] = nil\n    }\n\n    /* \u83b7\u53d6\u6240\u6709\u952e\u503c\u5bf9 */\n    func pairSet() -> [Pair] {\n        buckets.compactMap { $0 }\n    }\n\n    /* \u83b7\u53d6\u6240\u6709\u952e */\n    func keySet() -> [Int] {\n        buckets.compactMap { $0?.key }\n    }\n\n    /* \u83b7\u53d6\u6240\u6709\u503c */\n    func valueSet() -> [String] {\n        buckets.compactMap { $0?.val }\n    }\n\n    /* \u6253\u5370\u54c8\u5e0c\u8868 */\n    func print() {\n        for pair in pairSet() {\n            Swift.print(\"\\(pair.key) -> \\(pair.val)\")\n        }\n    }\n}\n
array_hash_map.js
/* \u952e\u503c\u5bf9 Number -> String */\nclass Pair {\n    constructor(key, val) {\n        this.key = key;\n        this.val = val;\n    }\n}\n\n/* \u57fa\u4e8e\u6570\u7ec4\u5b9e\u73b0\u7684\u54c8\u5e0c\u8868 */\nclass ArrayHashMap {\n    #buckets;\n    constructor() {\n        // \u521d\u59cb\u5316\u6570\u7ec4\uff0c\u5305\u542b 100 \u4e2a\u6876\n        this.#buckets = new Array(100).fill(null);\n    }\n\n    /* \u54c8\u5e0c\u51fd\u6570 */\n    #hashFunc(key) {\n        return key % 100;\n    }\n\n    /* \u67e5\u8be2\u64cd\u4f5c */\n    get(key) {\n        let index = this.#hashFunc(key);\n        let pair = this.#buckets[index];\n        if (pair === null) return null;\n        return pair.val;\n    }\n\n    /* \u6dfb\u52a0\u64cd\u4f5c */\n    set(key, val) {\n        let index = this.#hashFunc(key);\n        this.#buckets[index] = new Pair(key, val);\n    }\n\n    /* \u5220\u9664\u64cd\u4f5c */\n    delete(key) {\n        let index = this.#hashFunc(key);\n        // \u7f6e\u4e3a null \uff0c\u4ee3\u8868\u5220\u9664\n        this.#buckets[index] = null;\n    }\n\n    /* \u83b7\u53d6\u6240\u6709\u952e\u503c\u5bf9 */\n    entries() {\n        let arr = [];\n        for (let i = 0; i < this.#buckets.length; i++) {\n            if (this.#buckets[i]) {\n                arr.push(this.#buckets[i]);\n            }\n        }\n        return arr;\n    }\n\n    /* \u83b7\u53d6\u6240\u6709\u952e */\n    keys() {\n        let arr = [];\n        for (let i = 0; i < this.#buckets.length; i++) {\n            if (this.#buckets[i]) {\n                arr.push(this.#buckets[i].key);\n            }\n        }\n        return arr;\n    }\n\n    /* \u83b7\u53d6\u6240\u6709\u503c */\n    values() {\n        let arr = [];\n        for (let i = 0; i < this.#buckets.length; i++) {\n            if (this.#buckets[i]) {\n                arr.push(this.#buckets[i].val);\n            }\n        }\n        return arr;\n    }\n\n    /* \u6253\u5370\u54c8\u5e0c\u8868 */\n    print() {\n        let pairSet = this.entries();\n        for (const pair of pairSet) {\n            console.info(`${pair.key} -> ${pair.val}`);\n        }\n    }\n}\n
array_hash_map.ts
/* \u952e\u503c\u5bf9 Number -> String */\nclass Pair {\n    public key: number;\n    public val: string;\n\n    constructor(key: number, val: string) {\n        this.key = key;\n        this.val = val;\n    }\n}\n\n/* \u57fa\u4e8e\u6570\u7ec4\u5b9e\u73b0\u7684\u54c8\u5e0c\u8868 */\nclass ArrayHashMap {\n    private readonly buckets: (Pair | null)[];\n\n    constructor() {\n        // \u521d\u59cb\u5316\u6570\u7ec4\uff0c\u5305\u542b 100 \u4e2a\u6876\n        this.buckets = new Array(100).fill(null);\n    }\n\n    /* \u54c8\u5e0c\u51fd\u6570 */\n    private hashFunc(key: number): number {\n        return key % 100;\n    }\n\n    /* \u67e5\u8be2\u64cd\u4f5c */\n    public get(key: number): string | null {\n        let index = this.hashFunc(key);\n        let pair = this.buckets[index];\n        if (pair === null) return null;\n        return pair.val;\n    }\n\n    /* \u6dfb\u52a0\u64cd\u4f5c */\n    public set(key: number, val: string) {\n        let index = this.hashFunc(key);\n        this.buckets[index] = new Pair(key, val);\n    }\n\n    /* \u5220\u9664\u64cd\u4f5c */\n    public delete(key: number) {\n        let index = this.hashFunc(key);\n        // \u7f6e\u4e3a null \uff0c\u4ee3\u8868\u5220\u9664\n        this.buckets[index] = null;\n    }\n\n    /* \u83b7\u53d6\u6240\u6709\u952e\u503c\u5bf9 */\n    public entries(): (Pair | null)[] {\n        let arr: (Pair | null)[] = [];\n        for (let i = 0; i < this.buckets.length; i++) {\n            if (this.buckets[i]) {\n                arr.push(this.buckets[i]);\n            }\n        }\n        return arr;\n    }\n\n    /* \u83b7\u53d6\u6240\u6709\u952e */\n    public keys(): (number | undefined)[] {\n        let arr: (number | undefined)[] = [];\n        for (let i = 0; i < this.buckets.length; i++) {\n            if (this.buckets[i]) {\n                arr.push(this.buckets[i].key);\n            }\n        }\n        return arr;\n    }\n\n    /* \u83b7\u53d6\u6240\u6709\u503c */\n    public values(): (string | undefined)[] {\n        let arr: (string | undefined)[] = [];\n        for (let i = 0; i < this.buckets.length; i++) {\n            if (this.buckets[i]) {\n                arr.push(this.buckets[i].val);\n            }\n        }\n        return arr;\n    }\n\n    /* \u6253\u5370\u54c8\u5e0c\u8868 */\n    public print() {\n        let pairSet = this.entries();\n        for (const pair of pairSet) {\n            console.info(`${pair.key} -> ${pair.val}`);\n        }\n    }\n}\n
array_hash_map.dart
/* \u952e\u503c\u5bf9 */\nclass Pair {\n  int key;\n  String val;\n  Pair(this.key, this.val);\n}\n\n/* \u57fa\u4e8e\u6570\u7ec4\u5b9e\u73b0\u7684\u54c8\u5e0c\u8868 */\nclass ArrayHashMap {\n  late List<Pair?> _buckets;\n\n  ArrayHashMap() {\n    // \u521d\u59cb\u5316\u6570\u7ec4\uff0c\u5305\u542b 100 \u4e2a\u6876\n    _buckets = List.filled(100, null);\n  }\n\n  /* \u54c8\u5e0c\u51fd\u6570 */\n  int _hashFunc(int key) {\n    final int index = key % 100;\n    return index;\n  }\n\n  /* \u67e5\u8be2\u64cd\u4f5c */\n  String? get(int key) {\n    final int index = _hashFunc(key);\n    final Pair? pair = _buckets[index];\n    if (pair == null) {\n      return null;\n    }\n    return pair.val;\n  }\n\n  /* \u6dfb\u52a0\u64cd\u4f5c */\n  void put(int key, String val) {\n    final Pair pair = Pair(key, val);\n    final int index = _hashFunc(key);\n    _buckets[index] = pair;\n  }\n\n  /* \u5220\u9664\u64cd\u4f5c */\n  void remove(int key) {\n    final int index = _hashFunc(key);\n    _buckets[index] = null;\n  }\n\n  /* \u83b7\u53d6\u6240\u6709\u952e\u503c\u5bf9 */\n  List<Pair> pairSet() {\n    List<Pair> pairSet = [];\n    for (final Pair? pair in _buckets) {\n      if (pair != null) {\n        pairSet.add(pair);\n      }\n    }\n    return pairSet;\n  }\n\n  /* \u83b7\u53d6\u6240\u6709\u952e */\n  List<int> keySet() {\n    List<int> keySet = [];\n    for (final Pair? pair in _buckets) {\n      if (pair != null) {\n        keySet.add(pair.key);\n      }\n    }\n    return keySet;\n  }\n\n  /* \u83b7\u53d6\u6240\u6709\u503c */\n  List<String> values() {\n    List<String> valueSet = [];\n    for (final Pair? pair in _buckets) {\n      if (pair != null) {\n        valueSet.add(pair.val);\n      }\n    }\n    return valueSet;\n  }\n\n  /* \u6253\u5370\u54c8\u5e0c\u8868 */\n  void printHashMap() {\n    for (final Pair kv in pairSet()) {\n      print(\"${kv.key} -> ${kv.val}\");\n    }\n  }\n}\n
array_hash_map.rs
/* \u952e\u503c\u5bf9 */\n#[derive(Debug, Clone, PartialEq)]\npub struct Pair {\n    pub key: i32,\n    pub val: String,\n}\n\n/* \u57fa\u4e8e\u6570\u7ec4\u5b9e\u73b0\u7684\u54c8\u5e0c\u8868 */\npub struct ArrayHashMap {\n    buckets: Vec<Option<Pair>>,\n}\n\nimpl ArrayHashMap {\n    pub fn new() -> ArrayHashMap {\n        // \u521d\u59cb\u5316\u6570\u7ec4\uff0c\u5305\u542b 100 \u4e2a\u6876\n        Self {\n            buckets: vec![None; 100],\n        }\n    }\n\n    /* \u54c8\u5e0c\u51fd\u6570 */\n    fn hash_func(&self, key: i32) -> usize {\n        key as usize % 100\n    }\n\n    /* \u67e5\u8be2\u64cd\u4f5c */\n    pub fn get(&self, key: i32) -> Option<&String> {\n        let index = self.hash_func(key);\n        self.buckets[index].as_ref().map(|pair| &pair.val)\n    }\n\n    /* \u6dfb\u52a0\u64cd\u4f5c */\n    pub fn put(&mut self, key: i32, val: &str) {\n        let index = self.hash_func(key);\n        self.buckets[index] = Some(Pair {\n            key,\n            val: val.to_string(),\n        });\n    }\n\n    /* \u5220\u9664\u64cd\u4f5c */\n    pub fn remove(&mut self, key: i32) {\n        let index = self.hash_func(key);\n        // \u7f6e\u4e3a None \uff0c\u4ee3\u8868\u5220\u9664\n        self.buckets[index] = None;\n    }\n\n    /* \u83b7\u53d6\u6240\u6709\u952e\u503c\u5bf9 */\n    pub fn entry_set(&self) -> Vec<&Pair> {\n        self.buckets\n            .iter()\n            .filter_map(|pair| pair.as_ref())\n            .collect()\n    }\n\n    /* \u83b7\u53d6\u6240\u6709\u952e */\n    pub fn key_set(&self) -> Vec<&i32> {\n        self.buckets\n            .iter()\n            .filter_map(|pair| pair.as_ref().map(|pair| &pair.key))\n            .collect()\n    }\n\n    /* \u83b7\u53d6\u6240\u6709\u503c */\n    pub fn value_set(&self) -> Vec<&String> {\n        self.buckets\n            .iter()\n            .filter_map(|pair| pair.as_ref().map(|pair| &pair.val))\n            .collect()\n    }\n\n    /* \u6253\u5370\u54c8\u5e0c\u8868 */\n    pub fn print(&self) {\n        for pair in self.entry_set() {\n            println!(\"{} -> {}\", pair.key, pair.val);\n        }\n    }\n}\n
array_hash_map.c
/* \u952e\u503c\u5bf9 int->string */\ntypedef struct {\n    int key;\n    char *val;\n} Pair;\n\n/* \u57fa\u4e8e\u6570\u7ec4\u5b9e\u73b0\u7684\u54c8\u5e0c\u8868 */\ntypedef struct {\n    Pair *buckets[HASHTABLE_CAPACITY];\n} ArrayHashMap;\n\n/* \u6784\u9020\u51fd\u6570 */\nArrayHashMap *newArrayHashMap() {\n    ArrayHashMap *hmap = malloc(sizeof(ArrayHashMap));\n    return hmap;\n}\n\n/* \u6790\u6784\u51fd\u6570 */\nvoid delArrayHashMap(ArrayHashMap *hmap) {\n    for (int i = 0; i < HASHTABLE_CAPACITY; i++) {\n        if (hmap->buckets[i] != NULL) {\n            free(hmap->buckets[i]->val);\n            free(hmap->buckets[i]);\n        }\n    }\n    free(hmap);\n}\n\n/* \u6dfb\u52a0\u64cd\u4f5c */\nvoid put(ArrayHashMap *hmap, const int key, const char *val) {\n    Pair *Pair = malloc(sizeof(Pair));\n    Pair->key = key;\n    Pair->val = malloc(strlen(val) + 1);\n    strcpy(Pair->val, val);\n\n    int index = hashFunc(key);\n    hmap->buckets[index] = Pair;\n}\n\n/* \u5220\u9664\u64cd\u4f5c */\nvoid removeItem(ArrayHashMap *hmap, const int key) {\n    int index = hashFunc(key);\n    free(hmap->buckets[index]->val);\n    free(hmap->buckets[index]);\n    hmap->buckets[index] = NULL;\n}\n\n/* \u83b7\u53d6\u6240\u6709\u952e\u503c\u5bf9 */\nvoid pairSet(ArrayHashMap *hmap, MapSet *set) {\n    Pair *entries;\n    int i = 0, index = 0;\n    int total = 0;\n    /* \u7edf\u8ba1\u6709\u6548\u952e\u503c\u5bf9\u6570\u91cf */\n    for (i = 0; i < HASHTABLE_CAPACITY; i++) {\n        if (hmap->buckets[i] != NULL) {\n            total++;\n        }\n    }\n    entries = malloc(sizeof(Pair) * total);\n    for (i = 0; i < HASHTABLE_CAPACITY; i++) {\n        if (hmap->buckets[i] != NULL) {\n            entries[index].key = hmap->buckets[i]->key;\n            entries[index].val = malloc(strlen(hmap->buckets[i]->val) + 1);\n            strcpy(entries[index].val, hmap->buckets[i]->val);\n            index++;\n        }\n    }\n    set->set = entries;\n    set->len = total;\n}\n\n/* \u83b7\u53d6\u6240\u6709\u952e */\nvoid keySet(ArrayHashMap *hmap, MapSet *set) {\n    int *keys;\n    int i = 0, index = 0;\n    int total = 0;\n    /* \u7edf\u8ba1\u6709\u6548\u952e\u503c\u5bf9\u6570\u91cf */\n    for (i = 0; i < HASHTABLE_CAPACITY; i++) {\n        if (hmap->buckets[i] != NULL) {\n            total++;\n        }\n    }\n    keys = malloc(total * sizeof(int));\n    for (i = 0; i < HASHTABLE_CAPACITY; i++) {\n        if (hmap->buckets[i] != NULL) {\n            keys[index] = hmap->buckets[i]->key;\n            index++;\n        }\n    }\n    set->set = keys;\n    set->len = total;\n}\n\n/* \u83b7\u53d6\u6240\u6709\u503c */\nvoid valueSet(ArrayHashMap *hmap, MapSet *set) {\n    char **vals;\n    int i = 0, index = 0;\n    int total = 0;\n    /* \u7edf\u8ba1\u6709\u6548\u952e\u503c\u5bf9\u6570\u91cf */\n    for (i = 0; i < HASHTABLE_CAPACITY; i++) {\n        if (hmap->buckets[i] != NULL) {\n            total++;\n        }\n    }\n    vals = malloc(total * sizeof(char *));\n    for (i = 0; i < HASHTABLE_CAPACITY; i++) {\n        if (hmap->buckets[i] != NULL) {\n            vals[index] = hmap->buckets[i]->val;\n            index++;\n        }\n    }\n    set->set = vals;\n    set->len = total;\n}\n\n/* \u6253\u5370\u54c8\u5e0c\u8868 */\nvoid print(ArrayHashMap *hmap) {\n    int i;\n    MapSet set;\n    pairSet(hmap, &set);\n    Pair *entries = (Pair *)set.set;\n    for (i = 0; i < set.len; i++) {\n        printf(\"%d -> %s\\n\", entries[i].key, entries[i].val);\n    }\n    free(set.set);\n}\n
array_hash_map.zig
// \u952e\u503c\u5bf9\nconst Pair = struct {\n    key: usize = undefined,\n    val: []const u8 = undefined,\n\n   pub fn init(key: usize, val: []const u8) Pair {\n        return Pair {\n            .key = key,\n            .val = val,\n        };\n    }\n};\n\n// \u57fa\u4e8e\u6570\u7ec4\u5b9e\u73b0\u7684\u54c8\u5e0c\u8868\nfn ArrayHashMap(comptime T: type) type {\n    return struct {\n        bucket: ?std.ArrayList(?T) = null,\n        mem_allocator: std.mem.Allocator = undefined,\n\n        const Self = @This();\n\n        // \u6784\u9020\u51fd\u6570\n        pub fn init(self: *Self, allocator: std.mem.Allocator) !void {\n            self.mem_allocator = allocator;\n            // \u521d\u59cb\u5316\u4e00\u4e2a\u957f\u5ea6\u4e3a 100 \u7684\u6876\uff08\u6570\u7ec4\uff09\n            self.bucket = std.ArrayList(?T).init(self.mem_allocator);\n            var i: i32 = 0;\n            while (i < 100) : (i += 1) {\n                try self.bucket.?.append(null);\n            }\n        }\n\n        // \u6790\u6784\u51fd\u6570\n        pub fn deinit(self: *Self) void {\n            if (self.bucket != null) self.bucket.?.deinit();\n        }\n\n        // \u54c8\u5e0c\u51fd\u6570\n        fn hashFunc(key: usize) usize {\n            var index = key % 100;\n            return index;\n        }\n\n        // \u67e5\u8be2\u64cd\u4f5c\n        pub fn get(self: *Self, key: usize) []const u8 {\n            var index = hashFunc(key);\n            var pair = self.bucket.?.items[index];\n            return pair.?.val;\n        }\n\n        // \u6dfb\u52a0\u64cd\u4f5c\n        pub fn put(self: *Self, key: usize, val: []const u8) !void {\n            var pair = Pair.init(key, val);\n            var index = hashFunc(key);\n            self.bucket.?.items[index] = pair;\n        }\n\n        // \u5220\u9664\u64cd\u4f5c\n        pub fn remove(self: *Self, key: usize) !void {\n            var index = hashFunc(key);\n            // \u7f6e\u4e3a null \uff0c\u4ee3\u8868\u5220\u9664\n            self.bucket.?.items[index] = null;\n        }       \n\n        // \u83b7\u53d6\u6240\u6709\u952e\u503c\u5bf9\n        pub fn pairSet(self: *Self) !std.ArrayList(T) {\n            var entry_set = std.ArrayList(T).init(self.mem_allocator);\n            for (self.bucket.?.items) |item| {\n                if (item == null) continue;\n                try entry_set.append(item.?);\n            }\n            return entry_set;\n        }  \n\n        // \u83b7\u53d6\u6240\u6709\u952e\n        pub fn keySet(self: *Self) !std.ArrayList(usize) {\n            var key_set = std.ArrayList(usize).init(self.mem_allocator);\n            for (self.bucket.?.items) |item| {\n                if (item == null) continue;\n                try key_set.append(item.?.key);\n            }\n            return key_set;\n        }  \n\n        // \u83b7\u53d6\u6240\u6709\u503c\n        pub fn valueSet(self: *Self) !std.ArrayList([]const u8) {\n            var value_set = std.ArrayList([]const u8).init(self.mem_allocator);\n            for (self.bucket.?.items) |item| {\n                if (item == null) continue;\n                try value_set.append(item.?.val);\n            }\n            return value_set;\n        }\n\n        // \u6253\u5370\u54c8\u5e0c\u8868\n        pub fn print(self: *Self) !void {\n            var entry_set = try self.pairSet();\n            defer entry_set.deinit();\n            for (entry_set.items) |item| {\n                std.debug.print(\"{} -> {s}\\n\", .{item.key, item.val});\n            }\n        }\n    };\n}\n
Code Visualization

Full Screen >

"},{"location":"chapter_hashing/hash_map/#613-hash-collision-and-resizing","title":"6.1.3 \u00a0 Hash Collision and Resizing","text":"

Fundamentally, the role of the hash function is to map the entire input space of all keys to the output space of all array indices. However, the input space is often much larger than the output space. Therefore, theoretically, there must be situations where \"multiple inputs correspond to the same output\".

For the hash function in the above example, if the last two digits of the input key are the same, the output of the hash function will also be the same. For example, when querying for students with student numbers 12836 and 20336, we find:

12836 % 100 = 36\n20336 % 100 = 36\n

As shown in the Figure 6-3 , both student numbers point to the same name, which is obviously incorrect. This situation where multiple inputs correspond to the same output is known as \"hash collision\".

Figure 6-3 \u00a0 Example of hash collision

It is easy to understand that the larger the capacity \\(n\\) of the hash table, the lower the probability of multiple keys being allocated to the same bucket, and the fewer the collisions. Therefore, expanding the capacity of the hash table can reduce hash collisions.

As shown in the Figure 6-4 , before expansion, key-value pairs (136, A) and (236, D) collided; after expansion, the collision is resolved.

Figure 6-4 \u00a0 Hash table expansion

Similar to array expansion, resizing a hash table requires migrating all key-value pairs from the original hash table to the new one, which is time-consuming. Furthermore, since the capacity capacity of the hash table changes, we need to recalculate the storage positions of all key-value pairs using the hash function, which adds to the computational overhead of the resizing process. Therefore, programming languages often reserve a sufficiently large capacity for the hash table to prevent frequent resizing.

The \"load factor\" is an important concept for hash tables. It is defined as the ratio of the number of elements in the hash table to the number of buckets. It is used to measure the severity of hash collisions and is often used as a trigger for resizing the hash table. For example, in Java, when the load factor exceeds \\(0.75\\), the system will resize the hash table to twice its original size.

"},{"location":"chapter_hashing/summary/","title":"6.4 \u00a0 Summary","text":""},{"location":"chapter_hashing/summary/#1-key-review","title":"1. \u00a0 Key Review","text":"
  • Given an input key, a hash table can retrieve the corresponding value in \\(O(1)\\) time, which is highly efficient.
  • Common hash table operations include querying, adding key-value pairs, deleting key-value pairs, and traversing the hash table.
  • The hash function maps a key to an array index, allowing access to the corresponding bucket to retrieve the value.
  • Two different keys may end up with the same array index after hashing, leading to erroneous query results. This phenomenon is known as hash collision.
  • The larger the capacity of the hash table, the lower the probability of hash collisions. Therefore, hash table resizing can mitigate hash collisions. Similar to array resizing, hash table resizing is costly.
  • Load factor, defined as the ratio of the number of elements to the number of buckets in the hash table, reflects the severity of hash collisions and is often used as a trigger for resizing the hash table.
  • Chaining addresses hash collisions by converting each element into a linked list, storing all colliding elements in the same list. However, excessively long lists can reduce query efficiency, which can be improved by converting the lists into red-black trees.
  • Open addressing handles hash collisions through multiple probes. Linear probing uses a fixed step size but cannot delete elements and is prone to clustering. Multiple hashing uses several hash functions for probing, making it less susceptible to clustering but increasing computational load.
  • Different programming languages adopt various hash table implementations. For example, Java's HashMap uses chaining, while Python's dict employs open addressing.
  • In hash tables, we desire hash algorithms with determinism, high efficiency, and uniform distribution. In cryptography, hash algorithms should also possess collision resistance and the avalanche effect.
  • Hash algorithms typically use large prime numbers as moduli to ensure uniform distribution of hash values and reduce hash collisions.
  • Common hash algorithms include MD5, SHA-1, SHA-2, and SHA-3. MD5 is often used for file integrity checks, while SHA-2 is commonly used in secure applications and protocols.
  • Programming languages usually provide built-in hash algorithms for data types to calculate bucket indices in hash tables. Generally, only immutable objects are hashable.
"},{"location":"chapter_hashing/summary/#2-q-a","title":"2. \u00a0 Q & A","text":"

Q: When does the time complexity of a hash table degrade to \\(O(n)\\)?

The time complexity of a hash table can degrade to \\(O(n)\\) when hash collisions are severe. When the hash function is well-designed, the capacity is set appropriately, and collisions are evenly distributed, the time complexity is \\(O(1)\\). We usually consider the time complexity to be \\(O(1)\\) when using built-in hash tables in programming languages.

Q: Why not use the hash function \\(f(x) = x\\)? This would eliminate collisions.

Under the hash function \\(f(x) = x\\), each element corresponds to a unique bucket index, which is equivalent to an array. However, the input space is usually much larger than the output space (array length), so the last step of a hash function is often to take the modulo of the array length. In other words, the goal of a hash table is to map a larger state space to a smaller one while providing \\(O(1)\\) query efficiency.

Q: Why can hash tables be more efficient than arrays, linked lists, or binary trees, even though they are implemented using these structures?

Firstly, hash tables have higher time efficiency but lower space efficiency. A significant portion of memory in hash tables remains unused.

Secondly, they are only more efficient in specific use cases. If a feature can be implemented with the same time complexity using an array or a linked list, it's usually faster than using a hash table. This is because the computation of the hash function incurs overhead, making the constant factor in the time complexity larger.

Lastly, the time complexity of hash tables can degrade. For example, in chaining, we perform search operations in a linked list or red-black tree, which still risks degrading to \\(O(n)\\) time.

Q: Does multiple hashing also have the flaw of not being able to delete elements directly? Can space marked as deleted be reused?

Multiple hashing is a form of open addressing, and all open addressing methods have the drawback of not being able to delete elements directly; they require marking elements as deleted. Marked spaces can be reused. When inserting new elements into the hash table, and the hash function points to a position marked as deleted, that position can be used by the new element. This maintains the probing sequence of the hash table while ensuring efficient use of space.

Q: Why do hash collisions occur during the search process in linear probing?

During the search process, the hash function points to the corresponding bucket and key-value pair. If the key doesn't match, it indicates a hash collision. Therefore, linear probing will search downwards at a predetermined step size until the correct key-value pair is found or the search fails.

Q: Why can resizing a hash table alleviate hash collisions?

The last step of a hash function often involves taking the modulo of the array length \\(n\\), to keep the output within the array index range. When resizing, the array length \\(n\\) changes, and the indices corresponding to the keys may also change. Keys that were previously mapped to the same bucket might be distributed across multiple buckets after resizing, thereby mitigating hash collisions.

"},{"location":"chapter_introduction/","title":"Chapter 1. \u00a0 Introduction to Algorithms","text":"

Abstract

A graceful maiden dances, intertwined with the data, her skirt swaying to the melody of algorithms.

She invites you to a dance, follow her steps, and enter the world of algorithms full of logic and beauty.

"},{"location":"chapter_introduction/#chapter-contents","title":"Chapter Contents","text":"
  • 1.1 \u00a0 Algorithms are Everywhere
  • 1.2 \u00a0 What is an Algorithm
  • 1.3 \u00a0 Summary
"},{"location":"chapter_introduction/algorithms_are_everywhere/","title":"1.1 \u00a0 Algorithms are Everywhere","text":"

When we hear the word \"algorithm,\" we naturally think of mathematics. However, many algorithms do not involve complex mathematics but rely more on basic logic, which can be seen everywhere in our daily lives.

Before formally discussing algorithms, there's an interesting fact worth sharing: you have already unconsciously learned many algorithms and have become accustomed to applying them in your daily life. Here, I will give a few specific examples to prove this point.

Example 1: Looking Up a Dictionary. In an English dictionary, words are listed alphabetically. Suppose we're searching for a word that starts with the letter \\(r\\). This is typically done in the following way:

  1. Open the dictionary to about halfway and check the first letter on the page, let's say the letter is \\(m\\).
  2. Since \\(r\\) comes after \\(m\\) in the alphabet, we can ignore the first half of the dictionary and focus on the latter half.
  3. Repeat steps 1. and 2. until you find the page where the word starts with \\(r\\).
<1><2><3><4><5>

Figure 1-1 \u00a0 Process of Looking Up a Dictionary

This essential skill for elementary students, looking up a dictionary, is actually the famous \"Binary Search\" algorithm. From a data structure perspective, we can consider the dictionary as a sorted \"array\"; from an algorithmic perspective, the series of actions taken to look up a word in the dictionary can be viewed as \"Binary Search.\"

Example 2: Organizing Playing Cards. When playing cards, we need to arrange the cards in our hand in ascending order, as shown in the following process.

  1. Divide the playing cards into \"ordered\" and \"unordered\" sections, assuming initially the leftmost card is already in order.
  2. Take out a card from the unordered section and insert it into the correct position in the ordered section; after this, the leftmost two cards are in order.
  3. Continue to repeat step 2. until all cards are in order.

Figure 1-2 \u00a0 Playing Cards Sorting Process

The above method of organizing playing cards is essentially the \"Insertion Sort\" algorithm, which is very efficient for small datasets. Many programming languages' sorting functions include the insertion sort.

Example 3: Making Change. Suppose we buy goods worth \\(69\\) yuan at a supermarket and give the cashier \\(100\\) yuan, then the cashier needs to give us \\(31\\) yuan in change. They would naturally complete the thought process as shown below.

  1. The options are currencies smaller than \\(31\\), including \\(1\\), \\(5\\), \\(10\\), and \\(20\\).
  2. Take out the largest \\(20\\) from the options, leaving \\(31 - 20 = 11\\).
  3. Take out the largest \\(10\\) from the remaining options, leaving \\(11 - 10 = 1\\).
  4. Take out the largest \\(1\\) from the remaining options, leaving \\(1 - 1 = 0\\).
  5. Complete the change-making, with the solution being \\(20 + 10 + 1 = 31\\).

Figure 1-3 \u00a0 Change making process

In the above steps, we make the best choice at each step (using the largest denomination possible), ultimately resulting in a feasible change-making plan. From the perspective of data structures and algorithms, this method is essentially a \"Greedy\" algorithm.

From cooking a meal to interstellar travel, almost all problem-solving involves algorithms. The advent of computers allows us to store data structures in memory and write code to call the CPU and GPU to execute algorithms. In this way, we can transfer real-life problems to computers, solving various complex issues more efficiently.

Tip

If concepts such as data structures, algorithms, arrays, and binary search still seem somewhat obsecure, I encourage you to continue reading. This book will gently guide you into the realm of understanding data structures and algorithms.

"},{"location":"chapter_introduction/summary/","title":"1.3 \u00a0 Summary","text":"
  • Algorithms are ubiquitous in daily life and are not as inaccessible and complex as they might seem. In fact, we have already unconsciously learned many algorithms to solve various problems in life.
  • The principle of looking up a word in a dictionary is consistent with the binary search algorithm. The binary search algorithm embodies the important algorithmic concept of divide and conquer.
  • The process of organizing playing cards is very similar to the insertion sort algorithm. The insertion sort algorithm is suitable for sorting small datasets.
  • The steps of making change in currency essentially follow the greedy algorithm, where each step involves making the best possible choice at the moment.
  • An algorithm is a set of instructions or steps used to solve a specific problem within a finite amount of time, while a data structure is the way data is organized and stored in a computer.
  • Data structures and algorithms are closely linked. Data structures are the foundation of algorithms, and algorithms are the stage to utilize the functions of data structures.
  • We can liken data structures and algorithms to building blocks. The blocks represent data, the shape and connection method of the blocks represent data structures, and the steps of assembling the blocks correspond to algorithms.
"},{"location":"chapter_introduction/what_is_dsa/","title":"1.2 \u00a0 What is an Algorithm","text":""},{"location":"chapter_introduction/what_is_dsa/#121-definition-of-an-algorithm","title":"1.2.1 \u00a0 Definition of an Algorithm","text":"

An \"algorithm\" is a set of instructions or steps to solve a specific problem within a finite amount of time. It has the following characteristics:

  • The problem is clearly defined, including unambiguous definitions of input and output.
  • The algorithm is feasible, meaning it can be completed within a finite number of steps, time, and memory space.
  • Each step has a definitive meaning. The output is consistently the same under the same inputs and conditions.
"},{"location":"chapter_introduction/what_is_dsa/#122-definition-of-a-data-structure","title":"1.2.2 \u00a0 Definition of a Data Structure","text":"

A \"data structure\" is a way of organizing and storing data in a computer, with the following design goals:

  • Minimize space occupancy to save computer memory.
  • Make data operations as fast as possible, covering data access, addition, deletion, updating, etc.
  • Provide concise data representation and logical information to enable efficient algorithm execution.

Designing data structures is a balancing act, often requiring trade-offs. If you want to improve in one aspect, you often need to compromise in another. Here are two examples:

  • Compared to arrays, linked lists offer more convenience in data addition and deletion but sacrifice data access speed.
  • Graphs, compared to linked lists, provide richer logical information but require more memory space.
"},{"location":"chapter_introduction/what_is_dsa/#123-relationship-between-data-structures-and-algorithms","title":"1.2.3 \u00a0 Relationship Between Data Structures and Algorithms","text":"

As shown in the Figure 1-4 , data structures and algorithms are highly related and closely integrated, specifically in the following three aspects:

  • Data structures are the foundation of algorithms. They provide structured data storage and methods for manipulating data for algorithms.
  • Algorithms are the stage where data structures come into play. The data structure alone only stores data information; it is through the application of algorithms that specific problems can be solved.
  • Algorithms can often be implemented based on different data structures, but their execution efficiency can vary greatly. Choosing the right data structure is key.

Figure 1-4 \u00a0 Relationship between data structures and algorithms

Data structures and algorithms can be likened to a set of building blocks, as illustrated in the Figure 1-5 . A building block set includes numerous pieces, accompanied by detailed assembly instructions. Following these instructions step by step allows us to construct an intricate block model.

Figure 1-5 \u00a0 Assembling blocks

The detailed correspondence between the two is shown in the Table 1-1 .

Table 1-1 \u00a0 Comparing Data Structures and Algorithms to Building Blocks

Data Structures and Algorithms Building Blocks Input data Unassembled blocks Data structure Organization of blocks, including shape, size, connections, etc Algorithm A series of steps to assemble the blocks into the desired shape Output data Completed Block model

It's worth noting that data structures and algorithms are independent of programming languages. For this reason, this book is able to provide implementations in multiple programming languages.

Conventional Abbreviation

In real-life discussions, we often refer to \"Data Structures and Algorithms\" simply as \"Algorithms\". For example, the well-known LeetCode algorithm problems actually test both data structure and algorithm knowledge.

"},{"location":"chapter_preface/","title":"Chapter 0. \u00a0 Preface","text":"

Abstract

Algorithms are like a beautiful symphony, with each line of code flowing like a rhythm.

May this book ring softly in your mind, leaving a unique and profound melody.

"},{"location":"chapter_preface/#chapter-contents","title":"Chapter Contents","text":"
  • 0.1 \u00a0 About This Book
  • 0.2 \u00a0 How to Read
  • 0.3 \u00a0 Summary
"},{"location":"chapter_preface/about_the_book/","title":"0.1 \u00a0 About This Book","text":"

This open-source project aims to create a free, and beginner-friendly crash course on data structures and algorithms.

  • Using animated illustrations, it delivers structured insights into data structures and algorithmic concepts, ensuring comprehensibility and a smooth learning curve.
  • Run code with just one click, supporting Java, C++, Python, Go, JS, TS, C#, Swift, Rust, Dart, Zig and other languages.
  • Readers are encouraged to engage with each other in the discussion area for each section, questions and comments are usually answered within two days.
"},{"location":"chapter_preface/about_the_book/#011-target-audience","title":"0.1.1 \u00a0 Target Audience","text":"

If you are new to algorithms with limited exposure, or you have accumulated some experience in algorithms, but you only have a vague understanding of data structures and algorithms, and you are constantly jumping between \"yep\" and \"hmm\", then this book is for you!

If you have already accumulated a certain amount of problem-solving experience, and are familiar with most types of problems, then this book can help you review and organize your algorithm knowledge system. The repository's source code can be used as a \"problem-solving toolkit\" or an \"algorithm cheat sheet\".

If you are an algorithm expert, we look forward to receiving your valuable suggestions, or join us and collaborate.

Prerequisites

You should know how to write and read simple code in at least one programming language.

"},{"location":"chapter_preface/about_the_book/#012-content-structure","title":"0.1.2 \u00a0 Content Structure","text":"

The main content of the book is shown in the following figure.

  • Complexity Analysis: explores aspects and methods for evaluating data structures and algorithms. Covers methods of deriving time complexity and space complexity, along with common types and examples.
  • Data Structures: focuses on fundamental data types, classification methods, definitions, pros and cons, common operations, types, applications, and implementation methods of data structures such as array, linked list, stack, queue, hash table, tree, heap, graph, etc.
  • Algorithms: defines algorithms, discusses their pros and cons, efficiency, application scenarios, problem-solving steps, and includes sample questions for various algorithms such as search, sorting, divide and conquer, backtracking, dynamic programming, greedy algorithms, and more.

Figure 0-1 \u00a0 Main Content of the Book

"},{"location":"chapter_preface/about_the_book/#013-acknowledgements","title":"0.1.3 \u00a0 Acknowledgements","text":"

This book is continuously improved with the joint efforts of many contributors from the open-source community. Thanks to each writer who invested their time and energy, listed in the order generated by GitHub: krahets, codingonion, nuomi1, Gonglja, Reanon, justin-tse, danielsss, hpstory, S-N-O-R-L-A-X, night-cruise, msk397, gvenusleo, RiverTwilight, gyt95, zhuoqinyue, Zuoxun, Xia-Sang, mingXta, FangYuan33, GN-Yu, IsChristina, xBLACKICEx, guowei-gong, Cathay-Chen, mgisr, JoseHung, qualifier1024, pengchzn, Guanngxu, longsizhuo, L-Super, what-is-me, yuan0221, lhxsm, Slone123c, WSL0809, longranger2, theNefelibatas, xiongsp, JeffersonHuang, hongyun-robot, K3v123, yuelinxin, a16su, gaofer, malone6, Wonderdch, xjr7670, DullSword, Horbin-Magician, NI-SW, reeswell, XC-Zero, XiaChuerwu, yd-j, iron-irax, huawuque404, MolDuM, Nigh, KorsChen, foursevenlove, 52coder, bubble9um, youshaoXG, curly210102, gltianwen, fanchenggang, Transmigration-zhou, FloranceYeh, FreddieLi, ShiMaRing, lipusheng, Javesun99, JackYang-hellobobo, shanghai-Jerry, 0130w, Keynman, psychelzh, logan-qiu, ZnYang2018, MwumLi, 1ch0, Phoenix0415, qingpeng9802, Richard-Zhang1019, QiLOL, Suremotoo, Turing-1024-Lee, Evilrabbit520, GaochaoZhu, ZJKung, linzeyan, hezhizhen, ZongYangL, beintentional, czruby, coderlef, dshlstarr, szu17dmy, fbigm, gledfish, hts0000, boloboloda, iStig, jiaxianhua, wenjianmin, keshida, kilikilikid, lclc6, lwbaptx, liuxjerry, lucaswangdev, lyl625760, chadyi, noobcodemaker, selear, siqyka, syd168, 4yDX3906, tao363, wangwang105, weibk, yabo083, yi427, yishangzhang, zhouLion, baagod, ElaBosak233, xb534, luluxia, yanedie, thomasq0, YangXuanyi and th1nk3r-ing.

The code review work for this book was completed by codingonion, Gonglja, gvenusleo, hpstory, justin\u2010tse, krahets, night-cruise, nuomi1, and Reanon (listed in alphabetical order). Thanks to them for their time and effort, ensuring the standardization and uniformity of the code in various languages.

Throughout the creation of this book, numerous individuals provided invaluable assistance, including but not limited to:

  • Thanks to my mentor at the company, Dr. Xi Li, who encouraged me in a conversation to \"get moving fast,\" which solidified my determination to write this book;
  • Thanks to my girlfriend Bubble, as the first reader of this book, for offering many valuable suggestions from the perspective of a beginner in algorithms, making this book more suitable for newbies;
  • Thanks to Tengbao, Qibao, and Feibao for coming up with a creative name for this book, evoking everyone's fond memories of writing their first line of code \"Hello World!\";
  • Thanks to Xiaoquan for providing professional help in intellectual property, which has played a significant role in the development of this open-source book;
  • Thanks to Sutong for designing a beautiful cover and logo for this book, and for patiently making multiple revisions under my insistence;
  • Thanks to @squidfunk for providing writing and typesetting suggestions, as well as his developed open-source documentation theme Material-for-MkDocs.

Throughout the writing journey, I delved into numerous textbooks and articles on data structures and algorithms. These works served as exemplary models, ensuring the accuracy and quality of this book's content. I extend my gratitude to all who preceded me for their invaluable contributions!

This book advocates a combination of hands-on and minds-on learning, inspired in this regard by \"Dive into Deep Learning\". I highly recommend this excellent book to all readers.

Heartfelt thanks to my parents, whose ongoing support and encouragement have allowed me to do this interesting work.

"},{"location":"chapter_preface/suggestions/","title":"0.2 \u00a0 How to Read","text":"

Tip

For the best reading experience, it is recommended that you read through this section.

"},{"location":"chapter_preface/suggestions/#021-writing-conventions","title":"0.2.1 \u00a0 Writing Conventions","text":"
  • Chapters marked with '*' after the title are optional and contain relatively challenging content. If you are short on time, it is advisable to skip them.
  • Key technical terms and their English equivalents are enclosed in Bold + italics brackets, for example, array. It's advisable to familiarize yourself with these for better comprehension of technical texts.
  • Proprietary terms and words with specific meanings are indicated with \u201cquotation marks\u201d to avoid ambiguity.
  • Bolded text indicates key content or summary statements, which deserve special attention.
  • When it comes to terms that are inconsistent between programming languages, this book follows Python, for example using \\(\\text{None}\\) to mean \"null\".
  • This book partially ignores the comment conventions for programming languages in exchange for a more compact layout of the content. The comments primarily consist of three types: title comments, content comments, and multi-line comments.
PythonC++JavaC#GoSwiftJSTSDartRustCZig
\"\"\"Header comments for labeling functions, classes, test samples, etc\"\"\"\"\n\n# Comments for explaining details\n\n\"\"\"\nMultiline\ncomments\n\"\"\"\n
/* Header comments for labeling functions, classes, test samples, etc */\n\n// Comments for explaining details.\n\n/**\n * Multiline\n * comments\n */\n
/* Header comments for labeling functions, classes, test samples, etc */\n\n// Comments for explaining details.\n\n/**\n * Multiline\n * comments\n */\n
/* Header comments for labeling functions, classes, test samples, etc */\n\n// Comments for explaining details.\n\n/**\n * Multiline\n * comments\n */\n
/* Header comments for labeling functions, classes, test samples, etc */\n\n// Comments for explaining details.\n\n/**\n * Multiline\n * comments\n */\n
/* Header comments for labeling functions, classes, test samples, etc */\n\n// Comments for explaining details.\n\n/**\n * Multiline\n * comments\n */\n
/* Header comments for labeling functions, classes, test samples, etc */\n\n// Comments for explaining details.\n\n/**\n * Multiline\n * comments\n */\n
/* Header comments for labeling functions, classes, test samples, etc */\n\n// Comments for explaining details.\n\n/**\n * Multiline\n * comments\n */\n
/* Header comments for labeling functions, classes, test samples, etc */\n\n// Comments for explaining details.\n\n/**\n * Multiline\n * comments\n */\n
/* Header comments for labeling functions, classes, test samples, etc */\n\n// Comments for explaining details.\n\n/**\n * Multiline\n * comments\n */\n
/* Header comments for labeling functions, classes, test samples, etc */\n\n// Comments for explaining details.\n\n/**\n * Multiline\n * comments\n */\n
// Header comments for labeling functions, classes, test samples, etc\n\n// Comments for explaining details.\n\n// Multiline\n// comments\n
"},{"location":"chapter_preface/suggestions/#022-efficient-learning-via-animated-illustrations","title":"0.2.2 \u00a0 Efficient Learning via Animated Illustrations","text":"

Compared with text, videos and pictures have a higher density of information and are more structured, making them easier to understand. In this book, key and difficult concepts are mainly presented through animations and illustrations, with text serving as explanations and supplements.

When encountering content with animations or illustrations as shown in the Figure 0-2 , prioritize understanding the figure, with text as supplementary, integrating both for a comprehensive understanding.

Figure 0-2 \u00a0 Animated Illustration Example

"},{"location":"chapter_preface/suggestions/#023-deepen-understanding-through-coding-practice","title":"0.2.3 \u00a0 Deepen Understanding through Coding Practice","text":"

The source code of this book is hosted on the GitHub Repository. As shown in the Figure 0-3 , the source code comes with test examples and can be executed with just a single click.

If time permits, it's recommended to type out the code yourself. If pressed for time, at least read and run all the codes.

Compared to just reading code, writing code often yields more learning. Learning by doing is the real way to learn.

Figure 0-3 \u00a0 Running Code Example

Setting up to run the code involves three main steps.

Step 1: Install a local programming environment. Follow the tutorial in the appendix for installation, or skip this step if already installed.

Step 2: Clone or download the code repository. Visit the GitHub Repository.

If Git is installed, use the following command to clone the repository:

git clone https://github.com/krahets/hello-algo.git\n

Alternatively, you can also click the \"Download ZIP\" button at the location shown in the Figure 0-4 to directly download the code as a compressed ZIP file. Then, you can simply extract it locally.

Figure 0-4 \u00a0 Cloning Repository and Downloading Code

Step 3: Run the source code. As shown in the Figure 0-5 , for the code block labeled with the file name at the top, we can find the corresponding source code file in the codes folder of the repository. These files can be executed with a single click, which will help you save unnecessary debugging time and allow you to focus on learning.

Figure 0-5 \u00a0 Code Block and Corresponding Source Code File

"},{"location":"chapter_preface/suggestions/#024-learning-together-in-discussion","title":"0.2.4 \u00a0 Learning Together in Discussion","text":"

While reading this book, please don't skip over the points that you didn't learn. Feel free to post your questions in the comment section. We will be happy to answer them and can usually respond within two days.

As illustrated in the Figure 0-6 , each chapter features a comment section at the bottom. I encourage you to pay attention to these comments. They not only expose you to others' encountered problems, aiding in identifying knowledge gaps and sparking deeper contemplation, but also invite you to generously contribute by answering fellow readers' inquiries, sharing insights, and fostering mutual improvement.

Figure 0-6 \u00a0 Comment Section Example

"},{"location":"chapter_preface/suggestions/#025-algorithm-learning-path","title":"0.2.5 \u00a0 Algorithm Learning Path","text":"

Overall, the journey of mastering data structures and algorithms can be divided into three stages:

  1. Stage 1: Introduction to algorithms. We need to familiarize ourselves with the characteristics and usage of various data structures and learn about the principles, processes, uses, and efficiency of different algorithms.
  2. Stage 2: Practicing algorithm problems. It is recommended to start from popular problems, such as Sword for Offer and LeetCode Hot 100, and accumulate at least 100 questions to familiarize yourself with mainstream algorithmic problems. Forgetfulness can be a challenge when you start practicing, but rest assured that this is normal. We can follow the \"Ebbinghaus Forgetting Curve\" to review the questions, and usually after 3~5 rounds of repetitions, we will be able to memorize them.
  3. Stage 3: Building the knowledge system. In terms of learning, we can read algorithm column articles, solution frameworks, and algorithm textbooks to continuously enrich the knowledge system. In terms of practicing, we can try advanced strategies, such as categorizing by topic, multiple solutions for a single problem, and one solution for multiple problems, etc. Insights on these strategies can be found in various communities.

As shown in the Figure 0-7 , this book mainly covers \u201cStage 1,\u201d aiming to help you more efficiently embark on Stages 2 and 3.

Figure 0-7 \u00a0 Algorithm Learning Path

"},{"location":"chapter_preface/summary/","title":"0.3 \u00a0 Summary","text":"
  • The main audience of this book is beginners in algorithm. If you already have some basic knowledge, this book can help you systematically review your algorithm knowledge, and the source code in this book can also be used as a \"Coding Toolkit\".
  • The book consists of three main sections, Complexity Analysis, Data Structures, and Algorithms, covering most of the topics in the field.
  • For newcomers to algorithms, it is crucial to read an introductory book in the beginning stages to avoid many detours or common pitfalls.
  • Animations and figures within the book are usually used to introduce key points and difficult knowledge. These should be given more attention when reading the book.
  • Practice is the best way to learn programming. It is highly recommended that you run the source code and type in the code yourself.
  • Each chapter in the web version of this book features a discussion section, and you are welcome to share your questions and insights at any time.
"},{"location":"chapter_stack_and_queue/","title":"Chapter 5. \u00a0 Stack and Queue","text":"

Abstract

A stack is like cats placed on top of each other, while a queue is like cats lined up one by one.

They represent the logical relationships of Last-In-First-Out (LIFO) and First-In-First-Out (FIFO), respectively.

"},{"location":"chapter_stack_and_queue/#chapter-contents","title":"Chapter Contents","text":"
  • 5.1 \u00a0 Stack
  • 5.2 \u00a0 Queue
  • 5.3 \u00a0 Double-ended Queue
  • 5.4 \u00a0 Summary
"},{"location":"chapter_stack_and_queue/deque/","title":"5.3 \u00a0 Double-Ended Queue","text":"

In a queue, we can only delete elements from the head or add elements to the tail. As shown in the following diagram, a \"double-ended queue (deque)\" offers more flexibility, allowing the addition or removal of elements at both the head and the tail.

Figure 5-7 \u00a0 Operations in Double-Ended Queue

"},{"location":"chapter_stack_and_queue/deque/#531-common-operations-in-double-ended-queue","title":"5.3.1 \u00a0 Common Operations in Double-Ended Queue","text":"

The common operations in a double-ended queue are listed below, and the names of specific methods depend on the programming language used.

Table 5-3 \u00a0 Efficiency of Double-Ended Queue Operations

Method Name Description Time Complexity pushFirst() Add an element to the head \\(O(1)\\) pushLast() Add an element to the tail \\(O(1)\\) popFirst() Remove the first element \\(O(1)\\) popLast() Remove the last element \\(O(1)\\) peekFirst() Access the first element \\(O(1)\\) peekLast() Access the last element \\(O(1)\\)

Similarly, we can directly use the double-ended queue classes implemented in programming languages:

PythonC++JavaC#GoSwiftJSTSDartRustCZig deque.py
from collections import deque\n\n# Initialize the deque\ndeque: deque[int] = deque()\n\n# Enqueue elements\ndeque.append(2)      # Add to the tail\ndeque.append(5)\ndeque.append(4)\ndeque.appendleft(3)  # Add to the head\ndeque.appendleft(1)\n\n# Access elements\nfront: int = deque[0]  # The first element\nrear: int = deque[-1]  # The last element\n\n# Dequeue elements\npop_front: int = deque.popleft()  # The first element dequeued\npop_rear: int = deque.pop()       # The last element dequeued\n\n# Get the length of the deque\nsize: int = len(deque)\n\n# Check if the deque is empty\nis_empty: bool = len(deque) == 0\n
deque.cpp
/* Initialize the deque */\ndeque<int> deque;\n\n/* Enqueue elements */\ndeque.push_back(2);   // Add to the tail\ndeque.push_back(5);\ndeque.push_back(4);\ndeque.push_front(3);  // Add to the head\ndeque.push_front(1);\n\n/* Access elements */\nint front = deque.front(); // The first element\nint back = deque.back();   // The last element\n\n/* Dequeue elements */\ndeque.pop_front();  // The first element dequeued\ndeque.pop_back();   // The last element dequeued\n\n/* Get the length of the deque */\nint size = deque.size();\n\n/* Check if the deque is empty */\nbool empty = deque.empty();\n
deque.java
/* Initialize the deque */\nDeque<Integer> deque = new LinkedList<>();\n\n/* Enqueue elements */\ndeque.offerLast(2);   // Add to the tail\ndeque.offerLast(5);\ndeque.offerLast(4);\ndeque.offerFirst(3);  // Add to the head\ndeque.offerFirst(1);\n\n/* Access elements */\nint peekFirst = deque.peekFirst();  // The first element\nint peekLast = deque.peekLast();    // The last element\n\n/* Dequeue elements */\nint popFirst = deque.pollFirst();  // The first element dequeued\nint popLast = deque.pollLast();    // The last element dequeued\n\n/* Get the length of the deque */\nint size = deque.size();\n\n/* Check if the deque is empty */\nboolean isEmpty = deque.isEmpty();\n
deque.cs
/* Initialize the deque */\n// In C#, LinkedList is used as a deque\nLinkedList<int> deque = new();\n\n/* Enqueue elements */\ndeque.AddLast(2);   // Add to the tail\ndeque.AddLast(5);\ndeque.AddLast(4);\ndeque.AddFirst(3);  // Add to the head\ndeque.AddFirst(1);\n\n/* Access elements */\nint peekFirst = deque.First.Value;  // The first element\nint peekLast = deque.Last.Value;    // The last element\n\n/* Dequeue elements */\ndeque.RemoveFirst();  // The first element dequeued\ndeque.RemoveLast();   // The last element dequeued\n\n/* Get the length of the deque */\nint size = deque.Count;\n\n/* Check if the deque is empty */\nbool isEmpty = deque.Count == 0;\n
deque_test.go
/* Initialize the deque */\n// In Go, use list as a deque\ndeque := list.New()\n\n/* Enqueue elements */\ndeque.PushBack(2)      // Add to the tail\ndeque.PushBack(5)\ndeque.PushBack(4)\ndeque.PushFront(3)     // Add to the head\ndeque.PushFront(1)\n\n/* Access elements */\nfront := deque.Front() // The first element\nrear := deque.Back()   // The last element\n\n/* Dequeue elements */\ndeque.Remove(front)    // The first element dequeued\ndeque.Remove(rear)     // The last element dequeued\n\n/* Get the length of the deque */\nsize := deque.Len()\n\n/* Check if the deque is empty */\nisEmpty := deque.Len() == 0\n
deque.swift
/* Initialize the deque */\n// Swift does not have a built-in deque class, so Array can be used as a deque\nvar deque: [Int] = []\n\n/* Enqueue elements */\ndeque.append(2) // Add to the tail\ndeque.append(5)\ndeque.append(4)\ndeque.insert(3, at: 0) // Add to the head\ndeque.insert(1, at: 0)\n\n/* Access elements */\nlet peekFirst = deque.first! // The first element\nlet peekLast = deque.last!   // The last element\n\n/* Dequeue elements */\n// Using Array, popFirst has a complexity of O(n)\nlet popFirst = deque.removeFirst() // The first element dequeued\nlet popLast = deque.removeLast()   // The last element dequeued\n\n/* Get the length of the deque */\nlet size = deque.count\n\n/* Check if the deque is empty */\nlet isEmpty = deque.isEmpty\n
deque.js
/* Initialize the deque */\n// JavaScript does not have a built-in deque, so Array is used as a deque\nconst deque = [];\n\n/* Enqueue elements */\ndeque.push(2);\ndeque.push(5);\ndeque.push(4);\n// Note that unshift() has a time complexity of O(n) as it's an array\ndeque.unshift(3);\ndeque.unshift(1);\n\n/* Access elements */\nconst peekFirst = deque[0]; // The first element\nconst peekLast = deque[deque.length - 1]; // The last element\n\n/* Dequeue elements */\n// Note that shift() has a time complexity of O(n) as it's an array\nconst popFront = deque.shift(); // The first element dequeued\nconst popBack = deque.pop();    // The last element dequeued\n\n/* Get the length of the deque */\nconst size = deque.length;\n\n/* Check if the deque is empty */\nconst isEmpty = size === 0;\n
deque.ts
/* Initialize the deque */\n// TypeScript does not have a built-in deque, so Array is used as a deque\nconst deque: number[] = [];\n\n/* Enqueue elements */\ndeque.push(2);\ndeque.push(5);\ndeque.push(4);\n// Note that unshift() has a time complexity of O(n) as it's an array\ndeque.unshift(3);\ndeque.unshift(1);\n\n/* Access elements */\nconst peekFirst: number = deque[0]; // The first element\nconst peekLast: number = deque[deque.length - 1]; // The last element\n\n/* Dequeue elements */\n// Note that shift() has a time complexity of O(n) as it's an array\nconst popFront: number = deque.shift() as number; // The first element dequeued\nconst popBack: number = deque.pop() as number;    // The last element dequeued\n\n/* Get the length of the deque */\nconst size: number = deque.length;\n\n/* Check if the deque is empty */\nconst isEmpty: boolean = size === 0;\n
deque.dart
/* Initialize the deque */\n// In Dart, Queue is defined as a deque\nQueue<int> deque = Queue<int>();\n\n/* Enqueue elements */\ndeque.addLast(2);  // Add to the tail\ndeque.addLast(5);\ndeque.addLast(4);\ndeque.addFirst(3); // Add to the head\ndeque.addFirst(1);\n\n/* Access elements */\nint peekFirst = deque.first; // The first element\nint peekLast = deque.last;   // The last element\n\n/* Dequeue elements */\nint popFirst = deque.removeFirst(); // The first element dequeued\nint popLast = deque.removeLast();   // The last element dequeued\n\n/* Get the length of the deque */\nint size = deque.length;\n\n/* Check if the deque is empty */\nbool isEmpty = deque.isEmpty;\n
deque.rs
/* Initialize the deque */\nlet mut deque: VecDeque<u32> = VecDeque::new();\n\n/* Enqueue elements */\ndeque.push_back(2);  // Add to the tail\ndeque.push_back(5);\ndeque.push_back(4);\ndeque.push_front(3); // Add to the head\ndeque.push_front(1);\n\n/* Access elements */\nif let Some(front) = deque.front() { // The first element\n}\nif let Some(rear) = deque.back() {   // The last element\n}\n\n/* Dequeue elements */\nif let Some(pop_front) = deque.pop_front() { // The first element dequeued\n}\nif let Some(pop_rear) = deque.pop_back() {   // The last element dequeued\n}\n\n/* Get the length of the deque */\nlet size = deque.len();\n\n/* Check if the deque is empty */\nlet is_empty = deque.is_empty();\n
deque.c
// C does not provide a built-in deque\n
deque.zig
\n
Visualizing Code

https://pythontutor.com/render.html#code=from%20collections%20import%20deque%0A%0A%22%22%22Driver%20Code%22%22%22%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%20%20%23%20%E5%88%9D%E5%A7%8B%E5%8C%96%E5%8F%8C%E5%90%91%E9%98%9F%E5%88%97%0A%20%20%20%20deq%20%3D%20deque%28%29%0A%0A%20%20%20%20%23%20%E5%85%83%E7%B4%A0%E5%85%A5%E9%98%9F%0A%20%20%20%20deq.append%282%29%20%20%23%20%E6%B7%BB%E5%8A%A0%E8%87%B3%E9%98%9F%E5%B0%BE%0A%20%20%20%20deq.append%285%29%0A%20%20%20%20deq.append%284%29%0A%20%20%20%20deq.appendleft%283%29%20%20%23%20%E6%B7%BB%E5%8A%A0%E8%87%B3%E9%98%9F%E9%A6%96%0A%20%20%20%20deq.appendleft%281%29%0A%20%20%20%20print%28%22%E5%8F%8C%E5%90%91%E9%98%9F%E5%88%97%20deque%20%3D%22,%20deq%29%0A%0A%20%20%20%20%23%20%E8%AE%BF%E9%97%AE%E5%85%83%E7%B4%A0%0A%20%20%20%20front%20%3D%20deq%5B0%5D%20%20%23%20%E9%98%9F%E9%A6%96%E5%85%83%E7%B4%A0%0A%20%20%20%20print%28%22%E9%98%9F%E9%A6%96%E5%85%83%E7%B4%A0%20front%20%3D%22,%20front%29%0A%20%20%20%20rear%20%3D%20deq%5B-1%5D%20%20%23%20%E9%98%9F%E5%B0%BE%E5%85%83%E7%B4%A0%0A%20%20%20%20print%28%22%E9%98%9F%E5%B0%BE%E5%85%83%E7%B4%A0%20rear%20%3D%22,%20rear%29%0A%0A%20%20%20%20%23%20%E5%85%83%E7%B4%A0%E5%87%BA%E9%98%9F%0A%20%20%20%20pop_front%20%3D%20deq.popleft%28%29%20%20%23%20%E9%98%9F%E9%A6%96%E5%85%83%E7%B4%A0%E5%87%BA%E9%98%9F%0A%20%20%20%20print%28%22%E9%98%9F%E9%A6%96%E5%87%BA%E9%98%9F%E5%85%83%E7%B4%A0%20%20pop_front%20%3D%22,%20pop_front%29%0A%20%20%20%20print%28%22%E9%98%9F%E9%A6%96%E5%87%BA%E9%98%9F%E5%90%8E%20deque%20%3D%22,%20deq%29%0A%20%20%20%20pop_rear%20%3D%20deq.pop%28%29%20%20%23%20%E9%98%9F%E5%B0%BE%E5%85%83%E7%B4%A0%E5%87%BA%E9%98%9F%0A%20%20%20%20print%28%22%E9%98%9F%E5%B0%BE%E5%87%BA%E9%98%9F%E5%85%83%E7%B4%A0%20%20pop_rear%20%3D%22,%20pop_rear%29%0A%20%20%20%20print%28%22%E9%98%9F%E5%B0%BE%E5%87%BA%E9%98%9F%E5%90%8E%20deque%20%3D%22,%20deq%29%0A%0A%20%20%20%20%23%20%E8%8E%B7%E5%8F%96%E5%8F%8C%E5%90%91%E9%98%9F%E5%88%97%E7%9A%84%E9%95%BF%E5%BA%A6%0A%20%20%20%20size%20%3D%20len%28deq%29%0A%20%20%20%20print%28%22%E5%8F%8C%E5%90%91%E9%98%9F%E5%88%97%E9%95%BF%E5%BA%A6%20size%20%3D%22,%20size%29%0A%0A%20%20%20%20%23%20%E5%88%A4%E6%96%AD%E5%8F%8C%E5%90%91%E9%98%9F%E5%88%97%E6%98%AF%E5%90%A6%E4%B8%BA%E7%A9%BA%0A%20%20%20%20is_empty%20%3D%20len%28deq%29%20%3D%3D%200%0A%20%20%20%20print%28%22%E5%8F%8C%E5%90%91%E9%98%9F%E5%88%97%E6%98%AF%E5%90%A6%E4%B8%BA%E7%A9%BA%20%3D%22,%20is_empty%29&cumulative=false&curInstr=3&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=311&rawInputLstJSON=%5B%5D&textReferences=false

"},{"location":"chapter_stack_and_queue/deque/#532-implementing-a-double-ended-queue","title":"5.3.2 \u00a0 Implementing a Double-Ended Queue *","text":"

The implementation of a double-ended queue is similar to that of a regular queue, it can be based on either a linked list or an array as the underlying data structure.

"},{"location":"chapter_stack_and_queue/deque/#1-implementation-based-on-doubly-linked-list","title":"1. \u00a0 Implementation Based on Doubly Linked List","text":"

Recall from the previous section that we used a regular singly linked list to implement a queue, as it conveniently allows for deleting from the head (corresponding to the dequeue operation) and adding new elements after the tail (corresponding to the enqueue operation).

For a double-ended queue, both the head and the tail can perform enqueue and dequeue operations. In other words, a double-ended queue needs to implement operations in the opposite direction as well. For this, we use a \"doubly linked list\" as the underlying data structure of the double-ended queue.

As shown in the Figure 5-8 , we treat the head and tail nodes of the doubly linked list as the front and rear of the double-ended queue, respectively, and implement the functionality to add and remove nodes at both ends.

LinkedListDequepushLast()pushFirst()popLast()popFirst()

Figure 5-8 \u00a0 Implementing Double-Ended Queue with Doubly Linked List for Enqueue and Dequeue Operations

The implementation code is as follows:

PythonC++JavaC#GoSwiftJSTSDartRustCZig linkedlist_deque.py
class ListNode:\n    \"\"\"\u53cc\u5411\u94fe\u8868\u8282\u70b9\"\"\"\n\n    def __init__(self, val: int):\n        \"\"\"\u6784\u9020\u65b9\u6cd5\"\"\"\n        self.val: int = val\n        self.next: ListNode | None = None  # \u540e\u7ee7\u8282\u70b9\u5f15\u7528\n        self.prev: ListNode | None = None  # \u524d\u9a71\u8282\u70b9\u5f15\u7528\n\nclass LinkedListDeque:\n    \"\"\"\u57fa\u4e8e\u53cc\u5411\u94fe\u8868\u5b9e\u73b0\u7684\u53cc\u5411\u961f\u5217\"\"\"\n\n    def __init__(self):\n        \"\"\"\u6784\u9020\u65b9\u6cd5\"\"\"\n        self._front: ListNode | None = None  # \u5934\u8282\u70b9 front\n        self._rear: ListNode | None = None  # \u5c3e\u8282\u70b9 rear\n        self._size: int = 0  # \u53cc\u5411\u961f\u5217\u7684\u957f\u5ea6\n\n    def size(self) -> int:\n        \"\"\"\u83b7\u53d6\u53cc\u5411\u961f\u5217\u7684\u957f\u5ea6\"\"\"\n        return self._size\n\n    def is_empty(self) -> bool:\n        \"\"\"\u5224\u65ad\u53cc\u5411\u961f\u5217\u662f\u5426\u4e3a\u7a7a\"\"\"\n        return self.size() == 0\n\n    def push(self, num: int, is_front: bool):\n        \"\"\"\u5165\u961f\u64cd\u4f5c\"\"\"\n        node = ListNode(num)\n        # \u82e5\u94fe\u8868\u4e3a\u7a7a\uff0c\u5219\u4ee4 front \u548c rear \u90fd\u6307\u5411 node\n        if self.is_empty():\n            self._front = self._rear = node\n        # \u961f\u9996\u5165\u961f\u64cd\u4f5c\n        elif is_front:\n            # \u5c06 node \u6dfb\u52a0\u81f3\u94fe\u8868\u5934\u90e8\n            self._front.prev = node\n            node.next = self._front\n            self._front = node  # \u66f4\u65b0\u5934\u8282\u70b9\n        # \u961f\u5c3e\u5165\u961f\u64cd\u4f5c\n        else:\n            # \u5c06 node \u6dfb\u52a0\u81f3\u94fe\u8868\u5c3e\u90e8\n            self._rear.next = node\n            node.prev = self._rear\n            self._rear = node  # \u66f4\u65b0\u5c3e\u8282\u70b9\n        self._size += 1  # \u66f4\u65b0\u961f\u5217\u957f\u5ea6\n\n    def push_first(self, num: int):\n        \"\"\"\u961f\u9996\u5165\u961f\"\"\"\n        self.push(num, True)\n\n    def push_last(self, num: int):\n        \"\"\"\u961f\u5c3e\u5165\u961f\"\"\"\n        self.push(num, False)\n\n    def pop(self, is_front: bool) -> int:\n        \"\"\"\u51fa\u961f\u64cd\u4f5c\"\"\"\n        if self.is_empty():\n            raise IndexError(\"\u53cc\u5411\u961f\u5217\u4e3a\u7a7a\")\n        # \u961f\u9996\u51fa\u961f\u64cd\u4f5c\n        if is_front:\n            val: int = self._front.val  # \u6682\u5b58\u5934\u8282\u70b9\u503c\n            # \u5220\u9664\u5934\u8282\u70b9\n            fnext: ListNode | None = self._front.next\n            if fnext != None:\n                fnext.prev = None\n                self._front.next = None\n            self._front = fnext  # \u66f4\u65b0\u5934\u8282\u70b9\n        # \u961f\u5c3e\u51fa\u961f\u64cd\u4f5c\n        else:\n            val: int = self._rear.val  # \u6682\u5b58\u5c3e\u8282\u70b9\u503c\n            # \u5220\u9664\u5c3e\u8282\u70b9\n            rprev: ListNode | None = self._rear.prev\n            if rprev != None:\n                rprev.next = None\n                self._rear.prev = None\n            self._rear = rprev  # \u66f4\u65b0\u5c3e\u8282\u70b9\n        self._size -= 1  # \u66f4\u65b0\u961f\u5217\u957f\u5ea6\n        return val\n\n    def pop_first(self) -> int:\n        \"\"\"\u961f\u9996\u51fa\u961f\"\"\"\n        return self.pop(True)\n\n    def pop_last(self) -> int:\n        \"\"\"\u961f\u5c3e\u51fa\u961f\"\"\"\n        return self.pop(False)\n\n    def peek_first(self) -> int:\n        \"\"\"\u8bbf\u95ee\u961f\u9996\u5143\u7d20\"\"\"\n        if self.is_empty():\n            raise IndexError(\"\u53cc\u5411\u961f\u5217\u4e3a\u7a7a\")\n        return self._front.val\n\n    def peek_last(self) -> int:\n        \"\"\"\u8bbf\u95ee\u961f\u5c3e\u5143\u7d20\"\"\"\n        if self.is_empty():\n            raise IndexError(\"\u53cc\u5411\u961f\u5217\u4e3a\u7a7a\")\n        return self._rear.val\n\n    def to_array(self) -> list[int]:\n        \"\"\"\u8fd4\u56de\u6570\u7ec4\u7528\u4e8e\u6253\u5370\"\"\"\n        node = self._front\n        res = [0] * self.size()\n        for i in range(self.size()):\n            res[i] = node.val\n            node = node.next\n        return res\n
linkedlist_deque.cpp
/* \u53cc\u5411\u94fe\u8868\u8282\u70b9 */\nstruct DoublyListNode {\n    int val;              // \u8282\u70b9\u503c\n    DoublyListNode *next; // \u540e\u7ee7\u8282\u70b9\u6307\u9488\n    DoublyListNode *prev; // \u524d\u9a71\u8282\u70b9\u6307\u9488\n    DoublyListNode(int val) : val(val), prev(nullptr), next(nullptr) {\n    }\n};\n\n/* \u57fa\u4e8e\u53cc\u5411\u94fe\u8868\u5b9e\u73b0\u7684\u53cc\u5411\u961f\u5217 */\nclass LinkedListDeque {\n  private:\n    DoublyListNode *front, *rear; // \u5934\u8282\u70b9 front \uff0c\u5c3e\u8282\u70b9 rear\n    int queSize = 0;              // \u53cc\u5411\u961f\u5217\u7684\u957f\u5ea6\n\n  public:\n    /* \u6784\u9020\u65b9\u6cd5 */\n    LinkedListDeque() : front(nullptr), rear(nullptr) {\n    }\n\n    /* \u6790\u6784\u65b9\u6cd5 */\n    ~LinkedListDeque() {\n        // \u904d\u5386\u94fe\u8868\u5220\u9664\u8282\u70b9\uff0c\u91ca\u653e\u5185\u5b58\n        DoublyListNode *pre, *cur = front;\n        while (cur != nullptr) {\n            pre = cur;\n            cur = cur->next;\n            delete pre;\n        }\n    }\n\n    /* \u83b7\u53d6\u53cc\u5411\u961f\u5217\u7684\u957f\u5ea6 */\n    int size() {\n        return queSize;\n    }\n\n    /* \u5224\u65ad\u53cc\u5411\u961f\u5217\u662f\u5426\u4e3a\u7a7a */\n    bool isEmpty() {\n        return size() == 0;\n    }\n\n    /* \u5165\u961f\u64cd\u4f5c */\n    void push(int num, bool isFront) {\n        DoublyListNode *node = new DoublyListNode(num);\n        // \u82e5\u94fe\u8868\u4e3a\u7a7a\uff0c\u5219\u4ee4 front \u548c rear \u90fd\u6307\u5411 node\n        if (isEmpty())\n            front = rear = node;\n        // \u961f\u9996\u5165\u961f\u64cd\u4f5c\n        else if (isFront) {\n            // \u5c06 node \u6dfb\u52a0\u81f3\u94fe\u8868\u5934\u90e8\n            front->prev = node;\n            node->next = front;\n            front = node; // \u66f4\u65b0\u5934\u8282\u70b9\n        // \u961f\u5c3e\u5165\u961f\u64cd\u4f5c\n        } else {\n            // \u5c06 node \u6dfb\u52a0\u81f3\u94fe\u8868\u5c3e\u90e8\n            rear->next = node;\n            node->prev = rear;\n            rear = node; // \u66f4\u65b0\u5c3e\u8282\u70b9\n        }\n        queSize++; // \u66f4\u65b0\u961f\u5217\u957f\u5ea6\n    }\n\n    /* \u961f\u9996\u5165\u961f */\n    void pushFirst(int num) {\n        push(num, true);\n    }\n\n    /* \u961f\u5c3e\u5165\u961f */\n    void pushLast(int num) {\n        push(num, false);\n    }\n\n    /* \u51fa\u961f\u64cd\u4f5c */\n    int pop(bool isFront) {\n        if (isEmpty())\n            throw out_of_range(\"\u961f\u5217\u4e3a\u7a7a\");\n        int val;\n        // \u961f\u9996\u51fa\u961f\u64cd\u4f5c\n        if (isFront) {\n            val = front->val; // \u6682\u5b58\u5934\u8282\u70b9\u503c\n            // \u5220\u9664\u5934\u8282\u70b9\n            DoublyListNode *fNext = front->next;\n            if (fNext != nullptr) {\n                fNext->prev = nullptr;\n                front->next = nullptr;\n            }\n            delete front;\n            front = fNext; // \u66f4\u65b0\u5934\u8282\u70b9\n        // \u961f\u5c3e\u51fa\u961f\u64cd\u4f5c\n        } else {\n            val = rear->val; // \u6682\u5b58\u5c3e\u8282\u70b9\u503c\n            // \u5220\u9664\u5c3e\u8282\u70b9\n            DoublyListNode *rPrev = rear->prev;\n            if (rPrev != nullptr) {\n                rPrev->next = nullptr;\n                rear->prev = nullptr;\n            }\n            delete rear;\n            rear = rPrev; // \u66f4\u65b0\u5c3e\u8282\u70b9\n        }\n        queSize--; // \u66f4\u65b0\u961f\u5217\u957f\u5ea6\n        return val;\n    }\n\n    /* \u961f\u9996\u51fa\u961f */\n    int popFirst() {\n        return pop(true);\n    }\n\n    /* \u961f\u5c3e\u51fa\u961f */\n    int popLast() {\n        return pop(false);\n    }\n\n    /* \u8bbf\u95ee\u961f\u9996\u5143\u7d20 */\n    int peekFirst() {\n        if (isEmpty())\n            throw out_of_range(\"\u53cc\u5411\u961f\u5217\u4e3a\u7a7a\");\n        return front->val;\n    }\n\n    /* \u8bbf\u95ee\u961f\u5c3e\u5143\u7d20 */\n    int peekLast() {\n        if (isEmpty())\n            throw out_of_range(\"\u53cc\u5411\u961f\u5217\u4e3a\u7a7a\");\n        return rear->val;\n    }\n\n    /* \u8fd4\u56de\u6570\u7ec4\u7528\u4e8e\u6253\u5370 */\n    vector<int> toVector() {\n        DoublyListNode *node = front;\n        vector<int> res(size());\n        for (int i = 0; i < res.size(); i++) {\n            res[i] = node->val;\n            node = node->next;\n        }\n        return res;\n    }\n};\n
linkedlist_deque.java
/* \u53cc\u5411\u94fe\u8868\u8282\u70b9 */\nclass ListNode {\n    int val; // \u8282\u70b9\u503c\n    ListNode next; // \u540e\u7ee7\u8282\u70b9\u5f15\u7528\n    ListNode prev; // \u524d\u9a71\u8282\u70b9\u5f15\u7528\n\n    ListNode(int val) {\n        this.val = val;\n        prev = next = null;\n    }\n}\n\n/* \u57fa\u4e8e\u53cc\u5411\u94fe\u8868\u5b9e\u73b0\u7684\u53cc\u5411\u961f\u5217 */\nclass LinkedListDeque {\n    private ListNode front, rear; // \u5934\u8282\u70b9 front \uff0c\u5c3e\u8282\u70b9 rear\n    private int queSize = 0; // \u53cc\u5411\u961f\u5217\u7684\u957f\u5ea6\n\n    public LinkedListDeque() {\n        front = rear = null;\n    }\n\n    /* \u83b7\u53d6\u53cc\u5411\u961f\u5217\u7684\u957f\u5ea6 */\n    public int size() {\n        return queSize;\n    }\n\n    /* \u5224\u65ad\u53cc\u5411\u961f\u5217\u662f\u5426\u4e3a\u7a7a */\n    public boolean isEmpty() {\n        return size() == 0;\n    }\n\n    /* \u5165\u961f\u64cd\u4f5c */\n    private void push(int num, boolean isFront) {\n        ListNode node = new ListNode(num);\n        // \u82e5\u94fe\u8868\u4e3a\u7a7a\uff0c\u5219\u4ee4 front \u548c rear \u90fd\u6307\u5411 node\n        if (isEmpty())\n            front = rear = node;\n        // \u961f\u9996\u5165\u961f\u64cd\u4f5c\n        else if (isFront) {\n            // \u5c06 node \u6dfb\u52a0\u81f3\u94fe\u8868\u5934\u90e8\n            front.prev = node;\n            node.next = front;\n            front = node; // \u66f4\u65b0\u5934\u8282\u70b9\n        // \u961f\u5c3e\u5165\u961f\u64cd\u4f5c\n        } else {\n            // \u5c06 node \u6dfb\u52a0\u81f3\u94fe\u8868\u5c3e\u90e8\n            rear.next = node;\n            node.prev = rear;\n            rear = node; // \u66f4\u65b0\u5c3e\u8282\u70b9\n        }\n        queSize++; // \u66f4\u65b0\u961f\u5217\u957f\u5ea6\n    }\n\n    /* \u961f\u9996\u5165\u961f */\n    public void pushFirst(int num) {\n        push(num, true);\n    }\n\n    /* \u961f\u5c3e\u5165\u961f */\n    public void pushLast(int num) {\n        push(num, false);\n    }\n\n    /* \u51fa\u961f\u64cd\u4f5c */\n    private int pop(boolean isFront) {\n        if (isEmpty())\n            throw new IndexOutOfBoundsException();\n        int val;\n        // \u961f\u9996\u51fa\u961f\u64cd\u4f5c\n        if (isFront) {\n            val = front.val; // \u6682\u5b58\u5934\u8282\u70b9\u503c\n            // \u5220\u9664\u5934\u8282\u70b9\n            ListNode fNext = front.next;\n            if (fNext != null) {\n                fNext.prev = null;\n                front.next = null;\n            }\n            front = fNext; // \u66f4\u65b0\u5934\u8282\u70b9\n        // \u961f\u5c3e\u51fa\u961f\u64cd\u4f5c\n        } else {\n            val = rear.val; // \u6682\u5b58\u5c3e\u8282\u70b9\u503c\n            // \u5220\u9664\u5c3e\u8282\u70b9\n            ListNode rPrev = rear.prev;\n            if (rPrev != null) {\n                rPrev.next = null;\n                rear.prev = null;\n            }\n            rear = rPrev; // \u66f4\u65b0\u5c3e\u8282\u70b9\n        }\n        queSize--; // \u66f4\u65b0\u961f\u5217\u957f\u5ea6\n        return val;\n    }\n\n    /* \u961f\u9996\u51fa\u961f */\n    public int popFirst() {\n        return pop(true);\n    }\n\n    /* \u961f\u5c3e\u51fa\u961f */\n    public int popLast() {\n        return pop(false);\n    }\n\n    /* \u8bbf\u95ee\u961f\u9996\u5143\u7d20 */\n    public int peekFirst() {\n        if (isEmpty())\n            throw new IndexOutOfBoundsException();\n        return front.val;\n    }\n\n    /* \u8bbf\u95ee\u961f\u5c3e\u5143\u7d20 */\n    public int peekLast() {\n        if (isEmpty())\n            throw new IndexOutOfBoundsException();\n        return rear.val;\n    }\n\n    /* \u8fd4\u56de\u6570\u7ec4\u7528\u4e8e\u6253\u5370 */\n    public int[] toArray() {\n        ListNode node = front;\n        int[] res = new int[size()];\n        for (int i = 0; i < res.length; i++) {\n            res[i] = node.val;\n            node = node.next;\n        }\n        return res;\n    }\n}\n
linkedlist_deque.cs
/* \u53cc\u5411\u94fe\u8868\u8282\u70b9 */\nclass ListNode(int val) {\n    public int val = val;       // \u8282\u70b9\u503c\n    public ListNode? next = null; // \u540e\u7ee7\u8282\u70b9\u5f15\u7528\n    public ListNode? prev = null; // \u524d\u9a71\u8282\u70b9\u5f15\u7528\n}\n\n/* \u57fa\u4e8e\u53cc\u5411\u94fe\u8868\u5b9e\u73b0\u7684\u53cc\u5411\u961f\u5217 */\nclass LinkedListDeque {\n    ListNode? front, rear; // \u5934\u8282\u70b9 front, \u5c3e\u8282\u70b9 rear\n    int queSize = 0;      // \u53cc\u5411\u961f\u5217\u7684\u957f\u5ea6\n\n    public LinkedListDeque() {\n        front = null;\n        rear = null;\n    }\n\n    /* \u83b7\u53d6\u53cc\u5411\u961f\u5217\u7684\u957f\u5ea6 */\n    public int Size() {\n        return queSize;\n    }\n\n    /* \u5224\u65ad\u53cc\u5411\u961f\u5217\u662f\u5426\u4e3a\u7a7a */\n    public bool IsEmpty() {\n        return Size() == 0;\n    }\n\n    /* \u5165\u961f\u64cd\u4f5c */\n    void Push(int num, bool isFront) {\n        ListNode node = new(num);\n        // \u82e5\u94fe\u8868\u4e3a\u7a7a\uff0c\u5219\u4ee4 front \u548c rear \u90fd\u6307\u5411 node\n        if (IsEmpty()) {\n            front = node;\n            rear = node;\n        }\n        // \u961f\u9996\u5165\u961f\u64cd\u4f5c\n        else if (isFront) {\n            // \u5c06 node \u6dfb\u52a0\u81f3\u94fe\u8868\u5934\u90e8\n            front!.prev = node;\n            node.next = front;\n            front = node; // \u66f4\u65b0\u5934\u8282\u70b9                           \n        }\n        // \u961f\u5c3e\u5165\u961f\u64cd\u4f5c\n        else {\n            // \u5c06 node \u6dfb\u52a0\u81f3\u94fe\u8868\u5c3e\u90e8\n            rear!.next = node;\n            node.prev = rear;\n            rear = node;  // \u66f4\u65b0\u5c3e\u8282\u70b9\n        }\n\n        queSize++; // \u66f4\u65b0\u961f\u5217\u957f\u5ea6\n    }\n\n    /* \u961f\u9996\u5165\u961f */\n    public void PushFirst(int num) {\n        Push(num, true);\n    }\n\n    /* \u961f\u5c3e\u5165\u961f */\n    public void PushLast(int num) {\n        Push(num, false);\n    }\n\n    /* \u51fa\u961f\u64cd\u4f5c */\n    int? Pop(bool isFront) {\n        if (IsEmpty())\n            throw new Exception();\n        int? val;\n        // \u961f\u9996\u51fa\u961f\u64cd\u4f5c\n        if (isFront) {\n            val = front?.val; // \u6682\u5b58\u5934\u8282\u70b9\u503c\n            // \u5220\u9664\u5934\u8282\u70b9\n            ListNode? fNext = front?.next;\n            if (fNext != null) {\n                fNext.prev = null;\n                front!.next = null;\n            }\n            front = fNext;   // \u66f4\u65b0\u5934\u8282\u70b9\n        }\n        // \u961f\u5c3e\u51fa\u961f\u64cd\u4f5c\n        else {\n            val = rear?.val;  // \u6682\u5b58\u5c3e\u8282\u70b9\u503c\n            // \u5220\u9664\u5c3e\u8282\u70b9\n            ListNode? rPrev = rear?.prev;\n            if (rPrev != null) {\n                rPrev.next = null;\n                rear!.prev = null;\n            }\n            rear = rPrev;    // \u66f4\u65b0\u5c3e\u8282\u70b9\n        }\n\n        queSize--; // \u66f4\u65b0\u961f\u5217\u957f\u5ea6\n        return val;\n    }\n\n    /* \u961f\u9996\u51fa\u961f */\n    public int? PopFirst() {\n        return Pop(true);\n    }\n\n    /* \u961f\u5c3e\u51fa\u961f */\n    public int? PopLast() {\n        return Pop(false);\n    }\n\n    /* \u8bbf\u95ee\u961f\u9996\u5143\u7d20 */\n    public int? PeekFirst() {\n        if (IsEmpty())\n            throw new Exception();\n        return front?.val;\n    }\n\n    /* \u8bbf\u95ee\u961f\u5c3e\u5143\u7d20 */\n    public int? PeekLast() {\n        if (IsEmpty())\n            throw new Exception();\n        return rear?.val;\n    }\n\n    /* \u8fd4\u56de\u6570\u7ec4\u7528\u4e8e\u6253\u5370 */\n    public int?[] ToArray() {\n        ListNode? node = front;\n        int?[] res = new int?[Size()];\n        for (int i = 0; i < res.Length; i++) {\n            res[i] = node?.val;\n            node = node?.next;\n        }\n\n        return res;\n    }\n}\n
linkedlist_deque.go
/* \u57fa\u4e8e\u53cc\u5411\u94fe\u8868\u5b9e\u73b0\u7684\u53cc\u5411\u961f\u5217 */\ntype linkedListDeque struct {\n    // \u4f7f\u7528\u5185\u7f6e\u5305 list\n    data *list.List\n}\n\n/* \u521d\u59cb\u5316\u53cc\u7aef\u961f\u5217 */\nfunc newLinkedListDeque() *linkedListDeque {\n    return &linkedListDeque{\n        data: list.New(),\n    }\n}\n\n/* \u961f\u9996\u5143\u7d20\u5165\u961f */\nfunc (s *linkedListDeque) pushFirst(value any) {\n    s.data.PushFront(value)\n}\n\n/* \u961f\u5c3e\u5143\u7d20\u5165\u961f */\nfunc (s *linkedListDeque) pushLast(value any) {\n    s.data.PushBack(value)\n}\n\n/* \u961f\u9996\u5143\u7d20\u51fa\u961f */\nfunc (s *linkedListDeque) popFirst() any {\n    if s.isEmpty() {\n        return nil\n    }\n    e := s.data.Front()\n    s.data.Remove(e)\n    return e.Value\n}\n\n/* \u961f\u5c3e\u5143\u7d20\u51fa\u961f */\nfunc (s *linkedListDeque) popLast() any {\n    if s.isEmpty() {\n        return nil\n    }\n    e := s.data.Back()\n    s.data.Remove(e)\n    return e.Value\n}\n\n/* \u8bbf\u95ee\u961f\u9996\u5143\u7d20 */\nfunc (s *linkedListDeque) peekFirst() any {\n    if s.isEmpty() {\n        return nil\n    }\n    e := s.data.Front()\n    return e.Value\n}\n\n/* \u8bbf\u95ee\u961f\u5c3e\u5143\u7d20 */\nfunc (s *linkedListDeque) peekLast() any {\n    if s.isEmpty() {\n        return nil\n    }\n    e := s.data.Back()\n    return e.Value\n}\n\n/* \u83b7\u53d6\u961f\u5217\u7684\u957f\u5ea6 */\nfunc (s *linkedListDeque) size() int {\n    return s.data.Len()\n}\n\n/* \u5224\u65ad\u961f\u5217\u662f\u5426\u4e3a\u7a7a */\nfunc (s *linkedListDeque) isEmpty() bool {\n    return s.data.Len() == 0\n}\n\n/* \u83b7\u53d6 List \u7528\u4e8e\u6253\u5370 */\nfunc (s *linkedListDeque) toList() *list.List {\n    return s.data\n}\n
linkedlist_deque.swift
/* \u53cc\u5411\u94fe\u8868\u8282\u70b9 */\nclass ListNode {\n    var val: Int // \u8282\u70b9\u503c\n    var next: ListNode? // \u540e\u7ee7\u8282\u70b9\u5f15\u7528\n    weak var prev: ListNode? // \u524d\u9a71\u8282\u70b9\u5f15\u7528\n\n    init(val: Int) {\n        self.val = val\n    }\n}\n\n/* \u57fa\u4e8e\u53cc\u5411\u94fe\u8868\u5b9e\u73b0\u7684\u53cc\u5411\u961f\u5217 */\nclass LinkedListDeque {\n    private var front: ListNode? // \u5934\u8282\u70b9 front\n    private var rear: ListNode? // \u5c3e\u8282\u70b9 rear\n    private var _size: Int // \u53cc\u5411\u961f\u5217\u7684\u957f\u5ea6\n\n    init() {\n        _size = 0\n    }\n\n    /* \u83b7\u53d6\u53cc\u5411\u961f\u5217\u7684\u957f\u5ea6 */\n    func size() -> Int {\n        _size\n    }\n\n    /* \u5224\u65ad\u53cc\u5411\u961f\u5217\u662f\u5426\u4e3a\u7a7a */\n    func isEmpty() -> Bool {\n        size() == 0\n    }\n\n    /* \u5165\u961f\u64cd\u4f5c */\n    private func push(num: Int, isFront: Bool) {\n        let node = ListNode(val: num)\n        // \u82e5\u94fe\u8868\u4e3a\u7a7a\uff0c\u5219\u4ee4 front \u548c rear \u90fd\u6307\u5411 node\n        if isEmpty() {\n            front = node\n            rear = node\n        }\n        // \u961f\u9996\u5165\u961f\u64cd\u4f5c\n        else if isFront {\n            // \u5c06 node \u6dfb\u52a0\u81f3\u94fe\u8868\u5934\u90e8\n            front?.prev = node\n            node.next = front\n            front = node // \u66f4\u65b0\u5934\u8282\u70b9\n        }\n        // \u961f\u5c3e\u5165\u961f\u64cd\u4f5c\n        else {\n            // \u5c06 node \u6dfb\u52a0\u81f3\u94fe\u8868\u5c3e\u90e8\n            rear?.next = node\n            node.prev = rear\n            rear = node // \u66f4\u65b0\u5c3e\u8282\u70b9\n        }\n        _size += 1 // \u66f4\u65b0\u961f\u5217\u957f\u5ea6\n    }\n\n    /* \u961f\u9996\u5165\u961f */\n    func pushFirst(num: Int) {\n        push(num: num, isFront: true)\n    }\n\n    /* \u961f\u5c3e\u5165\u961f */\n    func pushLast(num: Int) {\n        push(num: num, isFront: false)\n    }\n\n    /* \u51fa\u961f\u64cd\u4f5c */\n    private func pop(isFront: Bool) -> Int {\n        if isEmpty() {\n            fatalError(\"\u53cc\u5411\u961f\u5217\u4e3a\u7a7a\")\n        }\n        let val: Int\n        // \u961f\u9996\u51fa\u961f\u64cd\u4f5c\n        if isFront {\n            val = front!.val // \u6682\u5b58\u5934\u8282\u70b9\u503c\n            // \u5220\u9664\u5934\u8282\u70b9\n            let fNext = front?.next\n            if fNext != nil {\n                fNext?.prev = nil\n                front?.next = nil\n            }\n            front = fNext // \u66f4\u65b0\u5934\u8282\u70b9\n        }\n        // \u961f\u5c3e\u51fa\u961f\u64cd\u4f5c\n        else {\n            val = rear!.val // \u6682\u5b58\u5c3e\u8282\u70b9\u503c\n            // \u5220\u9664\u5c3e\u8282\u70b9\n            let rPrev = rear?.prev\n            if rPrev != nil {\n                rPrev?.next = nil\n                rear?.prev = nil\n            }\n            rear = rPrev // \u66f4\u65b0\u5c3e\u8282\u70b9\n        }\n        _size -= 1 // \u66f4\u65b0\u961f\u5217\u957f\u5ea6\n        return val\n    }\n\n    /* \u961f\u9996\u51fa\u961f */\n    func popFirst() -> Int {\n        pop(isFront: true)\n    }\n\n    /* \u961f\u5c3e\u51fa\u961f */\n    func popLast() -> Int {\n        pop(isFront: false)\n    }\n\n    /* \u8bbf\u95ee\u961f\u9996\u5143\u7d20 */\n    func peekFirst() -> Int {\n        if isEmpty() {\n            fatalError(\"\u53cc\u5411\u961f\u5217\u4e3a\u7a7a\")\n        }\n        return front!.val\n    }\n\n    /* \u8bbf\u95ee\u961f\u5c3e\u5143\u7d20 */\n    func peekLast() -> Int {\n        if isEmpty() {\n            fatalError(\"\u53cc\u5411\u961f\u5217\u4e3a\u7a7a\")\n        }\n        return rear!.val\n    }\n\n    /* \u8fd4\u56de\u6570\u7ec4\u7528\u4e8e\u6253\u5370 */\n    func toArray() -> [Int] {\n        var node = front\n        var res = Array(repeating: 0, count: size())\n        for i in res.indices {\n            res[i] = node!.val\n            node = node?.next\n        }\n        return res\n    }\n}\n
linkedlist_deque.js
/* \u53cc\u5411\u94fe\u8868\u8282\u70b9 */\nclass ListNode {\n    prev; // \u524d\u9a71\u8282\u70b9\u5f15\u7528 (\u6307\u9488)\n    next; // \u540e\u7ee7\u8282\u70b9\u5f15\u7528 (\u6307\u9488)\n    val; // \u8282\u70b9\u503c\n\n    constructor(val) {\n        this.val = val;\n        this.next = null;\n        this.prev = null;\n    }\n}\n\n/* \u57fa\u4e8e\u53cc\u5411\u94fe\u8868\u5b9e\u73b0\u7684\u53cc\u5411\u961f\u5217 */\nclass LinkedListDeque {\n    #front; // \u5934\u8282\u70b9 front\n    #rear; // \u5c3e\u8282\u70b9 rear\n    #queSize; // \u53cc\u5411\u961f\u5217\u7684\u957f\u5ea6\n\n    constructor() {\n        this.#front = null;\n        this.#rear = null;\n        this.#queSize = 0;\n    }\n\n    /* \u961f\u5c3e\u5165\u961f\u64cd\u4f5c */\n    pushLast(val) {\n        const node = new ListNode(val);\n        // \u82e5\u94fe\u8868\u4e3a\u7a7a\uff0c\u5219\u4ee4 front \u548c rear \u90fd\u6307\u5411 node\n        if (this.#queSize === 0) {\n            this.#front = node;\n            this.#rear = node;\n        } else {\n            // \u5c06 node \u6dfb\u52a0\u81f3\u94fe\u8868\u5c3e\u90e8\n            this.#rear.next = node;\n            node.prev = this.#rear;\n            this.#rear = node; // \u66f4\u65b0\u5c3e\u8282\u70b9\n        }\n        this.#queSize++;\n    }\n\n    /* \u961f\u9996\u5165\u961f\u64cd\u4f5c */\n    pushFirst(val) {\n        const node = new ListNode(val);\n        // \u82e5\u94fe\u8868\u4e3a\u7a7a\uff0c\u5219\u4ee4 front \u548c rear \u90fd\u6307\u5411 node\n        if (this.#queSize === 0) {\n            this.#front = node;\n            this.#rear = node;\n        } else {\n            // \u5c06 node \u6dfb\u52a0\u81f3\u94fe\u8868\u5934\u90e8\n            this.#front.prev = node;\n            node.next = this.#front;\n            this.#front = node; // \u66f4\u65b0\u5934\u8282\u70b9\n        }\n        this.#queSize++;\n    }\n\n    /* \u961f\u5c3e\u51fa\u961f\u64cd\u4f5c */\n    popLast() {\n        if (this.#queSize === 0) {\n            return null;\n        }\n        const value = this.#rear.val; // \u5b58\u50a8\u5c3e\u8282\u70b9\u503c\n        // \u5220\u9664\u5c3e\u8282\u70b9\n        let temp = this.#rear.prev;\n        if (temp !== null) {\n            temp.next = null;\n            this.#rear.prev = null;\n        }\n        this.#rear = temp; // \u66f4\u65b0\u5c3e\u8282\u70b9\n        this.#queSize--;\n        return value;\n    }\n\n    /* \u961f\u9996\u51fa\u961f\u64cd\u4f5c */\n    popFirst() {\n        if (this.#queSize === 0) {\n            return null;\n        }\n        const value = this.#front.val; // \u5b58\u50a8\u5c3e\u8282\u70b9\u503c\n        // \u5220\u9664\u5934\u8282\u70b9\n        let temp = this.#front.next;\n        if (temp !== null) {\n            temp.prev = null;\n            this.#front.next = null;\n        }\n        this.#front = temp; // \u66f4\u65b0\u5934\u8282\u70b9\n        this.#queSize--;\n        return value;\n    }\n\n    /* \u8bbf\u95ee\u961f\u5c3e\u5143\u7d20 */\n    peekLast() {\n        return this.#queSize === 0 ? null : this.#rear.val;\n    }\n\n    /* \u8bbf\u95ee\u961f\u9996\u5143\u7d20 */\n    peekFirst() {\n        return this.#queSize === 0 ? null : this.#front.val;\n    }\n\n    /* \u83b7\u53d6\u53cc\u5411\u961f\u5217\u7684\u957f\u5ea6 */\n    size() {\n        return this.#queSize;\n    }\n\n    /* \u5224\u65ad\u53cc\u5411\u961f\u5217\u662f\u5426\u4e3a\u7a7a */\n    isEmpty() {\n        return this.#queSize === 0;\n    }\n\n    /* \u6253\u5370\u53cc\u5411\u961f\u5217 */\n    print() {\n        const arr = [];\n        let temp = this.#front;\n        while (temp !== null) {\n            arr.push(temp.val);\n            temp = temp.next;\n        }\n        console.log('[' + arr.join(', ') + ']');\n    }\n}\n
linkedlist_deque.ts
/* \u53cc\u5411\u94fe\u8868\u8282\u70b9 */\nclass ListNode {\n    prev: ListNode; // \u524d\u9a71\u8282\u70b9\u5f15\u7528 (\u6307\u9488)\n    next: ListNode; // \u540e\u7ee7\u8282\u70b9\u5f15\u7528 (\u6307\u9488)\n    val: number; // \u8282\u70b9\u503c\n\n    constructor(val: number) {\n        this.val = val;\n        this.next = null;\n        this.prev = null;\n    }\n}\n\n/* \u57fa\u4e8e\u53cc\u5411\u94fe\u8868\u5b9e\u73b0\u7684\u53cc\u5411\u961f\u5217 */\nclass LinkedListDeque {\n    private front: ListNode; // \u5934\u8282\u70b9 front\n    private rear: ListNode; // \u5c3e\u8282\u70b9 rear\n    private queSize: number; // \u53cc\u5411\u961f\u5217\u7684\u957f\u5ea6\n\n    constructor() {\n        this.front = null;\n        this.rear = null;\n        this.queSize = 0;\n    }\n\n    /* \u961f\u5c3e\u5165\u961f\u64cd\u4f5c */\n    pushLast(val: number): void {\n        const node: ListNode = new ListNode(val);\n        // \u82e5\u94fe\u8868\u4e3a\u7a7a\uff0c\u5219\u4ee4 front \u548c rear \u90fd\u6307\u5411 node\n        if (this.queSize === 0) {\n            this.front = node;\n            this.rear = node;\n        } else {\n            // \u5c06 node \u6dfb\u52a0\u81f3\u94fe\u8868\u5c3e\u90e8\n            this.rear.next = node;\n            node.prev = this.rear;\n            this.rear = node; // \u66f4\u65b0\u5c3e\u8282\u70b9\n        }\n        this.queSize++;\n    }\n\n    /* \u961f\u9996\u5165\u961f\u64cd\u4f5c */\n    pushFirst(val: number): void {\n        const node: ListNode = new ListNode(val);\n        // \u82e5\u94fe\u8868\u4e3a\u7a7a\uff0c\u5219\u4ee4 front \u548c rear \u90fd\u6307\u5411 node\n        if (this.queSize === 0) {\n            this.front = node;\n            this.rear = node;\n        } else {\n            // \u5c06 node \u6dfb\u52a0\u81f3\u94fe\u8868\u5934\u90e8\n            this.front.prev = node;\n            node.next = this.front;\n            this.front = node; // \u66f4\u65b0\u5934\u8282\u70b9\n        }\n        this.queSize++;\n    }\n\n    /* \u961f\u5c3e\u51fa\u961f\u64cd\u4f5c */\n    popLast(): number {\n        if (this.queSize === 0) {\n            return null;\n        }\n        const value: number = this.rear.val; // \u5b58\u50a8\u5c3e\u8282\u70b9\u503c\n        // \u5220\u9664\u5c3e\u8282\u70b9\n        let temp: ListNode = this.rear.prev;\n        if (temp !== null) {\n            temp.next = null;\n            this.rear.prev = null;\n        }\n        this.rear = temp; // \u66f4\u65b0\u5c3e\u8282\u70b9\n        this.queSize--;\n        return value;\n    }\n\n    /* \u961f\u9996\u51fa\u961f\u64cd\u4f5c */\n    popFirst(): number {\n        if (this.queSize === 0) {\n            return null;\n        }\n        const value: number = this.front.val; // \u5b58\u50a8\u5c3e\u8282\u70b9\u503c\n        // \u5220\u9664\u5934\u8282\u70b9\n        let temp: ListNode = this.front.next;\n        if (temp !== null) {\n            temp.prev = null;\n            this.front.next = null;\n        }\n        this.front = temp; // \u66f4\u65b0\u5934\u8282\u70b9\n        this.queSize--;\n        return value;\n    }\n\n    /* \u8bbf\u95ee\u961f\u5c3e\u5143\u7d20 */\n    peekLast(): number {\n        return this.queSize === 0 ? null : this.rear.val;\n    }\n\n    /* \u8bbf\u95ee\u961f\u9996\u5143\u7d20 */\n    peekFirst(): number {\n        return this.queSize === 0 ? null : this.front.val;\n    }\n\n    /* \u83b7\u53d6\u53cc\u5411\u961f\u5217\u7684\u957f\u5ea6 */\n    size(): number {\n        return this.queSize;\n    }\n\n    /* \u5224\u65ad\u53cc\u5411\u961f\u5217\u662f\u5426\u4e3a\u7a7a */\n    isEmpty(): boolean {\n        return this.queSize === 0;\n    }\n\n    /* \u6253\u5370\u53cc\u5411\u961f\u5217 */\n    print(): void {\n        const arr: number[] = [];\n        let temp: ListNode = this.front;\n        while (temp !== null) {\n            arr.push(temp.val);\n            temp = temp.next;\n        }\n        console.log('[' + arr.join(', ') + ']');\n    }\n}\n
linkedlist_deque.dart
/* \u53cc\u5411\u94fe\u8868\u8282\u70b9 */\nclass ListNode {\n  int val; // \u8282\u70b9\u503c\n  ListNode? next; // \u540e\u7ee7\u8282\u70b9\u5f15\u7528\n  ListNode? prev; // \u524d\u9a71\u8282\u70b9\u5f15\u7528\n\n  ListNode(this.val, {this.next, this.prev});\n}\n\n/* \u57fa\u4e8e\u53cc\u5411\u94fe\u8868\u5b9e\u73b0\u7684\u53cc\u5411\u5bf9\u5217 */\nclass LinkedListDeque {\n  late ListNode? _front; // \u5934\u8282\u70b9 _front\n  late ListNode? _rear; // \u5c3e\u8282\u70b9 _rear\n  int _queSize = 0; // \u53cc\u5411\u961f\u5217\u7684\u957f\u5ea6\n\n  LinkedListDeque() {\n    this._front = null;\n    this._rear = null;\n  }\n\n  /* \u83b7\u53d6\u53cc\u5411\u961f\u5217\u957f\u5ea6 */\n  int size() {\n    return this._queSize;\n  }\n\n  /* \u5224\u65ad\u53cc\u5411\u961f\u5217\u662f\u5426\u4e3a\u7a7a */\n  bool isEmpty() {\n    return size() == 0;\n  }\n\n  /* \u5165\u961f\u64cd\u4f5c */\n  void push(int _num, bool isFront) {\n    final ListNode node = ListNode(_num);\n    if (isEmpty()) {\n      // \u82e5\u94fe\u8868\u4e3a\u7a7a\uff0c\u5219\u4ee4 _front \u548c _rear \u90fd\u6307\u5411 node\n      _front = _rear = node;\n    } else if (isFront) {\n      // \u961f\u9996\u5165\u961f\u64cd\u4f5c\n      // \u5c06 node \u6dfb\u52a0\u81f3\u94fe\u8868\u5934\u90e8\n      _front!.prev = node;\n      node.next = _front;\n      _front = node; // \u66f4\u65b0\u5934\u8282\u70b9\n    } else {\n      // \u961f\u5c3e\u5165\u961f\u64cd\u4f5c\n      // \u5c06 node \u6dfb\u52a0\u81f3\u94fe\u8868\u5c3e\u90e8\n      _rear!.next = node;\n      node.prev = _rear;\n      _rear = node; // \u66f4\u65b0\u5c3e\u8282\u70b9\n    }\n    _queSize++; // \u66f4\u65b0\u961f\u5217\u957f\u5ea6\n  }\n\n  /* \u961f\u9996\u5165\u961f */\n  void pushFirst(int _num) {\n    push(_num, true);\n  }\n\n  /* \u961f\u5c3e\u5165\u961f */\n  void pushLast(int _num) {\n    push(_num, false);\n  }\n\n  /* \u51fa\u961f\u64cd\u4f5c */\n  int? pop(bool isFront) {\n    // \u82e5\u961f\u5217\u4e3a\u7a7a\uff0c\u76f4\u63a5\u8fd4\u56de null\n    if (isEmpty()) {\n      return null;\n    }\n    final int val;\n    if (isFront) {\n      // \u961f\u9996\u51fa\u961f\u64cd\u4f5c\n      val = _front!.val; // \u6682\u5b58\u5934\u8282\u70b9\u503c\n      // \u5220\u9664\u5934\u8282\u70b9\n      ListNode? fNext = _front!.next;\n      if (fNext != null) {\n        fNext.prev = null;\n        _front!.next = null;\n      }\n      _front = fNext; // \u66f4\u65b0\u5934\u8282\u70b9\n    } else {\n      // \u961f\u5c3e\u51fa\u961f\u64cd\u4f5c\n      val = _rear!.val; // \u6682\u5b58\u5c3e\u8282\u70b9\u503c\n      // \u5220\u9664\u5c3e\u8282\u70b9\n      ListNode? rPrev = _rear!.prev;\n      if (rPrev != null) {\n        rPrev.next = null;\n        _rear!.prev = null;\n      }\n      _rear = rPrev; // \u66f4\u65b0\u5c3e\u8282\u70b9\n    }\n    _queSize--; // \u66f4\u65b0\u961f\u5217\u957f\u5ea6\n    return val;\n  }\n\n  /* \u961f\u9996\u51fa\u961f */\n  int? popFirst() {\n    return pop(true);\n  }\n\n  /* \u961f\u5c3e\u51fa\u961f */\n  int? popLast() {\n    return pop(false);\n  }\n\n  /* \u8bbf\u95ee\u961f\u9996\u5143\u7d20 */\n  int? peekFirst() {\n    return _front?.val;\n  }\n\n  /* \u8bbf\u95ee\u961f\u5c3e\u5143\u7d20 */\n  int? peekLast() {\n    return _rear?.val;\n  }\n\n  /* \u8fd4\u56de\u6570\u7ec4\u7528\u4e8e\u6253\u5370 */\n  List<int> toArray() {\n    ListNode? node = _front;\n    final List<int> res = [];\n    for (int i = 0; i < _queSize; i++) {\n      res.add(node!.val);\n      node = node.next;\n    }\n    return res;\n  }\n}\n
linkedlist_deque.rs
/* \u53cc\u5411\u94fe\u8868\u8282\u70b9 */\npub struct ListNode<T> {\n    pub val: T,                                 // \u8282\u70b9\u503c\n    pub next: Option<Rc<RefCell<ListNode<T>>>>, // \u540e\u7ee7\u8282\u70b9\u6307\u9488\n    pub prev: Option<Rc<RefCell<ListNode<T>>>>, // \u524d\u9a71\u8282\u70b9\u6307\u9488\n}\n\nimpl<T> ListNode<T> {\n    pub fn new(val: T) -> Rc<RefCell<ListNode<T>>> {\n        Rc::new(RefCell::new(ListNode {\n            val,\n            next: None,\n            prev: None,\n        }))\n    }\n}\n\n/* \u57fa\u4e8e\u53cc\u5411\u94fe\u8868\u5b9e\u73b0\u7684\u53cc\u5411\u961f\u5217 */\n#[allow(dead_code)]\npub struct LinkedListDeque<T> {\n    front: Option<Rc<RefCell<ListNode<T>>>>, // \u5934\u8282\u70b9 front\n    rear: Option<Rc<RefCell<ListNode<T>>>>,  // \u5c3e\u8282\u70b9 rear\n    que_size: usize,                         // \u53cc\u5411\u961f\u5217\u7684\u957f\u5ea6\n}\n\nimpl<T: Copy> LinkedListDeque<T> {\n    pub fn new() -> Self {\n        Self {\n            front: None,\n            rear: None,\n            que_size: 0,\n        }\n    }\n\n    /* \u83b7\u53d6\u53cc\u5411\u961f\u5217\u7684\u957f\u5ea6 */\n    pub fn size(&self) -> usize {\n        return self.que_size;\n    }\n\n    /* \u5224\u65ad\u53cc\u5411\u961f\u5217\u662f\u5426\u4e3a\u7a7a */\n    pub fn is_empty(&self) -> bool {\n        return self.size() == 0;\n    }\n\n    /* \u5165\u961f\u64cd\u4f5c */\n    pub fn push(&mut self, num: T, is_front: bool) {\n        let node = ListNode::new(num);\n        // \u961f\u9996\u5165\u961f\u64cd\u4f5c\n        if is_front {\n            match self.front.take() {\n                // \u82e5\u94fe\u8868\u4e3a\u7a7a\uff0c\u5219\u4ee4 front \u548c rear \u90fd\u6307\u5411 node\n                None => {\n                    self.rear = Some(node.clone());\n                    self.front = Some(node);\n                }\n                // \u5c06 node \u6dfb\u52a0\u81f3\u94fe\u8868\u5934\u90e8\n                Some(old_front) => {\n                    old_front.borrow_mut().prev = Some(node.clone());\n                    node.borrow_mut().next = Some(old_front);\n                    self.front = Some(node); // \u66f4\u65b0\u5934\u8282\u70b9\n                }\n            }\n        }\n        // \u961f\u5c3e\u5165\u961f\u64cd\u4f5c\n        else {\n            match self.rear.take() {\n                // \u82e5\u94fe\u8868\u4e3a\u7a7a\uff0c\u5219\u4ee4 front \u548c rear \u90fd\u6307\u5411 node\n                None => {\n                    self.front = Some(node.clone());\n                    self.rear = Some(node);\n                }\n                // \u5c06 node \u6dfb\u52a0\u81f3\u94fe\u8868\u5c3e\u90e8\n                Some(old_rear) => {\n                    old_rear.borrow_mut().next = Some(node.clone());\n                    node.borrow_mut().prev = Some(old_rear);\n                    self.rear = Some(node); // \u66f4\u65b0\u5c3e\u8282\u70b9\n                }\n            }\n        }\n        self.que_size += 1; // \u66f4\u65b0\u961f\u5217\u957f\u5ea6\n    }\n\n    /* \u961f\u9996\u5165\u961f */\n    pub fn push_first(&mut self, num: T) {\n        self.push(num, true);\n    }\n\n    /* \u961f\u5c3e\u5165\u961f */\n    pub fn push_last(&mut self, num: T) {\n        self.push(num, false);\n    }\n\n    /* \u51fa\u961f\u64cd\u4f5c */\n    pub fn pop(&mut self, is_front: bool) -> Option<T> {\n        // \u82e5\u961f\u5217\u4e3a\u7a7a\uff0c\u76f4\u63a5\u8fd4\u56de None\n        if self.is_empty() {\n            return None;\n        };\n        // \u961f\u9996\u51fa\u961f\u64cd\u4f5c\n        if is_front {\n            self.front.take().map(|old_front| {\n                match old_front.borrow_mut().next.take() {\n                    Some(new_front) => {\n                        new_front.borrow_mut().prev.take();\n                        self.front = Some(new_front); // \u66f4\u65b0\u5934\u8282\u70b9\n                    }\n                    None => {\n                        self.rear.take();\n                    }\n                }\n                self.que_size -= 1; // \u66f4\u65b0\u961f\u5217\u957f\u5ea6\n                Rc::try_unwrap(old_front).ok().unwrap().into_inner().val\n            })\n        }\n        // \u961f\u5c3e\u51fa\u961f\u64cd\u4f5c\n        else {\n            self.rear.take().map(|old_rear| {\n                match old_rear.borrow_mut().prev.take() {\n                    Some(new_rear) => {\n                        new_rear.borrow_mut().next.take();\n                        self.rear = Some(new_rear); // \u66f4\u65b0\u5c3e\u8282\u70b9\n                    }\n                    None => {\n                        self.front.take();\n                    }\n                }\n                self.que_size -= 1; // \u66f4\u65b0\u961f\u5217\u957f\u5ea6\n                Rc::try_unwrap(old_rear).ok().unwrap().into_inner().val\n            })\n        }\n    }\n\n    /* \u961f\u9996\u51fa\u961f */\n    pub fn pop_first(&mut self) -> Option<T> {\n        return self.pop(true);\n    }\n\n    /* \u961f\u5c3e\u51fa\u961f */\n    pub fn pop_last(&mut self) -> Option<T> {\n        return self.pop(false);\n    }\n\n    /* \u8bbf\u95ee\u961f\u9996\u5143\u7d20 */\n    pub fn peek_first(&self) -> Option<&Rc<RefCell<ListNode<T>>>> {\n        self.front.as_ref()\n    }\n\n    /* \u8bbf\u95ee\u961f\u5c3e\u5143\u7d20 */\n    pub fn peek_last(&self) -> Option<&Rc<RefCell<ListNode<T>>>> {\n        self.rear.as_ref()\n    }\n\n    /* \u8fd4\u56de\u6570\u7ec4\u7528\u4e8e\u6253\u5370 */\n    pub fn to_array(&self, head: Option<&Rc<RefCell<ListNode<T>>>>) -> Vec<T> {\n        if let Some(node) = head {\n            let mut nums = self.to_array(node.borrow().next.as_ref());\n            nums.insert(0, node.borrow().val);\n            return nums;\n        }\n        return Vec::new();\n    }\n}\n
linkedlist_deque.c
/* \u53cc\u5411\u94fe\u8868\u8282\u70b9 */\ntypedef struct DoublyListNode {\n    int val;                     // \u8282\u70b9\u503c\n    struct DoublyListNode *next; // \u540e\u7ee7\u8282\u70b9\n    struct DoublyListNode *prev; // \u524d\u9a71\u8282\u70b9\n} DoublyListNode;\n\n/* \u6784\u9020\u51fd\u6570 */\nDoublyListNode *newDoublyListNode(int num) {\n    DoublyListNode *new = (DoublyListNode *)malloc(sizeof(DoublyListNode));\n    new->val = num;\n    new->next = NULL;\n    new->prev = NULL;\n    return new;\n}\n\n/* \u6790\u6784\u51fd\u6570 */\nvoid delDoublyListNode(DoublyListNode *node) {\n    free(node);\n}\n\n/* \u57fa\u4e8e\u53cc\u5411\u94fe\u8868\u5b9e\u73b0\u7684\u53cc\u5411\u961f\u5217 */\ntypedef struct {\n    DoublyListNode *front, *rear; // \u5934\u8282\u70b9 front \uff0c\u5c3e\u8282\u70b9 rear\n    int queSize;                  // \u53cc\u5411\u961f\u5217\u7684\u957f\u5ea6\n} LinkedListDeque;\n\n/* \u6784\u9020\u51fd\u6570 */\nLinkedListDeque *newLinkedListDeque() {\n    LinkedListDeque *deque = (LinkedListDeque *)malloc(sizeof(LinkedListDeque));\n    deque->front = NULL;\n    deque->rear = NULL;\n    deque->queSize = 0;\n    return deque;\n}\n\n/* \u6790\u6784\u51fd\u6570 */\nvoid delLinkedListdeque(LinkedListDeque *deque) {\n    // \u91ca\u653e\u6240\u6709\u8282\u70b9\n    for (int i = 0; i < deque->queSize && deque->front != NULL; i++) {\n        DoublyListNode *tmp = deque->front;\n        deque->front = deque->front->next;\n        free(tmp);\n    }\n    // \u91ca\u653e deque \u7ed3\u6784\u4f53\n    free(deque);\n}\n\n/* \u83b7\u53d6\u961f\u5217\u7684\u957f\u5ea6 */\nint size(LinkedListDeque *deque) {\n    return deque->queSize;\n}\n\n/* \u5224\u65ad\u961f\u5217\u662f\u5426\u4e3a\u7a7a */\nbool empty(LinkedListDeque *deque) {\n    return (size(deque) == 0);\n}\n\n/* \u5165\u961f */\nvoid push(LinkedListDeque *deque, int num, bool isFront) {\n    DoublyListNode *node = newDoublyListNode(num);\n    // \u82e5\u94fe\u8868\u4e3a\u7a7a\uff0c\u5219\u4ee4 front \u548c rear \u90fd\u6307\u5411node\n    if (empty(deque)) {\n        deque->front = deque->rear = node;\n    }\n    // \u961f\u9996\u5165\u961f\u64cd\u4f5c\n    else if (isFront) {\n        // \u5c06 node \u6dfb\u52a0\u81f3\u94fe\u8868\u5934\u90e8\n        deque->front->prev = node;\n        node->next = deque->front;\n        deque->front = node; // \u66f4\u65b0\u5934\u8282\u70b9\n    }\n    // \u961f\u5c3e\u5165\u961f\u64cd\u4f5c\n    else {\n        // \u5c06 node \u6dfb\u52a0\u81f3\u94fe\u8868\u5c3e\u90e8\n        deque->rear->next = node;\n        node->prev = deque->rear;\n        deque->rear = node;\n    }\n    deque->queSize++; // \u66f4\u65b0\u961f\u5217\u957f\u5ea6\n}\n\n/* \u961f\u9996\u5165\u961f */\nvoid pushFirst(LinkedListDeque *deque, int num) {\n    push(deque, num, true);\n}\n\n/* \u961f\u5c3e\u5165\u961f */\nvoid pushLast(LinkedListDeque *deque, int num) {\n    push(deque, num, false);\n}\n\n/* \u8bbf\u95ee\u961f\u9996\u5143\u7d20 */\nint peekFirst(LinkedListDeque *deque) {\n    assert(size(deque) && deque->front);\n    return deque->front->val;\n}\n\n/* \u8bbf\u95ee\u961f\u5c3e\u5143\u7d20 */\nint peekLast(LinkedListDeque *deque) {\n    assert(size(deque) && deque->rear);\n    return deque->rear->val;\n}\n\n/* \u51fa\u961f */\nint pop(LinkedListDeque *deque, bool isFront) {\n    if (empty(deque))\n        return -1;\n    int val;\n    // \u961f\u9996\u51fa\u961f\u64cd\u4f5c\n    if (isFront) {\n        val = peekFirst(deque); // \u6682\u5b58\u5934\u8282\u70b9\u503c\n        DoublyListNode *fNext = deque->front->next;\n        if (fNext) {\n            fNext->prev = NULL;\n            deque->front->next = NULL;\n            delDoublyListNode(deque->front);\n        }\n        deque->front = fNext; // \u66f4\u65b0\u5934\u8282\u70b9\n    }\n    // \u961f\u5c3e\u51fa\u961f\u64cd\u4f5c\n    else {\n        val = peekLast(deque); // \u6682\u5b58\u5c3e\u8282\u70b9\u503c\n        DoublyListNode *rPrev = deque->rear->prev;\n        if (rPrev) {\n            rPrev->next = NULL;\n            deque->rear->prev = NULL;\n            delDoublyListNode(deque->rear);\n        }\n        deque->rear = rPrev; // \u66f4\u65b0\u5c3e\u8282\u70b9\n    }\n    deque->queSize--; // \u66f4\u65b0\u961f\u5217\u957f\u5ea6\n    return val;\n}\n\n/* \u961f\u9996\u51fa\u961f */\nint popFirst(LinkedListDeque *deque) {\n    return pop(deque, true);\n}\n\n/* \u961f\u5c3e\u51fa\u961f */\nint popLast(LinkedListDeque *deque) {\n    return pop(deque, false);\n}\n\n/* \u6253\u5370\u961f\u5217 */\nvoid printLinkedListDeque(LinkedListDeque *deque) {\n    int *arr = malloc(sizeof(int) * deque->queSize);\n    // \u62f7\u8d1d\u94fe\u8868\u4e2d\u7684\u6570\u636e\u5230\u6570\u7ec4\n    int i;\n    DoublyListNode *node;\n    for (i = 0, node = deque->front; i < deque->queSize; i++) {\n        arr[i] = node->val;\n        node = node->next;\n    }\n    printArray(arr, deque->queSize);\n    free(arr);\n}\n
linkedlist_deque.zig
// \u53cc\u5411\u94fe\u8868\u8282\u70b9\nfn ListNode(comptime T: type) type {\n    return struct {\n        const Self = @This();\n\n        val: T = undefined,     // \u8282\u70b9\u503c\n        next: ?*Self = null,    // \u540e\u7ee7\u8282\u70b9\u6307\u9488\n        prev: ?*Self = null,    // \u524d\u9a71\u8282\u70b9\u6307\u9488\n\n        // Initialize a list node with specific value\n        pub fn init(self: *Self, x: i32) void {\n            self.val = x;\n            self.next = null;\n            self.prev = null;\n        }\n    };\n}\n\n// \u57fa\u4e8e\u53cc\u5411\u94fe\u8868\u5b9e\u73b0\u7684\u53cc\u5411\u961f\u5217\nfn LinkedListDeque(comptime T: type) type {\n    return struct {\n        const Self = @This();\n\n        front: ?*ListNode(T) = null,                    // \u5934\u8282\u70b9 front\n        rear: ?*ListNode(T) = null,                     // \u5c3e\u8282\u70b9 rear\n        que_size: usize = 0,                             // \u53cc\u5411\u961f\u5217\u7684\u957f\u5ea6\n        mem_arena: ?std.heap.ArenaAllocator = null,\n        mem_allocator: std.mem.Allocator = undefined,   // \u5185\u5b58\u5206\u914d\u5668\n\n        // \u6784\u9020\u51fd\u6570\uff08\u5206\u914d\u5185\u5b58+\u521d\u59cb\u5316\u961f\u5217\uff09\n        pub fn init(self: *Self, allocator: std.mem.Allocator) !void {\n            if (self.mem_arena == null) {\n                self.mem_arena = std.heap.ArenaAllocator.init(allocator);\n                self.mem_allocator = self.mem_arena.?.allocator();\n            }\n            self.front = null;\n            self.rear = null;\n            self.que_size = 0;\n        }\n\n        // \u6790\u6784\u51fd\u6570\uff08\u91ca\u653e\u5185\u5b58\uff09\n        pub fn deinit(self: *Self) void {\n            if (self.mem_arena == null) return;\n            self.mem_arena.?.deinit();\n        }\n\n        // \u83b7\u53d6\u53cc\u5411\u961f\u5217\u7684\u957f\u5ea6\n        pub fn size(self: *Self) usize {\n            return self.que_size;\n        }\n\n        // \u5224\u65ad\u53cc\u5411\u961f\u5217\u662f\u5426\u4e3a\u7a7a\n        pub fn isEmpty(self: *Self) bool {\n            return self.size() == 0;\n        }\n\n        // \u5165\u961f\u64cd\u4f5c\n        pub fn push(self: *Self, num: T, is_front: bool) !void {\n            var node = try self.mem_allocator.create(ListNode(T));\n            node.init(num);\n            // \u82e5\u94fe\u8868\u4e3a\u7a7a\uff0c\u5219\u4ee4 front \u548c rear \u90fd\u6307\u5411 node\n            if (self.isEmpty()) {\n                self.front = node;\n                self.rear = node;\n            // \u961f\u9996\u5165\u961f\u64cd\u4f5c\n            } else if (is_front) {\n                // \u5c06 node \u6dfb\u52a0\u81f3\u94fe\u8868\u5934\u90e8\n                self.front.?.prev = node;\n                node.next = self.front;\n                self.front = node;  // \u66f4\u65b0\u5934\u8282\u70b9\n            // \u961f\u5c3e\u5165\u961f\u64cd\u4f5c\n            } else {\n                // \u5c06 node \u6dfb\u52a0\u81f3\u94fe\u8868\u5c3e\u90e8\n                self.rear.?.next = node;\n                node.prev = self.rear;\n                self.rear = node;   // \u66f4\u65b0\u5c3e\u8282\u70b9\n            }\n            self.que_size += 1;      // \u66f4\u65b0\u961f\u5217\u957f\u5ea6\n        } \n\n        // \u961f\u9996\u5165\u961f\n        pub fn pushFirst(self: *Self, num: T) !void {\n            try self.push(num, true);\n        } \n\n        // \u961f\u5c3e\u5165\u961f\n        pub fn pushLast(self: *Self, num: T) !void {\n            try self.push(num, false);\n        } \n\n        // \u51fa\u961f\u64cd\u4f5c\n        pub fn pop(self: *Self, is_front: bool) T {\n            if (self.isEmpty()) @panic(\"\u53cc\u5411\u961f\u5217\u4e3a\u7a7a\");\n            var val: T = undefined;\n            // \u961f\u9996\u51fa\u961f\u64cd\u4f5c\n            if (is_front) {\n                val = self.front.?.val;     // \u6682\u5b58\u5934\u8282\u70b9\u503c\n                // \u5220\u9664\u5934\u8282\u70b9\n                var fNext = self.front.?.next;\n                if (fNext != null) {\n                    fNext.?.prev = null;\n                    self.front.?.next = null;\n                }\n                self.front = fNext;         // \u66f4\u65b0\u5934\u8282\u70b9\n            // \u961f\u5c3e\u51fa\u961f\u64cd\u4f5c\n            } else {\n                val = self.rear.?.val;      // \u6682\u5b58\u5c3e\u8282\u70b9\u503c\n                // \u5220\u9664\u5c3e\u8282\u70b9\n                var rPrev = self.rear.?.prev;\n                if (rPrev != null) {\n                    rPrev.?.next = null;\n                    self.rear.?.prev = null;\n                }\n                self.rear = rPrev;          // \u66f4\u65b0\u5c3e\u8282\u70b9\n            }\n            self.que_size -= 1;              // \u66f4\u65b0\u961f\u5217\u957f\u5ea6\n            return val;\n        } \n\n        // \u961f\u9996\u51fa\u961f\n        pub fn popFirst(self: *Self) T {\n            return self.pop(true);\n        } \n\n        // \u961f\u5c3e\u51fa\u961f\n        pub fn popLast(self: *Self) T {\n            return self.pop(false);\n        } \n\n        // \u8bbf\u95ee\u961f\u9996\u5143\u7d20\n        pub fn peekFirst(self: *Self) T {\n            if (self.isEmpty()) @panic(\"\u53cc\u5411\u961f\u5217\u4e3a\u7a7a\");\n            return self.front.?.val;\n        }  \n\n        // \u8bbf\u95ee\u961f\u5c3e\u5143\u7d20\n        pub fn peekLast(self: *Self) T {\n            if (self.isEmpty()) @panic(\"\u53cc\u5411\u961f\u5217\u4e3a\u7a7a\");\n            return self.rear.?.val;\n        }\n\n        // \u8fd4\u56de\u6570\u7ec4\u7528\u4e8e\u6253\u5370\n        pub fn toArray(self: *Self) ![]T {\n            var node = self.front;\n            var res = try self.mem_allocator.alloc(T, self.size());\n            @memset(res, @as(T, 0));\n            var i: usize = 0;\n            while (i < res.len) : (i += 1) {\n                res[i] = node.?.val;\n                node = node.?.next;\n            }\n            return res;\n        }\n    };\n}\n
"},{"location":"chapter_stack_and_queue/deque/#2-implementation-based-on-array","title":"2. \u00a0 Implementation Based on Array","text":"

As shown in the Figure 5-9 , similar to implementing a queue with an array, we can also use a circular array to implement a double-ended queue.

ArrayDequepushLast()pushFirst()popLast()popFirst()

Figure 5-9 \u00a0 Implementing Double-Ended Queue with Array for Enqueue and Dequeue Operations

The implementation only needs to add methods for \"front enqueue\" and \"rear dequeue\":

[file]{array_deque}-[func]{}\n
"},{"location":"chapter_stack_and_queue/deque/#533-applications-of-double-ended-queue","title":"5.3.3 \u00a0 Applications of Double-Ended Queue","text":"

The double-ended queue combines the logic of both stacks and queues, thus, it can implement all their respective use cases while offering greater flexibility.

We know that software's \"undo\" feature is typically implemented using a stack: the system pushes each change operation onto the stack and then pops to implement undoing. However, considering the limitations of system resources, software often restricts the number of undo steps (for example, only allowing the last 50 steps). When the stack length exceeds 50, the software needs to perform a deletion operation at the bottom of the stack (the front of the queue). But a regular stack cannot perform this function, where a double-ended queue becomes necessary. Note that the core logic of \"undo\" still follows the Last-In-First-Out principle of a stack, but a double-ended queue can more flexibly implement some additional logic.

"},{"location":"chapter_stack_and_queue/queue/","title":"5.2 \u00a0 Queue","text":"

\"Queue\" is a linear data structure that follows the First-In-First-Out (FIFO) rule. As the name suggests, a queue simulates the phenomenon of lining up, where newcomers join the queue at the rear, and the person at the front leaves the queue first.

As shown in the Figure 5-4 , we call the front of the queue the \"head\" and the back the \"tail.\" The operation of adding elements to the rear of the queue is termed \"enqueue,\" and the operation of removing elements from the front is termed \"dequeue.\"

Figure 5-4 \u00a0 Queue's First-In-First-Out Rule

"},{"location":"chapter_stack_and_queue/queue/#521-common-operations-on-queue","title":"5.2.1 \u00a0 Common Operations on Queue","text":"

The common operations on a queue are shown in the Table 5-2 . Note that method names may vary across different programming languages. Here, we use the same naming convention as that used for stacks.

Table 5-2 \u00a0 Efficiency of Queue Operations

Method Name Description Time Complexity push() Enqueue an element, add it to the tail \\(O(1)\\) pop() Dequeue the head element \\(O(1)\\) peek() Access the head element \\(O(1)\\)

We can directly use the ready-made queue classes in programming languages:

PythonC++JavaC#GoSwiftJSTSDartRustCZig queue.py
from collections import deque\n\n# Initialize the queue\n# In Python, we generally use the deque class as a queue\n# Although queue.Queue() is a pure queue class, it's not very user-friendly, so it's not recommended\nque: deque[int] = deque()\n\n# Enqueue elements\nque.append(1)\nque.append(3)\nque.append(2)\nque.append(5)\nque.append(4)\n\n# Access the first element\nfront: int = que[0]\n\n# Dequeue an element\npop: int = que.popleft()\n\n# Get the length of the queue\nsize: int = len(que)\n\n# Check if the queue is empty\nis_empty: bool = len(que) == 0\n
queue.cpp
/* Initialize the queue */\nqueue<int> queue;\n\n/* Enqueue elements */\nqueue.push(1);\nqueue.push(3);\nqueue.push(2);\nqueue.push(5);\nqueue.push(4);\n\n/* Access the first element*/\nint front = queue.front();\n\n/* Dequeue an element */\nqueue.pop();\n\n/* Get the length of the queue */\nint size = queue.size();\n\n/* Check if the queue is empty */\nbool empty = queue.empty();\n
queue.java
/* Initialize the queue */\nQueue<Integer> queue = new LinkedList<>();\n\n/* Enqueue elements */\nqueue.offer(1);\nqueue.offer(3);\nqueue.offer(2);\nqueue.offer(5);\nqueue.offer(4);\n\n/* Access the first element */\nint peek = queue.peek();\n\n/* Dequeue an element */\nint pop = queue.poll();\n\n/* Get the length of the queue */\nint size = queue.size();\n\n/* Check if the queue is empty */\nboolean isEmpty = queue.isEmpty();\n
queue.cs
/* Initialize the queue */\nQueue<int> queue = new();\n\n/* Enqueue elements */\nqueue.Enqueue(1);\nqueue.Enqueue(3);\nqueue.Enqueue(2);\nqueue.Enqueue(5);\nqueue.Enqueue(4);\n\n/* Access the first element */\nint peek = queue.Peek();\n\n/* Dequeue an element */\nint pop = queue.Dequeue();\n\n/* Get the length of the queue */\nint size = queue.Count;\n\n/* Check if the queue is empty */\nbool isEmpty = queue.Count == 0;\n
queue_test.go
/* Initialize the queue */\n// In Go, use list as a queue\nqueue := list.New()\n\n/* Enqueue elements */\nqueue.PushBack(1)\nqueue.PushBack(3)\nqueue.PushBack(2)\nqueue.PushBack(5)\nqueue.PushBack(4)\n\n/* Access the first element */\npeek := queue.Front()\n\n/* Dequeue an element */\npop := queue.Front()\nqueue.Remove(pop)\n\n/* Get the length of the queue */\nsize := queue.Len()\n\n/* Check if the queue is empty */\nisEmpty := queue.Len() == 0\n
queue.swift
/* Initialize the queue */\n// Swift does not have a built-in queue class, so Array can be used as a queue\nvar queue: [Int] = []\n\n/* Enqueue elements */\nqueue.append(1)\nqueue.append(3)\nqueue.append(2)\nqueue.append(5)\nqueue.append(4)\n\n/* Access the first element */\nlet peek = queue.first!\n\n/* Dequeue an element */\n// Since it's an array, removeFirst has a complexity of O(n)\nlet pool = queue.removeFirst()\n\n/* Get the length of the queue */\nlet size = queue.count\n\n/* Check if the queue is empty */\nlet isEmpty = queue.isEmpty\n
queue.js
/* Initialize the queue */\n// JavaScript does not have a built-in queue, so Array can be used as a queue\nconst queue = [];\n\n/* Enqueue elements */\nqueue.push(1);\nqueue.push(3);\nqueue.push(2);\nqueue.push(5);\nqueue.push(4);\n\n/* Access the first element */\nconst peek = queue[0];\n\n/* Dequeue an element */\n// Since the underlying structure is an array, shift() method has a time complexity of O(n)\nconst pop = queue.shift();\n\n/* Get the length of the queue */\nconst size = queue.length;\n\n/* Check if the queue is empty */\nconst empty = queue.length === 0;\n
queue.ts
/* Initialize the queue */\n// TypeScript does not have a built-in queue, so Array can be used as a queue \nconst queue: number[] = [];\n\n/* Enqueue elements */\nqueue.push(1);\nqueue.push(3);\nqueue.push(2);\nqueue.push(5);\nqueue.push(4);\n\n/* Access the first element */\nconst peek = queue[0];\n\n/* Dequeue an element */\n// Since the underlying structure is an array, shift() method has a time complexity of O(n)\nconst pop = queue.shift();\n\n/* Get the length of the queue */\nconst size = queue.length;\n\n/* Check if the queue is empty */\nconst empty = queue.length === 0;\n
queue.dart
/* Initialize the queue */\n// In Dart, the Queue class is a double-ended queue but can be used as a queue\nQueue<int> queue = Queue();\n\n/* Enqueue elements */\nqueue.add(1);\nqueue.add(3);\nqueue.add(2);\nqueue.add(5);\nqueue.add(4);\n\n/* Access the first element */\nint peek = queue.first;\n\n/* Dequeue an element */\nint pop = queue.removeFirst();\n\n/* Get the length of the queue */\nint size = queue.length;\n\n/* Check if the queue is empty */\nbool isEmpty = queue.isEmpty;\n
queue.rs
/* Initialize the double-ended queue */\n// In Rust, use a double-ended queue as a regular queue\nlet mut deque: VecDeque<u32> = VecDeque::new();\n\n/* Enqueue elements */\ndeque.push_back(1);\ndeque.push_back(3);\ndeque.push_back(2);\ndeque.push_back(5);\ndeque.push_back(4);\n\n/* Access the first element */\nif let Some(front) = deque.front() {\n}\n\n/* Dequeue an element */\nif let Some(pop) = deque.pop_front() {\n}\n\n/* Get the length of the queue */\nlet size = deque.len();\n\n/* Check if the queue is empty */\nlet is_empty = deque.is_empty();\n
queue.c
// C does not provide a built-in queue\n
queue.zig
\n
Code Visualization

Full Screen >

"},{"location":"chapter_stack_and_queue/queue/#522-implementing-a-queue","title":"5.2.2 \u00a0 Implementing a Queue","text":"

To implement a queue, we need a data structure that allows adding elements at one end and removing them at the other. Both linked lists and arrays meet this requirement.

"},{"location":"chapter_stack_and_queue/queue/#1-implementation-based-on-a-linked-list","title":"1. \u00a0 Implementation Based on a Linked List","text":"

As shown in the Figure 5-5 , we can consider the \"head node\" and \"tail node\" of a linked list as the \"front\" and \"rear\" of the queue, respectively. It is stipulated that nodes can only be added at the rear and removed at the front.

LinkedListQueuepush()pop()

Figure 5-5 \u00a0 Implementing Queue with Linked List for Enqueue and Dequeue Operations

Below is the code for implementing a queue using a linked list:

PythonC++JavaC#GoSwiftJSTSDartRustCZig linkedlist_queue.py
class LinkedListQueue:\n    \"\"\"\u57fa\u4e8e\u94fe\u8868\u5b9e\u73b0\u7684\u961f\u5217\"\"\"\n\n    def __init__(self):\n        \"\"\"\u6784\u9020\u65b9\u6cd5\"\"\"\n        self._front: ListNode | None = None  # \u5934\u8282\u70b9 front\n        self._rear: ListNode | None = None  # \u5c3e\u8282\u70b9 rear\n        self._size: int = 0\n\n    def size(self) -> int:\n        \"\"\"\u83b7\u53d6\u961f\u5217\u7684\u957f\u5ea6\"\"\"\n        return self._size\n\n    def is_empty(self) -> bool:\n        \"\"\"\u5224\u65ad\u961f\u5217\u662f\u5426\u4e3a\u7a7a\"\"\"\n        return not self._front\n\n    def push(self, num: int):\n        \"\"\"\u5165\u961f\"\"\"\n        # \u5728\u5c3e\u8282\u70b9\u540e\u6dfb\u52a0 num\n        node = ListNode(num)\n        # \u5982\u679c\u961f\u5217\u4e3a\u7a7a\uff0c\u5219\u4ee4\u5934\u3001\u5c3e\u8282\u70b9\u90fd\u6307\u5411\u8be5\u8282\u70b9\n        if self._front is None:\n            self._front = node\n            self._rear = node\n        # \u5982\u679c\u961f\u5217\u4e0d\u4e3a\u7a7a\uff0c\u5219\u5c06\u8be5\u8282\u70b9\u6dfb\u52a0\u5230\u5c3e\u8282\u70b9\u540e\n        else:\n            self._rear.next = node\n            self._rear = node\n        self._size += 1\n\n    def pop(self) -> int:\n        \"\"\"\u51fa\u961f\"\"\"\n        num = self.peek()\n        # \u5220\u9664\u5934\u8282\u70b9\n        self._front = self._front.next\n        self._size -= 1\n        return num\n\n    def peek(self) -> int:\n        \"\"\"\u8bbf\u95ee\u961f\u9996\u5143\u7d20\"\"\"\n        if self.is_empty():\n            raise IndexError(\"\u961f\u5217\u4e3a\u7a7a\")\n        return self._front.val\n\n    def to_list(self) -> list[int]:\n        \"\"\"\u8f6c\u5316\u4e3a\u5217\u8868\u7528\u4e8e\u6253\u5370\"\"\"\n        queue = []\n        temp = self._front\n        while temp:\n            queue.append(temp.val)\n            temp = temp.next\n        return queue\n
linkedlist_queue.cpp
/* \u57fa\u4e8e\u94fe\u8868\u5b9e\u73b0\u7684\u961f\u5217 */\nclass LinkedListQueue {\n  private:\n    ListNode *front, *rear; // \u5934\u8282\u70b9 front \uff0c\u5c3e\u8282\u70b9 rear\n    int queSize;\n\n  public:\n    LinkedListQueue() {\n        front = nullptr;\n        rear = nullptr;\n        queSize = 0;\n    }\n\n    ~LinkedListQueue() {\n        // \u904d\u5386\u94fe\u8868\u5220\u9664\u8282\u70b9\uff0c\u91ca\u653e\u5185\u5b58\n        freeMemoryLinkedList(front);\n    }\n\n    /* \u83b7\u53d6\u961f\u5217\u7684\u957f\u5ea6 */\n    int size() {\n        return queSize;\n    }\n\n    /* \u5224\u65ad\u961f\u5217\u662f\u5426\u4e3a\u7a7a */\n    bool isEmpty() {\n        return queSize == 0;\n    }\n\n    /* \u5165\u961f */\n    void push(int num) {\n        // \u5728\u5c3e\u8282\u70b9\u540e\u6dfb\u52a0 num\n        ListNode *node = new ListNode(num);\n        // \u5982\u679c\u961f\u5217\u4e3a\u7a7a\uff0c\u5219\u4ee4\u5934\u3001\u5c3e\u8282\u70b9\u90fd\u6307\u5411\u8be5\u8282\u70b9\n        if (front == nullptr) {\n            front = node;\n            rear = node;\n        }\n        // \u5982\u679c\u961f\u5217\u4e0d\u4e3a\u7a7a\uff0c\u5219\u5c06\u8be5\u8282\u70b9\u6dfb\u52a0\u5230\u5c3e\u8282\u70b9\u540e\n        else {\n            rear->next = node;\n            rear = node;\n        }\n        queSize++;\n    }\n\n    /* \u51fa\u961f */\n    int pop() {\n        int num = peek();\n        // \u5220\u9664\u5934\u8282\u70b9\n        ListNode *tmp = front;\n        front = front->next;\n        // \u91ca\u653e\u5185\u5b58\n        delete tmp;\n        queSize--;\n        return num;\n    }\n\n    /* \u8bbf\u95ee\u961f\u9996\u5143\u7d20 */\n    int peek() {\n        if (size() == 0)\n            throw out_of_range(\"\u961f\u5217\u4e3a\u7a7a\");\n        return front->val;\n    }\n\n    /* \u5c06\u94fe\u8868\u8f6c\u5316\u4e3a Vector \u5e76\u8fd4\u56de */\n    vector<int> toVector() {\n        ListNode *node = front;\n        vector<int> res(size());\n        for (int i = 0; i < res.size(); i++) {\n            res[i] = node->val;\n            node = node->next;\n        }\n        return res;\n    }\n};\n
linkedlist_queue.java
/* \u57fa\u4e8e\u94fe\u8868\u5b9e\u73b0\u7684\u961f\u5217 */\nclass LinkedListQueue {\n    private ListNode front, rear; // \u5934\u8282\u70b9 front \uff0c\u5c3e\u8282\u70b9 rear\n    private int queSize = 0;\n\n    public LinkedListQueue() {\n        front = null;\n        rear = null;\n    }\n\n    /* \u83b7\u53d6\u961f\u5217\u7684\u957f\u5ea6 */\n    public int size() {\n        return queSize;\n    }\n\n    /* \u5224\u65ad\u961f\u5217\u662f\u5426\u4e3a\u7a7a */\n    public boolean isEmpty() {\n        return size() == 0;\n    }\n\n    /* \u5165\u961f */\n    public void push(int num) {\n        // \u5728\u5c3e\u8282\u70b9\u540e\u6dfb\u52a0 num\n        ListNode node = new ListNode(num);\n        // \u5982\u679c\u961f\u5217\u4e3a\u7a7a\uff0c\u5219\u4ee4\u5934\u3001\u5c3e\u8282\u70b9\u90fd\u6307\u5411\u8be5\u8282\u70b9\n        if (front == null) {\n            front = node;\n            rear = node;\n        // \u5982\u679c\u961f\u5217\u4e0d\u4e3a\u7a7a\uff0c\u5219\u5c06\u8be5\u8282\u70b9\u6dfb\u52a0\u5230\u5c3e\u8282\u70b9\u540e\n        } else {\n            rear.next = node;\n            rear = node;\n        }\n        queSize++;\n    }\n\n    /* \u51fa\u961f */\n    public int pop() {\n        int num = peek();\n        // \u5220\u9664\u5934\u8282\u70b9\n        front = front.next;\n        queSize--;\n        return num;\n    }\n\n    /* \u8bbf\u95ee\u961f\u9996\u5143\u7d20 */\n    public int peek() {\n        if (isEmpty())\n            throw new IndexOutOfBoundsException();\n        return front.val;\n    }\n\n    /* \u5c06\u94fe\u8868\u8f6c\u5316\u4e3a Array \u5e76\u8fd4\u56de */\n    public int[] toArray() {\n        ListNode node = front;\n        int[] res = new int[size()];\n        for (int i = 0; i < res.length; i++) {\n            res[i] = node.val;\n            node = node.next;\n        }\n        return res;\n    }\n}\n
linkedlist_queue.cs
/* \u57fa\u4e8e\u94fe\u8868\u5b9e\u73b0\u7684\u961f\u5217 */\nclass LinkedListQueue {\n    ListNode? front, rear;  // \u5934\u8282\u70b9 front \uff0c\u5c3e\u8282\u70b9 rear \n    int queSize = 0;\n\n    public LinkedListQueue() {\n        front = null;\n        rear = null;\n    }\n\n    /* \u83b7\u53d6\u961f\u5217\u7684\u957f\u5ea6 */\n    public int Size() {\n        return queSize;\n    }\n\n    /* \u5224\u65ad\u961f\u5217\u662f\u5426\u4e3a\u7a7a */\n    public bool IsEmpty() {\n        return Size() == 0;\n    }\n\n    /* \u5165\u961f */\n    public void Push(int num) {\n        // \u5728\u5c3e\u8282\u70b9\u540e\u6dfb\u52a0 num\n        ListNode node = new(num);\n        // \u5982\u679c\u961f\u5217\u4e3a\u7a7a\uff0c\u5219\u4ee4\u5934\u3001\u5c3e\u8282\u70b9\u90fd\u6307\u5411\u8be5\u8282\u70b9\n        if (front == null) {\n            front = node;\n            rear = node;\n            // \u5982\u679c\u961f\u5217\u4e0d\u4e3a\u7a7a\uff0c\u5219\u5c06\u8be5\u8282\u70b9\u6dfb\u52a0\u5230\u5c3e\u8282\u70b9\u540e\n        } else if (rear != null) {\n            rear.next = node;\n            rear = node;\n        }\n        queSize++;\n    }\n\n    /* \u51fa\u961f */\n    public int Pop() {\n        int num = Peek();\n        // \u5220\u9664\u5934\u8282\u70b9\n        front = front?.next;\n        queSize--;\n        return num;\n    }\n\n    /* \u8bbf\u95ee\u961f\u9996\u5143\u7d20 */\n    public int Peek() {\n        if (IsEmpty())\n            throw new Exception();\n        return front!.val;\n    }\n\n    /* \u5c06\u94fe\u8868\u8f6c\u5316\u4e3a Array \u5e76\u8fd4\u56de */\n    public int[] ToArray() {\n        if (front == null)\n            return [];\n\n        ListNode? node = front;\n        int[] res = new int[Size()];\n        for (int i = 0; i < res.Length; i++) {\n            res[i] = node!.val;\n            node = node.next;\n        }\n        return res;\n    }\n}\n
linkedlist_queue.go
/* \u57fa\u4e8e\u94fe\u8868\u5b9e\u73b0\u7684\u961f\u5217 */\ntype linkedListQueue struct {\n    // \u4f7f\u7528\u5185\u7f6e\u5305 list \u6765\u5b9e\u73b0\u961f\u5217\n    data *list.List\n}\n\n/* \u521d\u59cb\u5316\u961f\u5217 */\nfunc newLinkedListQueue() *linkedListQueue {\n    return &linkedListQueue{\n        data: list.New(),\n    }\n}\n\n/* \u5165\u961f */\nfunc (s *linkedListQueue) push(value any) {\n    s.data.PushBack(value)\n}\n\n/* \u51fa\u961f */\nfunc (s *linkedListQueue) pop() any {\n    if s.isEmpty() {\n        return nil\n    }\n    e := s.data.Front()\n    s.data.Remove(e)\n    return e.Value\n}\n\n/* \u8bbf\u95ee\u961f\u9996\u5143\u7d20 */\nfunc (s *linkedListQueue) peek() any {\n    if s.isEmpty() {\n        return nil\n    }\n    e := s.data.Front()\n    return e.Value\n}\n\n/* \u83b7\u53d6\u961f\u5217\u7684\u957f\u5ea6 */\nfunc (s *linkedListQueue) size() int {\n    return s.data.Len()\n}\n\n/* \u5224\u65ad\u961f\u5217\u662f\u5426\u4e3a\u7a7a */\nfunc (s *linkedListQueue) isEmpty() bool {\n    return s.data.Len() == 0\n}\n\n/* \u83b7\u53d6 List \u7528\u4e8e\u6253\u5370 */\nfunc (s *linkedListQueue) toList() *list.List {\n    return s.data\n}\n
linkedlist_queue.swift
/* \u57fa\u4e8e\u94fe\u8868\u5b9e\u73b0\u7684\u961f\u5217 */\nclass LinkedListQueue {\n    private var front: ListNode? // \u5934\u8282\u70b9\n    private var rear: ListNode? // \u5c3e\u8282\u70b9\n    private var _size: Int\n\n    init() {\n        _size = 0\n    }\n\n    /* \u83b7\u53d6\u961f\u5217\u7684\u957f\u5ea6 */\n    func size() -> Int {\n        _size\n    }\n\n    /* \u5224\u65ad\u961f\u5217\u662f\u5426\u4e3a\u7a7a */\n    func isEmpty() -> Bool {\n        size() == 0\n    }\n\n    /* \u5165\u961f */\n    func push(num: Int) {\n        // \u5728\u5c3e\u8282\u70b9\u540e\u6dfb\u52a0 num\n        let node = ListNode(x: num)\n        // \u5982\u679c\u961f\u5217\u4e3a\u7a7a\uff0c\u5219\u4ee4\u5934\u3001\u5c3e\u8282\u70b9\u90fd\u6307\u5411\u8be5\u8282\u70b9\n        if front == nil {\n            front = node\n            rear = node\n        }\n        // \u5982\u679c\u961f\u5217\u4e0d\u4e3a\u7a7a\uff0c\u5219\u5c06\u8be5\u8282\u70b9\u6dfb\u52a0\u5230\u5c3e\u8282\u70b9\u540e\n        else {\n            rear?.next = node\n            rear = node\n        }\n        _size += 1\n    }\n\n    /* \u51fa\u961f */\n    @discardableResult\n    func pop() -> Int {\n        let num = peek()\n        // \u5220\u9664\u5934\u8282\u70b9\n        front = front?.next\n        _size -= 1\n        return num\n    }\n\n    /* \u8bbf\u95ee\u961f\u9996\u5143\u7d20 */\n    func peek() -> Int {\n        if isEmpty() {\n            fatalError(\"\u961f\u5217\u4e3a\u7a7a\")\n        }\n        return front!.val\n    }\n\n    /* \u5c06\u94fe\u8868\u8f6c\u5316\u4e3a Array \u5e76\u8fd4\u56de */\n    func toArray() -> [Int] {\n        var node = front\n        var res = Array(repeating: 0, count: size())\n        for i in res.indices {\n            res[i] = node!.val\n            node = node?.next\n        }\n        return res\n    }\n}\n
linkedlist_queue.js
/* \u57fa\u4e8e\u94fe\u8868\u5b9e\u73b0\u7684\u961f\u5217 */\nclass LinkedListQueue {\n    #front; // \u5934\u8282\u70b9 #front\n    #rear; // \u5c3e\u8282\u70b9 #rear\n    #queSize = 0;\n\n    constructor() {\n        this.#front = null;\n        this.#rear = null;\n    }\n\n    /* \u83b7\u53d6\u961f\u5217\u7684\u957f\u5ea6 */\n    get size() {\n        return this.#queSize;\n    }\n\n    /* \u5224\u65ad\u961f\u5217\u662f\u5426\u4e3a\u7a7a */\n    isEmpty() {\n        return this.size === 0;\n    }\n\n    /* \u5165\u961f */\n    push(num) {\n        // \u5728\u5c3e\u8282\u70b9\u540e\u6dfb\u52a0 num\n        const node = new ListNode(num);\n        // \u5982\u679c\u961f\u5217\u4e3a\u7a7a\uff0c\u5219\u4ee4\u5934\u3001\u5c3e\u8282\u70b9\u90fd\u6307\u5411\u8be5\u8282\u70b9\n        if (!this.#front) {\n            this.#front = node;\n            this.#rear = node;\n            // \u5982\u679c\u961f\u5217\u4e0d\u4e3a\u7a7a\uff0c\u5219\u5c06\u8be5\u8282\u70b9\u6dfb\u52a0\u5230\u5c3e\u8282\u70b9\u540e\n        } else {\n            this.#rear.next = node;\n            this.#rear = node;\n        }\n        this.#queSize++;\n    }\n\n    /* \u51fa\u961f */\n    pop() {\n        const num = this.peek();\n        // \u5220\u9664\u5934\u8282\u70b9\n        this.#front = this.#front.next;\n        this.#queSize--;\n        return num;\n    }\n\n    /* \u8bbf\u95ee\u961f\u9996\u5143\u7d20 */\n    peek() {\n        if (this.size === 0) throw new Error('\u961f\u5217\u4e3a\u7a7a');\n        return this.#front.val;\n    }\n\n    /* \u5c06\u94fe\u8868\u8f6c\u5316\u4e3a Array \u5e76\u8fd4\u56de */\n    toArray() {\n        let node = this.#front;\n        const res = new Array(this.size);\n        for (let i = 0; i < res.length; i++) {\n            res[i] = node.val;\n            node = node.next;\n        }\n        return res;\n    }\n}\n
linkedlist_queue.ts
/* \u57fa\u4e8e\u94fe\u8868\u5b9e\u73b0\u7684\u961f\u5217 */\nclass LinkedListQueue {\n    private front: ListNode | null; // \u5934\u8282\u70b9 front\n    private rear: ListNode | null; // \u5c3e\u8282\u70b9 rear\n    private queSize: number = 0;\n\n    constructor() {\n        this.front = null;\n        this.rear = null;\n    }\n\n    /* \u83b7\u53d6\u961f\u5217\u7684\u957f\u5ea6 */\n    get size(): number {\n        return this.queSize;\n    }\n\n    /* \u5224\u65ad\u961f\u5217\u662f\u5426\u4e3a\u7a7a */\n    isEmpty(): boolean {\n        return this.size === 0;\n    }\n\n    /* \u5165\u961f */\n    push(num: number): void {\n        // \u5728\u5c3e\u8282\u70b9\u540e\u6dfb\u52a0 num\n        const node = new ListNode(num);\n        // \u5982\u679c\u961f\u5217\u4e3a\u7a7a\uff0c\u5219\u4ee4\u5934\u3001\u5c3e\u8282\u70b9\u90fd\u6307\u5411\u8be5\u8282\u70b9\n        if (!this.front) {\n            this.front = node;\n            this.rear = node;\n            // \u5982\u679c\u961f\u5217\u4e0d\u4e3a\u7a7a\uff0c\u5219\u5c06\u8be5\u8282\u70b9\u6dfb\u52a0\u5230\u5c3e\u8282\u70b9\u540e\n        } else {\n            this.rear!.next = node;\n            this.rear = node;\n        }\n        this.queSize++;\n    }\n\n    /* \u51fa\u961f */\n    pop(): number {\n        const num = this.peek();\n        if (!this.front) throw new Error('\u961f\u5217\u4e3a\u7a7a');\n        // \u5220\u9664\u5934\u8282\u70b9\n        this.front = this.front.next;\n        this.queSize--;\n        return num;\n    }\n\n    /* \u8bbf\u95ee\u961f\u9996\u5143\u7d20 */\n    peek(): number {\n        if (this.size === 0) throw new Error('\u961f\u5217\u4e3a\u7a7a');\n        return this.front!.val;\n    }\n\n    /* \u5c06\u94fe\u8868\u8f6c\u5316\u4e3a Array \u5e76\u8fd4\u56de */\n    toArray(): number[] {\n        let node = this.front;\n        const res = new Array<number>(this.size);\n        for (let i = 0; i < res.length; i++) {\n            res[i] = node!.val;\n            node = node!.next;\n        }\n        return res;\n    }\n}\n
linkedlist_queue.dart
/* \u57fa\u4e8e\u94fe\u8868\u5b9e\u73b0\u7684\u961f\u5217 */\nclass LinkedListQueue {\n  ListNode? _front; // \u5934\u8282\u70b9 _front\n  ListNode? _rear; // \u5c3e\u8282\u70b9 _rear\n  int _queSize = 0; // \u961f\u5217\u957f\u5ea6\n\n  LinkedListQueue() {\n    _front = null;\n    _rear = null;\n  }\n\n  /* \u83b7\u53d6\u961f\u5217\u7684\u957f\u5ea6 */\n  int size() {\n    return _queSize;\n  }\n\n  /* \u5224\u65ad\u961f\u5217\u662f\u5426\u4e3a\u7a7a */\n  bool isEmpty() {\n    return _queSize == 0;\n  }\n\n  /* \u5165\u961f */\n  void push(int _num) {\n    // \u5728\u5c3e\u8282\u70b9\u540e\u6dfb\u52a0 _num\n    final node = ListNode(_num);\n    // \u5982\u679c\u961f\u5217\u4e3a\u7a7a\uff0c\u5219\u4ee4\u5934\u3001\u5c3e\u8282\u70b9\u90fd\u6307\u5411\u8be5\u8282\u70b9\n    if (_front == null) {\n      _front = node;\n      _rear = node;\n    } else {\n      // \u5982\u679c\u961f\u5217\u4e0d\u4e3a\u7a7a\uff0c\u5219\u5c06\u8be5\u8282\u70b9\u6dfb\u52a0\u5230\u5c3e\u8282\u70b9\u540e\n      _rear!.next = node;\n      _rear = node;\n    }\n    _queSize++;\n  }\n\n  /* \u51fa\u961f */\n  int pop() {\n    final int _num = peek();\n    // \u5220\u9664\u5934\u8282\u70b9\n    _front = _front!.next;\n    _queSize--;\n    return _num;\n  }\n\n  /* \u8bbf\u95ee\u961f\u9996\u5143\u7d20 */\n  int peek() {\n    if (_queSize == 0) {\n      throw Exception('\u961f\u5217\u4e3a\u7a7a');\n    }\n    return _front!.val;\n  }\n\n  /* \u5c06\u94fe\u8868\u8f6c\u5316\u4e3a Array \u5e76\u8fd4\u56de */\n  List<int> toArray() {\n    ListNode? node = _front;\n    final List<int> queue = [];\n    while (node != null) {\n      queue.add(node.val);\n      node = node.next;\n    }\n    return queue;\n  }\n}\n
linkedlist_queue.rs
/* \u57fa\u4e8e\u94fe\u8868\u5b9e\u73b0\u7684\u961f\u5217 */\n#[allow(dead_code)]\npub struct LinkedListQueue<T> {\n    front: Option<Rc<RefCell<ListNode<T>>>>, // \u5934\u8282\u70b9 front\n    rear: Option<Rc<RefCell<ListNode<T>>>>,  // \u5c3e\u8282\u70b9 rear\n    que_size: usize,                         // \u961f\u5217\u7684\u957f\u5ea6\n}\n\nimpl<T: Copy> LinkedListQueue<T> {\n    pub fn new() -> Self {\n        Self {\n            front: None,\n            rear: None,\n            que_size: 0,\n        }\n    }\n\n    /* \u83b7\u53d6\u961f\u5217\u7684\u957f\u5ea6 */\n    pub fn size(&self) -> usize {\n        return self.que_size;\n    }\n\n    /* \u5224\u65ad\u961f\u5217\u662f\u5426\u4e3a\u7a7a */\n    pub fn is_empty(&self) -> bool {\n        return self.size() == 0;\n    }\n\n    /* \u5165\u961f */\n    pub fn push(&mut self, num: T) {\n        // \u5728\u5c3e\u8282\u70b9\u540e\u6dfb\u52a0 num\n        let new_rear = ListNode::new(num);\n        match self.rear.take() {\n            // \u5982\u679c\u961f\u5217\u4e0d\u4e3a\u7a7a\uff0c\u5219\u5c06\u8be5\u8282\u70b9\u6dfb\u52a0\u5230\u5c3e\u8282\u70b9\u540e\n            Some(old_rear) => {\n                old_rear.borrow_mut().next = Some(new_rear.clone());\n                self.rear = Some(new_rear);\n            }\n            // \u5982\u679c\u961f\u5217\u4e3a\u7a7a\uff0c\u5219\u4ee4\u5934\u3001\u5c3e\u8282\u70b9\u90fd\u6307\u5411\u8be5\u8282\u70b9\n            None => {\n                self.front = Some(new_rear.clone());\n                self.rear = Some(new_rear);\n            }\n        }\n        self.que_size += 1;\n    }\n\n    /* \u51fa\u961f */\n    pub fn pop(&mut self) -> Option<T> {\n        self.front.take().map(|old_front| {\n            match old_front.borrow_mut().next.take() {\n                Some(new_front) => {\n                    self.front = Some(new_front);\n                }\n                None => {\n                    self.rear.take();\n                }\n            }\n            self.que_size -= 1;\n            Rc::try_unwrap(old_front).ok().unwrap().into_inner().val\n        })\n    }\n\n    /* \u8bbf\u95ee\u961f\u9996\u5143\u7d20 */\n    pub fn peek(&self) -> Option<&Rc<RefCell<ListNode<T>>>> {\n        self.front.as_ref()\n    }\n\n    /* \u5c06\u94fe\u8868\u8f6c\u5316\u4e3a Array \u5e76\u8fd4\u56de */\n    pub fn to_array(&self, head: Option<&Rc<RefCell<ListNode<T>>>>) -> Vec<T> {\n        if let Some(node) = head {\n            let mut nums = self.to_array(node.borrow().next.as_ref());\n            nums.insert(0, node.borrow().val);\n            return nums;\n        }\n        return Vec::new();\n    }\n}\n
linkedlist_queue.c
/* \u57fa\u4e8e\u94fe\u8868\u5b9e\u73b0\u7684\u961f\u5217 */\ntypedef struct {\n    ListNode *front, *rear;\n    int queSize;\n} LinkedListQueue;\n\n/* \u6784\u9020\u51fd\u6570 */\nLinkedListQueue *newLinkedListQueue() {\n    LinkedListQueue *queue = (LinkedListQueue *)malloc(sizeof(LinkedListQueue));\n    queue->front = NULL;\n    queue->rear = NULL;\n    queue->queSize = 0;\n    return queue;\n}\n\n/* \u6790\u6784\u51fd\u6570 */\nvoid delLinkedListQueue(LinkedListQueue *queue) {\n    // \u91ca\u653e\u6240\u6709\u8282\u70b9\n    while (queue->front != NULL) {\n        ListNode *tmp = queue->front;\n        queue->front = queue->front->next;\n        free(tmp);\n    }\n    // \u91ca\u653e queue \u7ed3\u6784\u4f53\n    free(queue);\n}\n\n/* \u83b7\u53d6\u961f\u5217\u7684\u957f\u5ea6 */\nint size(LinkedListQueue *queue) {\n    return queue->queSize;\n}\n\n/* \u5224\u65ad\u961f\u5217\u662f\u5426\u4e3a\u7a7a */\nbool empty(LinkedListQueue *queue) {\n    return (size(queue) == 0);\n}\n\n/* \u5165\u961f */\nvoid push(LinkedListQueue *queue, int num) {\n    // \u5c3e\u8282\u70b9\u5904\u6dfb\u52a0 node\n    ListNode *node = newListNode(num);\n    // \u5982\u679c\u961f\u5217\u4e3a\u7a7a\uff0c\u5219\u4ee4\u5934\u3001\u5c3e\u8282\u70b9\u90fd\u6307\u5411\u8be5\u8282\u70b9\n    if (queue->front == NULL) {\n        queue->front = node;\n        queue->rear = node;\n    }\n    // \u5982\u679c\u961f\u5217\u4e0d\u4e3a\u7a7a\uff0c\u5219\u5c06\u8be5\u8282\u70b9\u6dfb\u52a0\u5230\u5c3e\u8282\u70b9\u540e\n    else {\n        queue->rear->next = node;\n        queue->rear = node;\n    }\n    queue->queSize++;\n}\n\n/* \u8bbf\u95ee\u961f\u9996\u5143\u7d20 */\nint peek(LinkedListQueue *queue) {\n    assert(size(queue) && queue->front);\n    return queue->front->val;\n}\n\n/* \u51fa\u961f */\nint pop(LinkedListQueue *queue) {\n    int num = peek(queue);\n    ListNode *tmp = queue->front;\n    queue->front = queue->front->next;\n    free(tmp);\n    queue->queSize--;\n    return num;\n}\n\n/* \u6253\u5370\u961f\u5217 */\nvoid printLinkedListQueue(LinkedListQueue *queue) {\n    int *arr = malloc(sizeof(int) * queue->queSize);\n    // \u62f7\u8d1d\u94fe\u8868\u4e2d\u7684\u6570\u636e\u5230\u6570\u7ec4\n    int i;\n    ListNode *node;\n    for (i = 0, node = queue->front; i < queue->queSize; i++) {\n        arr[i] = node->val;\n        node = node->next;\n    }\n    printArray(arr, queue->queSize);\n    free(arr);\n}\n
linkedlist_queue.zig
// \u57fa\u4e8e\u94fe\u8868\u5b9e\u73b0\u7684\u961f\u5217\nfn LinkedListQueue(comptime T: type) type {\n    return struct {\n        const Self = @This();\n\n        front: ?*inc.ListNode(T) = null,                // \u5934\u8282\u70b9 front\n        rear: ?*inc.ListNode(T) = null,                 // \u5c3e\u8282\u70b9 rear\n        que_size: usize = 0,                            // \u961f\u5217\u7684\u957f\u5ea6\n        mem_arena: ?std.heap.ArenaAllocator = null,\n        mem_allocator: std.mem.Allocator = undefined,   // \u5185\u5b58\u5206\u914d\u5668\n\n        // \u6784\u9020\u51fd\u6570\uff08\u5206\u914d\u5185\u5b58+\u521d\u59cb\u5316\u961f\u5217\uff09\n        pub fn init(self: *Self, allocator: std.mem.Allocator) !void {\n            if (self.mem_arena == null) {\n                self.mem_arena = std.heap.ArenaAllocator.init(allocator);\n                self.mem_allocator = self.mem_arena.?.allocator();\n            }\n            self.front = null;\n            self.rear = null;\n            self.que_size = 0;\n        }\n\n        // \u6790\u6784\u51fd\u6570\uff08\u91ca\u653e\u5185\u5b58\uff09\n        pub fn deinit(self: *Self) void {\n            if (self.mem_arena == null) return;\n            self.mem_arena.?.deinit();\n        }\n\n        // \u83b7\u53d6\u961f\u5217\u7684\u957f\u5ea6\n        pub fn size(self: *Self) usize {\n            return self.que_size;\n        }\n\n        // \u5224\u65ad\u961f\u5217\u662f\u5426\u4e3a\u7a7a\n        pub fn isEmpty(self: *Self) bool {\n            return self.size() == 0;\n        }\n\n        // \u8bbf\u95ee\u961f\u9996\u5143\u7d20\n        pub fn peek(self: *Self) T {\n            if (self.size() == 0) @panic(\"\u961f\u5217\u4e3a\u7a7a\");\n            return self.front.?.val;\n        }  \n\n        // \u5165\u961f\n        pub fn push(self: *Self, num: T) !void {\n            // \u5728\u5c3e\u8282\u70b9\u540e\u6dfb\u52a0 num\n            var node = try self.mem_allocator.create(inc.ListNode(T));\n            node.init(num);\n            // \u5982\u679c\u961f\u5217\u4e3a\u7a7a\uff0c\u5219\u4ee4\u5934\u3001\u5c3e\u8282\u70b9\u90fd\u6307\u5411\u8be5\u8282\u70b9\n            if (self.front == null) {\n                self.front = node;\n                self.rear = node;\n            // \u5982\u679c\u961f\u5217\u4e0d\u4e3a\u7a7a\uff0c\u5219\u5c06\u8be5\u8282\u70b9\u6dfb\u52a0\u5230\u5c3e\u8282\u70b9\u540e\n            } else {\n                self.rear.?.next = node;\n                self.rear = node;\n            }\n            self.que_size += 1;\n        } \n\n        // \u51fa\u961f\n        pub fn pop(self: *Self) T {\n            var num = self.peek();\n            // \u5220\u9664\u5934\u8282\u70b9\n            self.front = self.front.?.next;\n            self.que_size -= 1;\n            return num;\n        } \n\n        // \u5c06\u94fe\u8868\u8f6c\u6362\u4e3a\u6570\u7ec4\n        pub fn toArray(self: *Self) ![]T {\n            var node = self.front;\n            var res = try self.mem_allocator.alloc(T, self.size());\n            @memset(res, @as(T, 0));\n            var i: usize = 0;\n            while (i < res.len) : (i += 1) {\n                res[i] = node.?.val;\n                node = node.?.next;\n            }\n            return res;\n        }\n    };\n}\n
Code Visualization

Full Screen >

"},{"location":"chapter_stack_and_queue/queue/#2-implementation-based-on-an-array","title":"2. \u00a0 Implementation Based on an Array","text":"

Deleting the first element in an array has a time complexity of \\(O(n)\\), which would make the dequeue operation inefficient. However, this problem can be cleverly avoided as follows.

We use a variable front to indicate the index of the front element and maintain a variable size to record the queue's length. Define rear = front + size, which points to the position immediately following the tail element.

With this design, the effective interval of elements in the array is [front, rear - 1]. The implementation methods for various operations are shown in the Figure 5-6 .

  • Enqueue operation: Assign the input element to the rear index and increase size by 1.
  • Dequeue operation: Simply increase front by 1 and decrease size by 1.

Both enqueue and dequeue operations only require a single operation, each with a time complexity of \\(O(1)\\).

ArrayQueuepush()pop()

Figure 5-6 \u00a0 Implementing Queue with Array for Enqueue and Dequeue Operations

You might notice a problem: as enqueue and dequeue operations are continuously performed, both front and rear move to the right and will eventually reach the end of the array and can't move further. To resolve this, we can treat the array as a \"circular array\" where connecting the end of the array back to its beginning.

In a circular array, front or rear needs to loop back to the start of the array upon reaching the end. This cyclical pattern can be achieved with a \"modulo operation\" as shown in the code below:

PythonC++JavaC#GoSwiftJSTSDartRustCZig array_queue.py
class ArrayQueue:\n    \"\"\"\u57fa\u4e8e\u73af\u5f62\u6570\u7ec4\u5b9e\u73b0\u7684\u961f\u5217\"\"\"\n\n    def __init__(self, size: int):\n        \"\"\"\u6784\u9020\u65b9\u6cd5\"\"\"\n        self._nums: list[int] = [0] * size  # \u7528\u4e8e\u5b58\u50a8\u961f\u5217\u5143\u7d20\u7684\u6570\u7ec4\n        self._front: int = 0  # \u961f\u9996\u6307\u9488\uff0c\u6307\u5411\u961f\u9996\u5143\u7d20\n        self._size: int = 0  # \u961f\u5217\u957f\u5ea6\n\n    def capacity(self) -> int:\n        \"\"\"\u83b7\u53d6\u961f\u5217\u7684\u5bb9\u91cf\"\"\"\n        return len(self._nums)\n\n    def size(self) -> int:\n        \"\"\"\u83b7\u53d6\u961f\u5217\u7684\u957f\u5ea6\"\"\"\n        return self._size\n\n    def is_empty(self) -> bool:\n        \"\"\"\u5224\u65ad\u961f\u5217\u662f\u5426\u4e3a\u7a7a\"\"\"\n        return self._size == 0\n\n    def push(self, num: int):\n        \"\"\"\u5165\u961f\"\"\"\n        if self._size == self.capacity():\n            raise IndexError(\"\u961f\u5217\u5df2\u6ee1\")\n        # \u8ba1\u7b97\u961f\u5c3e\u6307\u9488\uff0c\u6307\u5411\u961f\u5c3e\u7d22\u5f15 + 1\n        # \u901a\u8fc7\u53d6\u4f59\u64cd\u4f5c\u5b9e\u73b0 rear \u8d8a\u8fc7\u6570\u7ec4\u5c3e\u90e8\u540e\u56de\u5230\u5934\u90e8\n        rear: int = (self._front + self._size) % self.capacity()\n        # \u5c06 num \u6dfb\u52a0\u81f3\u961f\u5c3e\n        self._nums[rear] = num\n        self._size += 1\n\n    def pop(self) -> int:\n        \"\"\"\u51fa\u961f\"\"\"\n        num: int = self.peek()\n        # \u961f\u9996\u6307\u9488\u5411\u540e\u79fb\u52a8\u4e00\u4f4d\uff0c\u82e5\u8d8a\u8fc7\u5c3e\u90e8\uff0c\u5219\u8fd4\u56de\u5230\u6570\u7ec4\u5934\u90e8\n        self._front = (self._front + 1) % self.capacity()\n        self._size -= 1\n        return num\n\n    def peek(self) -> int:\n        \"\"\"\u8bbf\u95ee\u961f\u9996\u5143\u7d20\"\"\"\n        if self.is_empty():\n            raise IndexError(\"\u961f\u5217\u4e3a\u7a7a\")\n        return self._nums[self._front]\n\n    def to_list(self) -> list[int]:\n        \"\"\"\u8fd4\u56de\u5217\u8868\u7528\u4e8e\u6253\u5370\"\"\"\n        res = [0] * self.size()\n        j: int = self._front\n        for i in range(self.size()):\n            res[i] = self._nums[(j % self.capacity())]\n            j += 1\n        return res\n
array_queue.cpp
/* \u57fa\u4e8e\u73af\u5f62\u6570\u7ec4\u5b9e\u73b0\u7684\u961f\u5217 */\nclass ArrayQueue {\n  private:\n    int *nums;       // \u7528\u4e8e\u5b58\u50a8\u961f\u5217\u5143\u7d20\u7684\u6570\u7ec4\n    int front;       // \u961f\u9996\u6307\u9488\uff0c\u6307\u5411\u961f\u9996\u5143\u7d20\n    int queSize;     // \u961f\u5217\u957f\u5ea6\n    int queCapacity; // \u961f\u5217\u5bb9\u91cf\n\n  public:\n    ArrayQueue(int capacity) {\n        // \u521d\u59cb\u5316\u6570\u7ec4\n        nums = new int[capacity];\n        queCapacity = capacity;\n        front = queSize = 0;\n    }\n\n    ~ArrayQueue() {\n        delete[] nums;\n    }\n\n    /* \u83b7\u53d6\u961f\u5217\u7684\u5bb9\u91cf */\n    int capacity() {\n        return queCapacity;\n    }\n\n    /* \u83b7\u53d6\u961f\u5217\u7684\u957f\u5ea6 */\n    int size() {\n        return queSize;\n    }\n\n    /* \u5224\u65ad\u961f\u5217\u662f\u5426\u4e3a\u7a7a */\n    bool isEmpty() {\n        return size() == 0;\n    }\n\n    /* \u5165\u961f */\n    void push(int num) {\n        if (queSize == queCapacity) {\n            cout << \"\u961f\u5217\u5df2\u6ee1\" << endl;\n            return;\n        }\n        // \u8ba1\u7b97\u961f\u5c3e\u6307\u9488\uff0c\u6307\u5411\u961f\u5c3e\u7d22\u5f15 + 1\n        // \u901a\u8fc7\u53d6\u4f59\u64cd\u4f5c\u5b9e\u73b0 rear \u8d8a\u8fc7\u6570\u7ec4\u5c3e\u90e8\u540e\u56de\u5230\u5934\u90e8\n        int rear = (front + queSize) % queCapacity;\n        // \u5c06 num \u6dfb\u52a0\u81f3\u961f\u5c3e\n        nums[rear] = num;\n        queSize++;\n    }\n\n    /* \u51fa\u961f */\n    int pop() {\n        int num = peek();\n        // \u961f\u9996\u6307\u9488\u5411\u540e\u79fb\u52a8\u4e00\u4f4d\uff0c\u82e5\u8d8a\u8fc7\u5c3e\u90e8\uff0c\u5219\u8fd4\u56de\u5230\u6570\u7ec4\u5934\u90e8\n        front = (front + 1) % queCapacity;\n        queSize--;\n        return num;\n    }\n\n    /* \u8bbf\u95ee\u961f\u9996\u5143\u7d20 */\n    int peek() {\n        if (isEmpty())\n            throw out_of_range(\"\u961f\u5217\u4e3a\u7a7a\");\n        return nums[front];\n    }\n\n    /* \u5c06\u6570\u7ec4\u8f6c\u5316\u4e3a Vector \u5e76\u8fd4\u56de */\n    vector<int> toVector() {\n        // \u4ec5\u8f6c\u6362\u6709\u6548\u957f\u5ea6\u8303\u56f4\u5185\u7684\u5217\u8868\u5143\u7d20\n        vector<int> arr(queSize);\n        for (int i = 0, j = front; i < queSize; i++, j++) {\n            arr[i] = nums[j % queCapacity];\n        }\n        return arr;\n    }\n};\n
array_queue.java
/* \u57fa\u4e8e\u73af\u5f62\u6570\u7ec4\u5b9e\u73b0\u7684\u961f\u5217 */\nclass ArrayQueue {\n    private int[] nums; // \u7528\u4e8e\u5b58\u50a8\u961f\u5217\u5143\u7d20\u7684\u6570\u7ec4\n    private int front; // \u961f\u9996\u6307\u9488\uff0c\u6307\u5411\u961f\u9996\u5143\u7d20\n    private int queSize; // \u961f\u5217\u957f\u5ea6\n\n    public ArrayQueue(int capacity) {\n        nums = new int[capacity];\n        front = queSize = 0;\n    }\n\n    /* \u83b7\u53d6\u961f\u5217\u7684\u5bb9\u91cf */\n    public int capacity() {\n        return nums.length;\n    }\n\n    /* \u83b7\u53d6\u961f\u5217\u7684\u957f\u5ea6 */\n    public int size() {\n        return queSize;\n    }\n\n    /* \u5224\u65ad\u961f\u5217\u662f\u5426\u4e3a\u7a7a */\n    public boolean isEmpty() {\n        return queSize == 0;\n    }\n\n    /* \u5165\u961f */\n    public void push(int num) {\n        if (queSize == capacity()) {\n            System.out.println(\"\u961f\u5217\u5df2\u6ee1\");\n            return;\n        }\n        // \u8ba1\u7b97\u961f\u5c3e\u6307\u9488\uff0c\u6307\u5411\u961f\u5c3e\u7d22\u5f15 + 1\n        // \u901a\u8fc7\u53d6\u4f59\u64cd\u4f5c\u5b9e\u73b0 rear \u8d8a\u8fc7\u6570\u7ec4\u5c3e\u90e8\u540e\u56de\u5230\u5934\u90e8\n        int rear = (front + queSize) % capacity();\n        // \u5c06 num \u6dfb\u52a0\u81f3\u961f\u5c3e\n        nums[rear] = num;\n        queSize++;\n    }\n\n    /* \u51fa\u961f */\n    public int pop() {\n        int num = peek();\n        // \u961f\u9996\u6307\u9488\u5411\u540e\u79fb\u52a8\u4e00\u4f4d\uff0c\u82e5\u8d8a\u8fc7\u5c3e\u90e8\uff0c\u5219\u8fd4\u56de\u5230\u6570\u7ec4\u5934\u90e8\n        front = (front + 1) % capacity();\n        queSize--;\n        return num;\n    }\n\n    /* \u8bbf\u95ee\u961f\u9996\u5143\u7d20 */\n    public int peek() {\n        if (isEmpty())\n            throw new IndexOutOfBoundsException();\n        return nums[front];\n    }\n\n    /* \u8fd4\u56de\u6570\u7ec4 */\n    public int[] toArray() {\n        // \u4ec5\u8f6c\u6362\u6709\u6548\u957f\u5ea6\u8303\u56f4\u5185\u7684\u5217\u8868\u5143\u7d20\n        int[] res = new int[queSize];\n        for (int i = 0, j = front; i < queSize; i++, j++) {\n            res[i] = nums[j % capacity()];\n        }\n        return res;\n    }\n}\n
array_queue.cs
/* \u57fa\u4e8e\u73af\u5f62\u6570\u7ec4\u5b9e\u73b0\u7684\u961f\u5217 */\nclass ArrayQueue {\n    int[] nums;  // \u7528\u4e8e\u5b58\u50a8\u961f\u5217\u5143\u7d20\u7684\u6570\u7ec4\n    int front;   // \u961f\u9996\u6307\u9488\uff0c\u6307\u5411\u961f\u9996\u5143\u7d20\n    int queSize; // \u961f\u5217\u957f\u5ea6\n\n    public ArrayQueue(int capacity) {\n        nums = new int[capacity];\n        front = queSize = 0;\n    }\n\n    /* \u83b7\u53d6\u961f\u5217\u7684\u5bb9\u91cf */\n    int Capacity() {\n        return nums.Length;\n    }\n\n    /* \u83b7\u53d6\u961f\u5217\u7684\u957f\u5ea6 */\n    public int Size() {\n        return queSize;\n    }\n\n    /* \u5224\u65ad\u961f\u5217\u662f\u5426\u4e3a\u7a7a */\n    public bool IsEmpty() {\n        return queSize == 0;\n    }\n\n    /* \u5165\u961f */\n    public void Push(int num) {\n        if (queSize == Capacity()) {\n            Console.WriteLine(\"\u961f\u5217\u5df2\u6ee1\");\n            return;\n        }\n        // \u8ba1\u7b97\u961f\u5c3e\u6307\u9488\uff0c\u6307\u5411\u961f\u5c3e\u7d22\u5f15 + 1\n        // \u901a\u8fc7\u53d6\u4f59\u64cd\u4f5c\u5b9e\u73b0 rear \u8d8a\u8fc7\u6570\u7ec4\u5c3e\u90e8\u540e\u56de\u5230\u5934\u90e8\n        int rear = (front + queSize) % Capacity();\n        // \u5c06 num \u6dfb\u52a0\u81f3\u961f\u5c3e\n        nums[rear] = num;\n        queSize++;\n    }\n\n    /* \u51fa\u961f */\n    public int Pop() {\n        int num = Peek();\n        // \u961f\u9996\u6307\u9488\u5411\u540e\u79fb\u52a8\u4e00\u4f4d\uff0c\u82e5\u8d8a\u8fc7\u5c3e\u90e8\uff0c\u5219\u8fd4\u56de\u5230\u6570\u7ec4\u5934\u90e8\n        front = (front + 1) % Capacity();\n        queSize--;\n        return num;\n    }\n\n    /* \u8bbf\u95ee\u961f\u9996\u5143\u7d20 */\n    public int Peek() {\n        if (IsEmpty())\n            throw new Exception();\n        return nums[front];\n    }\n\n    /* \u8fd4\u56de\u6570\u7ec4 */\n    public int[] ToArray() {\n        // \u4ec5\u8f6c\u6362\u6709\u6548\u957f\u5ea6\u8303\u56f4\u5185\u7684\u5217\u8868\u5143\u7d20\n        int[] res = new int[queSize];\n        for (int i = 0, j = front; i < queSize; i++, j++) {\n            res[i] = nums[j % this.Capacity()];\n        }\n        return res;\n    }\n}\n
array_queue.go
/* \u57fa\u4e8e\u73af\u5f62\u6570\u7ec4\u5b9e\u73b0\u7684\u961f\u5217 */\ntype arrayQueue struct {\n    nums        []int // \u7528\u4e8e\u5b58\u50a8\u961f\u5217\u5143\u7d20\u7684\u6570\u7ec4\n    front       int   // \u961f\u9996\u6307\u9488\uff0c\u6307\u5411\u961f\u9996\u5143\u7d20\n    queSize     int   // \u961f\u5217\u957f\u5ea6\n    queCapacity int   // \u961f\u5217\u5bb9\u91cf\uff08\u5373\u6700\u5927\u5bb9\u7eb3\u5143\u7d20\u6570\u91cf\uff09\n}\n\n/* \u521d\u59cb\u5316\u961f\u5217 */\nfunc newArrayQueue(queCapacity int) *arrayQueue {\n    return &arrayQueue{\n        nums:        make([]int, queCapacity),\n        queCapacity: queCapacity,\n        front:       0,\n        queSize:     0,\n    }\n}\n\n/* \u83b7\u53d6\u961f\u5217\u7684\u957f\u5ea6 */\nfunc (q *arrayQueue) size() int {\n    return q.queSize\n}\n\n/* \u5224\u65ad\u961f\u5217\u662f\u5426\u4e3a\u7a7a */\nfunc (q *arrayQueue) isEmpty() bool {\n    return q.queSize == 0\n}\n\n/* \u5165\u961f */\nfunc (q *arrayQueue) push(num int) {\n    // \u5f53 rear == queCapacity \u8868\u793a\u961f\u5217\u5df2\u6ee1\n    if q.queSize == q.queCapacity {\n        return\n    }\n    // \u8ba1\u7b97\u961f\u5c3e\u6307\u9488\uff0c\u6307\u5411\u961f\u5c3e\u7d22\u5f15 + 1\n    // \u901a\u8fc7\u53d6\u4f59\u64cd\u4f5c\u5b9e\u73b0 rear \u8d8a\u8fc7\u6570\u7ec4\u5c3e\u90e8\u540e\u56de\u5230\u5934\u90e8\n    rear := (q.front + q.queSize) % q.queCapacity\n    // \u5c06 num \u6dfb\u52a0\u81f3\u961f\u5c3e\n    q.nums[rear] = num\n    q.queSize++\n}\n\n/* \u51fa\u961f */\nfunc (q *arrayQueue) pop() any {\n    num := q.peek()\n    // \u961f\u9996\u6307\u9488\u5411\u540e\u79fb\u52a8\u4e00\u4f4d\uff0c\u82e5\u8d8a\u8fc7\u5c3e\u90e8\uff0c\u5219\u8fd4\u56de\u5230\u6570\u7ec4\u5934\u90e8\n    q.front = (q.front + 1) % q.queCapacity\n    q.queSize--\n    return num\n}\n\n/* \u8bbf\u95ee\u961f\u9996\u5143\u7d20 */\nfunc (q *arrayQueue) peek() any {\n    if q.isEmpty() {\n        return nil\n    }\n    return q.nums[q.front]\n}\n\n/* \u83b7\u53d6 Slice \u7528\u4e8e\u6253\u5370 */\nfunc (q *arrayQueue) toSlice() []int {\n    rear := (q.front + q.queSize)\n    if rear >= q.queCapacity {\n        rear %= q.queCapacity\n        return append(q.nums[q.front:], q.nums[:rear]...)\n    }\n    return q.nums[q.front:rear]\n}\n
array_queue.swift
/* \u57fa\u4e8e\u73af\u5f62\u6570\u7ec4\u5b9e\u73b0\u7684\u961f\u5217 */\nclass ArrayQueue {\n    private var nums: [Int] // \u7528\u4e8e\u5b58\u50a8\u961f\u5217\u5143\u7d20\u7684\u6570\u7ec4\n    private var front: Int // \u961f\u9996\u6307\u9488\uff0c\u6307\u5411\u961f\u9996\u5143\u7d20\n    private var _size: Int // \u961f\u5217\u957f\u5ea6\n\n    init(capacity: Int) {\n        // \u521d\u59cb\u5316\u6570\u7ec4\n        nums = Array(repeating: 0, count: capacity)\n        front = 0\n        _size = 0\n    }\n\n    /* \u83b7\u53d6\u961f\u5217\u7684\u5bb9\u91cf */\n    func capacity() -> Int {\n        nums.count\n    }\n\n    /* \u83b7\u53d6\u961f\u5217\u7684\u957f\u5ea6 */\n    func size() -> Int {\n        _size\n    }\n\n    /* \u5224\u65ad\u961f\u5217\u662f\u5426\u4e3a\u7a7a */\n    func isEmpty() -> Bool {\n        size() == 0\n    }\n\n    /* \u5165\u961f */\n    func push(num: Int) {\n        if size() == capacity() {\n            print(\"\u961f\u5217\u5df2\u6ee1\")\n            return\n        }\n        // \u8ba1\u7b97\u961f\u5c3e\u6307\u9488\uff0c\u6307\u5411\u961f\u5c3e\u7d22\u5f15 + 1\n        // \u901a\u8fc7\u53d6\u4f59\u64cd\u4f5c\u5b9e\u73b0 rear \u8d8a\u8fc7\u6570\u7ec4\u5c3e\u90e8\u540e\u56de\u5230\u5934\u90e8\n        let rear = (front + size()) % capacity()\n        // \u5c06 num \u6dfb\u52a0\u81f3\u961f\u5c3e\n        nums[rear] = num\n        _size += 1\n    }\n\n    /* \u51fa\u961f */\n    @discardableResult\n    func pop() -> Int {\n        let num = peek()\n        // \u961f\u9996\u6307\u9488\u5411\u540e\u79fb\u52a8\u4e00\u4f4d\uff0c\u82e5\u8d8a\u8fc7\u5c3e\u90e8\uff0c\u5219\u8fd4\u56de\u5230\u6570\u7ec4\u5934\u90e8\n        front = (front + 1) % capacity()\n        _size -= 1\n        return num\n    }\n\n    /* \u8bbf\u95ee\u961f\u9996\u5143\u7d20 */\n    func peek() -> Int {\n        if isEmpty() {\n            fatalError(\"\u961f\u5217\u4e3a\u7a7a\")\n        }\n        return nums[front]\n    }\n\n    /* \u8fd4\u56de\u6570\u7ec4 */\n    func toArray() -> [Int] {\n        // \u4ec5\u8f6c\u6362\u6709\u6548\u957f\u5ea6\u8303\u56f4\u5185\u7684\u5217\u8868\u5143\u7d20\n        (front ..< front + size()).map { nums[$0 % capacity()] }\n    }\n}\n
array_queue.js
/* \u57fa\u4e8e\u73af\u5f62\u6570\u7ec4\u5b9e\u73b0\u7684\u961f\u5217 */\nclass ArrayQueue {\n    #nums; // \u7528\u4e8e\u5b58\u50a8\u961f\u5217\u5143\u7d20\u7684\u6570\u7ec4\n    #front = 0; // \u961f\u9996\u6307\u9488\uff0c\u6307\u5411\u961f\u9996\u5143\u7d20\n    #queSize = 0; // \u961f\u5217\u957f\u5ea6\n\n    constructor(capacity) {\n        this.#nums = new Array(capacity);\n    }\n\n    /* \u83b7\u53d6\u961f\u5217\u7684\u5bb9\u91cf */\n    get capacity() {\n        return this.#nums.length;\n    }\n\n    /* \u83b7\u53d6\u961f\u5217\u7684\u957f\u5ea6 */\n    get size() {\n        return this.#queSize;\n    }\n\n    /* \u5224\u65ad\u961f\u5217\u662f\u5426\u4e3a\u7a7a */\n    isEmpty() {\n        return this.#queSize === 0;\n    }\n\n    /* \u5165\u961f */\n    push(num) {\n        if (this.size === this.capacity) {\n            console.log('\u961f\u5217\u5df2\u6ee1');\n            return;\n        }\n        // \u8ba1\u7b97\u961f\u5c3e\u6307\u9488\uff0c\u6307\u5411\u961f\u5c3e\u7d22\u5f15 + 1\n        // \u901a\u8fc7\u53d6\u4f59\u64cd\u4f5c\u5b9e\u73b0 rear \u8d8a\u8fc7\u6570\u7ec4\u5c3e\u90e8\u540e\u56de\u5230\u5934\u90e8\n        const rear = (this.#front + this.size) % this.capacity;\n        // \u5c06 num \u6dfb\u52a0\u81f3\u961f\u5c3e\n        this.#nums[rear] = num;\n        this.#queSize++;\n    }\n\n    /* \u51fa\u961f */\n    pop() {\n        const num = this.peek();\n        // \u961f\u9996\u6307\u9488\u5411\u540e\u79fb\u52a8\u4e00\u4f4d\uff0c\u82e5\u8d8a\u8fc7\u5c3e\u90e8\uff0c\u5219\u8fd4\u56de\u5230\u6570\u7ec4\u5934\u90e8\n        this.#front = (this.#front + 1) % this.capacity;\n        this.#queSize--;\n        return num;\n    }\n\n    /* \u8bbf\u95ee\u961f\u9996\u5143\u7d20 */\n    peek() {\n        if (this.isEmpty()) throw new Error('\u961f\u5217\u4e3a\u7a7a');\n        return this.#nums[this.#front];\n    }\n\n    /* \u8fd4\u56de Array */\n    toArray() {\n        // \u4ec5\u8f6c\u6362\u6709\u6548\u957f\u5ea6\u8303\u56f4\u5185\u7684\u5217\u8868\u5143\u7d20\n        const arr = new Array(this.size);\n        for (let i = 0, j = this.#front; i < this.size; i++, j++) {\n            arr[i] = this.#nums[j % this.capacity];\n        }\n        return arr;\n    }\n}\n
array_queue.ts
/* \u57fa\u4e8e\u73af\u5f62\u6570\u7ec4\u5b9e\u73b0\u7684\u961f\u5217 */\nclass ArrayQueue {\n    private nums: number[]; // \u7528\u4e8e\u5b58\u50a8\u961f\u5217\u5143\u7d20\u7684\u6570\u7ec4\n    private front: number; // \u961f\u9996\u6307\u9488\uff0c\u6307\u5411\u961f\u9996\u5143\u7d20\n    private queSize: number; // \u961f\u5217\u957f\u5ea6\n\n    constructor(capacity: number) {\n        this.nums = new Array(capacity);\n        this.front = this.queSize = 0;\n    }\n\n    /* \u83b7\u53d6\u961f\u5217\u7684\u5bb9\u91cf */\n    get capacity(): number {\n        return this.nums.length;\n    }\n\n    /* \u83b7\u53d6\u961f\u5217\u7684\u957f\u5ea6 */\n    get size(): number {\n        return this.queSize;\n    }\n\n    /* \u5224\u65ad\u961f\u5217\u662f\u5426\u4e3a\u7a7a */\n    isEmpty(): boolean {\n        return this.queSize === 0;\n    }\n\n    /* \u5165\u961f */\n    push(num: number): void {\n        if (this.size === this.capacity) {\n            console.log('\u961f\u5217\u5df2\u6ee1');\n            return;\n        }\n        // \u8ba1\u7b97\u961f\u5c3e\u6307\u9488\uff0c\u6307\u5411\u961f\u5c3e\u7d22\u5f15 + 1\n        // \u901a\u8fc7\u53d6\u4f59\u64cd\u4f5c\u5b9e\u73b0 rear \u8d8a\u8fc7\u6570\u7ec4\u5c3e\u90e8\u540e\u56de\u5230\u5934\u90e8\n        const rear = (this.front + this.queSize) % this.capacity;\n        // \u5c06 num \u6dfb\u52a0\u81f3\u961f\u5c3e\n        this.nums[rear] = num;\n        this.queSize++;\n    }\n\n    /* \u51fa\u961f */\n    pop(): number {\n        const num = this.peek();\n        // \u961f\u9996\u6307\u9488\u5411\u540e\u79fb\u52a8\u4e00\u4f4d\uff0c\u82e5\u8d8a\u8fc7\u5c3e\u90e8\uff0c\u5219\u8fd4\u56de\u5230\u6570\u7ec4\u5934\u90e8\n        this.front = (this.front + 1) % this.capacity;\n        this.queSize--;\n        return num;\n    }\n\n    /* \u8bbf\u95ee\u961f\u9996\u5143\u7d20 */\n    peek(): number {\n        if (this.isEmpty()) throw new Error('\u961f\u5217\u4e3a\u7a7a');\n        return this.nums[this.front];\n    }\n\n    /* \u8fd4\u56de Array */\n    toArray(): number[] {\n        // \u4ec5\u8f6c\u6362\u6709\u6548\u957f\u5ea6\u8303\u56f4\u5185\u7684\u5217\u8868\u5143\u7d20\n        const arr = new Array(this.size);\n        for (let i = 0, j = this.front; i < this.size; i++, j++) {\n            arr[i] = this.nums[j % this.capacity];\n        }\n        return arr;\n    }\n}\n
array_queue.dart
/* \u57fa\u4e8e\u73af\u5f62\u6570\u7ec4\u5b9e\u73b0\u7684\u961f\u5217 */\nclass ArrayQueue {\n  late List<int> _nums; // \u7528\u4e8e\u50a8\u5b58\u961f\u5217\u5143\u7d20\u7684\u6570\u7ec4\n  late int _front; // \u961f\u9996\u6307\u9488\uff0c\u6307\u5411\u961f\u9996\u5143\u7d20\n  late int _queSize; // \u961f\u5217\u957f\u5ea6\n\n  ArrayQueue(int capacity) {\n    _nums = List.filled(capacity, 0);\n    _front = _queSize = 0;\n  }\n\n  /* \u83b7\u53d6\u961f\u5217\u7684\u5bb9\u91cf */\n  int capaCity() {\n    return _nums.length;\n  }\n\n  /* \u83b7\u53d6\u961f\u5217\u7684\u957f\u5ea6 */\n  int size() {\n    return _queSize;\n  }\n\n  /* \u5224\u65ad\u961f\u5217\u662f\u5426\u4e3a\u7a7a */\n  bool isEmpty() {\n    return _queSize == 0;\n  }\n\n  /* \u5165\u961f */\n  void push(int _num) {\n    if (_queSize == capaCity()) {\n      throw Exception(\"\u961f\u5217\u5df2\u6ee1\");\n    }\n    // \u8ba1\u7b97\u961f\u5c3e\u6307\u9488\uff0c\u6307\u5411\u961f\u5c3e\u7d22\u5f15 + 1\n    // \u901a\u8fc7\u53d6\u4f59\u64cd\u4f5c\u5b9e\u73b0 rear \u8d8a\u8fc7\u6570\u7ec4\u5c3e\u90e8\u540e\u56de\u5230\u5934\u90e8\n    int rear = (_front + _queSize) % capaCity();\n    // \u5c06 _num \u6dfb\u52a0\u81f3\u961f\u5c3e\n    _nums[rear] = _num;\n    _queSize++;\n  }\n\n  /* \u51fa\u961f */\n  int pop() {\n    int _num = peek();\n    // \u961f\u9996\u6307\u9488\u5411\u540e\u79fb\u52a8\u4e00\u4f4d\uff0c\u82e5\u8d8a\u8fc7\u5c3e\u90e8\uff0c\u5219\u8fd4\u56de\u5230\u6570\u7ec4\u5934\u90e8\n    _front = (_front + 1) % capaCity();\n    _queSize--;\n    return _num;\n  }\n\n  /* \u8bbf\u95ee\u961f\u9996\u5143\u7d20 */\n  int peek() {\n    if (isEmpty()) {\n      throw Exception(\"\u961f\u5217\u4e3a\u7a7a\");\n    }\n    return _nums[_front];\n  }\n\n  /* \u8fd4\u56de Array */\n  List<int> toArray() {\n    // \u4ec5\u8f6c\u6362\u6709\u6548\u957f\u5ea6\u8303\u56f4\u5185\u7684\u5217\u8868\u5143\u7d20\n    final List<int> res = List.filled(_queSize, 0);\n    for (int i = 0, j = _front; i < _queSize; i++, j++) {\n      res[i] = _nums[j % capaCity()];\n    }\n    return res;\n  }\n}\n
array_queue.rs
/* \u57fa\u4e8e\u73af\u5f62\u6570\u7ec4\u5b9e\u73b0\u7684\u961f\u5217 */\nstruct ArrayQueue {\n    nums: Vec<i32>,    // \u7528\u4e8e\u5b58\u50a8\u961f\u5217\u5143\u7d20\u7684\u6570\u7ec4\n    front: i32,        // \u961f\u9996\u6307\u9488\uff0c\u6307\u5411\u961f\u9996\u5143\u7d20\n    que_size: i32,     // \u961f\u5217\u957f\u5ea6\n    que_capacity: i32, // \u961f\u5217\u5bb9\u91cf\n}\n\nimpl ArrayQueue {\n    /* \u6784\u9020\u65b9\u6cd5 */\n    fn new(capacity: i32) -> ArrayQueue {\n        ArrayQueue {\n            nums: vec![0; capacity as usize],\n            front: 0,\n            que_size: 0,\n            que_capacity: capacity,\n        }\n    }\n\n    /* \u83b7\u53d6\u961f\u5217\u7684\u5bb9\u91cf */\n    fn capacity(&self) -> i32 {\n        self.que_capacity\n    }\n\n    /* \u83b7\u53d6\u961f\u5217\u7684\u957f\u5ea6 */\n    fn size(&self) -> i32 {\n        self.que_size\n    }\n\n    /* \u5224\u65ad\u961f\u5217\u662f\u5426\u4e3a\u7a7a */\n    fn is_empty(&self) -> bool {\n        self.que_size == 0\n    }\n\n    /* \u5165\u961f */\n    fn push(&mut self, num: i32) {\n        if self.que_size == self.capacity() {\n            println!(\"\u961f\u5217\u5df2\u6ee1\");\n            return;\n        }\n        // \u8ba1\u7b97\u961f\u5c3e\u6307\u9488\uff0c\u6307\u5411\u961f\u5c3e\u7d22\u5f15 + 1\n        // \u901a\u8fc7\u53d6\u4f59\u64cd\u4f5c\u5b9e\u73b0 rear \u8d8a\u8fc7\u6570\u7ec4\u5c3e\u90e8\u540e\u56de\u5230\u5934\u90e8\n        let rear = (self.front + self.que_size) % self.que_capacity;\n        // \u5c06 num \u6dfb\u52a0\u81f3\u961f\u5c3e\n        self.nums[rear as usize] = num;\n        self.que_size += 1;\n    }\n\n    /* \u51fa\u961f */\n    fn pop(&mut self) -> i32 {\n        let num = self.peek();\n        // \u961f\u9996\u6307\u9488\u5411\u540e\u79fb\u52a8\u4e00\u4f4d\uff0c\u82e5\u8d8a\u8fc7\u5c3e\u90e8\uff0c\u5219\u8fd4\u56de\u5230\u6570\u7ec4\u5934\u90e8\n        self.front = (self.front + 1) % self.que_capacity;\n        self.que_size -= 1;\n        num\n    }\n\n    /* \u8bbf\u95ee\u961f\u9996\u5143\u7d20 */\n    fn peek(&self) -> i32 {\n        if self.is_empty() {\n            panic!(\"index out of bounds\");\n        }\n        self.nums[self.front as usize]\n    }\n\n    /* \u8fd4\u56de\u6570\u7ec4 */\n    fn to_vector(&self) -> Vec<i32> {\n        let cap = self.que_capacity;\n        let mut j = self.front;\n        let mut arr = vec![0; self.que_size as usize];\n        for i in 0..self.que_size {\n            arr[i as usize] = self.nums[(j % cap) as usize];\n            j += 1;\n        }\n        arr\n    }\n}\n
array_queue.c
/* \u57fa\u4e8e\u73af\u5f62\u6570\u7ec4\u5b9e\u73b0\u7684\u961f\u5217 */\ntypedef struct {\n    int *nums;       // \u7528\u4e8e\u5b58\u50a8\u961f\u5217\u5143\u7d20\u7684\u6570\u7ec4\n    int front;       // \u961f\u9996\u6307\u9488\uff0c\u6307\u5411\u961f\u9996\u5143\u7d20\n    int queSize;     // \u5c3e\u6307\u9488\uff0c\u6307\u5411\u961f\u5c3e + 1\n    int queCapacity; // \u961f\u5217\u5bb9\u91cf\n} ArrayQueue;\n\n/* \u6784\u9020\u51fd\u6570 */\nArrayQueue *newArrayQueue(int capacity) {\n    ArrayQueue *queue = (ArrayQueue *)malloc(sizeof(ArrayQueue));\n    // \u521d\u59cb\u5316\u6570\u7ec4\n    queue->queCapacity = capacity;\n    queue->nums = (int *)malloc(sizeof(int) * queue->queCapacity);\n    queue->front = queue->queSize = 0;\n    return queue;\n}\n\n/* \u6790\u6784\u51fd\u6570 */\nvoid delArrayQueue(ArrayQueue *queue) {\n    free(queue->nums);\n    free(queue);\n}\n\n/* \u83b7\u53d6\u961f\u5217\u7684\u5bb9\u91cf */\nint capacity(ArrayQueue *queue) {\n    return queue->queCapacity;\n}\n\n/* \u83b7\u53d6\u961f\u5217\u7684\u957f\u5ea6 */\nint size(ArrayQueue *queue) {\n    return queue->queSize;\n}\n\n/* \u5224\u65ad\u961f\u5217\u662f\u5426\u4e3a\u7a7a */\nbool empty(ArrayQueue *queue) {\n    return queue->queSize == 0;\n}\n\n/* \u8bbf\u95ee\u961f\u9996\u5143\u7d20 */\nint peek(ArrayQueue *queue) {\n    assert(size(queue) != 0);\n    return queue->nums[queue->front];\n}\n\n/* \u5165\u961f */\nvoid push(ArrayQueue *queue, int num) {\n    if (size(queue) == capacity(queue)) {\n        printf(\"\u961f\u5217\u5df2\u6ee1\\r\\n\");\n        return;\n    }\n    // \u8ba1\u7b97\u961f\u5c3e\u6307\u9488\uff0c\u6307\u5411\u961f\u5c3e\u7d22\u5f15 + 1\n    // \u901a\u8fc7\u53d6\u4f59\u64cd\u4f5c\u5b9e\u73b0 rear \u8d8a\u8fc7\u6570\u7ec4\u5c3e\u90e8\u540e\u56de\u5230\u5934\u90e8\n    int rear = (queue->front + queue->queSize) % queue->queCapacity;\n    // \u5c06 num \u6dfb\u52a0\u81f3\u961f\u5c3e\n    queue->nums[rear] = num;\n    queue->queSize++;\n}\n\n/* \u51fa\u961f */\nint pop(ArrayQueue *queue) {\n    int num = peek(queue);\n    // \u961f\u9996\u6307\u9488\u5411\u540e\u79fb\u52a8\u4e00\u4f4d\uff0c\u82e5\u8d8a\u8fc7\u5c3e\u90e8\uff0c\u5219\u8fd4\u56de\u5230\u6570\u7ec4\u5934\u90e8\n    queue->front = (queue->front + 1) % queue->queCapacity;\n    queue->queSize--;\n    return num;\n}\n
array_queue.zig
// \u57fa\u4e8e\u73af\u5f62\u6570\u7ec4\u5b9e\u73b0\u7684\u961f\u5217\nfn ArrayQueue(comptime T: type) type {\n    return struct {\n        const Self = @This();\n\n        nums: []T = undefined,                          // \u7528\u4e8e\u5b58\u50a8\u961f\u5217\u5143\u7d20\u7684\u6570\u7ec4     \n        cap: usize = 0,                                 // \u961f\u5217\u5bb9\u91cf\n        front: usize = 0,                               // \u961f\u9996\u6307\u9488\uff0c\u6307\u5411\u961f\u9996\u5143\u7d20\n        queSize: usize = 0,                             // \u5c3e\u6307\u9488\uff0c\u6307\u5411\u961f\u5c3e + 1\n        mem_arena: ?std.heap.ArenaAllocator = null,\n        mem_allocator: std.mem.Allocator = undefined,   // \u5185\u5b58\u5206\u914d\u5668\n\n        // \u6784\u9020\u51fd\u6570\uff08\u5206\u914d\u5185\u5b58+\u521d\u59cb\u5316\u6570\u7ec4\uff09\n        pub fn init(self: *Self, allocator: std.mem.Allocator, cap: usize) !void {\n            if (self.mem_arena == null) {\n                self.mem_arena = std.heap.ArenaAllocator.init(allocator);\n                self.mem_allocator = self.mem_arena.?.allocator();\n            }\n            self.cap = cap;\n            self.nums = try self.mem_allocator.alloc(T, self.cap);\n            @memset(self.nums, @as(T, 0));\n        }\n\n        // \u6790\u6784\u51fd\u6570\uff08\u91ca\u653e\u5185\u5b58\uff09\n        pub fn deinit(self: *Self) void {\n            if (self.mem_arena == null) return;\n            self.mem_arena.?.deinit();\n        }\n\n        // \u83b7\u53d6\u961f\u5217\u7684\u5bb9\u91cf\n        pub fn capacity(self: *Self) usize {\n            return self.cap;\n        }\n\n        // \u83b7\u53d6\u961f\u5217\u7684\u957f\u5ea6\n        pub fn size(self: *Self) usize {\n            return self.queSize;\n        }\n\n        // \u5224\u65ad\u961f\u5217\u662f\u5426\u4e3a\u7a7a\n        pub fn isEmpty(self: *Self) bool {\n            return self.queSize == 0;\n        }\n\n        // \u5165\u961f\n        pub fn push(self: *Self, num: T) !void {\n            if (self.size() == self.capacity()) {\n                std.debug.print(\"\u961f\u5217\u5df2\u6ee1\\n\", .{});\n                return;\n            }\n            // \u8ba1\u7b97\u961f\u5c3e\u6307\u9488\uff0c\u6307\u5411\u961f\u5c3e\u7d22\u5f15 + 1\n            // \u901a\u8fc7\u53d6\u4f59\u64cd\u4f5c\u5b9e\u73b0 rear \u8d8a\u8fc7\u6570\u7ec4\u5c3e\u90e8\u540e\u56de\u5230\u5934\u90e8\n            var rear = (self.front + self.queSize) % self.capacity();\n            // \u5728\u5c3e\u8282\u70b9\u540e\u6dfb\u52a0 num\n            self.nums[rear] = num;\n            self.queSize += 1;\n        } \n\n        // \u51fa\u961f\n        pub fn pop(self: *Self) T {\n            var num = self.peek();\n            // \u961f\u9996\u6307\u9488\u5411\u540e\u79fb\u52a8\u4e00\u4f4d\uff0c\u82e5\u8d8a\u8fc7\u5c3e\u90e8\uff0c\u5219\u8fd4\u56de\u5230\u6570\u7ec4\u5934\u90e8\n            self.front = (self.front + 1) % self.capacity();\n            self.queSize -= 1;\n            return num;\n        } \n\n        // \u8bbf\u95ee\u961f\u9996\u5143\u7d20\n        pub fn peek(self: *Self) T {\n            if (self.isEmpty()) @panic(\"\u961f\u5217\u4e3a\u7a7a\");\n            return self.nums[self.front];\n        } \n\n        // \u8fd4\u56de\u6570\u7ec4\n        pub fn toArray(self: *Self) ![]T {\n            // \u4ec5\u8f6c\u6362\u6709\u6548\u957f\u5ea6\u8303\u56f4\u5185\u7684\u5217\u8868\u5143\u7d20\n            var res = try self.mem_allocator.alloc(T, self.size());\n            @memset(res, @as(T, 0));\n            var i: usize = 0;\n            var j: usize = self.front;\n            while (i < self.size()) : ({ i += 1; j += 1; }) {\n                res[i] = self.nums[j % self.capacity()];\n            }\n            return res;\n        }\n    };\n}\n
Code Visualization

Full Screen >

The above implementation of the queue still has its limitations: its length is fixed. However, this issue is not difficult to resolve. We can replace the array with a dynamic array that can expand itself if needed. Interested readers can try to implement this themselves.

The comparison of the two implementations is consistent with that of the stack and is not repeated here.

"},{"location":"chapter_stack_and_queue/queue/#523-typical-applications-of-queue","title":"5.2.3 \u00a0 Typical Applications of Queue","text":"
  • Amazon Orders. After shoppers place orders, these orders join a queue, and the system processes them in order. During events like Singles' Day, a massive number of orders are generated in a short time, making high concurrency a key challenge for engineers.
  • Various To-Do Lists. Any scenario requiring a \"first-come, first-served\" functionality, such as a printer's task queue or a restaurant's food delivery queue, can effectively maintain the order of processing with a queue.
"},{"location":"chapter_stack_and_queue/stack/","title":"5.1 \u00a0 Stack","text":"

A \"Stack\" is a linear data structure that follows the principle of Last-In-First-Out (LIFO).

We can compare a stack to a pile of plates on a table. To access the bottom plate, one must first remove the plates on top. By replacing the plates with various types of elements (such as integers, characters, objects, etc.), we obtain the data structure known as a stack.

As shown in the Figure 5-1 , we refer to the top of the pile of elements as the \"top of the stack\" and the bottom as the \"bottom of the stack.\" The operation of adding elements to the top of the stack is called \"push,\" and the operation of removing the top element is called \"pop.\"

Figure 5-1 \u00a0 Stack's Last-In-First-Out Rule

"},{"location":"chapter_stack_and_queue/stack/#511-common-operations-on-stack","title":"5.1.1 \u00a0 Common Operations on Stack","text":"

The common operations on a stack are shown in the Table 5-1 . The specific method names depend on the programming language used. Here, we use push(), pop(), and peek() as examples.

Table 5-1 \u00a0 Efficiency of Stack Operations

Method Description Time Complexity push() Push an element onto the stack (add to the top) \\(O(1)\\) pop() Pop the top element from the stack \\(O(1)\\) peek() Access the top element of the stack \\(O(1)\\)

Typically, we can directly use the stack class built into the programming language. However, some languages may not specifically provide a stack class. In these cases, we can use the language's \"array\" or \"linked list\" as a stack and ignore operations that are not related to stack logic in the program.

PythonC++JavaC#GoSwiftJSTSDartRustCZig stack.py
# Initialize the stack\n# Python does not have a built-in stack class, so a list can be used as a stack\nstack: list[int] = []\n\n# Push elements onto the stack\nstack.append(1)\nstack.append(3)\nstack.append(2)\nstack.append(5)\nstack.append(4)\n\n# Access the top element of the stack\npeek: int = stack[-1]\n\n# Pop an element from the stack\npop: int = stack.pop()\n\n# Get the length of the stack\nsize: int = len(stack)\n\n# Check if the stack is empty\nis_empty: bool = len(stack) == 0\n
stack.cpp
/* Initialize the stack */\nstack<int> stack;\n\n/* Push elements onto the stack */\nstack.push(1);\nstack.push(3);\nstack.push(2);\nstack.push(5);\nstack.push(4);\n\n/* Access the top element of the stack */\nint top = stack.top();\n\n/* Pop an element from the stack */\nstack.pop(); // No return value\n\n/* Get the length of the stack */\nint size = stack.size();\n\n/* Check if the stack is empty */\nbool empty = stack.empty();\n
stack.java
/* Initialize the stack */\nStack<Integer> stack = new Stack<>();\n\n/* Push elements onto the stack */\nstack.push(1);\nstack.push(3);\nstack.push(2);\nstack.push(5);\nstack.push(4);\n\n/* Access the top element of the stack */\nint peek = stack.peek();\n\n/* Pop an element from the stack */\nint pop = stack.pop();\n\n/* Get the length of the stack */\nint size = stack.size();\n\n/* Check if the stack is empty */\nboolean isEmpty = stack.isEmpty();\n
stack.cs
/* Initialize the stack */\nStack<int> stack = new();\n\n/* Push elements onto the stack */\nstack.Push(1);\nstack.Push(3);\nstack.Push(2);\nstack.Push(5);\nstack.Push(4);\n\n/* Access the top element of the stack */\nint peek = stack.Peek();\n\n/* Pop an element from the stack */\nint pop = stack.Pop();\n\n/* Get the length of the stack */\nint size = stack.Count;\n\n/* Check if the stack is empty */\nbool isEmpty = stack.Count == 0;\n
stack_test.go
/* Initialize the stack */\n// In Go, it is recommended to use a Slice as a stack\nvar stack []int\n\n/* Push elements onto the stack */\nstack = append(stack, 1)\nstack = append(stack, 3)\nstack = append(stack, 2)\nstack = append(stack, 5)\nstack = append(stack, 4)\n\n/* Access the top element of the stack */\npeek := stack[len(stack)-1]\n\n/* Pop an element from the stack */\npop := stack[len(stack)-1]\nstack = stack[:len(stack)-1]\n\n/* Get the length of the stack */\nsize := len(stack)\n\n/* Check if the stack is empty */\nisEmpty := len(stack) == 0\n
stack.swift
/* Initialize the stack */\n// Swift does not have a built-in stack class, so Array can be used as a stack\nvar stack: [Int] = []\n\n/* Push elements onto the stack */\nstack.append(1)\nstack.append(3)\nstack.append(2)\nstack.append(5)\nstack.append(4)\n\n/* Access the top element of the stack */\nlet peek = stack.last!\n\n/* Pop an element from the stack */\nlet pop = stack.removeLast()\n\n/* Get the length of the stack */\nlet size = stack.count\n\n/* Check if the stack is empty */\nlet isEmpty = stack.isEmpty\n
stack.js
/* Initialize the stack */\n// JavaScript does not have a built-in stack class, so Array can be used as a stack\nconst stack = [];\n\n/* Push elements onto the stack */\nstack.push(1);\nstack.push(3);\nstack.push(2);\nstack.push(5);\nstack.push(4);\n\n/* Access the top element of the stack */\nconst peek = stack[stack.length-1];\n\n/* Pop an element from the stack */\nconst pop = stack.pop();\n\n/* Get the length of the stack */\nconst size = stack.length;\n\n/* Check if the stack is empty */\nconst is_empty = stack.length === 0;\n
stack.ts
/* Initialize the stack */\n// TypeScript does not have a built-in stack class, so Array can be used as a stack\nconst stack: number[] = [];\n\n/* Push elements onto the stack */\nstack.push(1);\nstack.push(3);\nstack.push(2);\nstack.push(5);\nstack.push(4);\n\n/* Access the top element of the stack */\nconst peek = stack[stack.length - 1];\n\n/* Pop an element from the stack */\nconst pop = stack.pop();\n\n/* Get the length of the stack */\nconst size = stack.length;\n\n/* Check if the stack is empty */\nconst is_empty = stack.length === 0;\n
stack.dart
/* Initialize the stack */\n// Dart does not have a built-in stack class, so List can be used as a stack\nList<int> stack = [];\n\n/* Push elements onto the stack */\nstack.add(1);\nstack.add(3);\nstack.add(2);\nstack.add(5);\nstack.add(4);\n\n/* Access the top element of the stack */\nint peek = stack.last;\n\n/* Pop an element from the stack */\nint pop = stack.removeLast();\n\n/* Get the length of the stack */\nint size = stack.length;\n\n/* Check if the stack is empty */\nbool isEmpty = stack.isEmpty;\n
stack.rs
/* Initialize the stack */\n// Use Vec as a stack\nlet mut stack: Vec<i32> = Vec::new();\n\n/* Push elements onto the stack */\nstack.push(1);\nstack.push(3);\nstack.push(2);\nstack.push(5);\nstack.push(4);\n\n/* Access the top element of the stack */\nlet top = stack.last().unwrap();\n\n/* Pop an element from the stack */\nlet pop = stack.pop().unwrap();\n\n/* Get the length of the stack */\nlet size = stack.len();\n\n/* Check if the stack is empty */\nlet is_empty = stack.is_empty();\n
stack.c
// C does not provide a built-in stack\n
stack.zig
\n
Code Visualization

Full Screen >

"},{"location":"chapter_stack_and_queue/stack/#512-implementing-a-stack","title":"5.1.2 \u00a0 Implementing a Stack","text":"

To gain a deeper understanding of how a stack operates, let's try implementing a stack class ourselves.

A stack follows the principle of Last-In-First-Out, which means we can only add or remove elements at the top of the stack. However, both arrays and linked lists allow adding and removing elements at any position, therefore a stack can be seen as a restricted array or linked list. In other words, we can \"shield\" certain irrelevant operations of an array or linked list, aligning their external behavior with the characteristics of a stack.

"},{"location":"chapter_stack_and_queue/stack/#1-implementation-based-on-linked-list","title":"1. \u00a0 Implementation Based on Linked List","text":"

When implementing a stack using a linked list, we can consider the head node of the list as the top of the stack and the tail node as the bottom of the stack.

As shown in the Figure 5-2 , for the push operation, we simply insert elements at the head of the linked list. This method of node insertion is known as \"head insertion.\" For the pop operation, we just need to remove the head node from the list.

LinkedListStackpush()pop()

Figure 5-2 \u00a0 Implementing Stack with Linked List for Push and Pop Operations

Below is an example code for implementing a stack based on a linked list:

PythonC++JavaC#GoSwiftJSTSDartRustCZig linkedlist_stack.py
class LinkedListStack:\n    \"\"\"\u57fa\u4e8e\u94fe\u8868\u5b9e\u73b0\u7684\u6808\"\"\"\n\n    def __init__(self):\n        \"\"\"\u6784\u9020\u65b9\u6cd5\"\"\"\n        self._peek: ListNode | None = None\n        self._size: int = 0\n\n    def size(self) -> int:\n        \"\"\"\u83b7\u53d6\u6808\u7684\u957f\u5ea6\"\"\"\n        return self._size\n\n    def is_empty(self) -> bool:\n        \"\"\"\u5224\u65ad\u6808\u662f\u5426\u4e3a\u7a7a\"\"\"\n        return not self._peek\n\n    def push(self, val: int):\n        \"\"\"\u5165\u6808\"\"\"\n        node = ListNode(val)\n        node.next = self._peek\n        self._peek = node\n        self._size += 1\n\n    def pop(self) -> int:\n        \"\"\"\u51fa\u6808\"\"\"\n        num = self.peek()\n        self._peek = self._peek.next\n        self._size -= 1\n        return num\n\n    def peek(self) -> int:\n        \"\"\"\u8bbf\u95ee\u6808\u9876\u5143\u7d20\"\"\"\n        if self.is_empty():\n            raise IndexError(\"\u6808\u4e3a\u7a7a\")\n        return self._peek.val\n\n    def to_list(self) -> list[int]:\n        \"\"\"\u8f6c\u5316\u4e3a\u5217\u8868\u7528\u4e8e\u6253\u5370\"\"\"\n        arr = []\n        node = self._peek\n        while node:\n            arr.append(node.val)\n            node = node.next\n        arr.reverse()\n        return arr\n
linkedlist_stack.cpp
/* \u57fa\u4e8e\u94fe\u8868\u5b9e\u73b0\u7684\u6808 */\nclass LinkedListStack {\n  private:\n    ListNode *stackTop; // \u5c06\u5934\u8282\u70b9\u4f5c\u4e3a\u6808\u9876\n    int stkSize;        // \u6808\u7684\u957f\u5ea6\n\n  public:\n    LinkedListStack() {\n        stackTop = nullptr;\n        stkSize = 0;\n    }\n\n    ~LinkedListStack() {\n        // \u904d\u5386\u94fe\u8868\u5220\u9664\u8282\u70b9\uff0c\u91ca\u653e\u5185\u5b58\n        freeMemoryLinkedList(stackTop);\n    }\n\n    /* \u83b7\u53d6\u6808\u7684\u957f\u5ea6 */\n    int size() {\n        return stkSize;\n    }\n\n    /* \u5224\u65ad\u6808\u662f\u5426\u4e3a\u7a7a */\n    bool isEmpty() {\n        return size() == 0;\n    }\n\n    /* \u5165\u6808 */\n    void push(int num) {\n        ListNode *node = new ListNode(num);\n        node->next = stackTop;\n        stackTop = node;\n        stkSize++;\n    }\n\n    /* \u51fa\u6808 */\n    int pop() {\n        int num = top();\n        ListNode *tmp = stackTop;\n        stackTop = stackTop->next;\n        // \u91ca\u653e\u5185\u5b58\n        delete tmp;\n        stkSize--;\n        return num;\n    }\n\n    /* \u8bbf\u95ee\u6808\u9876\u5143\u7d20 */\n    int top() {\n        if (isEmpty())\n            throw out_of_range(\"\u6808\u4e3a\u7a7a\");\n        return stackTop->val;\n    }\n\n    /* \u5c06 List \u8f6c\u5316\u4e3a Array \u5e76\u8fd4\u56de */\n    vector<int> toVector() {\n        ListNode *node = stackTop;\n        vector<int> res(size());\n        for (int i = res.size() - 1; i >= 0; i--) {\n            res[i] = node->val;\n            node = node->next;\n        }\n        return res;\n    }\n};\n
linkedlist_stack.java
/* \u57fa\u4e8e\u94fe\u8868\u5b9e\u73b0\u7684\u6808 */\nclass LinkedListStack {\n    private ListNode stackPeek; // \u5c06\u5934\u8282\u70b9\u4f5c\u4e3a\u6808\u9876\n    private int stkSize = 0; // \u6808\u7684\u957f\u5ea6\n\n    public LinkedListStack() {\n        stackPeek = null;\n    }\n\n    /* \u83b7\u53d6\u6808\u7684\u957f\u5ea6 */\n    public int size() {\n        return stkSize;\n    }\n\n    /* \u5224\u65ad\u6808\u662f\u5426\u4e3a\u7a7a */\n    public boolean isEmpty() {\n        return size() == 0;\n    }\n\n    /* \u5165\u6808 */\n    public void push(int num) {\n        ListNode node = new ListNode(num);\n        node.next = stackPeek;\n        stackPeek = node;\n        stkSize++;\n    }\n\n    /* \u51fa\u6808 */\n    public int pop() {\n        int num = peek();\n        stackPeek = stackPeek.next;\n        stkSize--;\n        return num;\n    }\n\n    /* \u8bbf\u95ee\u6808\u9876\u5143\u7d20 */\n    public int peek() {\n        if (isEmpty())\n            throw new IndexOutOfBoundsException();\n        return stackPeek.val;\n    }\n\n    /* \u5c06 List \u8f6c\u5316\u4e3a Array \u5e76\u8fd4\u56de */\n    public int[] toArray() {\n        ListNode node = stackPeek;\n        int[] res = new int[size()];\n        for (int i = res.length - 1; i >= 0; i--) {\n            res[i] = node.val;\n            node = node.next;\n        }\n        return res;\n    }\n}\n
linkedlist_stack.cs
/* \u57fa\u4e8e\u94fe\u8868\u5b9e\u73b0\u7684\u6808 */\nclass LinkedListStack {\n    ListNode? stackPeek;  // \u5c06\u5934\u8282\u70b9\u4f5c\u4e3a\u6808\u9876\n    int stkSize = 0;   // \u6808\u7684\u957f\u5ea6\n\n    public LinkedListStack() {\n        stackPeek = null;\n    }\n\n    /* \u83b7\u53d6\u6808\u7684\u957f\u5ea6 */\n    public int Size() {\n        return stkSize;\n    }\n\n    /* \u5224\u65ad\u6808\u662f\u5426\u4e3a\u7a7a */\n    public bool IsEmpty() {\n        return Size() == 0;\n    }\n\n    /* \u5165\u6808 */\n    public void Push(int num) {\n        ListNode node = new(num) {\n            next = stackPeek\n        };\n        stackPeek = node;\n        stkSize++;\n    }\n\n    /* \u51fa\u6808 */\n    public int Pop() {\n        int num = Peek();\n        stackPeek = stackPeek!.next;\n        stkSize--;\n        return num;\n    }\n\n    /* \u8bbf\u95ee\u6808\u9876\u5143\u7d20 */\n    public int Peek() {\n        if (IsEmpty())\n            throw new Exception();\n        return stackPeek!.val;\n    }\n\n    /* \u5c06 List \u8f6c\u5316\u4e3a Array \u5e76\u8fd4\u56de */\n    public int[] ToArray() {\n        if (stackPeek == null)\n            return [];\n\n        ListNode? node = stackPeek;\n        int[] res = new int[Size()];\n        for (int i = res.Length - 1; i >= 0; i--) {\n            res[i] = node!.val;\n            node = node.next;\n        }\n        return res;\n    }\n}\n
linkedlist_stack.go
/* \u57fa\u4e8e\u94fe\u8868\u5b9e\u73b0\u7684\u6808 */\ntype linkedListStack struct {\n    // \u4f7f\u7528\u5185\u7f6e\u5305 list \u6765\u5b9e\u73b0\u6808\n    data *list.List\n}\n\n/* \u521d\u59cb\u5316\u6808 */\nfunc newLinkedListStack() *linkedListStack {\n    return &linkedListStack{\n        data: list.New(),\n    }\n}\n\n/* \u5165\u6808 */\nfunc (s *linkedListStack) push(value int) {\n    s.data.PushBack(value)\n}\n\n/* \u51fa\u6808 */\nfunc (s *linkedListStack) pop() any {\n    if s.isEmpty() {\n        return nil\n    }\n    e := s.data.Back()\n    s.data.Remove(e)\n    return e.Value\n}\n\n/* \u8bbf\u95ee\u6808\u9876\u5143\u7d20 */\nfunc (s *linkedListStack) peek() any {\n    if s.isEmpty() {\n        return nil\n    }\n    e := s.data.Back()\n    return e.Value\n}\n\n/* \u83b7\u53d6\u6808\u7684\u957f\u5ea6 */\nfunc (s *linkedListStack) size() int {\n    return s.data.Len()\n}\n\n/* \u5224\u65ad\u6808\u662f\u5426\u4e3a\u7a7a */\nfunc (s *linkedListStack) isEmpty() bool {\n    return s.data.Len() == 0\n}\n\n/* \u83b7\u53d6 List \u7528\u4e8e\u6253\u5370 */\nfunc (s *linkedListStack) toList() *list.List {\n    return s.data\n}\n
linkedlist_stack.swift
/* \u57fa\u4e8e\u94fe\u8868\u5b9e\u73b0\u7684\u6808 */\nclass LinkedListStack {\n    private var _peek: ListNode? // \u5c06\u5934\u8282\u70b9\u4f5c\u4e3a\u6808\u9876\n    private var _size: Int // \u6808\u7684\u957f\u5ea6\n\n    init() {\n        _size = 0\n    }\n\n    /* \u83b7\u53d6\u6808\u7684\u957f\u5ea6 */\n    func size() -> Int {\n        _size\n    }\n\n    /* \u5224\u65ad\u6808\u662f\u5426\u4e3a\u7a7a */\n    func isEmpty() -> Bool {\n        size() == 0\n    }\n\n    /* \u5165\u6808 */\n    func push(num: Int) {\n        let node = ListNode(x: num)\n        node.next = _peek\n        _peek = node\n        _size += 1\n    }\n\n    /* \u51fa\u6808 */\n    @discardableResult\n    func pop() -> Int {\n        let num = peek()\n        _peek = _peek?.next\n        _size -= 1\n        return num\n    }\n\n    /* \u8bbf\u95ee\u6808\u9876\u5143\u7d20 */\n    func peek() -> Int {\n        if isEmpty() {\n            fatalError(\"\u6808\u4e3a\u7a7a\")\n        }\n        return _peek!.val\n    }\n\n    /* \u5c06 List \u8f6c\u5316\u4e3a Array \u5e76\u8fd4\u56de */\n    func toArray() -> [Int] {\n        var node = _peek\n        var res = Array(repeating: 0, count: size())\n        for i in res.indices.reversed() {\n            res[i] = node!.val\n            node = node?.next\n        }\n        return res\n    }\n}\n
linkedlist_stack.js
/* \u57fa\u4e8e\u94fe\u8868\u5b9e\u73b0\u7684\u6808 */\nclass LinkedListStack {\n    #stackPeek; // \u5c06\u5934\u8282\u70b9\u4f5c\u4e3a\u6808\u9876\n    #stkSize = 0; // \u6808\u7684\u957f\u5ea6\n\n    constructor() {\n        this.#stackPeek = null;\n    }\n\n    /* \u83b7\u53d6\u6808\u7684\u957f\u5ea6 */\n    get size() {\n        return this.#stkSize;\n    }\n\n    /* \u5224\u65ad\u6808\u662f\u5426\u4e3a\u7a7a */\n    isEmpty() {\n        return this.size === 0;\n    }\n\n    /* \u5165\u6808 */\n    push(num) {\n        const node = new ListNode(num);\n        node.next = this.#stackPeek;\n        this.#stackPeek = node;\n        this.#stkSize++;\n    }\n\n    /* \u51fa\u6808 */\n    pop() {\n        const num = this.peek();\n        this.#stackPeek = this.#stackPeek.next;\n        this.#stkSize--;\n        return num;\n    }\n\n    /* \u8bbf\u95ee\u6808\u9876\u5143\u7d20 */\n    peek() {\n        if (!this.#stackPeek) throw new Error('\u6808\u4e3a\u7a7a');\n        return this.#stackPeek.val;\n    }\n\n    /* \u5c06\u94fe\u8868\u8f6c\u5316\u4e3a Array \u5e76\u8fd4\u56de */\n    toArray() {\n        let node = this.#stackPeek;\n        const res = new Array(this.size);\n        for (let i = res.length - 1; i >= 0; i--) {\n            res[i] = node.val;\n            node = node.next;\n        }\n        return res;\n    }\n}\n
linkedlist_stack.ts
/* \u57fa\u4e8e\u94fe\u8868\u5b9e\u73b0\u7684\u6808 */\nclass LinkedListStack {\n    private stackPeek: ListNode | null; // \u5c06\u5934\u8282\u70b9\u4f5c\u4e3a\u6808\u9876\n    private stkSize: number = 0; // \u6808\u7684\u957f\u5ea6\n\n    constructor() {\n        this.stackPeek = null;\n    }\n\n    /* \u83b7\u53d6\u6808\u7684\u957f\u5ea6 */\n    get size(): number {\n        return this.stkSize;\n    }\n\n    /* \u5224\u65ad\u6808\u662f\u5426\u4e3a\u7a7a */\n    isEmpty(): boolean {\n        return this.size === 0;\n    }\n\n    /* \u5165\u6808 */\n    push(num: number): void {\n        const node = new ListNode(num);\n        node.next = this.stackPeek;\n        this.stackPeek = node;\n        this.stkSize++;\n    }\n\n    /* \u51fa\u6808 */\n    pop(): number {\n        const num = this.peek();\n        if (!this.stackPeek) throw new Error('\u6808\u4e3a\u7a7a');\n        this.stackPeek = this.stackPeek.next;\n        this.stkSize--;\n        return num;\n    }\n\n    /* \u8bbf\u95ee\u6808\u9876\u5143\u7d20 */\n    peek(): number {\n        if (!this.stackPeek) throw new Error('\u6808\u4e3a\u7a7a');\n        return this.stackPeek.val;\n    }\n\n    /* \u5c06\u94fe\u8868\u8f6c\u5316\u4e3a Array \u5e76\u8fd4\u56de */\n    toArray(): number[] {\n        let node = this.stackPeek;\n        const res = new Array<number>(this.size);\n        for (let i = res.length - 1; i >= 0; i--) {\n            res[i] = node!.val;\n            node = node!.next;\n        }\n        return res;\n    }\n}\n
linkedlist_stack.dart
/* \u57fa\u4e8e\u94fe\u8868\u7c7b\u5b9e\u73b0\u7684\u6808 */\nclass LinkedListStack {\n  ListNode? _stackPeek; // \u5c06\u5934\u8282\u70b9\u4f5c\u4e3a\u6808\u9876\n  int _stkSize = 0; // \u6808\u7684\u957f\u5ea6\n\n  LinkedListStack() {\n    _stackPeek = null;\n  }\n\n  /* \u83b7\u53d6\u6808\u7684\u957f\u5ea6 */\n  int size() {\n    return _stkSize;\n  }\n\n  /* \u5224\u65ad\u6808\u662f\u5426\u4e3a\u7a7a */\n  bool isEmpty() {\n    return _stkSize == 0;\n  }\n\n  /* \u5165\u6808 */\n  void push(int _num) {\n    final ListNode node = ListNode(_num);\n    node.next = _stackPeek;\n    _stackPeek = node;\n    _stkSize++;\n  }\n\n  /* \u51fa\u6808 */\n  int pop() {\n    final int _num = peek();\n    _stackPeek = _stackPeek!.next;\n    _stkSize--;\n    return _num;\n  }\n\n  /* \u8bbf\u95ee\u6808\u9876\u5143\u7d20 */\n  int peek() {\n    if (_stackPeek == null) {\n      throw Exception(\"\u6808\u4e3a\u7a7a\");\n    }\n    return _stackPeek!.val;\n  }\n\n  /* \u5c06\u94fe\u8868\u8f6c\u5316\u4e3a List \u5e76\u8fd4\u56de */\n  List<int> toList() {\n    ListNode? node = _stackPeek;\n    List<int> list = [];\n    while (node != null) {\n      list.add(node.val);\n      node = node.next;\n    }\n    list = list.reversed.toList();\n    return list;\n  }\n}\n
linkedlist_stack.rs
/* \u57fa\u4e8e\u94fe\u8868\u5b9e\u73b0\u7684\u6808 */\n#[allow(dead_code)]\npub struct LinkedListStack<T> {\n    stack_peek: Option<Rc<RefCell<ListNode<T>>>>, // \u5c06\u5934\u8282\u70b9\u4f5c\u4e3a\u6808\u9876\n    stk_size: usize,                              // \u6808\u7684\u957f\u5ea6\n}\n\nimpl<T: Copy> LinkedListStack<T> {\n    pub fn new() -> Self {\n        Self {\n            stack_peek: None,\n            stk_size: 0,\n        }\n    }\n\n    /* \u83b7\u53d6\u6808\u7684\u957f\u5ea6 */\n    pub fn size(&self) -> usize {\n        return self.stk_size;\n    }\n\n    /* \u5224\u65ad\u6808\u662f\u5426\u4e3a\u7a7a */\n    pub fn is_empty(&self) -> bool {\n        return self.size() == 0;\n    }\n\n    /* \u5165\u6808 */\n    pub fn push(&mut self, num: T) {\n        let node = ListNode::new(num);\n        node.borrow_mut().next = self.stack_peek.take();\n        self.stack_peek = Some(node);\n        self.stk_size += 1;\n    }\n\n    /* \u51fa\u6808 */\n    pub fn pop(&mut self) -> Option<T> {\n        self.stack_peek.take().map(|old_head| {\n            match old_head.borrow_mut().next.take() {\n                Some(new_head) => {\n                    self.stack_peek = Some(new_head);\n                }\n                None => {\n                    self.stack_peek = None;\n                }\n            }\n            self.stk_size -= 1;\n            Rc::try_unwrap(old_head).ok().unwrap().into_inner().val\n        })\n    }\n\n    /* \u8bbf\u95ee\u6808\u9876\u5143\u7d20 */\n    pub fn peek(&self) -> Option<&Rc<RefCell<ListNode<T>>>> {\n        self.stack_peek.as_ref()\n    }\n\n    /* \u5c06 List \u8f6c\u5316\u4e3a Array \u5e76\u8fd4\u56de */\n    pub fn to_array(&self, head: Option<&Rc<RefCell<ListNode<T>>>>) -> Vec<T> {\n        if let Some(node) = head {\n            let mut nums = self.to_array(node.borrow().next.as_ref());\n            nums.push(node.borrow().val);\n            return nums;\n        }\n        return Vec::new();\n    }\n}\n
linkedlist_stack.c
/* \u57fa\u4e8e\u94fe\u8868\u5b9e\u73b0\u7684\u6808 */\ntypedef struct {\n    ListNode *top; // \u5c06\u5934\u8282\u70b9\u4f5c\u4e3a\u6808\u9876\n    int size;      // \u6808\u7684\u957f\u5ea6\n} LinkedListStack;\n\n/* \u6784\u9020\u51fd\u6570 */\nLinkedListStack *newLinkedListStack() {\n    LinkedListStack *s = malloc(sizeof(LinkedListStack));\n    s->top = NULL;\n    s->size = 0;\n    return s;\n}\n\n/* \u6790\u6784\u51fd\u6570 */\nvoid delLinkedListStack(LinkedListStack *s) {\n    while (s->top) {\n        ListNode *n = s->top->next;\n        free(s->top);\n        s->top = n;\n    }\n    free(s);\n}\n\n/* \u83b7\u53d6\u6808\u7684\u957f\u5ea6 */\nint size(LinkedListStack *s) {\n    return s->size;\n}\n\n/* \u5224\u65ad\u6808\u662f\u5426\u4e3a\u7a7a */\nbool isEmpty(LinkedListStack *s) {\n    return size(s) == 0;\n}\n\n/* \u5165\u6808 */\nvoid push(LinkedListStack *s, int num) {\n    ListNode *node = (ListNode *)malloc(sizeof(ListNode));\n    node->next = s->top; // \u66f4\u65b0\u65b0\u52a0\u8282\u70b9\u6307\u9488\u57df\n    node->val = num;     // \u66f4\u65b0\u65b0\u52a0\u8282\u70b9\u6570\u636e\u57df\n    s->top = node;       // \u66f4\u65b0\u6808\u9876\n    s->size++;           // \u66f4\u65b0\u6808\u5927\u5c0f\n}\n\n/* \u8bbf\u95ee\u6808\u9876\u5143\u7d20 */\nint peek(LinkedListStack *s) {\n    if (s->size == 0) {\n        printf(\"\u6808\u4e3a\u7a7a\\n\");\n        return INT_MAX;\n    }\n    return s->top->val;\n}\n\n/* \u51fa\u6808 */\nint pop(LinkedListStack *s) {\n    int val = peek(s);\n    ListNode *tmp = s->top;\n    s->top = s->top->next;\n    // \u91ca\u653e\u5185\u5b58\n    free(tmp);\n    s->size--;\n    return val;\n}\n
linkedlist_stack.zig
// \u57fa\u4e8e\u94fe\u8868\u5b9e\u73b0\u7684\u6808\nfn LinkedListStack(comptime T: type) type {\n    return struct {\n        const Self = @This();\n\n        stack_top: ?*inc.ListNode(T) = null,             // \u5c06\u5934\u8282\u70b9\u4f5c\u4e3a\u6808\u9876\n        stk_size: usize = 0,                             // \u6808\u7684\u957f\u5ea6\n        mem_arena: ?std.heap.ArenaAllocator = null,\n        mem_allocator: std.mem.Allocator = undefined,    // \u5185\u5b58\u5206\u914d\u5668\n\n        // \u6784\u9020\u51fd\u6570\uff08\u5206\u914d\u5185\u5b58+\u521d\u59cb\u5316\u6808\uff09\n        pub fn init(self: *Self, allocator: std.mem.Allocator) !void {\n            if (self.mem_arena == null) {\n                self.mem_arena = std.heap.ArenaAllocator.init(allocator);\n                self.mem_allocator = self.mem_arena.?.allocator();\n            }\n            self.stack_top = null;\n            self.stk_size = 0;\n        }\n\n        // \u6790\u6784\u51fd\u6570\uff08\u91ca\u653e\u5185\u5b58\uff09\n        pub fn deinit(self: *Self) void {\n            if (self.mem_arena == null) return;\n            self.mem_arena.?.deinit();\n        }\n\n        // \u83b7\u53d6\u6808\u7684\u957f\u5ea6\n        pub fn size(self: *Self) usize {\n            return self.stk_size;\n        }\n\n        // \u5224\u65ad\u6808\u662f\u5426\u4e3a\u7a7a\n        pub fn isEmpty(self: *Self) bool {\n            return self.size() == 0;\n        }\n\n        // \u8bbf\u95ee\u6808\u9876\u5143\u7d20\n        pub fn peek(self: *Self) T {\n            if (self.size() == 0) @panic(\"\u6808\u4e3a\u7a7a\");\n            return self.stack_top.?.val;\n        }  \n\n        // \u5165\u6808\n        pub fn push(self: *Self, num: T) !void {\n            var node = try self.mem_allocator.create(inc.ListNode(T));\n            node.init(num);\n            node.next = self.stack_top;\n            self.stack_top = node;\n            self.stk_size += 1;\n        } \n\n        // \u51fa\u6808\n        pub fn pop(self: *Self) T {\n            var num = self.peek();\n            self.stack_top = self.stack_top.?.next;\n            self.stk_size -= 1;\n            return num;\n        } \n\n        // \u5c06\u6808\u8f6c\u6362\u4e3a\u6570\u7ec4\n        pub fn toArray(self: *Self) ![]T {\n            var node = self.stack_top;\n            var res = try self.mem_allocator.alloc(T, self.size());\n            @memset(res, @as(T, 0));\n            var i: usize = 0;\n            while (i < res.len) : (i += 1) {\n                res[res.len - i - 1] = node.?.val;\n                node = node.?.next;\n            }\n            return res;\n        }\n    };\n}\n
Code Visualization

Full Screen >

"},{"location":"chapter_stack_and_queue/stack/#2-implementation-based-on-array","title":"2. \u00a0 Implementation Based on Array","text":"

When implementing a stack using an array, we can consider the end of the array as the top of the stack. As shown in the Figure 5-3 , push and pop operations correspond to adding and removing elements at the end of the array, respectively, both with a time complexity of \\(O(1)\\).

ArrayStackpush()pop()

Figure 5-3 \u00a0 Implementing Stack with Array for Push and Pop Operations

Since the elements to be pushed onto the stack may continuously increase, we can use a dynamic array, thus avoiding the need to handle array expansion ourselves. Here is an example code:

PythonC++JavaC#GoSwiftJSTSDartRustCZig array_stack.py
class ArrayStack:\n    \"\"\"\u57fa\u4e8e\u6570\u7ec4\u5b9e\u73b0\u7684\u6808\"\"\"\n\n    def __init__(self):\n        \"\"\"\u6784\u9020\u65b9\u6cd5\"\"\"\n        self._stack: list[int] = []\n\n    def size(self) -> int:\n        \"\"\"\u83b7\u53d6\u6808\u7684\u957f\u5ea6\"\"\"\n        return len(self._stack)\n\n    def is_empty(self) -> bool:\n        \"\"\"\u5224\u65ad\u6808\u662f\u5426\u4e3a\u7a7a\"\"\"\n        return self._stack == []\n\n    def push(self, item: int):\n        \"\"\"\u5165\u6808\"\"\"\n        self._stack.append(item)\n\n    def pop(self) -> int:\n        \"\"\"\u51fa\u6808\"\"\"\n        if self.is_empty():\n            raise IndexError(\"\u6808\u4e3a\u7a7a\")\n        return self._stack.pop()\n\n    def peek(self) -> int:\n        \"\"\"\u8bbf\u95ee\u6808\u9876\u5143\u7d20\"\"\"\n        if self.is_empty():\n            raise IndexError(\"\u6808\u4e3a\u7a7a\")\n        return self._stack[-1]\n\n    def to_list(self) -> list[int]:\n        \"\"\"\u8fd4\u56de\u5217\u8868\u7528\u4e8e\u6253\u5370\"\"\"\n        return self._stack\n
array_stack.cpp
/* \u57fa\u4e8e\u6570\u7ec4\u5b9e\u73b0\u7684\u6808 */\nclass ArrayStack {\n  private:\n    vector<int> stack;\n\n  public:\n    /* \u83b7\u53d6\u6808\u7684\u957f\u5ea6 */\n    int size() {\n        return stack.size();\n    }\n\n    /* \u5224\u65ad\u6808\u662f\u5426\u4e3a\u7a7a */\n    bool isEmpty() {\n        return stack.size() == 0;\n    }\n\n    /* \u5165\u6808 */\n    void push(int num) {\n        stack.push_back(num);\n    }\n\n    /* \u51fa\u6808 */\n    int pop() {\n        int num = top();\n        stack.pop_back();\n        return num;\n    }\n\n    /* \u8bbf\u95ee\u6808\u9876\u5143\u7d20 */\n    int top() {\n        if (isEmpty())\n            throw out_of_range(\"\u6808\u4e3a\u7a7a\");\n        return stack.back();\n    }\n\n    /* \u8fd4\u56de Vector */\n    vector<int> toVector() {\n        return stack;\n    }\n};\n
array_stack.java
/* \u57fa\u4e8e\u6570\u7ec4\u5b9e\u73b0\u7684\u6808 */\nclass ArrayStack {\n    private ArrayList<Integer> stack;\n\n    public ArrayStack() {\n        // \u521d\u59cb\u5316\u5217\u8868\uff08\u52a8\u6001\u6570\u7ec4\uff09\n        stack = new ArrayList<>();\n    }\n\n    /* \u83b7\u53d6\u6808\u7684\u957f\u5ea6 */\n    public int size() {\n        return stack.size();\n    }\n\n    /* \u5224\u65ad\u6808\u662f\u5426\u4e3a\u7a7a */\n    public boolean isEmpty() {\n        return size() == 0;\n    }\n\n    /* \u5165\u6808 */\n    public void push(int num) {\n        stack.add(num);\n    }\n\n    /* \u51fa\u6808 */\n    public int pop() {\n        if (isEmpty())\n            throw new IndexOutOfBoundsException();\n        return stack.remove(size() - 1);\n    }\n\n    /* \u8bbf\u95ee\u6808\u9876\u5143\u7d20 */\n    public int peek() {\n        if (isEmpty())\n            throw new IndexOutOfBoundsException();\n        return stack.get(size() - 1);\n    }\n\n    /* \u5c06 List \u8f6c\u5316\u4e3a Array \u5e76\u8fd4\u56de */\n    public Object[] toArray() {\n        return stack.toArray();\n    }\n}\n
array_stack.cs
/* \u57fa\u4e8e\u6570\u7ec4\u5b9e\u73b0\u7684\u6808 */\nclass ArrayStack {\n    List<int> stack;\n    public ArrayStack() {\n        // \u521d\u59cb\u5316\u5217\u8868\uff08\u52a8\u6001\u6570\u7ec4\uff09\n        stack = [];\n    }\n\n    /* \u83b7\u53d6\u6808\u7684\u957f\u5ea6 */\n    public int Size() {\n        return stack.Count;\n    }\n\n    /* \u5224\u65ad\u6808\u662f\u5426\u4e3a\u7a7a */\n    public bool IsEmpty() {\n        return Size() == 0;\n    }\n\n    /* \u5165\u6808 */\n    public void Push(int num) {\n        stack.Add(num);\n    }\n\n    /* \u51fa\u6808 */\n    public int Pop() {\n        if (IsEmpty())\n            throw new Exception();\n        var val = Peek();\n        stack.RemoveAt(Size() - 1);\n        return val;\n    }\n\n    /* \u8bbf\u95ee\u6808\u9876\u5143\u7d20 */\n    public int Peek() {\n        if (IsEmpty())\n            throw new Exception();\n        return stack[Size() - 1];\n    }\n\n    /* \u5c06 List \u8f6c\u5316\u4e3a Array \u5e76\u8fd4\u56de */\n    public int[] ToArray() {\n        return [.. stack];\n    }\n}\n
array_stack.go
/* \u57fa\u4e8e\u6570\u7ec4\u5b9e\u73b0\u7684\u6808 */\ntype arrayStack struct {\n    data []int // \u6570\u636e\n}\n\n/* \u521d\u59cb\u5316\u6808 */\nfunc newArrayStack() *arrayStack {\n    return &arrayStack{\n        // \u8bbe\u7f6e\u6808\u7684\u957f\u5ea6\u4e3a 0\uff0c\u5bb9\u91cf\u4e3a 16\n        data: make([]int, 0, 16),\n    }\n}\n\n/* \u6808\u7684\u957f\u5ea6 */\nfunc (s *arrayStack) size() int {\n    return len(s.data)\n}\n\n/* \u6808\u662f\u5426\u4e3a\u7a7a */\nfunc (s *arrayStack) isEmpty() bool {\n    return s.size() == 0\n}\n\n/* \u5165\u6808 */\nfunc (s *arrayStack) push(v int) {\n    // \u5207\u7247\u4f1a\u81ea\u52a8\u6269\u5bb9\n    s.data = append(s.data, v)\n}\n\n/* \u51fa\u6808 */\nfunc (s *arrayStack) pop() any {\n    val := s.peek()\n    s.data = s.data[:len(s.data)-1]\n    return val\n}\n\n/* \u83b7\u53d6\u6808\u9876\u5143\u7d20 */\nfunc (s *arrayStack) peek() any {\n    if s.isEmpty() {\n        return nil\n    }\n    val := s.data[len(s.data)-1]\n    return val\n}\n\n/* \u83b7\u53d6 Slice \u7528\u4e8e\u6253\u5370 */\nfunc (s *arrayStack) toSlice() []int {\n    return s.data\n}\n
array_stack.swift
/* \u57fa\u4e8e\u6570\u7ec4\u5b9e\u73b0\u7684\u6808 */\nclass ArrayStack {\n    private var stack: [Int]\n\n    init() {\n        // \u521d\u59cb\u5316\u5217\u8868\uff08\u52a8\u6001\u6570\u7ec4\uff09\n        stack = []\n    }\n\n    /* \u83b7\u53d6\u6808\u7684\u957f\u5ea6 */\n    func size() -> Int {\n        stack.count\n    }\n\n    /* \u5224\u65ad\u6808\u662f\u5426\u4e3a\u7a7a */\n    func isEmpty() -> Bool {\n        stack.isEmpty\n    }\n\n    /* \u5165\u6808 */\n    func push(num: Int) {\n        stack.append(num)\n    }\n\n    /* \u51fa\u6808 */\n    @discardableResult\n    func pop() -> Int {\n        if isEmpty() {\n            fatalError(\"\u6808\u4e3a\u7a7a\")\n        }\n        return stack.removeLast()\n    }\n\n    /* \u8bbf\u95ee\u6808\u9876\u5143\u7d20 */\n    func peek() -> Int {\n        if isEmpty() {\n            fatalError(\"\u6808\u4e3a\u7a7a\")\n        }\n        return stack.last!\n    }\n\n    /* \u5c06 List \u8f6c\u5316\u4e3a Array \u5e76\u8fd4\u56de */\n    func toArray() -> [Int] {\n        stack\n    }\n}\n
array_stack.js
/* \u57fa\u4e8e\u6570\u7ec4\u5b9e\u73b0\u7684\u6808 */\nclass ArrayStack {\n    #stack;\n    constructor() {\n        this.#stack = [];\n    }\n\n    /* \u83b7\u53d6\u6808\u7684\u957f\u5ea6 */\n    get size() {\n        return this.#stack.length;\n    }\n\n    /* \u5224\u65ad\u6808\u662f\u5426\u4e3a\u7a7a */\n    isEmpty() {\n        return this.#stack.length === 0;\n    }\n\n    /* \u5165\u6808 */\n    push(num) {\n        this.#stack.push(num);\n    }\n\n    /* \u51fa\u6808 */\n    pop() {\n        if (this.isEmpty()) throw new Error('\u6808\u4e3a\u7a7a');\n        return this.#stack.pop();\n    }\n\n    /* \u8bbf\u95ee\u6808\u9876\u5143\u7d20 */\n    top() {\n        if (this.isEmpty()) throw new Error('\u6808\u4e3a\u7a7a');\n        return this.#stack[this.#stack.length - 1];\n    }\n\n    /* \u8fd4\u56de Array */\n    toArray() {\n        return this.#stack;\n    }\n}\n
array_stack.ts
/* \u57fa\u4e8e\u6570\u7ec4\u5b9e\u73b0\u7684\u6808 */\nclass ArrayStack {\n    private stack: number[];\n    constructor() {\n        this.stack = [];\n    }\n\n    /* \u83b7\u53d6\u6808\u7684\u957f\u5ea6 */\n    get size(): number {\n        return this.stack.length;\n    }\n\n    /* \u5224\u65ad\u6808\u662f\u5426\u4e3a\u7a7a */\n    isEmpty(): boolean {\n        return this.stack.length === 0;\n    }\n\n    /* \u5165\u6808 */\n    push(num: number): void {\n        this.stack.push(num);\n    }\n\n    /* \u51fa\u6808 */\n    pop(): number | undefined {\n        if (this.isEmpty()) throw new Error('\u6808\u4e3a\u7a7a');\n        return this.stack.pop();\n    }\n\n    /* \u8bbf\u95ee\u6808\u9876\u5143\u7d20 */\n    top(): number | undefined {\n        if (this.isEmpty()) throw new Error('\u6808\u4e3a\u7a7a');\n        return this.stack[this.stack.length - 1];\n    }\n\n    /* \u8fd4\u56de Array */\n    toArray() {\n        return this.stack;\n    }\n}\n
array_stack.dart
/* \u57fa\u4e8e\u6570\u7ec4\u5b9e\u73b0\u7684\u6808 */\nclass ArrayStack {\n  late List<int> _stack;\n  ArrayStack() {\n    _stack = [];\n  }\n\n  /* \u83b7\u53d6\u6808\u7684\u957f\u5ea6 */\n  int size() {\n    return _stack.length;\n  }\n\n  /* \u5224\u65ad\u6808\u662f\u5426\u4e3a\u7a7a */\n  bool isEmpty() {\n    return _stack.isEmpty;\n  }\n\n  /* \u5165\u6808 */\n  void push(int _num) {\n    _stack.add(_num);\n  }\n\n  /* \u51fa\u6808 */\n  int pop() {\n    if (isEmpty()) {\n      throw Exception(\"\u6808\u4e3a\u7a7a\");\n    }\n    return _stack.removeLast();\n  }\n\n  /* \u8bbf\u95ee\u6808\u9876\u5143\u7d20 */\n  int peek() {\n    if (isEmpty()) {\n      throw Exception(\"\u6808\u4e3a\u7a7a\");\n    }\n    return _stack.last;\n  }\n\n  /* \u5c06\u6808\u8f6c\u5316\u4e3a Array \u5e76\u8fd4\u56de */\n  List<int> toArray() => _stack;\n}\n
array_stack.rs
/* \u57fa\u4e8e\u6570\u7ec4\u5b9e\u73b0\u7684\u6808 */\nstruct ArrayStack<T> {\n    stack: Vec<T>,\n}\n\nimpl<T> ArrayStack<T> {\n    /* \u521d\u59cb\u5316\u6808 */\n    fn new() -> ArrayStack<T> {\n        ArrayStack::<T> {\n            stack: Vec::<T>::new(),\n        }\n    }\n\n    /* \u83b7\u53d6\u6808\u7684\u957f\u5ea6 */\n    fn size(&self) -> usize {\n        self.stack.len()\n    }\n\n    /* \u5224\u65ad\u6808\u662f\u5426\u4e3a\u7a7a */\n    fn is_empty(&self) -> bool {\n        self.size() == 0\n    }\n\n    /* \u5165\u6808 */\n    fn push(&mut self, num: T) {\n        self.stack.push(num);\n    }\n\n    /* \u51fa\u6808 */\n    fn pop(&mut self) -> Option<T> {\n        match self.stack.pop() {\n            Some(num) => Some(num),\n            None => None,\n        }\n    }\n\n    /* \u8bbf\u95ee\u6808\u9876\u5143\u7d20 */\n    fn peek(&self) -> Option<&T> {\n        if self.is_empty() {\n            panic!(\"\u6808\u4e3a\u7a7a\")\n        };\n        self.stack.last()\n    }\n\n    /* \u8fd4\u56de &Vec */\n    fn to_array(&self) -> &Vec<T> {\n        &self.stack\n    }\n}\n
array_stack.c
/* \u57fa\u4e8e\u6570\u7ec4\u5b9e\u73b0\u7684\u6808 */\ntypedef struct {\n    int *data;\n    int size;\n} ArrayStack;\n\n/* \u6784\u9020\u51fd\u6570 */\nArrayStack *newArrayStack() {\n    ArrayStack *stack = malloc(sizeof(ArrayStack));\n    // \u521d\u59cb\u5316\u4e00\u4e2a\u5927\u5bb9\u91cf\uff0c\u907f\u514d\u6269\u5bb9\n    stack->data = malloc(sizeof(int) * MAX_SIZE);\n    stack->size = 0;\n    return stack;\n}\n\n/* \u6790\u6784\u51fd\u6570 */\nvoid delArrayStack(ArrayStack *stack) {\n    free(stack->data);\n    free(stack);\n}\n\n/* \u83b7\u53d6\u6808\u7684\u957f\u5ea6 */\nint size(ArrayStack *stack) {\n    return stack->size;\n}\n\n/* \u5224\u65ad\u6808\u662f\u5426\u4e3a\u7a7a */\nbool isEmpty(ArrayStack *stack) {\n    return stack->size == 0;\n}\n\n/* \u5165\u6808 */\nvoid push(ArrayStack *stack, int num) {\n    if (stack->size == MAX_SIZE) {\n        printf(\"\u6808\u5df2\u6ee1\\n\");\n        return;\n    }\n    stack->data[stack->size] = num;\n    stack->size++;\n}\n\n/* \u8bbf\u95ee\u6808\u9876\u5143\u7d20 */\nint peek(ArrayStack *stack) {\n    if (stack->size == 0) {\n        printf(\"\u6808\u4e3a\u7a7a\\n\");\n        return INT_MAX;\n    }\n    return stack->data[stack->size - 1];\n}\n\n/* \u51fa\u6808 */\nint pop(ArrayStack *stack) {\n    int val = peek(stack);\n    stack->size--;\n    return val;\n}\n
array_stack.zig
// \u57fa\u4e8e\u6570\u7ec4\u5b9e\u73b0\u7684\u6808\nfn ArrayStack(comptime T: type) type {\n    return struct {\n        const Self = @This();\n\n        stack: ?std.ArrayList(T) = null,     \n\n        // \u6784\u9020\u65b9\u6cd5\uff08\u5206\u914d\u5185\u5b58+\u521d\u59cb\u5316\u6808\uff09\n        pub fn init(self: *Self, allocator: std.mem.Allocator) void {\n            if (self.stack == null) {\n                self.stack = std.ArrayList(T).init(allocator);\n            }\n        }\n\n        // \u6790\u6784\u65b9\u6cd5\uff08\u91ca\u653e\u5185\u5b58\uff09\n        pub fn deinit(self: *Self) void {\n            if (self.stack == null) return;\n            self.stack.?.deinit();\n        }\n\n        // \u83b7\u53d6\u6808\u7684\u957f\u5ea6\n        pub fn size(self: *Self) usize {\n            return self.stack.?.items.len;\n        }\n\n        // \u5224\u65ad\u6808\u662f\u5426\u4e3a\u7a7a\n        pub fn isEmpty(self: *Self) bool {\n            return self.size() == 0;\n        }\n\n        // \u8bbf\u95ee\u6808\u9876\u5143\u7d20\n        pub fn peek(self: *Self) T {\n            if (self.isEmpty()) @panic(\"\u6808\u4e3a\u7a7a\");\n            return self.stack.?.items[self.size() - 1];\n        }  \n\n        // \u5165\u6808\n        pub fn push(self: *Self, num: T) !void {\n            try self.stack.?.append(num);\n        } \n\n        // \u51fa\u6808\n        pub fn pop(self: *Self) T {\n            var num = self.stack.?.pop();\n            return num;\n        } \n\n        // \u8fd4\u56de ArrayList\n        pub fn toList(self: *Self) std.ArrayList(T) {\n            return self.stack.?;\n        }\n    };\n}\n
Code Visualization

Full Screen >

"},{"location":"chapter_stack_and_queue/stack/#513-comparison-of-the-two-implementations","title":"5.1.3 \u00a0 Comparison of the Two Implementations","text":"

Supported Operations

Both implementations support all the operations defined in a stack. The array implementation additionally supports random access, but this is beyond the scope of a stack definition and is generally not used.

Time Efficiency

In the array-based implementation, both push and pop operations occur in pre-allocated contiguous memory, which has good cache locality and therefore higher efficiency. However, if the push operation exceeds the array capacity, it triggers a resizing mechanism, making the time complexity of that push operation \\(O(n)\\).

In the linked list implementation, list expansion is very flexible, and there is no efficiency decrease issue as in array expansion. However, the push operation requires initializing a node object and modifying pointers, so its efficiency is relatively lower. If the elements being pushed are already node objects, then the initialization step can be skipped, improving efficiency.

Thus, when the elements for push and pop operations are basic data types like int or double, we can draw the following conclusions:

  • The array-based stack implementation's efficiency decreases during expansion, but since expansion is a low-frequency operation, its average efficiency is higher.
  • The linked list-based stack implementation provides more stable efficiency performance.

Space Efficiency

When initializing a list, the system allocates an \"initial capacity,\" which might exceed the actual need; moreover, the expansion mechanism usually increases capacity by a specific factor (like doubling), which may also exceed the actual need. Therefore, the array-based stack might waste some space.

However, since linked list nodes require extra space for storing pointers, the space occupied by linked list nodes is relatively larger.

In summary, we cannot simply determine which implementation is more memory-efficient. It requires analysis based on specific circumstances.

"},{"location":"chapter_stack_and_queue/stack/#514-typical-applications-of-stack","title":"5.1.4 \u00a0 Typical Applications of Stack","text":"
  • Back and forward in browsers, undo and redo in software. Every time we open a new webpage, the browser pushes the previous page onto the stack, allowing us to go back to the previous page through the back operation, which is essentially a pop operation. To support both back and forward, two stacks are needed to work together.
  • Memory management in programs. Each time a function is called, the system adds a stack frame at the top of the stack to record the function's context information. In recursive functions, the downward recursion phase keeps pushing onto the stack, while the upward backtracking phase keeps popping from the stack.
"},{"location":"chapter_stack_and_queue/summary/","title":"5.4 \u00a0 Summary","text":""},{"location":"chapter_stack_and_queue/summary/#1-key-review","title":"1. \u00a0 Key Review","text":"
  • Stack is a data structure that follows the Last-In-First-Out (LIFO) principle and can be implemented using arrays or linked lists.
  • In terms of time efficiency, the array implementation of the stack has a higher average efficiency. However, during expansion, the time complexity for a single push operation can degrade to \\(O(n)\\). In contrast, the linked list implementation of a stack offers more stable efficiency.
  • Regarding space efficiency, the array implementation of the stack may lead to a certain degree of space wastage. However, it's important to note that the memory space occupied by nodes in a linked list is generally larger than that for elements in an array.
  • A queue is a data structure that follows the First-In-First-Out (FIFO) principle, and it can also be implemented using arrays or linked lists. The conclusions regarding time and space efficiency for queues are similar to those for stacks.
  • A double-ended queue (deque) is a more flexible type of queue that allows adding and removing elements at both ends.
"},{"location":"chapter_stack_and_queue/summary/#2-q-a","title":"2. \u00a0 Q & A","text":"

Q: Is the browser's forward and backward functionality implemented with a doubly linked list?

A browser's forward and backward navigation is essentially a manifestation of the \"stack\" concept. When a user visits a new page, the page is added to the top of the stack; when they click the back button, the page is popped from the top of the stack. A double-ended queue (deque) can conveniently implement some additional operations, as mentioned in the \"Double-Ended Queue\" section.

Q: After popping from a stack, is it necessary to free the memory of the popped node?

If the popped node will still be used later, it's not necessary to free its memory. In languages like Java and Python that have automatic garbage collection, manual memory release is not necessary; in C and C++, manual memory release is required.

Q: A double-ended queue seems like two stacks joined together. What are its uses?

A double-ended queue, which is a combination of a stack and a queue or two stacks joined together, exhibits both stack and queue logic. Thus, it can implement all applications of stacks and queues while offering more flexibility.

Q: How exactly are undo and redo implemented?

Undo and redo operations are implemented using two stacks: Stack A for undo and Stack B for redo.

  1. Each time a user performs an operation, it is pushed onto Stack A, and Stack B is cleared.
  2. When the user executes an \"undo\", the most recent operation is popped from Stack A and pushed onto Stack B.
  3. When the user executes a \"redo\", the most recent operation is popped from Stack B and pushed back onto Stack A.
"}]} \ No newline at end of file diff --git a/en/sitemap.xml.gz b/en/sitemap.xml.gz index 3b41214c14f0d0a9d7271fad198e75377e07e384..5af95e81565dbc00d18f26784d57271c6b6f8cd3 100644 GIT binary patch delta 15 Wcmey%{Fj+czMF$1l diff --git a/sitemap.xml.gz b/sitemap.xml.gz index 484706eee2c40ef23aeca23c6da4a49e2ba2f997..469fd98305c058ef27b092362e0c0d0703e27ea8 100644 GIT binary patch delta 15 WcmaFM{+69hzMF$1?&?Oi=ga^shy{HB delta 15 WcmaFM{+69hzMF%C|J+8l=ga^qiv=eD

Feel free to engage in Chinese-to-English translation and pull request review! For guidelines, please see #914.