C++ STL和几道经典的面试题
2017-12-08 09:53
477 查看
C++ STL 的实现:
1.vector: 底层数据结构为数组 ,支持快速随机访问。
2.list: 底层数据结构为双向链表,支持快速增删。
3.deque: 底层数据结构为一个中央控制器和多个缓冲区,详细见STL源码剖析P146,支持首尾(中间不能)快速增删,也支持随机访问。
4.stack : 底层一般用23实现,封闭头部即可,不用vector的原因应该是容量大小有限制,扩容耗时
5.queue: 底层一般用23实现,封闭头部即可,不用vector的原因应该是容量大小有限制,扩容耗时(stack和queue其实是适配器,而不叫容器,因为是对容器的再封装)
6.priority_queue: 的底层数据结构一般为vector为底层容器,堆heap为处理规则来管理底层容器实现
7.set: 底层数据结构为红黑树,有序,不重复。
8.multiset: 底层数据结构为红黑树,有序,可重复。
9.map: 底层数据结构为红黑树,有序,不重复。
10.multimap: 底层数据结构为红黑树,有序,可重复。
11.hash_set: 底层数据结构为hash表,无序,不重复。
12.hash_multiset: 底层数据结构为hash表,无序,可重复 。
13.hash_map : 底层数据结构为hash表,无序,不重复。
14.hash_multimap: 底层数据结构为hash表,无序,可重复。
1)不用算术运算符进行求和不使用算术运算求和那么只能考虑直接在二进制位上进行位运算,事实上利用异或运算(^)和与运算(&)就能完成加法运算要做的事情,其中异或运算完成相加但是不进位,而与运算计算出哪些地方需要进位,在通过左移运算(<<)就可以完成进位操作了。
2)利用位运算中异或运算的特点,两个相同的数异或的结果一定是0,那么将a和b中的所有元素做一次异或运算,最终的结果就是b比a多出的那个元素的值
3)题目:有一个已经排好序的数组,其中存在重复元素,请将重复元素删除掉,例如,A = [1, 1, 2, 2, 3],处理之后的数组应当为A = [1, 2, 3]。
在O(n)的时间复杂度内完成数组移动,如abcde,左移三位变为cdeab,如果数组长度为l,移动位数为n,如果n大于l的话相当于移动n%l位,如果用一般的循环移位时间复杂度为O(n×l),不能在规定的要求内完成,所以只能考虑在数组本身上下功夫,如abcde,移动3位,可以理解为剩下的前两位翻转,后3位翻转然后整个数组翻转,abcde->bacde->baedc->cdeab,这样就可以在O(n)等级的时间复杂度内完成操作。大致功能函数如下
4)F(M,N)求解不大于N的和是M的所有组合个数。使用递归求解组合个数。
5)打靶算法:靶环有10个环,那么当打中时分数可为1-10,如果未打中得分为0,也就是11种可能,比如现在求6枪50分的概率
1.vector: 底层数据结构为数组 ,支持快速随机访问。
2.list: 底层数据结构为双向链表,支持快速增删。
3.deque: 底层数据结构为一个中央控制器和多个缓冲区,详细见STL源码剖析P146,支持首尾(中间不能)快速增删,也支持随机访问。
4.stack : 底层一般用23实现,封闭头部即可,不用vector的原因应该是容量大小有限制,扩容耗时
5.queue: 底层一般用23实现,封闭头部即可,不用vector的原因应该是容量大小有限制,扩容耗时(stack和queue其实是适配器,而不叫容器,因为是对容器的再封装)
6.priority_queue: 的底层数据结构一般为vector为底层容器,堆heap为处理规则来管理底层容器实现
7.set: 底层数据结构为红黑树,有序,不重复。
8.multiset: 底层数据结构为红黑树,有序,可重复。
9.map: 底层数据结构为红黑树,有序,不重复。
10.multimap: 底层数据结构为红黑树,有序,可重复。
11.hash_set: 底层数据结构为hash表,无序,不重复。
12.hash_multiset: 底层数据结构为hash表,无序,可重复 。
13.hash_map : 底层数据结构为hash表,无序,不重复。
14.hash_multimap: 底层数据结构为hash表,无序,可重复。
1)不用算术运算符进行求和不使用算术运算求和那么只能考虑直接在二进制位上进行位运算,事实上利用异或运算(^)和与运算(&)就能完成加法运算要做的事情,其中异或运算完成相加但是不进位,而与运算计算出哪些地方需要进位,在通过左移运算(<<)就可以完成进位操作了。
#include"iostream.h" int sum(int a,int b){ if(b == 0) return a; int c = a ^ b; int d = (a & b) << 1; return sum(c, d);} int main(){ cout<<sum(12,13); return 0; }
2)利用位运算中异或运算的特点,两个相同的数异或的结果一定是0,那么将a和b中的所有元素做一次异或运算,最终的结果就是b比a多出的那个元素的值
#include"iostream.h" int find(int a[],int b[],int n){ int c = 0; for(int i = 0; i <n; i++) { c ^= a[i] ^ b[i]; } c ^= b ; return c; } int main(){ int a[6]={1, 3, 2, -4, 10, 18}; int b[]= {3, 55, 1, 2, 10, -4, 18}; cout<<find(a,b,6); return 0; }
3)题目:有一个已经排好序的数组,其中存在重复元素,请将重复元素删除掉,例如,A = [1, 1, 2, 2, 3],处理之后的数组应当为A = [1, 2, 3]。
public: int remove(int &A[],int n){ if(n==0) return 0; int index=0; for(int i=1;i<n;i++) { if(A[index]!=A[i]) A[++index]=A[i]; } index++; return index; }
在O(n)的时间复杂度内完成数组移动,如abcde,左移三位变为cdeab,如果数组长度为l,移动位数为n,如果n大于l的话相当于移动n%l位,如果用一般的循环移位时间复杂度为O(n×l),不能在规定的要求内完成,所以只能考虑在数组本身上下功夫,如abcde,移动3位,可以理解为剩下的前两位翻转,后3位翻转然后整个数组翻转,abcde->bacde->baedc->cdeab,这样就可以在O(n)等级的时间复杂度内完成操作。大致功能函数如下
int reverse(int i,int j,int *array) { for(;i>m;i++,m--) { temp = array[i]; array[i] = array[j]; array[j] = temp; } } int main() { int n;//移动的位数 reserve(0,n-1,A); reserve(n,L-n-1,A); reserve(0,n-1,A); }
4)F(M,N)求解不大于N的和是M的所有组合个数。使用递归求解组合个数。
#include "iostream" using namespace std; int f(int m,int n) { if(m==1) return 1; if(n==1) { return 1; } if(m<n) { return f(m,m); } if (m==n) { return 1+f(m,n-1); } return f(m,n-1)+f(m-n,f(m-n,n)); } int main() { cout<<f(3,3); }
5)打靶算法:靶环有10个环,那么当打中时分数可为1-10,如果未打中得分为0,也就是11种可能,比如现在求6枪50分的概率
#include <iostream> #include <time.h> using namespace std; int sum; int all=0; int n; int store[10]; void Output() { for(int i = 9; i>=0; --i) { cout<<store[i]<<" "; } cout<<endl; ++sum; } void Cumput(int score, int num) { if(score < 0 || score > (num+1)*10 ) //次数为0~9 return; if(num == 0) { store[num] = score; Output(); for(int i = 9; i>=10-num; --i) { all+=store[i]; } if(all==score){ n++; all=0; } return; } for(int i = 0; i <= 10; ++i) { store[num] = i; Cumput(score - i, num - 1); } } int main() { const double begin=(double)clock(); Cumput(50, 6); const double end=(double)clock(); cout<<"总的可能数量:"<<sum<<" ."<<"得分可能数量:"<<n<<endl; cout<<"用时:"<<end-begin<<endl; cout<<"概率"<<double(n)/sum; return 0; } ...................... ...................... 0 0 0 10 10 10 10 8 2 0 0 0 0 10 10 10 10 9 0 1 0 0 0 10 10 10 10 9 1 0 0 0 0 10 10 10 10 10 0 0 总的可能数量:195195 .得分可能数量:3003 用时:339931 概率0.0153846如果不用递归的思想,使用循环的方式的话,要打几枪需要写几层循环,虽然思路简单,如果是打是几十或上百那要写死了。
相关文章推荐