一、位操作的使用不僅能簡化代碼的書寫,還能有效的提高程序的執行效率。但位操作僅能用於整型類型存儲(int, char)的數
1、判斷奇偶數:
所有數都由2^n相加組成,偶數無2^0,所以偶數的二進制位最低位爲0,奇數爲1
偶數:(num&1)==0
奇數:(num&1)==1
注’==’優先級高於&,所以必須有括號
2、求平均數:
方法1:(num1+num2)/2; //存在num1+num2超出數值範圍危險,可計算任何數據類型
方法2:num1+((num2-num1)>>1); //num1,num2,num1的順序不可寫反(列:num1+((num1-num2)>>1))
方法3:(num1&num2)+((num1^num2)>>1); //兩個數的相同部分加上不同部分的一半,即爲平均數。
注:‘+’的優先級高於‘>>’所以必須有括號
3、交換兩個數(字符)
方法1:引用第三變量temp
temp=num1;
num1=num2;
num2=temp;
方法2:用’^’操作
num1^=num2;
num2^=num1;
num1^=num2;
4、交換二進制中的奇偶位
(((num&(0x55555555))<<1)|((num&(0xAAAAAAAA))>>1))//二進制奇偶位交換
二進制寄偶位交換思路:
(1)、取所有的奇數位,讓偶數位爲0,然後左移1位。此時所有奇數位都變爲偶數位
(2)、取所有的偶數位,讓奇數位爲0,然後右移1位。此時所有偶數位都變爲奇數位
(3)、再將奇數位與偶數位’ | ‘運算(合併)即可
& 0x5555 5555=0101 0101 0101 0101 0101 0101 0101 0101 (取所有的奇數位)
& 0xAAAA AAAA=1010 1010 1010 1010 1010 1010 1010 1010 (取所有的偶數位)
5、計算二進制位中有多少位1
while(num)//統計1數
{
num&=(num-1);
count ++;
//統計個數
}
6、輸出二進制中的每一位(正序)
for(i=31;i>=0;i--)//輸出每一位
{
printf("%d ",(num>>i)&1);
}
7、比較兩個數二進制位中有幾位不同
for(i=0;i<32;i++)
{
if(((num1>>i)&1)!=((num2>>i)&1))//比較位是否相同
n++;//統計個數
}
8、查出一組數中那個數出現了奇數次
根據a^a=0; 0^a=a; 所以最終剩餘的那個數便是奇數個
9、反轉一個數的二進制位
25->00000000000000000000000000011001
翻轉後:2550136832->10011000000000000000000000000000
for(i=0;i<32;i++)
{
bit=num>>i&1;//取二進制位,按低到高的順序取
num1=(num1+bit*pow(2.0,31-i));//計算所取得每位反轉後的值,並相加
}
二、代碼實例:
1.編寫函數:
unsigned int reverse_bit(unsigned int value);
這個函數的返回值value的二進制位模式從左到右翻轉後的值。
如:
在32位機器上25這個值包含下列各位:
25->00000000000000000000000000011001
翻轉後:
2550136832->10011000000000000000000000000000
#include<stdio.h>
#include<stdlib.h>
#include<math.h>
int change(int unsigned num)
{
int i=0;
int num1=0;
int bit=0;
for(i=0;i<32;i++)
{
bit=num>>i&1;//取二進制位,按低到高的順序取
num1=(num1+bit*pow(2.0,31-i));//計算所取得每位反轉後的值,並相加
}
return num1;
}
int main()
{
int unsigned num=0;
printf("輸入數字: ");
scanf("%d",&num);
printf("反轉後%u\n",change(num));
system("pause");
return 0;
}
2.編程實現:
一組數據中只有一個數字出現了一次。其他所有數字都是成對出現的。
請找出這個數字。(使用位運算)
#include<stdio.h>
#include<stdlib.h>
#define N 100 //假設數最多都有N位
int search( int num)
{
int num2=0;
int i=0;//數組下標
int num1[N]={0};
while(num)//整個數字拆分成多個數
{
num1[i]=num%10;
num=num/10;
i++;
}
num2=num1[0];
for(i=1;i<N;i++)
{
//根據a^a=0; 0^a=a; 所以最終剩餘的那個數便是一個或奇數個
num2=num2^num1[i];
}
return num2;
}
int main()
{
int num=243545020;
printf("非兩次出現數:%d\n",search(num));
system("pause");
return 0;
}
3、輸出二進制的每一位並統計有多少位爲1
#include<stdio.h>
#include<stdlib.h>
int main()
{
int num=0;
int count =0;
int i=0;
printf("輸入數值:");
scanf("%d",&num);
for(i=31;i>=0;i--)//輸出每一位
{
printf("%d ",(num>>i)&1);
}
while(num)//統計1數
{
num&=(num-1);
count ++;
}
printf("\n 爲一的有%d位\n",count );
system("pause");
return 0;
}
4、有一個字符數組的內容爲:”student a am i”,請你將數組的內容改爲”i am a student”.
#include<stdio.h>
#include<assert.h>
#include<ctype.h>
#include<stdlib.h>
void change2(char *q1, char *q2)
{
while(q1 < q2)
{
*q1 ^= *q2;
*q2 ^= *q1;
*q1 ^= *q2;
q1++;//指向下個字符
q2--;//指向上個字符
}
}
void change(char arr[])
{
char * p = arr;//用於指向單詞尾部
char * q = arr;//用於指向單詞頭部
assert(arr);//檢測函數,檢測arr是否爲NULL,頭文件#include<assert.h>
while(*p)//*p不爲'\0',字符串中的單詞交換
{
//判斷單詞是否結束,isspace(*p)如果*p爲空格返回1,頭文件#include<ctype.h>
if(isspace(*p))//if(*p1==' ')
{ //單詞結束,即交換單詞內容順序
change2(q,p-1);//交換此單詞內容順序,由於p1進入時指向的爲空格,所以-1
p++; //p指向下個單詞的頭部
q=p; //q指向下個單詞的頭部(第一個字母)
}
else //單詞未結束
p++;//指針指向下個字母
}//結束時p1指向'\0'
change2(arr,p-1);// 字符串整體交換 '\0'不可交換 p-1
}
int main()
{
char arr[]="student a am i";
printf("轉換前:%s \n",arr);
change(arr);
printf("轉換後:%s \n",arr);
system("pause");
return 0;
}
5、將數組組中的奇數排在前邊
#include<stdio.h>
#include<stdlib.h>
int change(int arr[],int sz)
{
int *p=arr;//指向前邊的數
int *q=&arr[sz-1];//指向後邊的數
while(p<q)
{
//注:所有數都是由2^n+2^k+...組成,偶數則無2^0,
//所以二進制最低位爲0則爲偶數,爲1則爲奇數,判斷奇偶數,使用位操作效率更高
if((*p&1)==0&&(*q&1)!=0)//前爲奇數,後爲偶數,交換
{
*p^=*q;
*q^=*p;
*p^=*q;
}
if(*p&1)//前邊爲奇數前指針後移
p++;
if((*q&1)==0)//後邊爲偶數後指針前移,注'=='優先級高於&,所以必須有括號
q--;
}
}
void print(int arr[],int sz)//輸出數組
{
int i=0;
for(i=0;i<sz;i++)
printf("%d ",arr[i]);
printf("\n");
}
int main()
{
int arr[]={1,2,3,4,5,6,9,8,7};
int sz=sizeof(arr)/sizeof(arr[0]);
print(arr,sz);
change(arr,sz);
printf("交換後\n");
print(arr,sz);
system("pause");
return 0;
}