2018C语言及数据结构面试题
1、如何判断合法的IP地址,尽可能考虑各种情况 (腾讯面试题)
规则有:
正确的“192.168.3.44”
(1)由数字字符和点号组成
(2)第一个数字字符不能是0
(3)数字字符和点号的存放
(4)每个数字的范围是0~255
代码如下:
static int CountPoint(const char *str)
{
int count = 0;
while(*str != ‘\0’)
{
if(*str == ‘.’)
count++;
str++;
}
return count;
}
bool TestIP(const char * str)
{
assert(str != NULL);
if(str == NULL)
{
return false;
}
if(CountPoint(str) != 3)
{
return false;
}
if(str[0] == '0')
{
return false;
}
int tmp = 0;
int countnum = 0;//标记数字的个数
while(*str != '\0')
{
if(isdigit(*str))
{
tmp =tmp*10+ *str-'0';
}
else if(*str != '.' ||tmp>255)
{
return false;
}
else
{
tmp = 0;
}
str++;
}
if(tmp > 255)//处理尾部数据
{
return false;
}
return true;
}
int main()
{
char arr[]="192.168.2.25";
char brr[]="169.3.2";
char crr[]="123.4.44.";
if(TestIP(arr))
{
printf("此IP地址合法\n");
}
else
{
printf("不合法\n");
}
if(TestIP(brr))
{
printf("此IP地址合法\n");
}
else
{
printf("不合法\n");
}
if(TestIP(crr))
{
printf("此IP地址合法\n");
}
else
{
printf("不合法\n");
}
return 0;
}
2、算法题:求一个有序数组中两个值相加为k的数字,返回这两个数字的下标。(腾讯面试题)
//算法分析:有序的数组(假设非降序),采取双向遍历,一个从前往后,一个从后往前,当前数字相加如果相等则返回,如果小于k则前面的继续往后,如果大于k则后面的继续往前
//代码如下:
bool FindNum(int *arr,int len,int k)//时间复杂度O(n)
{
assert(arr != NULL);
if(arr == NULL)
{
return false;
}
int low = 0;
int high = len-1;
while(low <= high)
{
if(arr[low] + arr[high] == k)
{
printf("%3d + %3d == %3d\n",arr[low],arr[high],k);
low++;
}
else if(arr[low] + arr[high] < k)
{
low++;
}
else
{
high --;
}
}
return true;
}
/2.2,如果是无序的数组呢?
//算法分析:1.先排序,在利用上面(2.1)的算法
3.用c语言判断操作系统是32位的还是64位
//分析:这个题目应该是判断当前平台是32位还是64位,最简洁的办法是判断指针的大小,如果4字节则为32位,8字节位64位,sizeof(int *);
//4.泛型冒泡(腾讯面试题)
typedef int (*PCmp)(void *vp1,void *vp2);//泛型比较
//泛型冒泡
void BubbleSort(void *arr,int len,int elemsize,PCmp cmp)
{
void *tmp = malloc(elemsize);//交换数据的中间变量
void *var1;//冒泡的第一个值的指针
void *var2;//冒泡的第二个值的指针
for(int i=0;i<len-1;i++)
{
for(int j=0;j+1<len-i;j++)
{
var1 = (char *)arr+j*elemsize;
var2 = (char *)arr + (j+1)*elemsize;
if(cmp(var1,var2) > 0) //交换数据
{
memcpy(tmp,var1,elemsize);
memcpy(var1,var2,elemsize);
memcpy(var2,tmp,elemsize);
}
}
}
}
int Cmp_int(void *vp1,void *vp2)
{
return *(int *)vp1 - *(int *)vp2;
}
int Cmp_str(void *vp1,void *vp2)
{
return strcmp(*(char **)vp1,*(char **)vp2);
}
int main()
{
int arr[] = {3,5,7,9,0,12,45,6,78,23,44,10};
BubbleSort(arr,sizeof(arr)/sizeof(arr[0]),sizeof(int),Cmp_int);
char *brr[] = {"abc","aaa","bcd","xyz","ccccc","hhh"};
BubbleSort(brr,sizeof(brr)/sizeof(brr[0]),sizeof(char *),Cmp_str);
return 0;
}
//5.(腾讯面试题)
假设环境均为x86,32位机器,linux环境下1、以下代码执行后b的值是什么
int a = 0xabcdefff;
char b = (char)a;
b=?
解答:将宽的数据类型强转成窄类型时,保留低数据,则b的值为0xff即-1
//6.(腾讯面试题)
c语言编码,实现函数long htonl(long a),也就是将主机序转化为网络序
//解析:主机序也称为本地字节序,分为大端和小端.大端:低地址放大数据;小端:低地址放小数据.网络序统一为大端
//该算法主要需要测试主机序,如果是大端则不做任何的改变,如果是小端则逆序
bool IsLittle()//判断主机序是否为小端
{
short a = 0x0001;//小数据为0x01,高数据为0x00
return *(char *)&a == 0x01; //低地址放小数据
}
long Htonl(long a)
{
long b = 0;
if( !IsLittle() )//大端
{
return a;
}
for(int i=0;i<sizeof(a);i++)//小端:0x12345678->0x78563412
{ //处理单位为字节,1字节8位
b = (b<<8) | (a & 0xff);
a >>= 8;
}
return b;
}
int main()
{
printf("%x\n",Htonl(0x12345678));
return 0;
}
//7、有一个集合由A-Z这26个字母组成,打印这个集合的所有子集,每个子集一行,写C代码实现,不能使用递归(腾讯面试题)
//解析:https://blog.****.net/K346K346/article/details/80436430
//str为A~Z的字母集合,n为需要处理的前n个字符集合,本题n为26,n是为了方便测试
void SubSet(int n)
{
const char *str = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
int maxnum = 1<<n; //2^n
for(int i=0;i<maxnum;i++)//处理0到2^n -1之间的数字
{
for(int j=0;j<n;j++)//j表示二进制右数第几位
{
if( (i&(1<<j)) != 0)//表示当前位不为0,则需要打印相应的字母
{
printf("%c ",str[j]);
}
}
printf("\n");
}
}
int main()
{
SubSet(3);
//printf("-----------\n");
//SubSet(26);//数据太大不好统计测试结果
return 0;
}
//8、介于0到1000000之间的n个整数,请对他们进行排序,要求时间复杂度为O(n),写c代码实现(腾讯面试题)
//算法解析:定义一个长度为1000000的数组brr,全部初始化为0,从头到尾遍历这n个数字,出现哪个数字则将其作为下标对应的数组值加1(哈希函数为y=x),然后从到到尾遍历brr,数字是几则将下标打印几次
void Sort(int *arr,int n) //时间复杂度O(n),空间复杂度O(数据的取值范围)
{
int i;
for(i=0;i<n;i++)
{
if(arr[i]<0 || arr[i]>=1000000)
{
printf("数据不在范围内,错误\n");
return ;
}
}
int *brr = (int *)calloc(1000000,sizeof(int));//calloc将每个值设为0
assert(brr != NULL);
for(i=0;i<n;i++)
{
brr[arr[i]]++;//哈希函数y = x = arr[i]
}
i = 0;
for(int j=0;j<1000000;j++)
{
for(int k=0;k<brr[j];k++)
{
arr[i++] = j;
}
}
free(brr);
}
int main()
{
int arr[] = {5,8,0,9,12,34,56,7,8,89,13,44,76,88,98,69};
Sort(arr,sizeof(arr)/sizeof(arr[0]));
return 0;
}
9、将数字n转为指定进制下的数字字符串,2<=进制radix&&radix<=36
算法 ,每次取数字n的末尾,再丢弃末尾,然后在逆置字符串
代码如下:
void Myitoa(char *str,int n,int radix)
{
if(radix <2 || radix >36)
{
return ;
}
int tmp;
while(n != 0)
{
tmp = n%radix;
if(tmp < 10)
{
*str = tmp +'0';
}
else
{
*str = (tmp-10) +'a';
}
n /= radix;
str++;
}
*str = '\0';
}
void Reverse(char *str)
{
char *p;
for(p=str;*p!='\0';p++) ;
char t;
p--;
while(str < p)//str != p
{
t = *str;
*str = *p;
*p = t;
str++;
p--;
}
}
/*
int main()
{
char p[100];
Myitoa(p,20,2);
printf("%s\n",p);
Myitoa(p,20,16);
printf("%s\n",p);
Myitoa(p,200,16);
printf("%s\n",p);
Myitoa(p,12345,10);
printf("%s\n",p);
return 0;
}