位操作的精巧使用

一、位操作的使用不僅能簡化代碼的書寫,還能有效的提高程序的執行效率。但位操作僅能用於整型類型存儲(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;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章