我没去参加笔试,但据比木同学说,广电的笔试很基础,总共就四道题:1、josephus数小孩问题。2、二分查找法。3、用栈实现递归。4、有关通信、网络方面的汉译英、英译汉。
用栈实现递归,我以前专门写过一篇文章。读者可以去翻来看看。现在,我自己来解答前两个问题。
1、josephus问题的描述:编号是1,2,……,n的n个人按照顺时针方向围坐一圈,每个人只有一个密码(正整数)。一开始任选一个正整数作为报数上限值m,从第一个人开始顺时针方向自1开始顺序报数,报到m时停止报数。报m的人出列,将他的密码作为新的m值,从他在顺时针方向的下一个人开始重新从1报数,如此下去,直到所有人全部出列为止。设计一个程序来求出出列顺序。
解这道题有两种方法,一种是递归法、一种是选代法。给出程序:
/
/
// 递归法求解joseph问题,
/ /
// m:第一次的报数次数
// pos:报数的起始位置
// A[][2]:一个二维数组,A[i][0]存放成员的编号,A[i][1]存放成员的密码
// n:成员个数
void joseph_1( int m, int pos, int A[][ 2 ], int n)
{
// base case
if (n == 1 )
{
cout << " 最后一个离开的是 " << A[ 0 ][ 0 ] << " 号 " << endl;
return ;
}
// 根据m值,求出将要离队的成员在数姐中的位置
// 考因为是循环数数,故用求模法
int out = (pos + m - 1 ) % n;
// 根据离队成员的密码,决定下一次偏移量
m = A[ out ][ 1 ];
// 离队的成员编号
int num = A[ out ][ 0 ];
// 离队处理
cout << " 成员 " << num << " 号离队 " << endl;
// 离开后,该成员后面的所有成员向前移动一位
for ( int i = out ; i < n - 1 ; i ++ )
{
A[i][ 0 ] = A[i + 1 ][ 0 ];
A[i][ 1 ] = A[i + 1 ][ 1 ];
}
// 对下一次进行处理
joseph(m, out ,A, n - 1 );
}
// //
// 迭代法求解joseph问题
// /
void joseph_2( int m, int pos, int A[][ 2 ], int n)
{
int out ;
while (n > 1 )
{
// 离队的位置
out = (pos + m - 1 ) % n;
// 下一次离队的偏移量
m = A[ out ][ 1 ];
// 离队公告
cout << " 成员 " << A[ out ][ 0 ] << " 号离队 " << endl;
// 紧凑队伍
for ( int i = out ; i < n - 1 ; i ++ )
{
A[i][ 0 ] = A[i + 1 ][ 0 ];
A[i][ 1 ] = A[i + 1 ][ 1 ];
}
// 下一次计数的起始位置
pos = out ;
// 人数减1
n -- ;
}
cout << " 最后一位离队的成员是 " << A[ 0 ][ 0 ] << " 号 " << endl;
return ;
}
// 提供测试数据
int A[ 7 ][ 2 ] =
{
{ 1 , 3 },{ 2 , 1 },{ 3 , 7 },{ 4 , 2 },{ 5 , 4 },{ 6 , 7 },{ 7 , 4 }
};
// 递归法求解joseph问题,
/ /
// m:第一次的报数次数
// pos:报数的起始位置
// A[][2]:一个二维数组,A[i][0]存放成员的编号,A[i][1]存放成员的密码
// n:成员个数
void joseph_1( int m, int pos, int A[][ 2 ], int n)
{
// base case
if (n == 1 )
{
cout << " 最后一个离开的是 " << A[ 0 ][ 0 ] << " 号 " << endl;
return ;
}
// 根据m值,求出将要离队的成员在数姐中的位置
// 考因为是循环数数,故用求模法
int out = (pos + m - 1 ) % n;
// 根据离队成员的密码,决定下一次偏移量
m = A[ out ][ 1 ];
// 离队的成员编号
int num = A[ out ][ 0 ];
// 离队处理
cout << " 成员 " << num << " 号离队 " << endl;
// 离开后,该成员后面的所有成员向前移动一位
for ( int i = out ; i < n - 1 ; i ++ )
{
A[i][ 0 ] = A[i + 1 ][ 0 ];
A[i][ 1 ] = A[i + 1 ][ 1 ];
}
// 对下一次进行处理
joseph(m, out ,A, n - 1 );
}
// //
// 迭代法求解joseph问题
// /
void joseph_2( int m, int pos, int A[][ 2 ], int n)
{
int out ;
while (n > 1 )
{
// 离队的位置
out = (pos + m - 1 ) % n;
// 下一次离队的偏移量
m = A[ out ][ 1 ];
// 离队公告
cout << " 成员 " << A[ out ][ 0 ] << " 号离队 " << endl;
// 紧凑队伍
for ( int i = out ; i < n - 1 ; i ++ )
{
A[i][ 0 ] = A[i + 1 ][ 0 ];
A[i][ 1 ] = A[i + 1 ][ 1 ];
}
// 下一次计数的起始位置
pos = out ;
// 人数减1
n -- ;
}
cout << " 最后一位离队的成员是 " << A[ 0 ][ 0 ] << " 号 " << endl;
return ;
}
// 提供测试数据
int A[ 7 ][ 2 ] =
{
{ 1 , 3 },{ 2 , 1 },{ 3 , 7 },{ 4 , 2 },{ 5 , 4 },{ 6 , 7 },{ 7 , 4 }
};
2、二分查找法,我一直觉得二分查找法,是一种非常优美的方法,写起来非常漂亮:
//
// 二分查找法
//
// A[]:一个已经从小到大排好序的数组
// n:元素个数
// key:欲查找的关键码
// 如果找到,返回关键码所在的下标,否则返回n
int binarySearch( int A[], int n, int key)
{
// 数组边界
int left = - 1 ;
int right = n;
// 当left == right-1时,边界中间已经没有元素了。
while (left < right - 1 )
{
int mid = (left + right) / 2 ; // 中间点
if (key < A[mid])
right = mid;
if (key == A[mid])
return mid; // 找到了
else
left = mid;
}
// 没有找到
return n;
}
// 二分查找法
//
// A[]:一个已经从小到大排好序的数组
// n:元素个数
// key:欲查找的关键码
// 如果找到,返回关键码所在的下标,否则返回n
int binarySearch( int A[], int n, int key)
{
// 数组边界
int left = - 1 ;
int right = n;
// 当left == right-1时,边界中间已经没有元素了。
while (left < right - 1 )
{
int mid = (left + right) / 2 ; // 中间点
if (key < A[mid])
right = mid;
if (key == A[mid])
return mid; // 找到了
else
left = mid;
}
// 没有找到
return n;
}