Podejrzewam, że masz ten kod z tej samej książki, którą czytam ... Sam kod nie jest tak tajemniczy jak operatory- | =, &, i <<, których normalnie nie używa my laicy - autor nie zawracał sobie głowy poświęcaniem dodatkowego czasu na wyjaśnienie procesu ani na temat rzeczywistej mechaniki. Na początku byłem zadowolony z poprzedniej odpowiedzi w tym wątku, ale tylko na poziomie abstrakcyjnym. Wróciłem do tego, bo czułem, że potrzebne jest bardziej konkretne wyjaśnienie - brak jednego zawsze wywołuje we mnie niepokój.
Ten operator << jest lewostronnym przesuwnikiem bitowym, który przyjmuje binarną reprezentację tej liczby lub operandu i przesuwa ją o dowolną liczbę miejsc określonych przez operand lub liczbę po prawej stronie, tak jak w liczbach dziesiętnych tylko w binarnych. Mnożymy przez podstawę 2 - kiedy przesuwamy się w górę, jednak o wiele miejsc nie ma podstawy 10 - więc liczba po prawej stronie jest wykładnikiem, a liczba po lewej jest podstawą wielokrotności 2.
Ten operator | = bierze operand po lewej stronie i lub jest z operandem po prawej - a ten - „&” i jest bitami obu operandów po lewej i po prawej stronie.
Mamy tu więc tablicę skrótów, która jest przechowywana w 32-bitowej liczbie binarnej za każdym razem, gdy kontroler otrzyma or'd ( checker |= (1 << val)
) z wyznaczoną wartością binarną litery, której odpowiadający jej bit jest ustawiany na true. Wartość znaku jest równa i oznaczona za pomocą checker ( checker & (1 << val)) > 0
) - jeśli jest większa niż 0, wiemy, że mamy podwójną wartość, ponieważ dwa identyczne bity ustawione na wartość true i razem zwrócą wartość true lub '1' '.
Istnieje 26 miejsc binarnych, z których każde odpowiada małej literze - autor powiedział, że łańcuch zawiera tylko małe litery - a to dlatego, że pozostało nam tylko 6 (w 32-bitowej liczbie całkowitej) miejsc do wykorzystania - i niż my dostać kolizję
00000000000000000000000000000001 a 2^0
00000000000000000000000000000010 b 2^1
00000000000000000000000000000100 c 2^2
00000000000000000000000000001000 d 2^3
00000000000000000000000000010000 e 2^4
00000000000000000000000000100000 f 2^5
00000000000000000000000001000000 g 2^6
00000000000000000000000010000000 h 2^7
00000000000000000000000100000000 i 2^8
00000000000000000000001000000000 j 2^9
00000000000000000000010000000000 k 2^10
00000000000000000000100000000000 l 2^11
00000000000000000001000000000000 m 2^12
00000000000000000010000000000000 n 2^13
00000000000000000100000000000000 o 2^14
00000000000000001000000000000000 p 2^15
00000000000000010000000000000000 q 2^16
00000000000000100000000000000000 r 2^17
00000000000001000000000000000000 s 2^18
00000000000010000000000000000000 t 2^19
00000000000100000000000000000000 u 2^20
00000000001000000000000000000000 v 2^21
00000000010000000000000000000000 w 2^22
00000000100000000000000000000000 x 2^23
00000001000000000000000000000000 y 2^24
00000010000000000000000000000000 z 2^25
Tak więc, dla ciągu wejściowego „azya”, przechodząc krok po kroku
ciąg „a”
a =00000000000000000000000000000001
checker=00000000000000000000000000000000
checker='a' or checker;
// checker now becomes = 00000000000000000000000000000001
checker=00000000000000000000000000000001
a and checker=0 no dupes condition
ciąg „az”
checker=00000000000000000000000000000001
z =00000010000000000000000000000000
z and checker=0 no dupes
checker=z or checker;
// checker now becomes 00000010000000000000000000000001
ciąg „azy”
checker= 00000010000000000000000000000001
y = 00000001000000000000000000000000
checker and y=0 no dupes condition
checker= checker or y;
// checker now becomes = 00000011000000000000000000000001
ciąg „azya”
checker= 00000011000000000000000000000001
a = 00000000000000000000000000000001
a and checker=1 we have a dupe
Teraz deklaruje duplikat