1.堆栈
2.SQL 数据库是面向对象还是面向过程的
3.为什么选软件测试,优势
前端:
1.语义化的理解
2.闭包的理解
(1) for(var i=0;i<=3;i++){
setTimeout(function(){
alert(i);
},0);
} //4
(2) var a = 6;
setTimeout(function(){
alert(a);
a = 666;
},1000);
a = 66; //结果 弹出66;(setTimeout(function(){alert(a);a=666;},1000)是1000毫秒后,把function(){alert(a);a=666;}加入到队列,等前面没有其他进程运行的时候再执行;由于setTimeout是异步的,所不会阻塞下面的语句执行;然后执行a=66,等到1000毫秒后且没有其他进程运行的时候执行函数体,所以弹出66(?))
3.JS继承
call()和apply()的区别
4.div嵌套居中
5.http状态码:
100-199 用于指定客户端应相应的某些动作。
200-299 用于表示请求成功。
300-399 用于已经移动的文件并且常被包含在定位头信息中指定新的地址信息。
400-499 用于指出客户端的错误。400 1、语义有误,当前请求无法被服务器理解。401 当前请求需要用户验证 403 服务器已经理解请求,但是拒绝执行它。
500-599 用于支持服务器错误。 503 – 服务不可用
6.二分法查找数组某一个元素下标:
function binarySearch(arr, val){
var low = 0, high = arr.length-1,mid=0;
while(low<=high){
mid = Math.floor( (low + high) / 2);
if(arr[mid] == val){
return mid;
}
else if(arr[mid] > val){
high = mid - 1;
}
else{
low = mid + 1;
}
}
return -1;
}
alert(binarySearch([1,2,5,7,8,9,11],9));
7. P id class style 优先级
8.双向链表排序
笔试:
C/C++
概念:
struct 和 class
线程 进程 同步方式 :临界区 信号量 事件 互斥量
char * const p; p为指向字符变量的指针,地址不变,地址内容可变const char *p;p为指向字符变量的指针,地址可变,地址内容不变
char const *p; 与 const char *p; 等价,只是个人的书写习惯
TCP/IP 五层模型 TCP/IP层次模型共分为五层:应用层HTTP、传输层TCP、网络层IP、数据链路层Data-link、物理层physical。
死锁产生条件:产生死锁的原因主要是:
(1) 因为系统资源不足。
(2) 进程运行推进的顺序不合适。
(3) 资源分配不当等。
如果系统资源充足,进程的资源请求都能够得到满足,死锁出现的可能性就很低,否则
就会因争夺有限的资源而陷入死锁。其次,进程运行推进顺序与速度不同,也可能产生死锁。
产生死锁的四个必要条件:
(1) 互斥条件:一个资源每次只能被一个进程使用。
(2) 请求与保持条件:一个进程因请求资源而阻塞时,对已获得的资源保持不放。
(3) 不剥夺条件:进程已获得的资源,在末使用完之前,不能强行剥夺。
(4) 循环等待条件:若干进程之间形成一种头尾相接的循环等待资源关系。
这四个条件是死锁的必要条件,只要系统发生死锁,这些条件必然成立,而只要上述条件之
一不满足,就不会发生死锁。
1.二叉排序树
2.二维数组
3.排序
4.冒泡排序
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
|
#include
#define SIZE 8
void
bubble_sort(
int
a[],
int
n);
void
bubble_sort(
int
a[],
int
n)
{
int
i, j, temp;
for
(j = 0; j < n - 1; j++)
for
(i = 0; i < n - 1 - j; i++)
{
if
(a[i] > a[i + 1])
{
temp = a[i];
a[i] = a[i + 1];
a[i + 1] = temp;
}
}
}
int
main()
{
int
number[SIZE] = {95, 45, 15, 78, 84, 51, 24, 12};
int
i;
bubble_sort(number, SIZE);
for
(i = 0; i < SIZE; i++)
{
printf
(
"%d"
, number[i]);
}
printf
(
"\n"
);
}
|
5.查找
(1)折半查找
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
|
intBinSearch(SeqList*R,intn,KeyTypeK)
{
//在有序表R[0..n-1]中进行二分查找,成功时返回结点的位置,失败时返回-1
intlow=0,high=n-1,mid;
//置当前查找区间上、下界的初值
while
(low<=high)
{
if
(R[low].key==K)
returnlow;
if
(R[high].key==k)
returnhigh;
//当前查找区间R[low..high]非空
mid=low+((high-low)/2);
//使用(low+high)/2会有整数溢出的问题
//(问题会出现在当low+high的结果大于表达式结果类型所能表示的最大值时,
//这样,产生溢出后再/2是不会产生正确结果的,而low+((high-low)/2)不存在这个问题
if
(R[mid].key==K)
returnmid;
//查找成功返回
if
(R[mid].key low=mid+1;
//继续在R[mid+1..high]中查找
else
high=mid-1;
//继续在R[low..mid-1]中查找
}
if
(low>high)
return
-1;
//当low>high时表示所查找区间内没有结果,查找失败
}
//BinSeareh
------------上面代码复杂难懂-----------------
intbsearchWithoutRecursion(intarray[],intlow,inthigh,inttarget)
{
while
(low<=high)
{
intmid=(low+high)/2;
if
(array[mid]>target)
high=mid-1;
elseif(array[mid] low=mid+1;
else
//findthetarget
returnmid;
}
//thearraydoesnotcontainthetarget
return
-1;
}
----------------------------------------
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
intbinary_search(constintarr[],intlow,inthigh,intkey)
{
intmid=low+(high-low)/2;
if
(low>high)
return
-1;
else
{
if
(arr[mid]==key)
returnmid;
elseif(arr[mid]>key)
returnbinary_search(arr,low,mid-1,key);
else
returnbinary_search(arr,mid+1,high,key);
}
}
|
6.C语言编写 1到10 的整数相加
#include
using namespace std;
#include
#include
void main()
{
int i=0;
for(int j=1;j<=10;j++)
{
i+=j;
}
cout<<"1+2+...+10="<
system("pause");
}
7.
void main()
{
int a = 1;
int b = a++;
cout<
}
void main()
{
int a = 1;
int c = ++a;
cout<
}
8.1到n求和
(1)void main()
{
int n;
printf("请输入一个整数:\n");
scanf("%d",&n);
printf("运算结果:%d",(n+1)*n/2);
system("pause");
}
(2)
int sum(int n)
{
int result = 0;
if(n == 1)
{
result = 1;
}
else if(n > 1)
{
result = sum(n-1) + n;
}
return result;
}
void main()
{
int n;
printf("请输入一个整数:\n");
scanf("%d",&n);
int result = sum(n);
cout<
}
(3)指针+递归
void Add(int *n,int *ret){if (*n<1){return;}else{*ret+=*n;*n=*n-1;Add(n,ret);}}void main(){int n;int ret=0;printf("请输入一个整数:\n");scanf("%d",&n);Add(&n,&ret);printf("运算结果:%d\n",ret); system("pause");}
9. GDI 绘图的类和函数
10.C/S架构 服务器访问人数不能超过1万人,如果很多用户同时访问一个服务器会导致速度变慢,服务器是 PC SERVER(具体题目记不太清楚了)
(1、修改连接池。
2、进行压力测试。
3、给需要查询最多的数据库字段创建索引。
4、再就是关于硬件、内存、网速的配置了。
5、设置并发数量。
仔细的分析后台代码,找出瓶颈所在,并通过优化算法等改进性能
PC Server是使用普通的PC做服务器小型机就是我们真正的高端配置的服务器性能,兼容性差别很大)
11.求最大子序列和
#include
using namespace std;
int* MaxSum(int arr[],int count){ //start_tmp和max_tmp是临时存储开始位置和 //最大和的变量
int Start,End,Max,result[3],start_tmp,max_tmp;
int i;
Start=End=start_tmp=0;
Max=max_tmp=arr[0];
for(i=1;i
{
if(max_tmp>=0)
max_tmp+=arr[i];
else {
max_tmp=arr[i];
start_tmp=i;
}
if(Max
{
Max=max_tmp;
Start=start_tmp;
End=i;
}
}
result[0]=Max; //“+1”是把数组的0号元素当成第一个来数 //这样比较直观
result[1]=Start+1;
result[2]=End+1;
return result;
}//测试
void main(){
int arr[7]={0,6,-1,1,-6,7,-5};
int *result=MaxSum(arr,7);
cout<
system("pause");}
最大字段和 n个整数(含负数)
int
max_sum(
int
s[],
int
n) {
int
max = 0;
int
sum = 0;
for
(
int
i = 0; i < n; i++) {
if
(sum + s[i] > 0)
sum = sum + s[i];
else
sum = 0;
if
(sum > max)
max = sum;
}
return
max;
}
int
main() {
int
a[12]={27,6,-50,21,-3,14,16,-8,42,33,-21,9};
cout << max_sum(a,12) << endl;
cin.get();
}
13.二叉树
层次遍历
void level(BTNode *p)
{
int front,rear;
BTNode *que[maxsize];
front =rear = 0;
BTNode *q;
if(p!=NULL)
{
rear = (rear + 1) % maxsize;
que[rear]=p;
while(front!=rear)
{
front = (front+1)%maxsize;
q = que[front];
visit(q);
if(q->lchild!=null)
{
rear = (rear + 1)%maxsize;
que[rear]=q->lchild;
}
if(q->rchild!=null)
{
rear=(rear+1)%maxsize;
que[rear] = q->rchild;
}
}
}
}
struct BiNode { char data; struct BiNode *lchild, *rchild; }BiNode; struct BiNode *T; struct BiNode *CreateBiTree(struct BiNode *T) { //创建 char data; scanf("%c", &data); if((data=='#')||(data=='\n')) { T = NULL; } else { T = (struct BiNode *)malloc(sizeof(struct BiNode)); if(T==NULL) { printf("memory error"); } T->data = data; T->lchild = CreateBiTree(T->lchild); T->rchild = CreateBiTree(T->rchild); } return T; } void PreOrderTraverse(struct BiNode *T) { //先序遍历 if(T==NULL) { return; } else { printf("%c ", T->data); PreOrderTraverse(T->lchild); PreOrderTraverse(T->rchild); } } int height(struct BiNode *T) //求高度 { int lh,rh,h=0; if(T==NULL) h=0; else {lh=height(T->lchild); rh=height(T->rchild); h=(lh>rh ? lh:rh)+1;} return h; } int main() { int mul; T = NULL; T = CreateBiTree(T); printf("先序遍历: \n"); PreOrderTraverse(T); printf("\n"); printf("%d",height(T)); getch(); return 0; }
14. #include<>和#include " " 的区别
< >引用的是编译器的类库路径里面的头文件 " "引用的是你程序目录的相对路径中的头文件 假如你编译器定义的自带头文件引用在C:\Keil\c51\INC\下面 则#include15.将数字型字符串转换成整数引用的就是C:\Keil\c51\INC\stdio.h这个头文件 不管你的项目在什么目录里,C:\Keil\c51\INC\stdio.h这个路径就定下来了 一般是引用自带的一些头文件:stdio.h、conio.h、string.h、stdlib.h等等之类的。。 假如你的项目目录是在D:\Projects\tmp\ 则#include "my.h" 引用的就是D:\Projects\tmp\my.h这个头文件 一般是用来引用自己写的一些头文件 如果使用" ",它是会先在你项目的当前目录查找是否有对应头文件 如果没有,它还是会在对应的引用目录里面查找对应的头文件 意思就是,使用#include "stdio.h"如果你项目目录里面,没有stdio.h这个头文件,它还是会定位到C:\Keil\c51\INC\stdio.h这个头文件的
#include
using namespace std;
long fun ( char *p)
{
int i, len, t;
long x=0;
len=strlen(p);
if(p[0]=='-')
{
t=-1; len--; p++;
}
else
t=1;
while(*p)
x=10*x+(*p-48),p++;
return x*t;
}
void main()
{
char s[6];
long n;
printf("Enter a string:\n") ;
gets(s);
n = fun(s);
printf("%ld\n",n);
system("pause");
}
16.数组和链表的区别
*C++语言中可以用数组处理一组数据类型相同的数据,但不允许动态定义数组的大小,即在使用数组之前必须确定数组的大小。而在实际应用中,用户使用数组之前有时无法准确确定数组的大小,只能将数组定义成足够大小,这样数组中有些空间可能不被使用,从而造成内存空间的浪费。链表是一种常见的数据组织形式,它采用动态分配内存的形式实现。需要时可以用new分配内存空间,不需要时用delete将已分配的空间释放,不会造成内存空间的浪费。
(1) 从逻辑结构角度来看
a, 数组必须事先定义固定的长度(元素个数),不能适应数据动态地增减的情况。当数据增加时,可能超出原先定义的元素个数;当数据减少时,造成内存浪费。
b,链表动态地进行存储分配,可以适应数据动态地增减的情况,且可以方便地插入、删除数据项。(数组中插入、删除数据项时,需要移动其它数据项)
(2)从内存存储角度来看
a,(静态)数组从栈中分配空间, 对于程序员方便快速,但自由度小。
b, 链表从堆中分配空间, 自由度大但申请管理比较麻烦.
C++中,浅复制和深复制对于完全的值类型没有区别。 如果类或结构体的实例中含有指向不同属于一个对象的其它对象的指针时,那么浅复制和深复制的行为就有差异。浅复制仅复制对象本身(其中包括是指针的成员),这样不同被复制对象的成员中的对应非空指针会指向同一对象,被成员指针引用的对象成为共享的,无法直接通过指针成员安全地删除(因为若直接删除,另外对象中的指针就会无效,而访问无效指针是危险的;除非这些指针有引用计数或者其它手段确保被指对象的所有权);而深复制在浅复制的基础上,连同指针指向的对象也一起复制,代价比较高,但是相对容易管理。 Java/C#用引用类型代替指针类型,在语言的特定上下文中有特定的操作模式和约定。具体可以见LS两位提供的链接。
深拷贝和浅拷贝
(1)什么时候用到拷贝函数?
如果在类中没有显式地声明一个拷贝构造函数,那么,编译器将会自动生成一个默认的拷贝构造函数,该构造函数完成对象之间的位拷贝。位拷贝又称浅拷贝
(2)是否应该自定义拷贝函数?
(3)什么叫深拷贝?什么是浅拷贝?两者异同?
自定义拷贝构造函数是一种良好的编程风格,它可以阻止编译器形成默认的拷贝构造函数,提高源码效率。
(4)深拷贝好还是浅拷贝好?
如果实行位拷贝,也就是把对象里的值完全复制给另一个对象,如A=B。这时,如果B中有一个成员变量指针已经申请了内存,那A中的那个成员变量也指向同一块内存。这就出现了问题:当B把内存释放了(如:析构),这时A内的指针就是野指针了,出现运行错误。
相同点:都可用于申请动态内存和释放内存
不同点:
(1)操作对象有所不同。
malloc与free是C++/C 语言的标准库函数,new/delete 是C++的运算符。对于非内部数据类的对象而言,光用maloc/free 无法满足动态对象的要求。对象在创建的同时要自动执行构造函数, 对象消亡之前要自动执行析构函数。由于malloc/free 是库函数而不是运算符,不在编译器控制权限之内,不能够把执行构造函数和析构函数的任务强加malloc/free。
(2)用法上也有所不同。
函数malloc 的原型如下:
void * malloc(size_t size);
用malloc 申请一块长度为length 的整数类型的内存,程序如下:
int *p = (int *) malloc(sizeof(int) * length);
我们应当把注意力集中在两个要素上:“类型转换”和“sizeof”。
1、malloc 返回值的类型是void *,所以在调用malloc 时要显式地进行类型转换,将void * 转换成所需要的指针类型。
2、 malloc 函数本身并不识别要申请的内存是什么类型,它只关心内存的总字节数。
函数free 的原型如下:
void free( void * memblock );
为什么free 函数不象malloc 函数那样复杂呢?这是因为指针p 的类型以及它所指的内存的容量事先都是知道的,语句free(p)能正确地释放内存。如果p 是NULL 指针,那么free
对p 无论操作多少次都不会出问题。如果p 不是NULL 指针,那么free 对p连续操作两次就会导致程序运行错误。
#include
using namespace std;
#include
// 将字符串s中的内容拷贝到d中,包括字符串结束符'\0'
char *strcpy(char *d, const char *s)
{
char *p = d;
while (1)
{
*p = *s;
if (*p == '\0') break;
p++;
s++;
}
return p;
}
// 按ascii码比较字符串a和b的内容大小,a > b返回正整数,a < b返回负整数,a == b返回0
int strcmp(const char *a, const char *b)
{
while(*a != '\0' && *a == *b)
{
a++;
b++;
}
return (int)(*a - *b);
}
// 测试这两个自定义函数
int main()
{
char s[20];
char *p = "abc";
char *q = "ab";
strcpy(s, p);
printf("%s\n", s);
printf("%d\n", strcmp(p, q));
system("pause");
return 0;
}
20.单链表创建 插入节点 删除节点 单链表反转
反转单链表。假设单链表的数据结构定义如下:
typedef
struct
LNode
{
int
data;
struct
LNode *next;
}LNode, *LinkedList;
|
并且这个单链表有一个头指针list指向第一个结点,最后一个结点指向NULL,很容易理解。
最容易想到的第一种方法就是重新建立一个单链表newList,每次将list中的第一个结点放到newList后面。注释比较详细,所以就不具体说了,直接看代码吧:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
|
LinkedList ReverseSinglyLinkedList(LinkedList list)
{
LinkedList newList;
//新链表的头结点
LNode *tmp;
//指向list的第一个结点,也就是要摘除的结点
//
//参数为空或者内存分配失败则返回NULL
//
if
(list == NULL || (newList = (LinkedList)
malloc
(
sizeof
(LNode))) == NULL)
{
return
NULL;
}
//
//初始化newList
//
newList->data = list->data;
newList->next = NULL;
//
//依次将list的第一个结点放到newList的第一个结点位置
//
while
(list->next != NULL)
{
tmp = newList->next;
//保存newList中的后续结点
newList->next = list->next;
//将list的第一个结点放到newList中
list->next = list->next->next;
//从list中摘除这个结点
newList->next->next = tmp;
//恢复newList中后续结点的指针
}
//
//原头结点应该释放掉,并返回新头结点的指针
//
free
(list);
return
newList;
}
|
第二种方法是每次都将原第一个结点之后的那个结点放在list后面,下图是原始的单链表。
为了反转这个单链表,我们先让头结点的next域指向结点2,再让结点1的next域指向结点3,最后将结点2的next域指向结点1,就完成了第一次交换,顺序就变成了Header-结点2-结点1-结点3-结点4-NULL,然后进行相同的交换将结点3移动到结点2的前面,然后再将结点4移动到结点3的前面就完成了反转,思路有了,就该写代码了:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
LinkedList ReverseSinglyLinkedList(LinkedList list)
{
LNode *tmp = NULL;
LNode *p = NULL;
if
(list == NULL)
{
return
NULL;
}
tmp = list->next;
while
(tmp->next != NULL)
{
p = tmp->next;
tmp->next = p->next;
p->next = list->next;
list->next = p;
}
return
list;
}
|
C++语言支持函数重载,C 语言不支持函数重载。函数被C++编译后在库中的名字
与C 语言的不同。假设某个函数的原型为: void foo(int x, int y);
该函数被C 编译器编译后在库中的名字为_foo , 而C++ 编译器则会产生像
_foo_int_int 之类的名字。
C++提供了C 连接交换指定符号extern“C”来解决名字匹配问题。
如果C++程序要调用已经被编译后的C函数,该怎么办? 假设某个C函数的声明如下: void foo(int x, int y); 该函数被C编译器编译后在库中的名字为_foo,而C++编译器则会产生像_foo_int_int之类的名字用来支持函数重载和类型安全连接。由于编译后的名字不同,C++程序不能直接调用C函数。C++提供了一个C连接交换指定符号extern“C”来解决这个问题。例如: extern “C” { void foo(int x, int y); … // 其它函数 } 或者写成 extern “C” { #include “myheader.h” … // 其它C头文件 } 这就告诉C++编译译器,函数foo是个C连接,应该到库中找名字_foo而不是找_foo_int_int。C++编译器开发商已经对C标准库的头文件作了extern“C”处理,所以我们可以用#include 直接引用这些头文件。
22.输入两个正整数,求其最大公倍数和公约数
23.设计程序按从大到小依次输出函数f(a+b)=2*a*a+b*b的最小的100个函数值
24.
';
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
|
#include
using
namespace
std;
void
sort(
int
a[],
int
n)
//升序排序
{
int
temp = 0;
for
(
int
i=0;i
for
(
int
j=i+1;j
{
if
(a[i]>a[j])
{
temp = a[i];
a[i] = a[j];
a[j] = temp;
}
}
}
bool
IsShunZi(
int
a[],
int
n)
{
sort(a,n);
//升序排列
int
num = 0;
//大小王的个数(一幅牌中,可以为0,1,2)
for
(
int
i=0;i
if
(a[i]==20)
num++;
//牌出现重复的情况
for
(
int
i=0;i
for
(
int
j=i+1;j
if
(a[i]==a[j])
return
false
;
switch
(num)
{
case
0:
if
(a[4]-a[0]==4)
return
true
;
else
return
false
;
break
;
case
1:
if
(a[3]-a[0]<=4)
return
true
;
else
return
false
;
break
;
case
2:
if
(a[2]-a[0]<=4)
return
true
;
else
return
false
;
break
;
default
:
return
false
;
break
;
}
}
int
main( )
{
int
a[5] = {2,3,20,6,20};
//扑克牌对应的数组
bool
bt = IsShunZi(a,5);
//函数调用
if
(bt)
{
cout<<
"顺子!"
<
}
else
{
cout<<
"不是顺子!"
<
}
system
(
"pause"
);
return
0;
}
|
测试:
1.白盒测试 黑盒测试 概念 区别 黑盒测试的类型
白盒测试方法按照程序内部的结构测试程序,检验程序中的每条通路是否都能按预定要求正确工作,而不顾它的功能。
白盒测试的主要方法有逻辑覆盖、基本路径测试等
逻辑覆盖包括:
1、语句覆盖
2、判断覆盖
3、条件覆盖
4、判断/条件覆盖
5、条件组合覆盖
6、路径覆盖
黑盒测试并不涉及程序的内部结构和内容特性,主要根据规格说明,只依靠被测试程序的输入和输出之间关系或程序的功能来设计测试用例。
黑盒测试主要包括边界值分析法、等价类划分法、因果图法、决策表法等。
前端:
1.({fpp:true}).foo
2.判断A、B、C不相等
3.创建person的一个实例
4.
function A()
{
this.do = function(){return 'foo';}
}
A.prototype = function()
{
this.do = function(){return 'bar';}
}
var x = new A().do();
var printName = function()
{
alert('matt');
printName = function()
{
alert('James');
}
}
var copy = printName;
printName();
copy();
matt matt
5.比较输入的两个Json的内容是否完全相同
6.区分单双字节来截取字符
function substr(str, len)
{
if( ! str || ! len)
{
return '';
}
// 预期计数:中文2字节,英文1字节
var a = 0;
// 循环计数
var i = 0;
// 临时字串
var temp = '';
for (i = 0; i < str.length; i ++ )
{
if (str.charCodeAt(i) > 255)
{
// 按照预期计数增加2
a += 2;
}
else
{
a ++ ;
}
// 如果增加计数后长度大于限定长度,就直接返回临时字符串
if(a > len)
{
return temp;
}
// 将当前内容加到临时字符串
temp += str.charAt(i);
}
// 如果全部是单字节字符,就直接返回源字符串
return str;
}
var str = "你a好Tom";
var len = 3;
document.write("" + substr(str, len) + "
");