web-dev-qa-db-fra.com

Que signifie (nombre et -numéro) dans la programmation de bits?

Par exemple:

int get(int i) {
    int res = 0;
    while (i) {
        res = (res + tree[i]) % MOD;
        i -= ( (i) & (-i) );
    }
    return res;
}

Une fonction de mise à jour de l'arborescence:

void update(int i, int val) {
    while (i <= m) {
        tree[i] = (tree[i] + val) % MOD;
        i += ( (i) & (-i) );
    }
}

Pouvez-vous expliquer ce qu'ils font dans le code en utilisant ( (i) & (-i) )?

64
SwadhIn

Ces deux fonctions sont une implémentation modifiée d'une structure de données arbre d'index binaire (arbre de Fenwick) .
Voici deux images pour compléter la réponse de MikeCAT montrant comment i la variable se met à jour pour différentes valeurs.

La fonction "get":
Pour supposer que la valeur maximale de l'entrée dans la fonction est 15 pour la simplicité de la représentation.
enter image description here
Un nœud avec le numéro t dessus représente l'arbre [t] dans l'arborescence.
Si vous appelez obtenez la fonction pour i le retour la valeur est la somme de arbre [i] plus la somme de tout arbre tableau les éléments dont leur index dans le tableau est un parent de i dans l'image, sauf zéro.
Voici quelques exemples:

get(15) = tree[15] + tree[14] + tree[12] + tree[8]
get(14) = tree[14] + tree[12] + tree[8]
get(13) = tree[13] + tree[12] + tree[8]
get(12) = tree[12] + tree[8]
get(11) = tree[11] + tree[10] + tree[8]
get(10) = tree[10] + tree[8]
get(9) = tree[9] + tree[8]
get(8) = tree[8]
get(7) = tree[7] + tree[6] + tree[4]
get(6) = tree[6] + tree[4]
get(5) = tree[5] + tree[4]
get(4) = tree[4]
get(3) = tree[3] + tree[2]
get(2) = tree[2]


Les nombres sur les étiquettes des nœuds dans l'image ci-dessus ont la propriété que le parent de chaque nœud est cette étiquette de nœud moins la moins significative 1 (très bien expliqué sur la réponse @MikeCAT) La fonction "mise à jour":
Pour simplifier l'image, supposons que la longueur maximale de l'arborescence est de 16.
La fonction de mise à jour est un peu plus délicate.
enter image description here
Il ajoute val à arbre [i] et tous les éléments d'arbre dont leur index est parent du nœud avec l'étiquette i sur la photo.

update(16, val) --> tree[16] += val;
update(15, val) --> tree[15] += val, tree[16] += val;
update(14, val) --> tree[14] += val, tree[16] += val;
update(13, val) --> tree[13] += val, tree[14] += val; tree[16] += val;
update(12, val) --> tree[12] += val, tree[16] += val;
update(11, val) --> tree[11] += val, tree[12] += val, tree[16] += val;
update(10, val) --> tree[10] += val, tree[12] += val, tree[16] += val;
update(9, val)  --> tree[9] += val, tree[10] += val, tree[12] += val, tree[16] += val;
update(8, val)  --> tree[8] += val, tree[16] += val;
update(7, val)  --> tree[7] += val, tree[8] += val, tree[16] += val;
update(6, val)  --> tree[6] += val, tree[8] += val, tree[16] += val;
update(5, val)  --> tree[5] += val, tree[6] += val, tree[8] += val, tree[16] += val;
update(4, val)  --> tree[4] += val, tree[8] += val, tree[16] += val;
update(3, val)  --> tree[3] += val, tree[4] += val, tree[8] += val, tree[16] += val;
update(2, val)  --> tree[2] += val, tree[4] += val, tree[8] += val, tree[16] += val;
update(1, val)  --> tree[1] += val, tree[2] += val, tree[4] += val, tree[8] += val, tree[16] += val;
10
FazeL

Permettez-moi de supposer que la valeur négative est représentée en utilisant le complément à deux. Dans ce cas, -i peut être calculé comme (~i)+1 (retournez les bits, puis ajoutez 1).

Par exemple, permettez-moi de considérer i = 44. Ensuite, en binaire,

i           = 0000 0000 0000 0000 0000 0000 0010 1100
~i          = 1111 1111 1111 1111 1111 1111 1101 0011
-i = (~i)+1 = 1111 1111 1111 1111 1111 1111 1101 0100
(i) & (-i)  = 0000 0000 0000 0000 0000 0000 0000 0100

Comme vous le voyez, le moindre bit égal à 1 peut être calculé à l'aide de (i) & (-i).

85
MikeCAT

Au cas où quelqu'un voudrait également une preuve plus générale,

Supposons que x a le format a10k (ce qui signifie ici, une chaîne de bits a, suivie d'un 1, suivi de k zéros).

-x est (par définition) la même chose que ~x + 1, donc

  • x & -x = (remplir)
  • a10k & - (a10k) = (déf. de négation)
  • a10k & ~ (a10k) + 1 = (appliquer l'inversion)
  • a10k & ~ a01k + 1 = (ajouter 1)
  • a10k & ~ a10k = (ET entre quelque chose et son inverse)
  • wdixk

Il ne nous reste donc que le 1 le plus à droite que nous supposions exister.

L'hypothèse concernant la forme de x laisse de côté le cas où x = 0, auquel cas le résultat est évidemment toujours nul.

21
harold