继续我的找工笔试面试题整理。
1. 快排的两种写法
以前一直用第一种方式进行快排的,笔试中出现了第二种头尾指针的快排。
第一种:
代码
template<class T,class TCOMP>void quicksort(T a[],int start,int end,TCOMP cmpf=NULL)
{
int i;
if(start>=end)
return;
int middle = start;
T temp = a[start];
bool flag;
for(i=start+1;i<end;i++)
{
if(cmpf==NULL)
flag = a[i]<temp;
else
flag = cmpf(a[i],temp);
if(flag)
swap(a[++middle],a[i]);
}
swap(a[middle],a[start]);
quicksort(a,start,middle,cmpf);
quicksort(a,middle+1,end,cmpf);
}
{
int i;
if(start>=end)
return;
int middle = start;
T temp = a[start];
bool flag;
for(i=start+1;i<end;i++)
{
if(cmpf==NULL)
flag = a[i]<temp;
else
flag = cmpf(a[i],temp);
if(flag)
swap(a[++middle],a[i]);
}
swap(a[middle],a[start]);
quicksort(a,start,middle,cmpf);
quicksort(a,middle+1,end,cmpf);
}
第二种:
代码
void quicksort2side(int* first,int*last)
{
if(first>=last)
return;
int*left = first;
int*right = last;
int temp =*first;
while(left<right)
{
while(*right>temp&&right>left)
{
right--;
}
*left =*right;
while(*left<=temp&&left<right)
{
left++;
}
*right =*left;
}
*left = temp;
quicksort2side(first,left-1);
quicksort2side(right+1,last);
}
{
if(first>=last)
return;
int*left = first;
int*right = last;
int temp =*first;
while(left<right)
{
while(*right>temp&&right>left)
{
right--;
}
*left =*right;
while(*left<=temp&&left<right)
{
left++;
}
*right =*left;
}
*left = temp;
quicksort2side(first,left-1);
quicksort2side(right+1,last);
}
2. 结构体内存对齐问题
这个是非常常见的,笔试面试都很容易被问到,这里总结一下。
结构体各成员变量存放的起始地址相对于结构的起始地址的偏移量必须为该变量的类型所占用的字节数的倍数。空缺的字节自动填充。同时为了确保结构的大小为结构的字节边界数(即该结构中占用最大空间的类型所占用的字节数)的倍数,所以在为最后一个成员变量申请空间后,还会根据需要自动填充空缺的字节。
代码
typedef struct A
{
char a;
char a1[102];
}A;
//103字节,最后结构体整体按sizeof(char)对齐
typedef struct C
{
char a;
short b; //起始地址要2的倍数
char c;
char d;
}C;
//6字节,最后按short对齐
typedef struct B
{
char a;
double i; //起始地址8倍数
short b;
}B;
//24字节
{
char a;
char a1[102];
}A;
//103字节,最后结构体整体按sizeof(char)对齐
typedef struct C
{
char a;
short b; //起始地址要2的倍数
char c;
char d;
}C;
//6字节,最后按short对齐
typedef struct B
{
char a;
double i; //起始地址8倍数
short b;
}B;
//24字节
另外,还有pack和align修饰符的规定。
#pragma pack规定的对齐长度,实际使用的规则是:
结构,联合,或者类的数据成员,第一个放在偏移为0的地方,以后每个数据成员的对齐,按照#pragma pack指定的数值和这个数据成员自身长度中,比较小的那个进行。
当数据定义中出现__declspec( align() )时,指定类型的对齐长度还要用自身长度和这里指定的数值比较,然后取其中较大的。最终类/结构的对齐长度也需要和这个数值比较,然后取其中较大的。
可以这样理解, __declspec( align() ) 和 #pragma pack是一对兄弟,前者规定了对齐的最小值,后者规定了对齐的最大值,两者同时出现时,前者拥有更高的优先级。
3.在循环有序数组中查找某个元素
这个题目比较有意思,在普通有序数组查找直接折半即可,但是循环有序数组还得考虑一下很多问题。因为并不知道循环的起始位置。如下:
123456
234561
456123
PS:仅针对顺时针有序循环数组
代码
//在循环有序数组中查找某个元素,复杂度O(logN)
int find_in_cycle_array(int a[],int n,int elem)
{
int start =0;
int end = n-1;
while(start<=end)
{
int middle = (start+end)/2;
if(a[middle]==elem)
return middle;
if(a[end]>a[start])
{
if(a[middle]>elem)
end=middle-1;
else
start = middle+1;
}
else
{
if(a[middle]>=a[start])
{
if(a[middle]>elem&&a[start]<=elem)
end = middle-1;
else
start = middle+1;
}
else
{
if(a[middle]<elem&&a[end]>=elem)
start = middle+1;
else
end = middle-1;
}
}
}
return-1;
}
int find_in_cycle_array(int a[],int n,int elem)
{
int start =0;
int end = n-1;
while(start<=end)
{
int middle = (start+end)/2;
if(a[middle]==elem)
return middle;
if(a[end]>a[start])
{
if(a[middle]>elem)
end=middle-1;
else
start = middle+1;
}
else
{
if(a[middle]>=a[start])
{
if(a[middle]>elem&&a[start]<=elem)
end = middle-1;
else
start = middle+1;
}
else
{
if(a[middle]<elem&&a[end]>=elem)
start = middle+1;
else
end = middle-1;
}
}
}
return-1;
}