Kapag ang iyong pag-uuri ng mga klasipikasyon ay kinasasangkutan ng malalaking hanay ng maliliit na integersi gaya ng mga grado, edad, o mga kodigong klasiko na klasikong paghahambing-based algorithms tulad ng QuickSort o MergeSort ay maaaring makadama ng tulad ng overkill. Ang mga algorithm na ito ay tumatakbo sa oras na O(n log n), ngunit kung ang saklaw ng posibleng mga pagpapahalaga ay limitado, maaari mong uriin sa linear O(n + k) na may [[T:0] ⁇ [[T] ⁇ ] ⁇ [ ⁇ ] ⁇ ] ⁇ ] ⁇ [ ⁇ ] ⁇ ] ⁇ ⁇ ] ⁇ [ ⁇ ] ⁇ ⁇ ] ⁇ [ ⁇ ] ⁇ ] ⁇ ⁇ ] ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇

Kung Paano Gumagana ang Pagbilang sa Uri

Ang pagbilang ng Uri ay nagsasamantala sa kaalaman na ang input na mga pamantayan ay mga integram na hinango mula sa isang maliit na saklaw . sa halip na magkatambal na paghahambing, ito ay gumagawa ng isang frequency histagram ng mga pagpapahalaga at pagkatapos ay ginagamit ang histagram upang ilagay ang bawat elemento sa tamang naihihiwalay na posisyon nito.

Ang Pangunahing Paraan: Tuwirang Pagkukumpuni

Ang pinakasimpleng bersiyon ng pagbilang ng mga Uri ay gumagana sa dalawang daanan:

  1. CRCE frequency – Inufactory sa pamamagitan ng input array at incrender a counter para sa bawat halaga na nakikita mo.
  2. Overwrite the input – Maglakad sa hanay kontra mula pinakamaliit hanggang pinakamalaki at, sa bawat halaga, isulat ito pabalik sa input array ng maraming beses ng bilang nito.

Ito ay nagbibigay ng isang bukod na output ngunit gumagawa not preserbahin ang relatibong order ng mga kopya (hindi ito matatag)..Ang matatag na mga bagay kapag ikaw ay nag-uri sa isang susi habang pinananatili ang orihinal na pagkakasunud-sunod ng mga rekord na may pantay na mga key. Ang matatag na variant, na inilalarawan sa susunod, ay ang pinaka-karaniwang ginagamit sa pagsasagawa.

Ang Kapampangan: Mga Kondeng May Katatagan

Upang gawing matatag ang pagbilang, idinagdag natin ang ikatlong talata:

  1. Isalang ang frequency ng sigarilyo gaya ng dati.
  2. Pagbabago ng frequency array sa isang pagegram na bibilang. Pagkatapos ng hakbang na ito, hawak ang bilang ng mga elemento ⁇ i.
  3. I-ere ang input array sa baligtad (mula sa huling elemento hanggang sa una). Para sa bawat elemento, gamitin ang bolyum nitong bilang upang mahanap ang posisyon nito sa hanay ng output, ilagay ito, at i-decrement ang bilang.

Dahil sa ating pagtawid sa baligtad, ang relatibong pagkakasunud-sunod ng mga pantay na elemento ay napreserba. Ang hanay ng output ay hiwalay sa input, kaya ang bersiyong ito ay gumagamit ng O(n) ng karagdagang espasyo para sa output, samantalang ang saligang bersyon ay maaaring mag-uri sa in-point sa pamamagitan ng labis na pag-ukit ng input.

Pagtaya sa Uri ng Pagbilang sa C#

Nasa ibaba ang dalawang pagpapatupad ng C#: ang pangunahing in-point na bersyon (para sa mga senaryo kung saan hindi kinakailangan ang katatagan) at ang matatag na bersyon na gumagamit ng isang auxiliary array. kapwa nangangailangan ng pag-alam ng sukdulang halaga nang patiuna.

Pangunahin (Nondestable) na Pagbilang sa Uri

Ang pagkakaibang ito ay tuwirang tulad ng input array na walang ekstrang output buffer.

public static void CountingSortBasic(int[] array, int maxValue)
{
 int[] counts = new int[maxValue + 1];

 // Count each element's frequency
 for (int i = 0; i < array.Length; i++)
 {
 counts[array[i]]++;
 }

 // Overwrite the original array in sorted order
 int index = 0;
 for (int value = 0; value <= maxValue; value++)
 {
 while (counts[value]-- > 0)
 {
 array[index++] = value;
 }
 }
}

