一、上课内容
1. 位运算及应用位运算 : 针对二进制 ( 数字本来 int,4 字节 , 下面假设为 1 字节 )12:0000 110013:0000 1101~12:1111 0011 按位取反12&13:0000 1100 按位与 , 相同的位都为 1 才为 112 | 13:0000 1101 按位或 , 相同的位只要有 1 就为 112^13:0000 0001 按位异或 , 相同的位不一样就为 112<<1:000 11000 按位左移 , 右边补 0( 离符号太远 )24=12*2 左移相当于乘法 ( 正数 ) 乘以 2 的位移次方12>>1:00000 110 右移 , 左边补符号位 ( 如果是无符号数补 0, 有符号数符号位为 0 则补 0, 为 1 则补1)6=12/2 右移相当于除法 ( 正数 ), 除以 2 的位移次方
具体运算如下 : 下面的运算都是针对二进制去掉最后一位 | (101101->10110) | x>>1在最后加一个 0 | (101101->1011010) | x<<1在最后加一个 1 | (101101->1011011) | (x<<1) | 1把最后一位变成 1 | (101100->101101) | x|1把最后一位变成 0 | (101101->101100) | (x>>1) <<1 x&~1最后一位取反 | (101101->101100) | x^1把右数第 k 位变成 1 | (101001->101101,k=3) | x|(1<<(k-1))把右数第 k 位变成 0 | (101101->101001,k=3) | x&111011 -> x&~(1<<(k-1))右数第 k 位取反 | (101001->101101,k=3) | x^100 -> x^(1<<(k-1))1. 确定符号 2. 确定数字 3. 构造数字得到 1 | 1 ( 这一位是 1)得到 0 &0( 这一位是 0)取反 ^1取最右边的 1 位 | (1101101->1) | x&1 , x%2取末三位 | (1101101->101) | x&111->x&((1<<3)-1) ,x&7取末 k 位 | (1101101->1101,k=4) | x&((1<<k)-1)取右数第 k 位 | (1101101->1,k=4) | (x>>(k-1))&1
编程1:所有的数字成对,只有一个数字只出现一次,找到它
//1^3^5^3^1=1^1^3^3^5=5
//找打单的数字
int SingleNum(int* arr, int len)//O(n)
{
int tmp = 0;
for (int i = 0; i < len; i++)
tmp ^= arr[i];
return tmp;
}
int main()
{
int arr[] = {1,5,3,7,9,6,1,3,9,6,5};//所有的数字成对,只有一个数字只出现一次,找
到它
//算法1:1.排序;2.遍历 O(nlogn)
//算法2:从头到尾按位异或(按位异或相同的数字为0,5^5==0)
int n = SingleNum(arr,sizeof(arr)/sizeof(arr[0]));
printf("%d\n",n);
return 0;
}
编程应用2:统计一个数字二进制1的个数.例如9转为二进制是0000 1001,那么二进制中1的个数为2.
//算法1:利用%2和/2
//统计十进制数字中1的个数例如1231212->3 得个位n%10 ,丢个位n/=10
//统计二进制中1的个数
int Bits(unsigned int n)//-1 ->11111111111111111111111111111111
{
int count = 0;//计数器
while (n != 0)
{
if (n % 2 == 1)
count++;
n /= 2;
}
return count;
}
int main()
{
printf("%d\n",Bits(12345678));
printf("%d\n", Bits(0x12345678));//1+1+2+1+2+2+3+1
printf("%d\n", Bits(-1));//32
return 0;
}
//算法2:利用位运算,统计最右边1的个数
int Bits2(unsigned int n)
{//n&1:得到二进制右数第1位; n>>=1:丢弃右数第1位
int count = 0;
while (n != 0)//0x10000000
{
count += n & 1;
n >>= 1;
}
return count;
}
int main()
{
printf("%d\n",Bits(12345678));
printf("%d\n", Bits(0x12345678));//1+1+2+1+2+2+3+1
printf("%d\n", Bits(-1));//32
return 0;
}
//算法3:利用x&(x-1)进行统计
int Bits(unsigned int n)
{
int count = 0;
while (n != 0)
{
count++;
n &= n - 1; //丢弃二进制最右边的1
}
return count;
}
int main()
{
printf("%d\n",Bits(12345678));
printf("%d\n", Bits(0x12345678));//1+1+2+1+2+2+3+1
printf("%d\n", Bits(-1));//32
return 0;
}
x&(x-1) 的作用 ? 答 : 丢弃最右边的 1 , 如下面的举例 :x :3 11x-1 :2 10结果 :2 10x :4 100x-1 :3 011结果 :0 000x :5 101x-1 :4 100结果 :4 100x :6 110x-1 :5 101结果 :4 100
//其他算法
int func(unsigned i) //统计二进制1的个数
{
unsigned temp = i;
temp = (temp & 0x55555555) + ((temp & 0xaaaaaaaa) >> 1);
temp = (temp & 0x33333333) + ((temp & 0xcccccccc) >> 2);
temp = (temp & 0x0f0f0f0f) + ((temp & 0xf0f0f0f0) >> 4);
temp = (temp & 0xff00ff) + ((temp & 0xff00ff00) >> 8);
temp = (temp & 0xffff) + ((temp & 0xffff0000) >> 16);
return temp;
}
int main()
{
printf("%d\n", func(0x7f530829));//3+4+2+2+1+1+2=15
return 0;
}
2. 泛型编程void *p: 通用指针 , 也称泛型指针 , 没有类型的指针 , 仅仅记录地址的开头 , 不能算术运算 ,p+1, 不能*p.malloc 的返回值就是 void *;
void *memcpy(
void *dest,
const void *src,
size_t count
);//内存拷贝函数
dest:目标地址
sec:源地址
count:拷贝的字节数
下面以交换数据为例.
void Swap_char(char* p1, char* p2)
{
char tmp = *p1;
*p1 = *p2;
*p2 = tmp;
}
void Swap_short(short* p1, short* p2)
{
short tmp = *p1;
*p1 = *p2;
*p2 = tmp;
}
void Swap_int(int* p1, int* p2)
{
int tmp = *p1;
*p1 = *p2;
*p2 = tmp;
}
int main()
{
char a = 'x';
char b = 'y';
short c = 10;
short d = 20;
int e = 500;
int f = 600;
printf("%c,%c\n", a, b);
Swap_char(&a,&b);
printf("%c,%c\n",a,b);
printf("%d,%d\n", c, d);
Swap_short(&c,&d);
printf("%d,%d\n",c,d);
printf("%d,%d\n", e, f);
Swap_int(&e,&f);
printf("%d,%d\n",e,f);
return 0;
}
从上面的代码能发现,交换的过程是一样的,不一样的只有数据类型.
下面的函数能针对所有的数据类型进行数据交换
//size:字节数
void Swap(void* vp1, void* vp2,int size)
{
void* tmp = malloc(size);
memcpy(tmp, vp1, size);
memcpy(vp1,vp2,size);
memcpy(vp2,tmp,size);
free(tmp);
}
int main()
{
char a = 'x';
char b = 'y';
short c = 10;
short d = 20;
int e = 500;
int f = 600;
printf("%c,%c\n", a, b);
Swap(&a,&b,sizeof(char));
printf("%c,%c\n",a,b);
printf("%d,%d\n", c, d);
Swap(&c,&d,sizeof(short));
printf("%d,%d\n",c,d);
printf("%d,%d\n", e, f);
Swap(&e,&f,sizeof(int));
printf("%d,%d\n",e,f);
return 0;
}