文章目录

  • 笔试题
  • 知识点: 堆和栈的区别
  • 知识点: 进程(Process)和线程(Thread)的区别
  • 知识点: 二叉树的性质
  • 知识点: 指针
  • 知识点: 黑盒测试——等价类划分
  • 知识点: 进程通信
  • 知识点:十大经典排序操作
  • 知识点:HTTP协议
  • 编程题:给出一串阿拉伯数字,输出对应的中文读法


笔试题


  1. 对于堆和栈的描述,正确的是()
    A.栈的大小会随着函数调用层次的变化而变化
    B.从堆上申请内存,没有释放的话,会造成内存泄漏;栈的内存由编译器管理,不会内存泄漏
    C.在windows上,堆的生长方向是向下的,随着内存地址减小的方向增长;栈的生长方向是向上的,即向着内存地址增加的方向增长
    D.在C语言中,指针只能指向堆上的内存,不能指向栈上的内存
知识点: 堆和栈的区别
  • 堆和栈都是临时存储数据的地方
    堆:利用完全二叉树的结构来维护一组数据,然后进行相关操作,一般的操作进行一次的时间复杂度在O(1)~O(logn)之间。
    栈:先进后出的数据结构
  • 栈一般默认大小,地址空间连续;
  • 栈由编译器需要的时候分配内存,不需要的时候自动清除,由系统管理。而堆是由程序员来释放的,容易产生内存泄漏;
  • 堆向高地址增长,栈向低地址增长;
  1. 对于线程和进程的描述,正确的是()
    A.进程退出前,需要手动销毁所有线程,否则进程退出后,依然会有线程在运行,可能导致不可预测的后果
    B.在单核的CPU上使用多线程,并不会比单线程有优势
    C.进程是调度和拥有资源的基本单位
    D.使用全局变量、内存时,需要使用同步机制,因为它们在同一地址空间内
知识点: 进程(Process)和线程(Thread)的区别
  • 进程的销毁方式:自行退出、手动结束;
    线程的结束不一定需要手动销毁,有以下几种方式:
    run所有代码逻辑执行完成,线程结束
    线程在执行过程中抛出了一个异常或者error,线程结束
    调用了该线程的stop、resume、suspend或者Runtime.runFinalizersOnExit这几个暴力方法,线程结束
    使用interrupt方法终端线程
  • 通常一个任务不光CPU要花时间,I/O也要花时间,一个进程等I/O时,CPU是闲置的,另一个进程可以利用CPU进行计算。单核多线程指的是单核CPU轮流执行多个线程,通过给每个线程分配CPU时间片来实现,因为时间片非常短用户感觉是多个线程同时执行。
  • 进程是资源分配的基本单位(划分地盘);线程是处理器调度的基本单位(调用CPU等)。
  1. 某二叉树有2000个节点,则二叉树的最小高度为:
    A.9 B.10 C.11 D.12
    解:最小高度,则这个二叉树是一个满二叉树的时候高度最小。所以高度K = log2(n)+1 = log2(2000) +1 ≈ 11。 (其中log2(2000)要向下取整)
知识点: 二叉树的性质
  • 二叉树中,第 i 层最多有
  • android leanback 阿拉伯语 焦点无法左右切换_Test

  • 个结点;
  • 深度为K的二叉树,最多有
  • android leanback 阿拉伯语 焦点无法左右切换_二叉树_02

  • 个结点;
  • 二叉树中,终端结点数(叶子节点数)为n0,度为2的节点数为n2,则n0 = n2+1
  • 满二叉树、完全二叉树等的性质
  1. 在C++中,定义“int *p=new int(10)”,释放p指向的内存,语句是()
    A.delete *p B.delete &p C.delete p D.delete []p
知识点: 指针
  • int *p=new int[10]指的是定义一个指针p并给其分配10个int大小的空间,首地址为*p;
  • int *p=new int(10)分配一个int型变量所占大小的空间,并赋值10;
  • 一般用法是new一个数组的话用delete [],其他直接用delete即可。
  1. 某函数有且只有2个输入参数,参数A的取值可划分为5个等价类,参数B的取值可划分为3个等价类。至少应为函数设计()组测试数据
    A.4 B.10 C.15 D.30
知识点: 黑盒测试——等价类划分
  • 黑盒测试:通过各种输入观察软件的各种输出结果来发现软件的缺陷,而不关心具体时间如何实现的。
  • 常用的黑盒测试方法:
  1. 下列哪些linux的跨进程通信方式不适合数据传输()
    A.pipe,管道 B.shared memory,共享内存 C.socket,套接字 D.semaphore,信号量
