使用异或交换数据犯的错
异或
异或特性
-
参与运算的两个值,如果两个相应位相同,则结果为 0,否则为 1
0^0=0, 1^1=0 1^0=1, 0^1=1
-
任何数异或自己,等于把自己置 0
-
对于任何数 x,都有
x^x=0,x^0=x
-
1 异或任何数,其结果 = 任何数取反
-
交换律:
a ^ b = b ^ a
-
结合律:
(a^b)^c == a^(b^c)
异或交换数值
-
交换方法
A^=B B^=A A^=B
-
a=10100001, b=00000110
a=a^b; //a=10100111 b=b^a; //b=10100001 a=a^b; //a=00000110
-
原理:数 a 两次异或同一个数
b(a=a^b^b)
仍然为原值 a . -
分析:
a(新) = a(原) ^ b(原) b(新) = b(原) ^ a(新) = b(原) ^ a(原) ^ b(原) = a(原) ^ b(原) ^ b(原) = a(原) ^ 0 = a(原) a(新2)= a(新) ^ b(新) = a(原) ^ b(原) ^ a(原) = b(原) ^ a(原) ^ a(原) = b(原) ^ 0 = b(原)
异或交换数据的坑
-
在写快排算法时
int test_arry[18] = {1, 3, 4, 5, 532, 0, 3, 19, 2, 19, 100, 128, 69, 39, 98, 99, 399, 5000}; void swap(int *a, int *b) // Got a problem in quick sort when swap data { *a ^= (*b); *b ^= (*a); *a ^= (*b); } void swap2(int *a, int *b) { int tmp = (*a); *a = (*b); *b = tmp; } int partion(int arry[], int low, int high) { int pivot = arry[low]; int start = low; while(low<high) { while((low<high) && (arry[high]>=pivot)) { high--; } while((low<high) && (arry[low]<=pivot)) { low++; } if(low>=high) { break; } swap(&arry[low], &arry[high]); } swap(&arry[low], &arry[start]); return low; } void ns_qsort(int arry[], int low, int high) { if (low<high) { int pos = partion(arry, low, high); ns_qsort(arry, 0, pos-1); ns_qsort(arry, pos+1, high); } } void test_quick_sort(void) { print_int_arry(test_arry, 18); printf("Arry is sorted: %s\n", if_arry_sorted(test_arry, 18, mycompare) ? "Yes" : "No"); ns_qsort(test_arry, 0, 17); print_int_arry(test_arry, 18); printf("Arry is sorted: %s\n", if_arry_sorted(test_arry, 18, mycompare) ? "Yes" : "No"); } 使用 swap() 的输出结果(排序后,结果出错): [1, 3, 4, 5, 532, 0, 3, 19, 2, 19, 100, 128, 69, 39, 98, 99, 399, 5000] Arry is sorted: No [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 100, 128, 399, 532, 5000] 使用 swap2() 的输出结果(排序后,结果正常): [1, 3, 4, 5, 532, 0, 3, 19, 2, 19, 100, 128, 69, 39, 98, 99, 399, 5000] Arry is sorted: No [0, 1, 2, 3, 3, 4, 5, 19, 19, 39, 69, 98, 99, 100, 128, 399, 532, 5000] Arry is sorted: Yes
-
原因分析
- 在 swap() 中加入调试信息
我们发现,有多次操作,我们 swap 操作了同一块内存,并且数组 index 相同,且都是位于 while 循环外调用的 swap_t , 原因在于// 异或出现 0 值,只有自己把自己异或掉的时候才有这种情况 void swap_t(int *a, int *b, int indexa, int indexb, int flag) // Got a problem in quick sort when swap data { // flag == 0 means using swap_t in while loop, flag == 1 means using swap_t outside while loop *a ^= (*b); *b ^= (*a); *a ^= (*b); if(a == b) { printf("swap: %p, %p; index_a = %d, index_b = %d; flag = %s\n",a,b, indexa, indexb, 0?"in":"out"); } } 输出结果 ... swap: 0x602088, 0x602088; index_a = 2, index_b = 2; flag = out swap: 0x602080, 0x602080; index_a = 0, index_b = 0; flag = out ...
while((low<high) && (arry[high]>=pivot)) while((low<high) && (arry[low]<=pivot)) 其中的 >= 和 <= 符号的等号(=) 即当 ns_qsort(arry, low, high) 对比到 (low + 1) == high 时,一个变量对自己亦或,就会是 0,注意, 如果是两个值相同的不同变量采用异或交换法,结果是正确的,但此处,操作同一块内存,那么至始至终都是一个变量在对自己异或操作
- 在 swap() 中加入调试信息
-
改进方法
void swap(int *a, int *b) // Perfect { if (a == b) { return; } *a ^= (*b); *b ^= (*a); *a ^= (*b); }