设计一个函数需要注意 “严进宽出”
严禁是对参数的严格检查 指针 和长度 空值等等
宽出是???
1.求一个整数二进制数中有多少个1
常规解法:
判断这个位是否为1 是则计数++
代码:int GetDwordBitForOne_EX_EX(unsigned int num) { int count = 0; while(num) { if(1 == (num & 1)) count++; num >>= 1; } return count; }
基于这个思想 可以想到 如果这个位为0则不加 1则加
那么我们可以用于计数
代码:int GetDwordBitForOne_EX(unsigned int num) { int count = 0; while(num) { count += (num&1); //count = count + (num & 1); num >>=1; } return count; //0111 0011 0001 0000 }
还有一种几点的算法 就是异或比整数小1的数
比如:8(1000) & 7 (0111)就是去除8最右边的1
会找到最右边的1并去除 原因是相邻两个二进制是+1 -1的关系 进行与操作会把这个位置0 最后这个数肯定会变为0 只要num不是0 就一直去除最右边的1 同时计数
代码:int GetDwordBitForOne(int num) { int count = 0; while(num) { count++; num = num&(num-1);/*num & (num - 1) 会找到最右边的1并去除 原因是相邻两个二进制也是+1 进行与操作会把这个位置0 最后这个数肯定会变为0 只要num不是0 就一直去除最右边的1 同时计数*/ } return count; }
关于负数
只要将值取反+1即可(补码求负数)
代码:int GetDwordBit(int num) { // -10 10 if(num < 0) num = ~num + 1; return GetDwordBitForOne(num); }
2.实现一个strlen
常规方法:判断!= \0即可
代码:int _strlen(const char *str) { int count = 0; if(str==NULL) { return 0; } while(*str!='\0') { str++; count++; } return count; }
使用三木运算符 + 递归一句搞定
int _strlen2(const char *str) { return (str==NULL || *str=='\0')?0:1+_strlen2(str+1); }
3.逆置字符串
使用递归可以很快解决这个问题
代码:void Reserver_str(char* str,int len) { if(NULL == str || len <= 1) return; char strtemp = *str; *str = *(str + len - 1); *(str + len - 1) = strtemp; Reserver_str(str+1,len-2); }
也可以使用循环
void reverse_str(char* str) { if(str==NULL) { return; } intlen = _strlen(str); for(inti = 0; i < len/2; i++) { chartmp; tmp = str[i]; str[i]= str[len-i-1]; str[len-i-1]=tmp; } }
4.逆置单词
思路是 先整体逆置一遍 然后将是空格的地方分开来分别逆置
代码:void ReverseByWord(char* pchSentence) { if(NULL == pchSentence) { return; } //字符串整体逆置 Reserver_str(pchSentence,strlen(pchSentence)); //两个指针一前一后 char*pFirst , *pSecond = pchSentence; while(' ' == *pSecond)//如果第一个就是空格特殊 { ++pSecond; } if('\0'== *pSecond) { return; } pFirst = pSecond; for( ; *pSecond != '\0'; ++pSecond) { if(*pSecond != ' ') { continue; } Reserver_str(pFirst, pSecond - pFirst); //再寻找下一个单词的开始位置,以空格作为判断 while(' ' == *pSecond) ++pSecond; if('\0'== *pSecond) { break; } pFirst = pSecond; } Reserver_str(pFirst,pSecond - pFirst); }
5.左旋字符串
思路:
逆序排列abcd:abcd1234 → dcba1234;
逆序排列1234:dcba1234 → dcba4321;
全部逆序:dcba4321 → 1234abcd。
即:分别逆序排序 > 全部逆置
代码:void MoveWord_Left(char* str,int MoveNum) { if( NULL == str || *str == '\0'|| 0 == MoveNum) return; /* 逆序排列abcd:abcd1234 → dcba1234; 逆序排列1234:dcba1234 → dcba4321; 全部逆序:dcba4321 → 1234abcd。 */ size_t len = strlen(str); Reserver_str(str,MoveNum); Reserver_str(str + MoveNum,len - MoveNum); Reserver_str(str,len); //左旋 -- 思路 :分别逆序排序 > 全部逆置 }
6.右旋字符串思路:
全部逆序 abcd1234 -> 4321dcba
逆序排序 4321 :4321dcba -> 1234dcba
逆序排序 dcba :1234dcba -> 1234dcba
即:全部逆置 — >单个逆置
代码:就是上面代码 全部逆序排序提前void MoveWord_Right(char* str,int MoveNum) { if( NULL == str || *str == '\0'|| 0 == MoveNum) return; size_t len = strlen(str); Reserver_str(str,len); Reserver_str(str + MoveNum,len - MoveNum); Reserver_str(str,MoveNum); //右旋 -- 思路 : 全逆置 - > 分别逆置 }
7:改变一个整数的大小端存储0×12345678 -> 0×78563412
思路:是用一个0值来临时存储数据 使用 |=
把整数的第1字节,第2字节,第3字节,第四4字节一次左移24位,16位,8位和0位 并 |=临时变量
代码:void change_save(int* num) { inti = 0,ret = 0; char* p = NULL; if(num == NULL || *num == 0) return; p = (char*)num;//指向整数的低地址,取一个字节 i = sizeof(int) - 1; while(i>=0) { ret |= *p <<(i*8);//把整数的第1字节,第2字节,第3字节,第四4字节一次左移24位,16位,8位和0位 //printf("%x\n",ret); p ++ ; i --; } *num = ret; }
也可以是使用递归来解决这个问题 这个问题跟逆置字符串一致需要注意的是这个len是不包括\0的
void change_save_Ex_dowrd(char* num,int len) { if( NULL == num || len <=1) return; char temp = *num; *num = *(num + len - 1); *(num + len -1) = temp; change_save_Ex_dowrd(num + 1,len - 2); }
8:判断当前大小端存储 即是算法也是面试
如果是低位优先 则1在最后一位 如果是高位优先 则1在第一位 以此来判断大小端处理
int i = 1;
低位优先:0×00000001
高位优先:0×10000000
思路:i的指针的第一位如果是1则高位 反之低位
代码:BOOL is_integer_lower_store() { int i = 0x1; char *p = (char*)&p; if(*p == 1) return true; else return false; //如果是低位优先 则1在最后一位 如果是高位优先 则1在第一位 以此来判断大小端处理 }
也可以通过共用体来实现判断代码:
typedef union{ charc; inta; }U; BOOL is_integer_lower_store_Ex() { U u; u.a = 1; if(u.c == 1) return true; else return false; //原理同上 }
算法练习
最新推荐文章于 2019-07-21 22:11:09 发布