知识点: 进程通信
  • 进程通信的概念:进程用户空间是相互独立的,一般而言是不能相互访问的。但很多情况下进程间需要互相通信,来完成系统的某项功能。进程通过与内核及其它进程之间的互相通信来协调它们的行为。
  • 进程通信的应用场景:
    数据传输:一个进程需要将它的数据发送给另一个进程,发送的数据量在一个字节到几兆字节之间。
    共享数据:多个进程想要操作共享数据,一个进程对共享数据的修改,别的进程应该立刻看到。
    通知事件:一个进程需要向另一个或一组进程发送消息,通知它(它们)发生了某种事件(如进程终止时要通知父进程)。
    资源共享:多个进程之间共享同样的资源。为了作到这一点,需要内核提供锁和同步机制。
    进程控制:有些进程希望完全控制另一个进程的执行(如Debug进程),此时控制进程希望能够拦截另一个进程的所有陷入和异常,并能够及时知道它的状态改变。
  • Linux进程通信有6种方式:管道、信号量、信号、消息队列、共享内存和套接字。
  • android leanback 阿拉伯语 焦点无法左右切换_二叉树_03


  • 管道
    无名管道是一种半双工的通信方式,数据只能单向流动,而且只能在具有亲缘关系的进程间使用;
    有名管道也是一种半双工的通信方式,但是它允许无亲缘关系进程间的通信。
  • 共享内存
    共享内存使多个进程访问同一块内存空间。
  • 套接字
    套接字用于不同机器之间的进程间通信。
    套接字的特性由3个属性确定,它们分别是:域、类型和协议。
  • 信号量
    信号量作为进程间同进程不同线程间的同步手段。
  • 信号
    信号是一种比较复杂的通信方式,用于通知接收进程某个事件已经发生。可用于进程间通信和进程本身通信
  • 消息队列
    消息队列是消息的链表,允许一个或多个进程向它写入与读取消息。
  1. 使用以下哪种技术无法伪装自己的IP地址()
    A.HTTP Proxy B.Socks Prox C.VPN D.修改DNS
    修改DNS可以提高上网的速度,可以访问某些因为域名解析存在问题而不能访问的网站,可以屏蔽运营商的广告避免被钓鱼的危险,但并不能伪装IP地址。
  2. 有一项考试的成绩,目前是按照完成时间进行升序排列的,需要按照考试成绩进行排序,成绩高的排在前面,如果成绩相同,则完成时间短的排在前面。以上场景适合采用下列哪些排序算法?
    A.插入排序 B.快速排序 C.堆排序 D.冒泡排序
    【解析】本题实际考察哪种排序算法是稳定的,插入、冒泡是稳定的,快速和堆是不稳定的。
知识点:十大经典排序操作
  1. 下列关于HTTP协议,描述正确的是
    A.HTTP协议工作在应用层
    B.HTTP只能使用80端口,HTTPS只能使用443端口
    C.HTTP是有状态协议
    D.HTTP协议支持一定时间内的TCP连接保持,这个连接可以用于发送/接收多次请求
知识点:HTTP协议
  • HTTP常用端口80/8080/3128/8081/9098,HTTPS默认端口TCP/443,UDP/443;
  • HTTP是无状态协议。由于Web服务器不保存发送请求的Web浏览器进程的任何信息,因此HTTP协议属于无状态协议,可以通过Cookie和Session将状态分别保存在客户端和服务器端;
  • HTTP是建立在TCP协议之上的,建立和释放连接的时间都很短,所以HTTP是一种短连接,为了解决每次连接释放效率低的问题,提出keep-alive保持连接特性,可以在一段时间内多次发送、接收。
编程题:给出一串阿拉伯数字,输出对应的中文读法

输入描述:
输入数字字符串
输出描述:
数字字符串所对应的中文读法,只考虑最高5位数的情况。
样例:
输入:18
输出:十八

  • 分析:
    对于零的读法问题:
  1. 12345:正常读;
  2. 01234:最前边的0省略;
  3. 10234:中间的0读出来,且省略位的读法;
  4. 12003:连续零时只读一个0;

注意:18读作十八,而不是一十八,因此对10-19的读法做特殊处理。

思路30min,解决2hour。。。

  • 代码:
#include<iostream>
#include<string>
using namespace std;

void NumToRead(string str)
{
	if(str == "")
		return;
	int len = str.size();
	string str1[] = {"", "十", "百", "千", "万"};
	string str2[10] = {"零", "一", "二", "三", "四", "五", "六", "七", "八", "九"};

	int i=0, j=len-1;
	int *num;
	num = (int*)malloc(sizeof(int)*len);
	for(i,j;i<len;i++,j--)
	{
		num[j] = str[i] - '0';
	}

	if(len==2 && num[1]==1)
	{
		cout<<"十";
		cout<<str2[num[0]];
		return;
	}

	int x = len-1;
	while(x>0)
	{
		if(num[x] == 0)
		{
			x--;
			if(x == 0)
				cout<<"零";
		}
		else
			break;
		
	}
	
	int count0=0;


	while(x>=0)
	{
		if(num[x] != 0)
		{
			cout<<str2[num[x]];
			if(x != 0)//当str1[0]=""时,这步其实可以忽略判断
				cout<<str1[x];
			x--;
		}
		if(num[x] == 0 && x>=0)
		{
			count0++;
			x--;
		}
		if(x<0)//x-count0 == 0改成x<0
			break;
		else if(num[x]==0)//
			continue;
		else if(count0>0)
		{
			cout<<str2[0];
			count0=0;
		}
		
		if(x>0)
		{
			cout<<str2[num[x]];
			if(x != 0)
				cout<<str1[x];
			x--;
		}

	}
	free(num);
}

int main()
{
	//测试用例
	cout<<"Test 1:"<<endl;
	string s = "12345";
	NumToRead(s);
	cout<<"\nTest 1 pass"<<endl;
	cout<<"\n";

	cout<<"Test 2:"<<endl;
	string s1 = "01234";
	NumToRead(s1);
	cout<<"\nTest 2 pass"<<endl;
	cout<<"\n";

	cout<<"Test 3:"<<endl;
	string s2 = "12340";
	NumToRead(s2);
	cout<<"\nTest 3 pass"<<endl;
	cout<<"\n";

	cout<<"Test 4:"<<endl;
	string s3 = "10234";
	NumToRead(s3);
	cout<<"\nTest 4 pass"<<endl;
	cout<<"\n";

	cout<<"Test 5:"<<endl;
	string s4 = "12003";
	NumToRead(s4);
	cout<<"\nTest 5 pass"<<endl;
	cout<<"\n";

	
	return 0;
}