http://blog.csdn.net/Hackbuteer1
1、进程切换需要注意哪些问题?
保存处理器PC寄存器的值到被中止进程的私有堆栈; 保存处理器PSW寄存器的值到被中止进程的私有堆栈; 保存处理器SP寄存器的值到被中止进程的进程控制块;
保存处理器其他寄存器的值到被中止进程的私有堆栈; 自待运行进程的进程控制块取SP值并存入处理器的寄存器SP; 自待运行进程的私有堆栈恢复处理器各寄存器的值;
自待运行进程的私有堆栈中弹出PSW值并送入处理器的PSW; 自待运行进程的私有堆栈中弹出PC值并送入处理器的PC。
2、输入一个升序数组,然后在数组中快速寻找两个数字,其和等于一个给定的值。
这个编程之美上面有这个题目的,很简单的,用两个指针一个指向数组前面,一个指向数组的后面,遍历一遍就可以了。
3、有一个名人和很多平民在一块,平民都认识这个名人,但是这个名人不认识任何一个平民,任意两个平民之间是否认识是未知的,请设计一个算法,快速找个这个人中的那个名人。 已知已经实现了一个函数 bool know(int a,int b) 这个函数返回true的时候,表明a认识b,返回false的时候表明a不认识b。
思路:首先将n个人分为n/2组,每一组有2个人,然后每个组的两个人调用这个know函数,假设为know(a,b),返回true的时候说明a认识b,则a肯定不是名人,a可以排除掉了,依次类推,每个组都调用这个函数依次,那么n个人中就有n/2个人被排除掉了,数据规模将为n/2。同理在剩下的n/2个人中在使用这个方法,那么规模就会将为n/4,这样所有的遍历次数为n/2+n/4+n/8+........ 这个一个等比数列,时间复杂度为o(n)。
4、判断一个自然数是否是某个数的平方。当然不能使用开方运算。
方法1:
遍历从1到N的数字,求取平方并和N进行比较。
如果平方小于N,则继续遍历;如果等于N,则成功退出;如果大于N,则失败退出。
复杂度为O(n^0.5)。
方法2:
使用二分查找法,对1到N之间的数字进行判断。
复杂度为O(log n)。
方法3:
由于
(n+1)^2
=n^2 + 2n + 1,
= ...
= 1 + (2*1 + 1) + (2*2 + 1) + ... + (2*n + 1)
注意到这些项构成了等差数列(每项之间相差2)。
所以我们可以比较 N-1, N - 1 - 3, N - 1 - 3 - 5 ... 和0的关系。
如果大于0,则继续减;如果等于0,则成功退出;如果小于 0,则失败退出。
复杂度为O(n^0.5)。不过方法3中利用加减法替换掉了方法1中的乘法,所以速度会更快些。
例如:3^2 = 9 = 1 + 2*1+1 + 2*2+1 = 1 + 3 + 5
4^2 = 16 = 1 + 2*1 + 1 + 2*2+1 + 2*3+1
- int square(int n)
- {
- int i = 1;
- n = n - i;
- while( n > 0 )
- {
- i += 2;
- n -= i;
- }
- if( n == 0 ) //是某个数的平方
- return 1;
- else //不是某个数的平方
- return 0;
- }
一、算法设计
1、设rand(s,t)返回[s,t]之间的随机小数,利用该函数在一个半径为R的圆内找随机n个点,并给出时间复杂度分析。
思路:这个使用数学中的极坐标来解决,先调用[s1,t1]随机产生一个数r,归一化后乘以半径,得到R*(r-s1)/(t1-s1),然后在调用[s2,t2]随机产生一个数a,归一化后得到角度:360*(a-s2)/(t2-s2)
2、为分析用户行为,系统常需存储用户的一些query,但因query非常多,故系统不能全存,设系统每天只存m个query,现设计一个算法,对用户请求的query进行随机选择m个,请给一个方案,使得每个query被抽中的概率相等,并分析之,注意:不到最后一刻,并不知用户的总请求量。
思路:如果用户查询的数量小于m,那么直接就存起来。如果用户查询的数量大于m,假设为m+i,那么在1-----m+i之间随机产生一个数,如果选择的是前面m条查询进行存取,那么概率为m/(m+i),如果选择的是后面i条记录中的查询,那么用这个记录来替换前面m条查询记录的概率为m/(m+i)*(1-1/m)=(m-1)/(m+i),当查询记录量很大的时候,m/(m+i)== (m-1)/(m+i),所以每个query被抽中的概率是相等的。
3、C++ STL中vector的相关问题:
(1)、调用push_back时,其内部的内存分配是如何进行的?
(2)、调用clear时,内部是如何具体实现的?若想将其内存释放,该如何操作?
vector的工作原理是系统预先分配一块CAPACITY大小的空间,当插入的数据超过这个空间的时候,这块空间会让某种方式扩展,但是你删除数据的时候,它却不会缩小。
vector为了防止大量分配连续内存的开销,保持一块默认的尺寸的内存,clear只是清数据了,未清内存,因为vector的capacity容量未变化,系统维护一个的默认值。
有什么方法可以释放掉vector中占用的全部内存呢?
标准的解决方法如下
template < class T >
void ClearVector( vector< T >& vt )
{
vector< T > vtTemp;
veTemp.swap( vt );
}
事实上,vector根本就不管内存,它只是负责向内存管理框架acquire/release内存,内存管理框架如果发现内存不够了,就malloc,但是当vector释放资源的时候(比如destruct), stl根本就不调用free以减少内存,因为内存分配在stl的底层:stl假定如果你需要更多的资源就代表你以后也可能需要这么多资源(你的list, hashmap也是用这些内存),所以就没必要不停地malloc/free。如果是这个逻辑的话这可能是个trade-off
一般的STL内存管理器allocator都是用内存池来管理内存的,所以某个容器申请内存或释放内存都只是影响到内存池的剩余内存量,而不是真的把内存归还给系统。这样做一是为了避免内存碎片,二是提高了内存申请和释放的效率——不用每次都在系统内存里寻找一番。
二、系统设计
正常用户端每分钟最多发一个请求至服务端,服务端需做一个异常客户端行为的过滤系统,设服务器在某一刻收到客户端A的一个请求,则1分钟内的客户端任何其它请求都需要被过滤,现知每一客户端都有一个IPv6地址可作为其ID,客户端个数太多,以至于无法全部放到单台服务器的内存hash表中,现需简单设计一个系统,使用支持高效的过滤,可使用多台机器,但要求使用的机器越少越好,请将关键的设计和思想用图表和代码表现出来。
三、求一个全排列函数:
如p([1,2,3])输出:
[123]、[132]、[213]、[231]、[321]、[323]
求一个组合函数
如p([1,2,3])输出:
[1]、[2]、[3]、[1,2]、[2,3]、[1,3]、[1,2,3]
这两问可以用伪代码。
1、对于一个内存地址是32位、内存页是8KB的系统。0X0005F123这个地址的页号与页内偏移分别是多少。
2、如果X大于0并小于65536,用移位法计算X乘以255的值为: (X<<8)-X
X<<8-X是不对的,因为移位运算符的优先级没有减号的优先级高,首先计算8-X为0,X左移0位还是8。
3、一个包含n个节点的四叉树,每个节点都有四个指向孩子节点的指针,这4n个指针中有 3n+1 个空指针。
4、以下两个语句的区别是:第一个动态申请的空间里面的值是随机值,第二个进行了初始化,里面的值为0
- int *p1 = new int[10];
- int *p2 = new int[10]();
5、计算机在内存中存储数据时使用了大、小端模式,请分别写出A=0X123456在不同情况下的首字节是,大端模式:0X12 小端模式:0X56 X86结构的计算机使用 小端 模式。
一般来说,大部分用户的操作系统(如windows, FreeBsd,Linux)是小端模式的。少部分,如MAC OS,是大端模式 的。
6、在游戏设计中,经常会根据不同的游戏状态调用不同的函数,我们可以通过函数指针来实现这一功能,请声明一个参数为int *,返回值为int的函数指针:
int (*fun)(int *)
7、下面程序运行后的结果为:to test something
- char str[] = "glad to test something";
- char *p = str;
- p++;
- int *p1 = static_cast<int *>(p);
- p1++;
- p = static_cast<char *>(p1);
- printf("result is %s\n",p);
8、在一冒险游戏里,你见到一个宝箱,身上有N把钥匙,其中一把可以打开宝箱,假如没有任何提示,随机尝试,问:
(1)恰好第K次(1=<K<=N)打开宝箱的概率是多少。 (1-1/n)*(1-1/(n-1))*(1-1/(n-2))***(1/(n-k+1)) = 1/n
(2)平均需要尝试多少次。
这个就是求期望值 由于每次打开宝箱的概率都是1/n,则期望值为: 1*(1/n)+2*(1/n)+3*(1/n)+......+n*(1/n) = (n+1)/2
1、对于如下程序:
- #include <iostream>
- using namespace std;
- class A
- {
- public:
- A()
- {
- cout<<"A"<<endl;
- }
- };
- int main(void)
- {
- A a[4], b,*p;
- }
会输出多少个A?( C )
A、2 B、3 C、5 D、6
p只是一个对象指针,并没有指向一个对象的内存空间,所以没有调用构造函数。
2、头文件中的 ifndef/define/endif 有什么作用?
答:防止该头文件被重复引用,避免变量、类型等被重新定义。
3、const 有什么用途?(请至少说明两种)
答:(1)可以定义 const 常量。
(2)const可以修饰函数的参数、返回值,甚至函数的定义体。被const修饰的东西都受到强制保护,可以预防意外的变动,能提高程序的健壮性。
4、如下的字符串函数,用于生存一个字符串 ”连接号码异常” ,并返回它的指针
- char* strfun()
- {
- char str[20];
- strcpy(str, “连接号码异常”);
- printf(“%s \n”, str); //printf语句1
- return str;
- }
- void main()
- {
- char *pstr = strfun();
- printf("%s \n", pstr); //printf语句2
- }
问题1 : printf语句1和printf语句2哪个能在屏幕上正在打印出来?
问题2 : 如果不能正常在屏幕上打印出字符串,请说明原因。
问题3 : 如果不修改strfun的声明,请问该如何修改上述程序的错误。
答:
问题1:语句1可以正常打印,语句2不能正常打印;
问题2:语句2使用的指针所指向的内存空间str[20],在函数strfun返回时已经被释放了;
问题3:可以将函数strfun中的语句char str[20];改为char *str = new char[20];
5、下面是交换两个double型数据的函数,
- void swap( double* p1, double* p2 )
- {
- double *p;
- *p = *p1;
- *p1 = *p2;
- *p2 = *p;
- }
- void main()
- {
- double a = 0.1;
- double b = 0.2;
- swap( &a, &b );
- }
请找出上述代码的错误,指出错误的原因,并改正。
答:函数swap中混淆了double型指针与double型变量的差别,对于一个未初始化的指针访问其内存空间是非常危险的。对swap函数修改如下:
- void swap( double* p1, double* p2 )
- {
- double p;
- p = *p1;
- *p1 = *p2;
- *p2 =p;
- }
6、在电信业务的后台处理程序中,经常会涉及到处理字符串,除了用char *处理字符串之外,C++还为我们提供了封装了的字符串类string,其本质也是用一个动态数组来保存字符串,类String的原型为:
- class String
- {
- public:
- String(const char *str = NULL); // 普通构造函数
- String(const String &other); // 拷贝构造函数
- ~String(void); // 析构函数
- String & operate =(const String &other); // 赋值函数
- private:
- char *m_data; // 用于保存字符串
- };
请编写String的上述4个函数普通构造函数、拷贝构造函数、析构函数和赋值函数。
代码如下:
- class String
- {
- private:
- char *m_data;
- public:
- String();
- String(const char *str = NULL);
- String(const String &other);
- ~String(void);
- String & operator =(const String &other);
- };
- String::String()
- {
- m_data = NULL;
- }
- String::String(const char *str = NULL) //带一个指针的普通构造函数
- {
- if(str == NULL)
- {
- m_data = new char[1];
- assert(m_data != NULL);
- *m_data = '\0';
- }
- else
- {
- int length=strlen(str);
- m_data = new char[length+1];
- assert(m_data != NULL);
- strcpy(m_data,str);
- }
- }
- String::String(const String &other) //拷贝构造函数
- {
- m_data = new char[other.length+1];
- assert(m_data != NULL);
- strcpy((*this).m_data,other.m_data);
- }
- String::~String(void) //析构函数
- {
- if(m_data != NULL)
- {
- delete m_data;
- m_data = NULL;
- }
- }
- String & String::operator=(const String &other) //赋值函数
- {
- if(&other != this)
- {
- delete [](*this).m_data;
- (*this).m_data = new char[other.length+1];
- assert((*this).m_data != NULL);
- strcpy((*this).m_data,other.m_data);
- }
- }
一、单选题
1、我们有很多瓶无色的液体,其中有一瓶是毒药,其它都是蒸馏水,实验的小白鼠喝了以后会在5分钟后死亡,而喝到蒸馏水的小白鼠则一切正常。现在有5只小白鼠,请问一下,我们用这五只小白鼠,5分钟的时间,能够检测多少瓶液体的成分(C)
A、5瓶 B、6瓶 C、31瓶 D、32瓶
2、若某链表最常用的操作是在最后一个结点之后插入一个结点和删除最后一个结点,则采用()存储方式最节省时间?
A、单链表 B、带头结点的非循环双链表 C、带头节点的双循环链表 D、循环链表
3、如果需要对磁盘上的1000W条记录构建索引,你认为下面哪种数据结构来存储索引最合适?()
A、Hash Table B、AVL-Tree C、B-Tree D、List
4、可用来检测一个web服务器是否正常工作的命令是()
A、ping B、tracert C、telnet D、ftp
只有C可以测试Web主机的网页服务器是否工作正常,假设该服务器的网页服务器使用的是默认端口,则可以使用命令telnet hostname 80 来测试其是否工作。
5、下面哪个操作是Windows独有的I/O技术()
A、Select B、Poll C、IOCP D、Epoll
6、IPV6地址包含了()位
A、16 B、32 C、64 D、128
7、数据库里建索引常用的数据结构是()
A、链表 B、队列 C、树 D、哈希表
8、在公司局域网上ping www.taobao.com没有涉及到的网络协议是()
A、ARP B、DNS C、TCP D、ICMP
DNS是将域名www.taobao.com映射成主机的IP地址,ARP是将IP地址映射成物理地址,ICMP是报文控制协议,由路由器发送给执行ping命令的主机,而一个ping命令并不会建立一条TCP连接,故没有涉及TCP协议。
二、填空题
1、http属于(应用层)协议,ICMP属于(网络层)协议。
2、深度为k的完全二叉树至少有(2^(k-1))个结点,至多有(2^k-1)个结点。
3、字节为6位的二进制有符号整数,其最小值是(-32)。
4、设有28盏灯,拟公用一个电源,则至少需有4插头的接线板数(9)个。
第一个板4个口,此后每增加1个板会消耗1个原来的口,总的只增加3个口,故N个接线板能提供 1+3*N个电源口。
三、综合题
1、有一颗结构如下的树,对其做镜像反转后如下,请写出能实现该功能的代码。注意:请勿对该树做任何假设,它不一定是平衡树,也不一定有序。
1 1
/ | \ / | \
2 3 4 4 3 2
/|\ /\ | | / \ / | \
6 5 7 8 9 10 10 9 8 7 5 6
答:以孩子、兄弟的存储结构来存储这棵树,使之成为一颗二叉树,然后对二叉树进行链表的转换。
- typedef struct TreeNode
- {
- int data;
- struct TreeNode *firstchild;
- struct TreeNode *nextsibling;
- }TreeNode,*Tree;
- void MirrorTree(Tree root)
- {
- if(!root)
- return ;
- if(root->firstchild)
- {
- Tree p=root->firstchild;
- Tree cur=p->nextsibling;
- p->nextsibling=NULL;
- while(cur)
- {
- Tree curnext=cur->nextsibling;
- cur->nextsibling=p;
- if(p->firstchild)
- MirrorTree(p);
- p=cur;
- cur=curnext;
- }
- root->firstchild=p;
- }
- }
- int main(void)
- {
- TreeNode *root=(TreeNode *)malloc(sizeof(TreeNode));
- Init();
- MirrorTree(root);
- OutPut();
- }
2、假设某个网站每天有超过10亿次的页面访问量,出于安全考虑,网站会记录访问客户端访问的ip地址和对应的时间,如果现在已经记录了1000亿条数据,想统计一个指定时间段内的区域ip地址访问量,那么这些数据应该按照何种方式来组织,才能尽快满足上面的统计需求呢,设计完方案后,并指出该方案的优缺点,比如在什么情况下,可能会非常慢?
答:用B+树来组织,非叶子节点存储(某个时间点,页面访问量),叶子节点是访问的IP地址。这个方案的优点是查询某个时间段内的IP访问量很快,但是要统计某个IP的访问次数或是上次访问时间就不得不遍历整个树的叶子节点。答:
或者可以建立二级索引,分别是时间和地点来建立索引。
四、附加题
1、写出C语言的地址对齐宏ALIGN(PALGNBYTES),其中P是要对齐的地址,ALIGNBYTES是要对齐的字节数(2的N次方),比如说:ALIGN(13,16)=16
- ALIGN(P,ALIGNBYTES) ( (void*)( ((unsigned long)P+ALIGNBYTES-1)&~(ALIGNBYTES-1) ) )
2、在高性能服务器的代码中经常会看到类似这样的代码:
typedef union
{
erts_smp_rwmtx_t rwmtx;
byte cache_line_align_[ERTS_ALC_CACHE_LINE_ALIGN_SIZE(sizeof(erts_smp_rwmtx_t))];
}erts_meta_main_tab_lock_t;
erts_meta_main_tab_lock_t main_tab_lock[16];
请问其中用来填充的cache_line_align的作用是?
3、在现代web服务系统的设计中,为了减轻源站的压力,通常采用分布式缓存技术,其原理如下图所示,前端的分配器将针对不同内容的用户请求分配给不同的缓存服务器向用户提供服务。
分配器
/ | \
缓存 缓存 ...缓存
服务器1 服务器2 ...服务器n
1)请问如何设置分配策略,可以保证充分利用每个缓存服务器的存储空间(每个内容只在一个缓存服务器有副本)
2)当部分缓存服务器故障,或是因为系统扩容,导致缓存服务器的数量动态减少或增加时,你的分配策略是否可以保证较小的缓存文件重分配的开销,如果不能,如何改进?
3)当各个缓存服务器的存储空间存在差异时(如有4个缓存服务器,存储空间比为4:9:15:7),如何改进你的策略,按照如上的比例将内容调度到缓存服务器?
1、操作系统中的同步和异步有什么区别?分别应用在什么场合?
答:同步,就是说你的程序在执行某一个操作时一直等待直到操作完成。 最常见的例子就是 SendMessage。该函数发送一个消息给某个窗口,在对方处理完消息之前,这个函数不返回。当对方处理完毕以后,该函数才把消息处理函数所返回的 LRESULT值返回给调用者。
异步,就是说程序在执行某一个操作时,只是发出开始的指令;由另外的并行程序执行这段代码,当完成时再通知调用者。 当一个客户端通过调用 Connect函数发出一个连接请求后,调用者线程立刻可以朝下运行。当连接真正建立起来以后,socket底层会发送一个消息通知该对象。
打个比喻:
有一个男的 看上了两个漂亮MM 想通过写信的方式跟他们交流感情 这两个MM分别是 A女、B女
同步:他先给A女写了封信 然后发了出去。等了好几天 A女给他回了信,之后他才给B女写信。就是说等到一个任务返回或者结束 他才继续往下做他想做的任务。
异步:他先给A女写了封信,然后发了出去,马上又给B女写了封信 也发了出去。 就是说不用等到一个任务结束就去做下一个任务。
但是如果第一个任务需要第二个任务的返回值 那就得用同步让第一个任务等待第二个任务结束后,获取第二个任务的返回值,在继续往下做。
并行:两个帅哥同时给这两个妹妹写信。
同步和异步的简单区别:
举个例子:普通B/S模式(同步)AJAX技术(异步)
同步:提交请求->等待服务器处理->处理完毕返回 这个期间客户端浏览器不能干任何事
异步: 请求通过事件触发->服务器处理(这是浏览器仍然可以作其他事情)->处理完毕
--------------------------------------------------------------------------------------------------------------------
同步就是你叫我去吃饭,我听到了就和你去吃饭;如果没有听到,你就不停的叫,直到我告诉你听到了,才一起去吃饭。
异步就是你叫我,然后自己去吃饭,我得到消息后可能立即走,也可能等到下班才去吃饭。
所以,要我请你吃饭就用同步的方法,要请我吃饭就用异步的方法,这样你可以省钱。
--------------------------------------------------------------------------------------------------------------------
举个例子:打电话是同步,发消息是异步。
2、数据库的ACID特定是什么?以及他们分别应用的场合?
答:ACID是指数据库事务具有的四个特性:原子性、一致性、隔离性、持久性
原子性:事务是数据库的逻辑工作单位,事务中包括的操作要么都做,要么都不做。只有使据库事务中所有的操作都执行成功,才算整个事务成功;事务中任何一个SQL语句执行失败,那么已经执行成功的SQL语句也必须撤销,数据库状态应该回滚(ROLLBACK)到执行事务前的状态。
一致性:如果在执行事务之前数据库是一致的,那么在执行事务之后数据库也还是一致的;事务执行的结果必须是使数据库从一个一致性状态变到另一个一致性状态。因此当数据库只包含成功事务提交的结果时,就说数据库处于一致性状态。如果数据库系统运行中发生故障,有些事务尚未完成就被迫中断,这些尚未完成的事务对数据库所做的修改有一部分已写入物理数据库,这时数据库就处于一种不正确的状态,或者说是不一致的状态。例如某公司在银行中有A、B两个账号,现在公司想从A中减去一万元,存入账号B。那么就可以定义一个事务,该事务包括两个操作,第一个操作就是从账号A减去一万元,第二个操作就是向账号B中加入一万元。这两个操作要么全做,要么全不做,数据库都处于一致性状态。如果只做一个操作则用户逻辑上就会发生错误,少了一万元,这时数据库就处于不一致状态。可见一致性与原子性是密切相关的。
隔离性:一个事务的执行不能被其他事务干扰。即一个事务内部的操作及使用的数据对其他并发事务是隔离的,并发执行的各个事务之间不能互相干扰。独立的数据库事务集合以不相互冲突的方式执行。仍使用这个银行类比,考虑两个客户同时在帐户之间转移资金。数据库必须分别跟踪两个转帐;否则,资金可能进入错误的帐户。
持久性:指一个事务一旦提交,它对数据库中数据的改变就应该是永久性的。接下来的其他操作或故障不应该对其执行结果有任何影响。 只要事务成功结束,它对数据库所做的更新就必须永久保存下来。即使发生系统崩溃,重新启动数据库系统后,数据库还能恢复到事务成功结束时的状态。
3、TCP和UDP的区别以及应用有什么不同?
答:TCP与UDP的区别
TCP---传输控制协议,提供的是面向连接、可靠的字节流服务。当客户和服务器彼此交换数据前,必须先在双方之间建立一个TCP连接,之后才能传输数据。TCP提供超时重发,丢弃重复数据,检验数据,流量控制等功能,保证数据能从一端传到另一端。
UDP---用户数据报协议,是一个简单的面向数据报的运输层协议。UDP不提供可靠性,它只是把应用程序传给IP层的数据报发送出去,但是并不能保证它们能到达目的地。由于UDP在传输数据报前不用在客户和服务器之间建立一个连接,且没有超时重发等机制,故而传输速度很快。
应用: HTTP协议在运输层采用的就是TCP协议,在浏览器中输入IP地址后,与服务器建立连接,采用的就是TCP协议,是一种面向连接、可靠的字节流服务。
当强调传输性能而不是传输的完整性时,如:音频、多媒体应用和视频会议时,UDP是最好的选择。另外,腾讯QQ采用也是UDP协议。
4、判断字符串是否为IP地址。
思路:输入字符串的时候,把分隔符“.”读取出来,然后判断分隔符旁边的数字是否在0~~255之间,然后判断是否合法。
- #include <stdio.h>
- #include <string.h>
- int main(void)
- {
- char str[31],temp[31];
- int a,b,c,d;
- while(gets(str)!=NULL)
- {
- if(sscanf(str, "%d.%d.%d.%d ",&a,&b,&c,&d)==4 && a>=0 && a<=255 && b>=0 && b<=255 && c>=0 && c<=255 && d>=0 && d<=255)
- {
- sprintf(temp, "%d.%d.%d.%d",a,b,c,d); //把格式化的数据写入字符串temp
- if(strcmp(temp,str)==0)
- {
- printf("YES\n");
- }
- else
- {
- printf("NO\n");
- }
- }
- else
- {
- printf("NO\n");
- }
- }
- return 0;
- }
5、指针和引用的区别?
1、从现象上看:指针在运行时可以改变其所指向的值,而引用一旦和某个对象绑定后就不再改变。
2、从内存分配上看:程序为指针变量分配内存区域,而引用不分配内存区域。
3、从编译上看:程序在编译时分别将指针和引用添加到符号表上,符号表上记录的是变量名及变量所对应地址。指针变量在符号表上对应的地址值为指针变量的地址值,而引用在符号表上对应的地址值为引用对象的地址值。符号表生成后就不会再改,因此指针可以改变指向的对象(指针变量中的值可以改),而引用对象不能改。
引用:一个变量的别名,为什么引入别名呢?原因是我们想定义一个变量,他共享另一个变量的内存空间,使用别名无疑是一个好的选择。变量是什么?是一个内存空间的名字,如果我们给这个内存空间在起另外一个名字,那就是能够共享这个内存了,引用(别名)的由此而来。
指针:指向另一个内存空间的变量,我们可以通过它来索引另一个内存空间的内容,本身有自己的内存空间。
二者区别:(1)引用访问一个变量是直接访问,而指针是间接访问。
(2)引用是一个变量的别名,本身不单独分配自己的内存空间,而指针有自己的内存空间,指针是一个实体,而引用不是。
(3)引用在开始的时候就绑定到了一个内存空间(开始必须赋初值),所以他只能是这个内存空间的名字,而不能改成其他的,当然可以改变这个内存空间的值。
例如
int i = 3,j = 4;
int &x = i; //成为i的别名
x = j; //不能否认x仍然引用i,并没有成为j的别名,只是修改了x和i共享的内存空间的值为4
6、指针和数组的区别?
7、进程和线程的区别?
8、两个进程之间的通信方式有哪几种?
浙江大华2011.10.10校园招聘会笔试题
请写出下面程序的输出结果:(答案在下面)
1、
- int count = 3;
- int main(void)
- {
- int i, sum, count = 2;
- for(i=0,sum=0; i<count; i+=2,count++)
- {
- static int count = 4;
- count++;
- if(i%2 == 0)
- {
- extern int count;
- count++;
- sum += count;
- }
- sum += count;
- }
- printf("%d %d\n",count, sum);
- return 0;
- }
2、
- void func(char str[50])
- {
- printf("A %d B %d ",sizeof(str), strlen(str));
- }
- int main(void)
- {
- char stra[] = "HelloWorld";
- char *strb = stra;
- printf("C %d D %d ",sizeof(stra), sizeof(strb++));
- func(++strb);
- printf("E %d F %d\n",strlen(stra), strlen(strb++));
- return 0;
- }
printf("C %d D %d ",sizeof(stra),sizeof(strb++)); 中的sizeof(strb++)并不对sizeof函数中strb进行自增运算,只是简单的求这个指针的大小,此时的strb指针还是指向stra。
3、
- #include <vector>
- int func(std::vector<int>vec)
- {
- static int k = 2;
- std::vector<int>::reverse_iterator it;
- for(it = vec.rbegin(); it!=vec.rend(); ++it)
- {
- k += *it%2==0? ++*it: (*it)++;
- }
- return k;
- }
- int main(void)
- {
- std::vector<int>vec;
- for(int i = 0; i<4; i++)
- {
- vec.push_back(i);
- printf("%d ",func(vec));
- }
- return 0;
- }
4、
- class Base
- {
- public:
- int m_a;
- Base(int a=2):m_a(a)
- {
- printf("A %d ",m_a);
- }
- virtual ~Base()
- {
- printf("B %d ",m_a);
- }
- };
- class Derived:public Base
- {
- public:
- Derived(int a=4):Base(a)
- {
- printf("C %d ",m_a);
- }
- ~Derived()
- {
- printf("D %d ",m_a);
- }
- };
- int main(void)
- {
- Base *aa,bb;
- aa = new Derived;
- delete aa;
- return 0;
- }
5、
- class Base
- {
- public:
- int m_a,m_b;
- Base(int a = 2,int b = 5):m_a(a),m_b(b) { }
- int func_a()
- {
- return m_a - m_b;
- }
- virtual int func_b()
- {
- return m_a + m_b;
- }
- };
- class Derived:public Base
- {
- public:
- Derived(int a = 4, int b = 7):Base(a, b) { }
- virtual int func_a()
- {
- return m_b + m_a;
- }
- int func_b()
- {
- return m_b - m_a;
- }
- };
- int main(void)
- {
- Base *aa, *bb;
- aa = new Base(4, 7);
- bb = new Derived(3, 5);
- printf("%d %d %d %d\n",aa->func_a(), aa->func_b(), bb->func_a(), bb->func_b());
- delete aa;
- delete bb;
- return 0;
- }
6、
- struct SC
- {
- int a;
- int b;
- int c;
- };
- struct SD
- {
- int a;
- int b;
- int c;
- int d;
- };
- int main(void)
- {
- struct SC c1[] = {{3},{4},{5},{6}};
- struct SD *c2 = (struct SD*)c1 + 1;
- printf("%d %d %d %d\n",c2->a,c2->b,c2->c,c2->d);
- return 0;
- }
7、
- int func(int n)
- {
- int k = 1;
- if(n > 0)
- {
- k += func(--n);
- printf("%d ", n);
- k += func(--n);
- }
- return k;
- }
- int main(void)
- {
- int a = 3;
- printf("%d\n",func(a));
- return 0;
- }
答案:
1、 4 20
2、 C 11 D 4 A 4 B 9 E 10 F 9
3、 3 5 10 18
4、 A 2 A 4 C 4 D 4 B 4
5、 -3 11 -2 2
6、 0 0 5 0
7、 0 1 2 0 9
编程题:
1、函数checkstr判断一字符串是不是对称的。其中msg为输入的字符串,对称返回0,不对称返回-1,实现该函数。
int checkstr(const char *msg);
- int checkstr(const char *msg)
- {
- int len = strlen(msg);
- int i, j;
- for(i = 0,j = len-1; i <= j; i++,j--)
- {
- if(msg[i] != msg[j])
- break;
- }
- if(i>j)
- return 0;
- else
- return -1;
- }
2、给出一个单向链表的头指针,输出该链表中倒数第K个节点的指针,链表的倒数第0个节点为链表的尾节点(尾节点的next成员为NULL)
typedef struct Node
{
struct Node *next;
}NODE;
NODE* findnode(NODE *head,unsigned int k);
思路:在遍历时维持两个指针,第一个指针从链表的头指针开始遍历,在第k-1步之前,第二个指针p保持不动;
在第k-1步开始,第二个指针p也开始从链表的头指针开始遍历。由于两个指针的距离保持在k-1,当第一个(走在前面的)指针pcur到达链表的尾结点时,第二个指针指针p正好是倒数第k个结点。
这种思路只需要遍历链表一次。对于很长的链表,只需要把每个结点从硬盘导入到内存一次。因此这一方法的时间效率比较高。
- typedef struct Node
- {
- struct Node *next;
- }NODE;
- NODE* findnode(NODE *head, unsigned int k)
- {
- if(head==NULL)
- return NULL;
- NODE *p, *pcur;
- pcur = head;
- for(unsigned int i = 0; i < k; i++)
- {
- if(pcur->next != NULL) //在第k-1步之前,第二个指针p保持不动
- pcur = pcur->next;
- else
- return NULL; //k比链表中节点的数目要大,找不到倒数第k个节点,直接返回空
- }
- p = head;
- while(pcur->next)
- {
- pcur = pcur->next;
- p = p->next;
- }
- return p;
- }
简答题:
1、简述动态链接库DLL和静态链接库lib的差别。
2、请简述MFC中的窗口收到WM_PAINT消息是如何处理的,什么情况下会产生WM_PAINT消息。
3、请简述Critical Section 、Mutex、Semaphore的功能和差别
4、简述多线程程序对比单线程程序的优点和缺点。
1、以下哪些协议不是应用层通信协议?
A、HTTP、TELNET B、FTP、SMTP C、SNMP、NBNS D、ICMP、ARP
2、Ping命令是使用以下哪个协议实现的()
A、UDP B、ARP C、IGMP D、ICMP E、SMTP
ICMP(Internet Control Message Protocol )网际控制报文协议的一个重要应用就是分组网间探测Ping,用来测试两个主机之间的连通性。Ping使用了ICMP回送请求与回送回答报文,Ping是应用层直接使用网络层ICMP的一个例子,它没有通过运输层的TCP或UDP。
3、以下哪个协议通常用来收取邮件(C)
A、SMTP B、MAIL C、POP3 D、SNMP(简单网络管理协议 属于应用层) E、ICMP
SMTP(Simple Mail Transfer Protocol)简单邮件发送协议
POP3(Post Office Protocol)邮局协议 SMTP和POP3都属于应用层协议
一个电子邮件系统具有三个主要组成构件,就是用户代理、邮件服务器以及邮件发送协议(SMTP)和邮件读取协议(POP3)
不要把SMTP和POP3协议弄混。发件人的用户代理向发送方邮件服务器发送邮件,以及发送方邮件服务器向接收方邮件服务器发送邮件,都是使用SMTP协议。而POP3协议则是用户代理从接受方邮件服务器上读取邮件的时候所使用的协议。
4、CSMA/CD发生在OSI模型中的哪一层(B)
A、物理层 B、数据链路层 C、网络层 D、传输层 E、会话层
5、
- void Test(int *a,int *b)
- {
- int *temp;
- temp=a;
- a=b;
- b=temp;
- }
- int main(void)
- {
- int a = 1,b = 2;
- Test(&a, &b);
- printf("%d %d\n",a,b);
- return 0;
- }
上面那段程序的输出结果为(D)
A、2 1 B、2 2 C、1 1 D、1 2
6、
- int main(void)
- {
- int m = 0256,n = 256;
- printf("%o %o\n",m,n);
- return 0;
- }
上面那段程序的输出结果为(C)
A、0256 0400 B、0256 256 C、256 400 D、 400 400
m的值 0256 表示的是8进制,实际上在内存里面保存的是十进制的174。题目的意思是讲174 和 256 分别是8进制的形式输出,那么输出的就是 256 和 400 了。
7、下列排序算法中,其中(D)是稳定的。
A、堆排序 、冒泡排序 B、快速排序、堆排序
C、直接选择排序、归并排序 D、归并排序、冒泡排序
8、什么函数不能声明为虚函数(AD)
A、构造函数 B、析构函数 C、成员函数 D、友元函数
因为C++不支持友元函数的继承,对于没有继承特性的函数没有虚函数的说法。
9、定义一个有10个指针的数组tmp,该指针是指向一个整形数: int *tmp[10];
10、一个指向有10个整形数数组的指针tmp: int (*tmp)[10];
11、一个指向函数的指针,该函数有一个整型参数并返回一个整型数: int (*fun)(int );
11、一个有10个指针的数组,该指针指向一个函数该函数有一个整型参数并返回一个整型数: int (*fun[10])(int );
1、下列哪种数据类型不能用作switch的表达式变量(C)
A、byte B、char C、long D、enum
2、在图采用邻接表存储时,求最小生成树的 Prim 算法的时间复杂度为( B )。
A、 O(n) B、O(n+e) C、 O(n2) D、O(n3)
3、在图采用邻接矩阵存储时,求最小生成树的 Prim 算法的时间复杂度为( C )。
A、 O(n) B、 O(n+e) C、 O(n2) D、O(n3)
4、树的后根遍历序列等同于该树对应的二叉树的( B ).
A、先序序列 B、中序序列 C、后序序列
5、“Abc汉字”的长度为( D )
A、5 B、6 C、7 D、8
- int main(void)
- {
- char str[]="Abc汉字";
- cout<<sizeof(str)<<endl;
- return 0;
- }
汉字存储的时候占用2个字节
6、下面程序的输出结果为( C )
- unsigned int a=1;
- cout<<a*-2<<endl;
A、-4 B、4 C、4294967294 D、4294967295
考查的是unsigned int和int在一起混合运算,int转化为unsigned int
-2的补码就是2^32-2,即是4294967294 ,乘以1的结果还是这个数字。
7、下面程序的输出结果为( B )
- void fn(int *b)
- {
- cout<<(*b)++;
- }
- int main(void)
- {
- int a=7;
- fn(&a);
- cout<<a;
- return 0;
- }
A、77 B、78 C、89 D、undefined
8、下面程序的输出结果为( C )
- #pragma pack(8)
- union A
- {
- char a[13];
- int b;
- };
- int main(void)
- {
- cout<<sizeof(A)<<endl;
- return 0;
- }
A、4 B、8 C、16 D、12
9、下面程序的输出结果为( A )
- class A
- {
- public:
- A(int a)
- {
- printf("%d ",a);
- }
- };
- A a(1);
- int main(void)
- {
- printf("main ");
- A c(2);
- static A b(3);
- return 0;
- }
A、1 main 2 3 B、1 main 3 2 C、main 1 2 3 D、main 1 3 2
10、下面程序的输出结果为( B )
- struct Test
- {
- unsigned short int a:5;
- unsigned short int b:5;
- unsigned short int c:6;
- };
- int main(void)
- {
- Test test;
- test.a=16;
- test.b=4;
- test.c=0;
- int i=*(short*)&test;
- printf("%d\n",i);
- return 0;
- }
A、6 B、144 C、5 D、95
11、n个结点的线索二叉树上含有的线索数为( C )
A、2n B、n-l C、n+l D、n
12、( C)的遍历仍需要栈的支持.
A、前序线索树 B、中序线索树 C、后序线索树
13、二叉树在线索后,仍不能有效求解的问题是( D )。
A、前(先)序线索二叉树中求前(先)序后继
B、中序线索二叉树中求中序后继
C、中序线索二叉树中求中序前驱
D、后序线索二叉树中求后序后继
14、求解最短路径的Floyd算法的时间复杂度为( D )。
A、O(n) B、 O(n+c) C、O(n*n) D、O(n*n*n)
通用试题部分:
选择题
1、在按层次遍历二叉树的算法中, 需要借助的辅组数据结构是
A、队列
B、栈
C、线性表
D、有序表
2、所谓指令周期是指
A、取指令和取操作数的时间
B、执行指令和存储操作结果的时间
C、取操作数和执行指令的时间
D、取指令和执行指令的时间
3、 调用一成员函数时, 使用动态联编的情况是
A、通过对象调用一虚函数
B、通过指针或引用调用一虚函数
C、通过对象调用静态函数
D、通过指针或应用调用一静态函数
4、配置管理能起到以下哪些作用
A、版本管理
B、变更管理
C、需求管理
D、测试管理
简答题
我们在开发中经常强调要面向接口编程(又称契约式编程), 请问采用接口有什么优点呢, 接口和抽象类又有什么区别呢? 分别使用在哪些场景?
编程题(不区分编程语言)
完成一段代码, 代码有三个线程, 主线程由Main进入, 启动一个生产者线程和一个消费者线程, 生产者线程随机产生整数, 并且把这个整数放入一个List中, 消费者从List中取出数据进行显示
综合设计题
现由于业务要求, 需要对每日的积分进出帐与支付宝的现金进出帐进行对账. 帐务数据每天约100万条纪录, 现采用按时段生成帐务文件, 帐务文件通过http协议下载. 在次日凌晨下载帐务文件, 与本地的进出明细帐务做逐条核对.
问题 1: 如何保证每个时段的文件都下载了?
问题 2: 如何保证通过http下载的文件都是完整的?
问题 3: 现将本地帐务也生成文件, 帐务文件格式为: "交易号, 进帐金额, 出帐金额"三个字段用逗号分隔. 支付宝帐务文件格式完全相同, 请设计对账流程, 并实现对账算法的主要思路.
C++开发/搜索引擎开发/数学算法开发
1、以下程序运行后的输出结果是
- void main()
- {
- int p[7]={11, 13, 14, 15, 16, 17, 18};
- int i=0, j=0;
- while(i<7 && p[i]%2==1)
- j+=p[i++];
- printf("%d\n",j);
- }
输出结果是:24
2、列举出STL中常用的容器,并指出下列场景中分别应该使用哪种容器?
从文件中循环读取一系列不重复的英文单词放入容器中, 并在放入的同时进行排序, 并提供检索特定的单词是否存在于容器中的功能.
从文件中循环读取一系列数目不定的可重复的英文单词放入容器中, 要求读取并放置完后, 能够删除中间单词, 并且能够按以前的顺序再输出到另外的文件中.
从文件中循环读取一系列数目固定的可重复的英文单词放入容器中, 要求提供访问第n个单词的功能.
从文件中循环读取一系列数目不定的大量重复的英文单词放入容器, 要求统计每个单词出现的次数, 并能够检索特定的单词的出现次数.
3、若有以下说明和语句, int c[4][5], (*p)[5]; p=c; 如何使用p而不用c来表示c[2][3]这个元素, 答案中不能出现[]操作符。
答案:*(*(p+2)+3)
- int main(void)
- {
- int c[4][5]={1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20};
- int (*p)[5];
- p=c;
- printf("%d\n",*(*(p+2)+3));
- return 0;
- }
4、拷贝构造函数在什么时候被调用, 请写出示例代码
5、有以下定义和语句
int a[3][2]={1,2,3,4,5,6,},*p[3];
p[0]=a[1];
则*(p[0]+1)所代表的数组元素是
- void main()
- {
- int a[3][2]={1,2,3,4,5,6,},*p[3]; //p先和[]结合,所以是一个数组,数组的元素是int型指针
- p[0]=a[1]; //p[0]指向a数组第二行的首地址
- printf("%d\n",*(p[0]+1)); //输出a数组第二行第二列的元素:4
- }
6、有以下程序, 程序运行后的输出结果是
- void main()
- {
- char str[][10]={"China", "Beijing"}, *p=str[0];
- printf("%s\n",p+10);
- }
输出为:Beijing
软件测试
1、 [语句分析, 本懒虫不打了]
2、HTTP1.1协议中规定便是正常响应的状态代码是
A、400 B、200 C、 100 D、0
3、单链表的每个结点中包括一个指针link, 它指向该结点的后继结点. 现要将指针q指向的新结点插入到指针p指向的单结点之后, 下面的操作序列中哪一个是真确的?
A、q:=p^.link; p^.link:=q^.link
B、p^.link:=q^.link; q:=p^.link
C、 q^.link:=p^.link; p^.link:=q
D、p^.link:=q; q^.link:=p^.link
4、[逻辑判断题]
5、给出以下定义, 则正确的叙述为
char x[]="abcdefg";
char y[]={'a','b','c','d','e','f','g'};
A、数组X和数组Y等价
B、数组X和数组Y长度相同
C、数组X的长度大于数组Y的长度
D、数组X的长度小于数组Y的长度
printf("%d\n",sizeof(x)); 输出8
printf("%d\n",sizeof(y)); 输出7
因为x数组是字符串数组,后面还有结束符:“\0”,所以长度为:8
而y数组就是普通的字符数组,没有“\0”结束符的,所以长度为:7
6、 下列程序的返回值是多少:
- int countx=0;
- int x=17373;
- int f()
- {
- while(x)
- {
- countx++;
- x=x&(x-1);
- }
- return countx;
- }
countx的值记录的就是x的二进制中1的个数,把x的二进制写出来,数一下其中有多少个1就可以了。。
数据库开发
1、本地管理表空间和字典管理表空间的特点,ASSM有什么特点。
2、日志的作用是什么?
答:日志文件是用来记录你所对数据库的操作信息的 例如对数据库的操作等引起的问题 日记文件都有记载下来 。 如果数据库有问题的时候可以去看那个日记文件来分析出错的原因。
3、如果系统现在需要在一个很大的表上创建一个索引, 你会考虑哪些因素, 如何做以尽量减小对应用的影响。
专业试题部分
Java开发
1. 请列出Test执行时的输出结果
A. 编译不通过
B. SSA
C. SSS
D. SAA
Test代码如下:
class A{
public void printValue(){
System.out.print("A");
}
}
class S extends A{
public void printValue(){
System.out.print("S");
}
}
public class Test {
public static void main(String[] args){
S s=new S();
s.printValue();
A as=(A)s;
as.printValue();
as=new A();
as.printValue();
}
}
2. String compare:
A
String s1="java";
String s2="java";
(1) s1==s2 (2) s1.equals(s2)
Result: (1) (2)
B
String s="ja";
String s1=s+"va";
String s2="java";
(1) s1==s2 (2) s1.equals(s2)
Result: (1) (2)
3. True or False: Readers have methods that can read and return floats and doubles.
A. True
B. False
4. 在//point x处的哪些声明是句法上合法的(多选)
class Person{
private int a;
public int change(int m){
return m;
}
}
public class Teacher extends Person {
public int b;
public static void main(String arg[]){
Person p=new Person();
Teacher t=new Teacher();
int i;
//point x
}
}
A. i=m; B. i=t.b; C. i=p.a; D. i=p.change(30);
5. Given the following code, what will be the output?
class Value{
public int i=5;
}
public class Test_1 {
public static void main(String argv[]){
Test_1 t=new Test_1();
t.first();
}
public void first(){
int i=5;
Value v=new Value();
v.i=25;
second(v,i);
System.out.print(v.i);
}
public void second(Value v, int i){
i=0;
v.i=20;
Value val=new Value();
v=val;
System.out.print(v.i+" "+i);
}
}
A. 15 0 20
B. 15 0 15
C. 20 0 20
D. 0 15 20
6. 下面哪一个interface的定义是错误的?
A.
interface interface1 extends interface2, interface3{
void undo(int i);
void process();
}
B.
interface interface1{
public void undo(int i);
}
C.
interface interface1{
String aa;
}
D.
interface interface1{
private String var;
process(){};
}
前端开发
1. Google Chrome浏览器对CSS的支持度和下面哪个浏览器基本一致:
A. IE7 B. Firefox 3.1 C. Opera 9.5 D. Safari 3.1
2. 下面这段javascript代码,
var msg='hello';
for (var i=0; i<10; i++){
var msg='hello'+i*2+i;
}
alert(msg);
最后一句alert的输出结果是:
A. hello B. hello189 C. hello30 D. hello27
3. 下面哪个Hack属性, IE7浏览器不能识别:
A. @color:red B. *color:red; C. _color:red; D. +color:red;
4. 请问在javascript程序中, alert(undefined==null)的输出结果是:
A. undefined B. null C. true D. false
5. 根据下图, 请您用符合Web语义的(X)HTML代码书写结构[此题目图片懒得搞了, 反正这题也很简单, 省略]
6. 请手写一段javascript程序, 对数组[5, 1000, 6, 3, 8, 123, -12]按从小到大进行排序, 如果你有多种解法, 请阐述各种解法的思路及其优缺点.(仅需用代码实现一种算法, 其他解法用文字阐述思路即可)
网络系统运维
1、 在Linux系统中, 为找到文件try_grep含有以a字母为行开头的内容, 可以使用命令:
A、grep -E #$ try_grep
B、grep -E #a try_grep
C、grep -E ^$ try_grep
D、grep -E ^a try_grep
^M 以M开头的行,^表示开始的意思
M$ 以M结尾的行,$表示结束的意思
2、在Linux系统中, 检查硬盘空间使用情况应该使用什么命令?
A、df B、 du C、fd D、free
3、 ping命令使用的协议是:
A、ICMP B、IMAP C、POP D、 SNMP
4、以下设备中哪种最适合做网站负载均衡设备(Load Balance):
A、二层交换机 B、 路由器 C、四层交换机 D、 防火墙
5、查看当前主机的网关配置地址是多少, 请将地址写入到./ga.txt中。
6、修改当前目录下的smb.conf, 将当前/etc目录共享出去。
1、下面的排序算法中,初始数据集的排列顺序对算法的性能无影响的是(B)
A、插入排序 B、堆排序 C、冒泡排序 D、快速排序
2、以下关于Cache的叙述中,正确的是(B)
A、CPU中的Cache容量应大于CPU之外的Cache容量
B、Cache的设计思想是在合理成本下提高命中率
C、Cache的设计目标是容量尽可能与主存容量相等
D、在容量确定的情况下,替换算法的时间复杂度是影响Cache命中率的关键因素
3、数据存储在磁盘上的排列方式会影响I/O服务的性能,一个圆环的磁道上有10个物理块,10个数据记录R1------R10存放在这个磁道上,记录的安排顺序如下表所示:
物理块 |
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
逻辑记录 |
R1 |
R2 |
R3 |
R4 |
R5 |
R6 |
R7 |
R8 |
R9 |
R10 |
假设磁盘的旋转速度为20ms/周,磁盘当前处在R1的开头处,若系统顺序扫描后将数据放入单缓冲区内,处理数据的时间为4ms(然后再读取下个记录),则处理这10个记录的最长时间为(C)
A、180ms B、200ms C、204ms D、220ms
4、随着IP网络的发展,为了节省可分配的注册IP地址,有一些地址被拿出来用于私有IP地址,以下不属于私有IP地址范围的是(C)
A、10.6.207.84 B、172.23.30.28 C、172.32.50.80 D、192.168.1.100
A: 10.0.0.0~10.255.255.255 /8 B: 172.16.0.0~172.31.255.255 /12 C: 192.168.0.0~192.168.255.255 /16
5、下列关于一个类的静态成员的描述中,不正确的是(D)
A、该类的对象共享其静态成员变量的值 B、静态成员变量可被该类的所有方法访问
C、该类的静态方法只能访问该类的静态成员变量 D、该类的静态数据成员变量的值不可修改
6、已知一个线性表(38,25,74,63,52,48),假定采用散列函数h(key) = key%7计算散列地址,并散列存储在散列表A【0....6】中,若采用线性探测方法解决冲突,则在该散列表上进行等概率成功查找的平均查找长度为(C)
A、1.5 B、1.7 C、2.0 D、2.3
依次进行取模运算求出哈希地址:
A |
0 |
1 |
2 |
3 |
4 |
5 |
6 |
记录 |
63 |
48 |
|
38 |
25 |
74 |
52 |
查找次数 |
1 |
3 |
|
1 |
1 |
2 |
4 |
74应该放在下标为4的位置,由于25已经放在这个地方,所以74往后移动,放在了下标为5的位置上了。
由于是等概率查找,所以结果为:1/6*(1+3+1+1+2+4)= 2.0
7、表达式“X=A+B*(C--D)/E”的后缀表示形式可以为(C)
A、XAB+CDE/-*= B、XA+BC-DE/*= C、XABCD-*E/+= D、XABCDE+*/=
8、(B)设计模式将抽象部分与它的实现部分相分离。
A、Singleton(单例) B、 Bridge(桥接)
C、 Composite(组合) D、 Facade(外观)
9、下面程序的输出结果为多少?
- void Func(char str_arg[100])
- {
- printf("%d\n",sizeof(str_arg));
- }
- int main(void)
- {
- char str[]="Hello";
- printf("%d\n",sizeof(str));
- printf("%d\n",strlen(str));
- char *p = str;
- printf("%d\n",sizeof(p));
- Func(str);
- }
输出结果为:6 5 4 4
对字符串进行sizeof操作的时候,会把字符串的结束符“\0”计算进去的,进行strlen操作求字符串的长度的时候,不计算\0的。
数组作为函数参数传递的时候,已经退化为指针了,Func函数的参数str_arg只是表示一个指针,那个100不起任何作用的。
10、下面程序的输出结果为多少?
- void Func(char str_arg[2])
- {
- int m = sizeof(str_arg); //指针的大小为4
- int n = strlen(str_arg); //对数组求长度,str_arg后面的那个2没有任何意义,数组已经退化为指针了
- printf("%d\n",m);
- printf("%d\n",n);
- }
- int main(void)
- {
- char str[]="Hello";
- Func(str);
- }
输出结果为: 4 5
strlen只是对传递给Func函数的那个字符串求长度,跟str_arg中的那个2是没有任何关系的,即使把2改为200也是不影响输出结果的。。
11、到商店里买200的商品返还100优惠券(可以在本商店代替现金)。请问实际上折扣是多少?
12、题目:已知rand7() 可以产生 1~7 的7个数(均匀概率),利用rand7() 产生rand10() 1~10(均匀概率)
记住这道题重点是:均匀概率
- //rand7 产生的数概率是一样的,即1~7出现概率一样,由于我们对结果做了一定的筛选只能通过 1~5,而1~5出现的概率也是一样的,又由于范围为1~5 所以 temp1 出现 1~5的概率 为1/5 ,同理 后面的 出现 temp2 的概率为 1/2
- //首先temp1出现在1~5的概率为1/5,而temp2出现 1~2 的概率为1/2,也就是说 5*(temp2-1) 出现5或0的概率为1/2,所以假如你要得到1~5的数的话 那么 5*(temp2-1) 必须0,所以因为你要保证 5*(temp2-1)=0,这个概率只有1/2,再加上 你前面指定1~5 的概率 为1/5 ,所以结果为 1/5*1/2=1/10
- int rand10()
- {
- int temp1;
- int temp2;
- do
- {
- temp1 = rand7();
- }while(temp1>5);
- do
- {
- temp2 = rand7();
- }while(temp2>2);
- return temp1+5*(temp2-1);
- }
13、给定能随机生成整数1到5的函数,写出能随机生成整数1到7的函数。
算法编程题:
1、给定一个字符串,求出其最长的重复子串。
思路:使用后缀数组,对一个字符串生成相应的后缀数组后,然后再排序,排完序依次检测相邻的两个字符串的开头公共部分。
这样的时间复杂度为:
生成后缀数组 O(N)
排序 O(NlogN*N) 最后面的 N 是因为字符串比较也是 O(N)
依次检测相邻的两个字符串 O(N * N)
总的时间复杂度是 O(N^2*logN),
1、 堆和栈的区别?
答:1、栈区(stack)— 由编译器自动分配释放 ,存放函数的参数值,局部变量的值等。其操作方式类似于数据结构中的栈。
2、堆区(heap) 一般由程序员分配释放, 若程序员不释放,程序结束时可能由OS回收 。注意它与数据结构中的堆是两回事,分配方式倒是类似于链表,呵呵。
3、栈是向下增长的,堆是向上增长的。(可以参考上一篇博客)
下面是一个例子程序:
- //main.cpp
- int a = 0; //全局初始化区
- char *p1; //全局未初始化区
- void main()
- {
- int b; //栈
- char s[] = "abc"; //栈
- char *p2; //栈
- char *p3 = "123456"; // 123456\0在常量区,p3在栈上。
- static int c=0; //全局(静态)初始化区
- p1 = (char *)malloc(10); //在堆上动态开辟空间
- p2 = (char *)malloc(20);
- //分配来的10和20字节的区域就在堆区。
- strcpy(p1, "123456"); //123456\0放在常量区,编译器可能会将它与p3所指向的"123456" 优化成一个地方。
- }
申请方式不同:
stack: 由系统自动分配。速度较快。但程序员是无法控制的。 例如,在函数中声明一个局部变量 int b; 系统自动在栈中为b开辟空间
heap: 需要程序员自己申请,并指明大小,一般速度比较慢,而且容易产生内存碎片,不过用起来最方便。在c中malloc函数。
如p1 = (char *)malloc(10);
在C++中用new运算符
如p2 = new char[10];
但是注意p1、p2本身是在栈中的。
2、进程和线程区别?
线程是指进程内的一个执行单元,也是进程内的可调度实体.
与进程的区别:
(1)地址空间:进程内的一个执行单元;进程至少有一个线程;它们共享进程的地址空间;而进程有自己独立的地址空间;
(2)资源拥有:进程是资源分配和拥有的单位,同一个进程内的线程共享进程的资源
(3)线程是处理器调度的基本单位,但进程不是。4)二者均可并发执行。
进程和线程都是由操作系统所体会的程序运行的基本单元,系统利用该基本单元实现系统对应用的并发性。进程和线程的区别:
简而言之,一个程序至少有一个进程,一个进程至少有一个线程。
线程的划分尺度小于进程,使得多线程程序的并发性高。
另外,进程在执行过程中拥有独立的内存单元,而多个线程共享内存,从而极大地提高了程序的运行效率。
线程在执行过程中与进程还是有区别的。每个独立的线程有一个程序运行的入口、顺序执行序列和程序的出口。但是线程不能够独立执行,必须依存在应用程序中,由应用程序提供多个线程执行控制。
从逻辑角度来看,多线程的意义在于一个应用程序中,有多个执行部分可以同时执行。但操作系统并没有将多个线程看做多个独立的应用,来实现进程的调度和管理以及资源分配。这就是进程和线程的重要区别。
进程是具有一定独立功能的程序关于某个数据集合上的一次运行活动,进程是系统进行资源分配和调度的一个独立单位。
线程是进程的一个实体,是CPU调度和分派的基本单位,它是比进程更小的能独立运行的基本单位.线程自己基本上不拥有系统资源,只拥有一点在运行中必不可少的资源(如程序计数器,一组寄存器和栈),但是它可与同属一个进程的其他的线程共享进程所拥有的全部资源。
一个线程可以创建和撤销另一个线程;同一个进程中的多个线程之间可以并发执行。
3、C语言中两种方式使用#include命令,#include <>与#include ””的区别是什么?
答:"#include <stdlib.h> ” 用于标准库文件或系统提供的头文件,到保存系统标准头文件的位置查找头文件。
而"#include "userdefined.h"用于用户自定义的头文件,先从当前目录查找是否有指定名称的头文件,若当前目录未找到该头文件,再从标准文件目录中查找。这两种方式有他们的本质区别。
在c语言程序设计中包含的头文件可分为系统标准头文件和用户工程中自定义的头文件,对于系统标准库头文件可以用这两种方式进行包含,但是采用第一种方式更节省时间,所以一般建议采用第一种方式。对于用户自己定义的头文件(保存在工程路径下)只能用第二种方式进行包含操作,否则出错(当然也可以把自己定义的工程中需要的头文件放在标准头文件路径下,但是这违背常规操作)。
4、抽象类为什么不能实例化?
抽象类中的纯虚函数没有具体的实现,所以没办法实例化。
5、设计模式:工厂模式 和 单例模式 介绍一下?
工程模式即将对象创建过程封装即为工厂模式。
单例模式即整个类只有一个对象,并且不允许显示创建。
6、vector 和 list的区别?
vector内部使用顺序存储,访问速度快,但是删除数据比较耗性能。
list内部使用链式存储,访问速度慢,但是删除数据比较快。
7、纯虚函数是怎样实现的?在编译原理上讲一下?
答:在类内部添加一个虚拟函数表指针,该指针指向一个虚拟函数表,该虚拟函数表包含了所有的虚拟函数的入口地址,每个类的虚拟函数表都不一样,在运行阶段可以循此脉络找到自己的函数入口。
8、两个线程,几个变量,线程执行次序不确定,某个变量的可能取值。。
9、hash冲突时候的解决方法?
1)、开放地址法
2)、再哈希法
3)、链地址法
4)、建立一个公共溢出区
10、单链表的倒置。
- //逆转链表,并返回逆转后的头节点
- node* reverse(node *head)
- {
- if(head == NULL || head->next == NULL)
- {
- return head;
- }
- node *cur = head;
- node *pre = NULL;
- node *tmp;
- while(cur->next)
- {
- tmp = pre;
- pre = cur;
- cur = cur->next;
- pre->next = tmp; //操作pre的next逆转
- }
- cur->next = pre; //结束时,操作cur的next逆转
- return cur;
- }
实现一个挺高级的字符匹配算法:
给一串很长字符串,要求找到符合要求的字符串,例如目的串:123
1******3***2 ,12*****3 这些都要找出来,其实就是类似一些和谐系统。。。。。
这题的真正意思就是,给你一个目标串,如“123”,只要一个字符串里面同时包含1、2和3,那么这个字符串就匹配了。系统越和谐,说明错杀的可能行也就越大。加入目标串的长度为m,模式串的长度为n,我们很容易想到O(mn)的算法,就是两遍for循环搞定。那么有没有更快的方法呢?
我们考虑问题的时候,如果想时间变得快,有一种方法就叫做“空间换时间”。哈希表是一种比较复杂的数据结构。由于比较复杂,STL中没有实现哈希表,因此需要我们自己实现一个。但由于本题的特殊性,我们只需要一个非常简单的哈希表就能满足要求。由于字符(char)是一个长度为8的数据类型,因此总共有可能256 种可能。于是我们创建一个长度为256的数组,每个字母根据其ASCII码值作为数组的下标对应数组的对应项,而数组中存储的0、1对应每个字符是否出现。这样我们就创建了一个大小为256,以字符ASCII码为键值的哈希表。(并不仅限于英文字符,所以这里要考虑256种可能)。
知道了这点,我们可以构建一个数组来统计模式串中某个字符是否出现,然后在对目标串进行扫描,看看对应的所有位上是否出现,从而判断是否匹配。分析一下复杂度,大概是O(m+n)。
实现代码如下:
- //强大的和谐系统
- int is_contain(char *src, char *des)
- {
- //创建一个哈希表,并初始化
- const int tableSize = 256;
- int hashTable[tableSize];
- int len,i;
- for(i = 0; i < tableSize; i++)
- hashTable[i] = 0;
- len = strlen(src);
- for(i = 0; i < len; i++)
- hashTable[src[i]] = 1;
- len = strlen(des);
- for(i = 0; i < len; i++)
- {
- if(hashTable[des[i]] == 0)
- return 0; //匹配失败
- }
- return 1; //匹配成功
- }
偶然间在网上看到几个原来没见过的面试智力题,有几个题目在国内流传相当广,什么n个人怎么分饼最公平,屋里的三个灯泡分别由哪个开关控制,三架飞机环游世界,用火柴和两根绳子测量45分钟之类的题目,火星得已经可以考古了,这里就不再说了。
1、考虑一个双人游戏。游戏在一个圆桌上进行。每个游戏者都有足够多的硬币。他们需要在桌子上轮流放置硬币,每次必需且只能放置一枚硬币,要求硬币完全置于桌面内(不能有一部分悬在桌子外面),并且不能与原来放过的硬币重叠。谁没有地方放置新的硬币,谁就输了。游戏的先行者还是后行者有必胜策略?这种策略是什么?
答案:先行者在桌子中心放置一枚硬币,以后的硬币总是放在与后行者刚才放的地方相对称的位置。这样,只要后行者能放,先行者一定也有地方放。先行者必胜。
2、 用线性时间和常数附加空间将一篇文章的单词(不是字符)倒序。
答案:先将整篇文章的所有字符逆序(从两头起不断交换位置相对称的字符);然后用同样的办法将每个单词内部的字符逆序。这样,整篇文章的单词顺序颠倒了,但单词本身又被转回来了。
3、 用线性时间和常数附加空间将一个长度为n的字符串向左循环移动m位(例如,"abcdefg"移动3位就变成了"defgabc")。
答案:把字符串切成长为m和n-m的两半。将这两个部分分别逆序,再对整个字符串逆序。
4、一个矩形蛋糕,蛋糕内部有一块矩形的空洞。只用一刀,如何将蛋糕切成大小相等的两块?
答案:注意到平分矩形面积的线都经过矩形的中心。过大矩形和空心矩形各自的中心画一条线,这条线显然把两个矩形都分成了一半,它们的差当然也是相等的。
5、 一块矩形的巧克力,初始时由N x M个小块组成。每一次你只能把一块巧克力掰成两个小矩形。最少需要几次才能把它们掰成N x M块1x1的小巧克力?
答案:N x M - 1次显然足够了。这个数目也是必需的,因为每掰一次后当前巧克力的块数只能增加一,把巧克力分成N x M块当然需要至少掰N x M - 1次。
6、如何快速找出一个32位整数的二进制表达里有多少个"1"?用关于"1"的个数的线性时间?
答案1(关于数字位数线性):for(n=0; b; b >>= 1) if (b & 1) n++;
答案2(关于"1"的个数线性):for(n=0; b; n++) b &= b-1;
7、 一个大小为N的数组,所有数都是不超过N-1的正整数。用O(N)的时间找出重复的那个数(假设只有一个)。一个大小为N的数组,所有数都是不超过N+1的正整数。用O(N)的时间找出没有出现过的那个数(假设只有一个)。
答案:计算数组中的所有数的和,再计算出从1到N-1的所有数的和,两者之差即为重复的那个数。计算数组中的所有数的和,再计算出从1到N+1的所有数的和,两者之差即为缺少的那个数。
8、 给出一行C语言表达式,判断给定的整数是否是一个2的幂。
答案:(b & (b-1)) == 0
9、地球上有多少个点,使得从该点出发向南走一英里,向东走一英里,再向北走一英里之后恰好回到了起点?
答案:“北极点”是一个传统的答案,其实这个问题还有其它的答案。事实上,满足要求的点有无穷多个。所有距离南极点1 + 1/(2π)英里的地方都是满足要求的,向南走一英里后到达距离南极点1/(2π)的地方,向东走一英里后正好绕行纬度圈一周,再向北走原路返回到起点。事实上,这仍然不是满足要求的全部点。距离南极点1 + 1/(2kπ)的地方都是可以的,其中k可以是任意一个正整数。
10、A、B两人分别在两座岛上。B生病了,A有B所需要的药。C有一艘小船和一个可以上锁的箱子。C愿意在A和B之间运东西,但东西只能放在箱子里。只要箱子没被上锁,C都会偷走箱子里的东西,不管箱子里有什么。如果A和B各自有一把锁和只能开自己那把锁的钥匙,A应该如何把东西安全递交给B?
答案:A把药放进箱子,用自己的锁把箱子锁上。B拿到箱子后,再在箱子上加一把自己的锁。箱子运回A后,A取下自己的锁。箱子再运到B手中时,B取下自己的锁,获得药物。
11、 一对夫妇邀请N-1对夫妇参加聚会(因此聚会上总共有2N人)。每个人都和所有自己不认识的人握了一次手。然后,男主人问其余所有人(共2N-1个人)各自都握了几次手,得到的答案全部都不一样。假设每个人都认识自己的配偶,那么女主人握了几次手?
答案:握手次数只可能是从0到2N-2这2N-1个数。除去男主人外,一共有2N-1个人,因此每个数恰好出现了一次。其中有一个人(0)没有握手,有一个人(2N-2)和所有其它的夫妇都握了手。这两个人肯定是一对夫妻,否则后者将和前者握手(从而前者的握手次数不再是0)。除去这对夫妻外,有一个人(1)只与(2N-2)握过手,有一个人(2N-3)和除了(0)以外的其它夫妇都握了手。这两个人肯定是一对夫妻,否则后者将和前者握手(从而前者的握手次数不再是1)。以此类推,直到握过N-2次手的人和握过N次手的人配成一对。此时,除了男主人及其配偶以外,其余所有人都已经配对。根据排除法,最后剩下来的那个握手次数为N-1的人就是女主人了。
12、两个机器人,初始时位于数轴上的不同位置。给这两个机器人输入一段相同的程序,使得这两个机器人保证可以相遇。程序只能包含“左移n个单位”、“右移n个单位”,条件判断语句If,循环语句while,以及两个返回Boolean值的函数“在自己的起点处”和“在对方的起点处”。你不能使用其它的变量和计数器。
答案:两个机器人同时开始以单位速度右移,直到一个机器人走到另外一个机器人的起点处。然后,该机器人以双倍速度追赶对方。程序如下。
while(!at_other_robots_start) {
move_right 1
}
while(true) {
move_right 2
}
13、 如果叫你从下面两种游戏中选择一种,你选择哪一种?为什么?
a. 写下一句话。如果这句话为真,你将获得10美元;如果这句话为假,你获得的金钱将少于10美元或多于10美元(但不能恰好为10美元)。
b. 写下一句话。不管这句话的真假,你都会得到多于10美元的钱。
答案:选择第一种游戏,并写下“我既不会得到10美元,也不会得到10000000美元”。
14、你在一幢100层大楼下,有21根电线线头标有数字1..21。这些电线一直延伸到大楼楼顶,楼顶的线头处标有字母A..U。你不知道下面的数字和上面的字母的对应关系。你有一个电池,一个灯泡,和许多很短的电线。如何只上下楼一次就能确定电线线头的对应关系?
答案:在下面把2,3连在一起,把4到6全连在一起,把7到10全连在一起,等等,这样你就把电线分成了6个“等价类”,大小分别为1, 2, 3, 4, 5, 6。然后到楼顶,测出哪根线和其它所有电线都不相连,哪些线和另外一根相连,哪些线和另外两根相连,等等,从而确定出字母A..U各属于哪个等价类。现在,把每个等价类中的第一个字母连在一起,形成一个大小为6的新等价类;再把后5个等价类中的第二个字母连在一起,形成一个大小为5的新等价类;以此类推。回到楼下,把新的等价类区别出来。这样,你就知道了每个数字对应了哪一个原等价类的第几个字母,从而解决问题。
15、某种药方要求非常严格,你每天需要同时服用A、B两种药片各一颗,不能多也不能少。这种药非常贵,你不希望有任何一点的浪费。一天,你打开装药片A的药瓶,倒出一粒药片放在手心;然后打开另一个药瓶,但不小心倒出了两粒药片。现在,你手心上有一颗药片A,两颗药片B,并且你无法区别哪个是A,哪个是B。你如何才能严格遵循药方服用药片,并且不能有任何的浪费?
答案:把手上的三片药各自切成两半,分成两堆摆放。再取出一粒药片A,也把它切成两半,然后在每一堆里加上半片的A。现在,每一堆药片恰好包含两个半片的A和两个半片的B。一天服用其中一堆即可。
16、 你在一个飞船上,飞船上的计算机有n个处理器。突然,飞船受到外星激光武器的攻击,一些处理器被损坏了。你知道有超过一半的处理器仍然是好的。你可以向一个处理器询问另一个处理器是好的还是坏的。一个好的处理器总是说真话,一个坏的处理器总是说假话。用n-2次询问找出一个好的处理器。
答案:给处理器从1到n标号。用符号a->b表示向标号为a的处理器询问处理器b是不是好的。首先问1->2,如果1说不是,就把他们俩都去掉(去掉了一个好的和一个坏的,则剩下的处理器中好的仍然过半),然后从3->4开始继续发问。如果1说2是好的,就继续问2->3,3->4,……直到某一次j说j+1是坏的,把j和j+1去掉,然后问j-1 -> j+2;或者从j+2 -> j+3开始发问,如果前面已经没有j-1了(之前已经被去掉过了)。注意到你始终维护着这样一个“链”,前面的每一个处理器都说后面那个是好的。这条链里的所有处理器要么都是好的,要么都是坏的。当这条链越来越长,剩下的处理器越来越少时,总有一个时候这条链超过了剩下的处理器的一半,此时可以肯定这条链里的所有处理器都是好的。或者,越来越多的处理器都被去掉了,链的长度依旧为0,而最后只剩下一个或两个处理器没被问过,那他们一定就是好的了。另外注意到,第一个处理器的好坏从来没被问过,仔细想想你会发现最后一个处理器的好坏也不可能被问到(一旦链长超过剩余处理器的一半,或者最后没被去掉的就只剩这一个了时,你就不问了),因此询问次数不会超过n-2。
17、一个圆盘被涂上了黑白二色,两种颜色各占一个半圆。圆盘以一个未知的速度、按一个未知的方向旋转。你有一种特殊的相机可以让你即时观察到圆上的一个点的颜色。你需要多少个相机才能确定圆盘旋转的方向?
答案:你可以把两个相机放在圆盘上相近的两点,然后观察哪个点先变色。事实上,只需要一个相机就够了。控制相机绕圆盘中心顺时针移动,观察颜色多久变一次;然后让相机以相同的速度逆时针绕着圆盘中心移动,再次观察变色的频率。可以断定,变色频率较慢的那一次,相机的转动方向是和圆盘相同的。
18、有25匹马,速度都不同,但每匹马的速度都是定值。现在只有5条赛道,无法计时,即每赛一场最多只能知道5匹马的相对快慢。问最少赛几场可以找出25匹马中速度最快的前3名?(百度2008年面试题)
每匹马都至少要有一次参赛的机会,所以25匹马分成5组,一开始的这5场比赛是免不了的。接下来要找冠军也很容易,每一组的冠军在一起赛一场就行了(第6场)。最后就是要找第2和第3名。我们按照第6场比赛中得到的名次依次把它们在前5场比赛中所在的组命名为A、B、C、D、E。即:A组的冠军是第6场的第1名,B组的冠军是第6场的第2名……每一组的5匹马按照他们已经赛出的成绩从快到慢编号:
A组:1,2,3,4,5
B组:1,2,3,4,5
C组:1,2,3,4,5
D组:1,2,3,4,5
E组:1,2,3,4,5
从现在所得到的信息,我们可以知道哪些马已经被排除在3名以外。只要已经能确定有3匹或3匹以上的马比这匹马快,那么它就已经被淘汰了。可以看到,只有上表中粗体的那5匹马是有可能为2、3名的。即:A组的2、3名;B组的1、2名,C组的第1名。取这5匹马进行第7场比赛,第7场比赛的前两名就是25匹马中的2、3名。故一共最少要赛7场。
这道题有一些变体,比如64匹马找前4名。方法是一样的,在得出第1名以后寻找后3名的候选竞争者就可以了。
19、题目如下:
0 1 2 3 4 5 6 7 8 9
_ _ _ _ _ _ _ _ _ _
在横线上填写数字,使之符合要求。
要求如下:对应的数字下填入的数,代表上面的数在下面出现的次数,比如3下面是1,代表3要在下面出现一次。
正确答案是:0 1 2 3 4 5 6 7 8 9
6 2 1 0 0 0 1 0 0 0
我的思路是:因为第二行的数字是第一行的数在下面出现的次数,下面10个格子,总共10次。。。所以第2排数字之和为10。
首先从0入手,先填9,肯定不可能,9下面要是1,只剩8个位填0,不够填8,8下面要填1,1要至少填2,后面不用再想,因为已经剩下7个位置,不够填0……如此类推。到0下面填6的时候就得到我上面的答案了。。
其实可以推出这个题目的两个关键条件:
1、第2排数字之和为10。
2、两排数字上下相乘之和也是10!
满足这两个条件的就是答案,下面来编写程序实现!
- //原始数值: 0,1,2,3,4,5,6,7,8,9
- //出现次数: 6,2,1,0,0,0,1,0,0,0
- #include "iostream"
- using namespace std;
- #define len 10
- class NumberTB
- {
- private:
- int top[len];
- int bottom[len];
- bool success;
- public:
- NumberTB();
- int *getBottom();
- void setNextBottom();
- int getFrequecy(int num);
- };
- NumberTB::NumberTB()
- {
- success = false;
- //format top
- for(int i = 0; i < len; i++)
- {
- top[i] = i;
- }
- }
- int *NumberTB::getBottom()
- {
- int i = 0;
- while(!success)
- {
- i++;
- setNextBottom();
- }
- return bottom;
- }
- //set next bottom
- void NumberTB::setNextBottom()
- {
- bool reB = true;
- for(int i = 0; i < len; i++)
- {
- int frequecy = getFrequecy(i);
- if(bottom[i] != frequecy)
- {
- bottom[i] = frequecy;
- reB = false;
- }
- }
- success = reB;
- }
- //get frequency in bottom
- int NumberTB::getFrequecy(int num) //此处的num 即指上排的数i
- {
- int count = 0;
- for(int i = 0; i < len; i++)
- {
- if(bottom[i] == num)
- count++;
- }
- return count; //cout 即对应frequecy
- }
- int main(void)
- {
- int i;
- NumberTB nTB;
- int *result = nTB.getBottom();
- cout<<"原始数值:";
- for(i=0;i<10;i++)
- cout<<i<<" ";
- cout<<endl;
- cout<<"出现次数:";
- for(i = 0; i < len; i++)
- {
- cout << *result++ <<" ";
- }
- cout<<endl;
- system("pause");
- return 0;
- }