Matatag na Uri ng Pagbilang

Ang matatag na bersiyon ay nangangailangan ng isang hanay ng output na kasinlaki ng input. Gumagamit din ito ng mga copulated aspects sa posisyong tama ng mga elemento.

public static int[] CountingSortStable(int[] array, int maxValue)
{
 int[] counts = new int[maxValue + 1];
 int[] output = new int[array.Length];

 // Step 1: Count occurrences
 foreach (int num in array)
 {
 counts[num]++;
 }

 // Step 2: Transform counts to cumulative counts
 for (int i = 1; i <= maxValue; i++)
 {
 counts[i] += counts[i - 1];
 }

 // Step 3: Build the output array (iterate input in reverse for stability)
 for (int i = array.Length - 1; i >= 0; i--)
 {
 int value = array[i];
 output[counts[value] - 1] = value;
 counts[value]--;
 }

 return output;
}

Sa parehong pagpapatupad, ang pinakamalaking integrasyon na lumilitaw sa array. kung ang tunay na sukdulan ay hindi alam, maaari mo itong i-compile sa pamamagitan ng preparatory scan (O(n). Ang matatag na bersyon ay nagbabalik ng isang bagong separated array, na nag-iiwan ng orihinal na hindi nagbabago.

Masalimuot na Pagsusuri

Hayaang n ang bilang ng mga elemento at k = max – mi + 1 (ang saklaw ng posibleng mga halaga).

  • Ang pagbilang ng Uri ay tumatakbo sa O(n + k)[[[[[3]]. Ang yugto ng pagbilang ay O(n), ang pinagsamang unlapi ay O(k), at ang muling pagtatayo ay O(n). Kapag ang k ay O(n), ang algorithm ay linear.
  • [Space: Ang saligang bersyon ay gumagamit ng O(k) ekstrang espasyo para sa hanay ng mga konde. Ang matatag na bersyon ay gumagamit ng O(n + k) dahil ito rin ang nag-aalok ng hanay ng output. Ito ay gumagawa sa pagbibilang ng Sari-sari na hindi angkop kapag ang saklaw ay malaki-laking relatibo sa bilang ng mga bagay.
  • Commarson sa iba pang uri: Ang paghahambing ng mga uri ng quickSort at MergeSort ay nangangailangan ng hindi bababa sa O(n log n) na paghahambing. Para sa maliit na k (e.g., k < 10,000 at n > 100,000), ang pagbilang ng Sari ay maaaring maging mga order ng magnitude ng mas mabilis.

Mga Pagbabago at mga Paglalaho

Pakikitungo sa Negatibong mga Manggagantso

Upang pangasiwaan ang negatibong mga pamantayan, baguhin ang buong saklaw upang ang pinakamaliit ay maging sero. Halimbawa, kung ang mga numero ay mula -1000 hanggang 1000, takpan ang bawat elemento ng +1000. Ang hanay ng bilang kung gayon ay may sukat .

public static int[] CountingSortWithNegative(int[] array)
{
 if (array.Length == 0) return array;

 int min = array.Min();
 int max = array.Max();
 int range = max - min + 1;

 int[] counts = new int[range];
 int[] output = new int[array.Length];

 foreach (int num in array)
 counts[num - min]++;

 for (int i = 1; i < range; i++)
 counts[i] += counts[i - 1];

 for (int i = array.Length - 1; i >= 0; i--)
 {
 int value = array[i];
 output[counts[value - min] - 1] = value;
 counts[value - min]--;
 }

 return output;
}

Paggawa ng Mapa Hindi ng mga Susi sa Pag - iisip

Kung ang iyong datos ay binubuo ng mga karakter (bytes), o mga talaan na maaaring ihulma sa mga integers, maaari mo pa ring ikapit ito sa mas malalaking bagay, maaari mong kunin ang isang integer key at uriin ang mga bagay na naaayon sa paraang Ridix Uri ay kung paano kadalasang ginagamit ng Radix Dorld ang panloob na subroutine nito.

Radix Uri ng Combo

Ang Radix Surity process digits (o bits) bawat isa, at ang pagbilang ng mga Uri ang natural na pagpipilian para sa bawat paglipas kapag ang base (hal., 10 o 256) ay maliit.Ito ay nagpapahintulot sa linear greytime na uriin ang mga integers na hindi lamang maliliit.

Praktikal na mga Pag - iingat sa C#

Memory Footprint at Malaking k

Halimbawa, ang pinakamalaking silo ay ang pag - uuri sa isang hanay na mas malaki pa sa makukuhang memorya.

Pagkakatulad at Pagsangga ng TTH;

Para sa labis na malalaking mga array, maaari mong ihanay ang yugto ng pagbilang sa pamamagitan ng paghahati ng input sa mga sinulid. Ang bawat sinulid ay binibilang ang bahagi nito sa isang pribadong hanay, at pagkatapos ang mga bahagyang resulta ay aggregated. Ang paggamit at para sa hanay ng bilang ay maaaring magbawas ng mga allocation kapag ang saklaw ay maliit.

Mga Kaso ng Pangangatawan

  • [Empty array – bumalik agad.
  • [Single element – ang pag-uuri ay maliit.
  • Ang lahat ng mga magkatulad na halaga – ang bilang na hanay ay may isang non anzero entry; ang muling pagtatayo ay tumatakbo sa O(n).
  • Ang lawak ng large ngunit kakaunti ang datos – ang pagbilang ng Uri ay nagiging hindi mabisa dahil ang karamihan sa mga entidad ng pagbilang ay sero. Isaalang-alang ang isang hash standing na pagbibilang ng paraan o Bucket Sabwat.

Mga Mungkahi sa Pagganap

Gamitin ang Pagbilang ng Uri kapag alam mo ang input integers na bumabagsak sa maliit na range (hal.g., grades 0–100, edad 0–120, o error code 0–255). Para sa mas malaking hanay, isaalang-alang ang Radix Sari - sari o isang hybrid na bumabalik sa QuickSort para sa mataas na partikulong pang-care.

Kung Kailan Gagamitin ang Bilangin (at Kapag Hindi Pa)

SituationRecommendation
Small integer range (k ~ n)Excellent choice – linear time, simple code.
Large integer range (k >> n)Avoid – memory waste and O(k) overhead.
Need stabilityUse the stable variant (cumulative counts).
Strings or objectsConsider Radix Sort or a comparison sort.
Extremely large datasetsCounting Sort can be parallelized; but watch memory.

Pagmamarka at Pag - aayos

Sa isang karaniwang benchmark na may n = 1,000,000 at k = 1,000, ang pagbibilang ng Uri ay tumatapos sa mga 20–30% ng panahong ginugol ng (na gumagamit ng introsort). Ang puwang ay lumalapad habang ang k ay nababawasan. Ang ibaba ay isang tinatayang paghahambing (excutation time sa isang modernong CPU na may .NET 8):

n = 1,000,000 | k = 1,000
Array.Sort (QuickSort variant) : 68 ms
CountingSortBasic : 12 ms
CountingSortStable : 18 ms

Kapag ang range ay lumaki sa 10,000, ang pagbibilang Sari-saring mga Uri ay panalo pa rin, ngunit ang mardyin ay kumikipot. para sa k = 100,000, ang memorya sa itaas ( ⁇ 400 KB para sa count array) ay nagsisimulang saktan ang cache ng CPU, at ang pagsasagawa ay maaaring mapahina.

Pagsasaayos

Ang pagbilang ng Uri ay isang mapanlinlang na simpleng algorithm na nagbibigay ng linear performance kapag ang mga datos ay angkop sa mga limitasyon nito.Para sa mga C# developer na nakikitungo sa malalaking hanay ng maliliit na integers, ito ay isang mahalagang kasangkapan na lubhang makababawas sa pag - uuri ng panahon. Tingnan ang saklaw ng iyong datos: kung ito ay maliit at kilala, ang pagbilang ng mga bagay ay mag - aalis ng anumang paghahambing na may depektong mapagpipilian. Para sa mas pangkalahatang pag - uuri, gamitin ang yaring calclin [[LT:11], subalit laging handa na gumawa ng mga numero kapag ang mga numero ay nakakalkula at sa pamamagitan ng element.

Para sa higit pang pagbasa, sumangguni sa artikulo Wikipedia sa Pagbibilang ng Uri, ang Microsoft docs on Array.Sort, at isang praktikal na gabay mula GeeksforGeeks.