Praktycznie tak - w pierwszym wypadku kompilator zmieni to na jeden if (jedno porównanie), w drugim będzie to wyglądało tak (pseudokod):
(pomijam fakt, że kompilator zauważy, że w podanym przykładzie liczba = 50)
if( liczba < 50 )
goto case liczba;
goto koniec;
case 1: tab[ liczba ] ++; break;
case 5: tab[ liczba ] ++; break;
case 10: tab[ liczba ] ++; break;
case 11: tab[ liczba ] ++; break;
case 14: tab[ liczba ] ++; break;
case 16: tab[ liczba ] ++; break;
case 18: tab[ liczba ] ++; break;
case 20: tab[ liczba ] ++; break;
case 30: tab[ liczba ] ++; break;
case 50: tab[ liczba ] ++; break;
case 0:
case 2:
case 3:
...itd, wszystkie inne liczby
koniec:
Jedno porównanie/skok (if .. goto)+ skok (break). Jeśli liczba byłaby charem, możliwa byłaby implementacja bez tego porównania - tablica adresów (case) miałaby wtedy 256 pól.
Więc, różnica jednej instrukcji (jeśli to int).
Z kolei if: jedno porównanie/skok, break niepotrzebny.
Ale if..else if to już porównanie/skok + skok + porównanie/skok.
Tyle co do liczb koło siebie. Teraz ciekawszy przypadek (nie odpowiadam na nic konkretnie, tylko rozwijam temat). Powiedzmy że mamy 100000 warunków, rozrzuconych po całym zakresie inta (4 miliardy). Zdecydowanie za dużo na jedną tablicę.
Więc realizacja będzie wyglądać tak:
switch( liczba & 0xFFFF ) {
case 0:...
case 1:...
...
case 200:
switch( liczba >> 16 ) albo if...else if
case...
case 65535
:...}
Średnio na jeden case przypada 1,52587890625 (100000/2^16) możliwości, dla średniego przypadku kompilator wygeneruje 1,52587890625 porównania.
Czyli, złożoność ciągle jest praktycznie stała, nawet dla najgorszego (teoretycznie) przypadku.
Dlatego switch będzie zawsze albo szybszy, albo taki sam jak zwykłe if..else if.
(w przypadku kilkunastu warunków kompilator może wygenerować drugi switch - rozkład liczby warunków powinien zgadzać się z rozkładem gaussa)
W praktyce więcej niż ~2000 warunków raczej nie będzie - a to daje nam średnio 0,030518043793392843518730449378195 porównania/skok + jeden skok (w przypadku najgorszego możliwego rozstrzelenia liczb). W porównaniu do średnio 1000 porównań/skoków + 1 w if...else if.
A większość stałych/itd jest zazwyczaj koło siebie (wiadomości win api np).
Nigdzie tutaj nie ma złożoności logarytmicznej.
P.S. Taka ciekawostka - jak kiedyś, ręcznie, optymalizowano switchem
Duff's device