美文网首页
2018-08-23网易测试开发工程师题目练习补充

2018-08-23网易测试开发工程师题目练习补充

作者: 流注 | 来源:发表于2018-08-23 14:22 被阅读0次

    1、B/S与C/S的区别

        B/S:即Browser/Server(浏览器/服务器)结构,就是只安装维护一个服务器(Server),而客户端采用浏览器(Browse)运行软件。

        主要特点是交互性强、具有安全的存取模式、网络通信量低、响应速度快、利于处理大量数据。但是该结构的程序是针对性开发,变更不够灵活,维护和管理的难度较大。通常只局限于小型局域网,不利于扩展。并且,由于该结构的每台客户机都需要安装相应的客户端程序,分布功能弱且兼容性差,不能实现快速部署安装和配置,因此缺少通用性,具有较大的局限性。

        C/S:CS即Client/Server(客户机/服务器)结构。

        主要特点是分布性强、维护方便、开发简单且共享性强、总体拥有成本低。但数据安全性问题、对服务器要求过高、数据传输速度慢、软件的个性化特点明显降低。

    2、Linux软链接与硬链接的区别

        硬链接(hard-link):若A是B的硬链接,则A与B指向的是相同的inode节点。这里的“硬”我理解为物理上的,指向同一块存储地址。两个文件名指向同一个文件,A和B对文件系统来说是完全平等的。如果删除了其中一个,对另外一个没有影响。每增加一个文件名,inode节点上的链接数增加一,每删除一个对应的文件名,inode节点上的链接数减一,直到为0,inode节点和对应的数据块被回收。注:文件和文件名是不同的东西,rm A删除的只是A这个文件名,而A对应的数据块(文件)只有在inode节点链接数减少为0的时候才会被系统回收。

        由于硬链接是有着相同 inode 号仅文件名不同的文件,因此硬链接存在以下几点特性:

            1、文件有相同的 inode 及 data block;

            2、只能对已存在的文件进行创建;

            3、不能交叉文件系统进行硬链接的创建;

            4、不能对目录进行创建,只可对文件创建;

            5、删除一个硬链接文件并不影响其他有相同 inode 号的文件。

        软链接(soft-link):又称符号链接,若A是B的软连接,则A的数据区存放的就是B的文件路径。这里的“软”我理解为逻辑上的。

        软链接有着自己的 inode 号以及用户数据块。因此软链接的创建与使用没有类似硬链接的诸多限制:

            1、软链接有自己的文件属性及权限等;

            2、可对不存在的文件或目录创建软链接;

            3、软链接可交叉文件系统;

            4、软链接可对文件或目录创建;

            5、创建软链接时,链接计数 i_nlink 不会增加;

            6、删除软链接并不影响被指向的文件,但若被指向的原文件被删除,则相关软连接被称为死链接(即 dangling link,若被指向路径文件被重新创建,死链接可恢复为正常的软链接)。

        相关命令:

    硬:ln 源文件 链接名

    软:ln -s 源文件 链接名

    3、Linux进程内存空间各段分布(stack ,heap,bss segment,code segment/text segment,data segment)

    以4G内存为例

    代码段:代码段是用来存放可执行文件的操作指令,也就是说是它是可执行程序在内存种的镜像。代码段需要防止在运行时被非法修改,所以只准许读取操作,而不允许写入(修改)操作——它是不可写的。

    数据段:数据段用来存放可执行文件中已初始化全局变量,换句话说就是存放程序静态分配的变量和全局变量。

    BSS段:BSS段包含了程序中未初始化全局变量,在内存中bss段全部置零。

    堆(heap):堆是用于存放进程运行中被动态分配的内存段,它大小并不固定,可动态扩张或缩减。当进程调用malloc/new等函数分配内存时,新分配的内存就被动态添加到堆上(堆被扩张);当利用free等函数释放内存时,被释放的内存从堆中被剔除(堆被缩减)

    栈(stack):栈是用户存放程序临时创建的局部变量,也就是说我们函数括弧“{}”中定义的变量(但不包括static声明的变量,static意味这在数据段中存放变量)。除此以外在函数被调用时,其参数也会被压入发起调用的进程栈中,并且待到调用结束后,函数的返回值也回被存放回栈中。由于栈的先进先出特点,所以栈特别方便用来保存/恢复调用现场。从这个意义上将我们可以把堆栈看成一个临时数据寄存、交换的内存区。

    4、快速排序

        核心思想是找到一个基准值,使得其左边的值都小于它,右边的都大于它(实质是每次排序都让一个值处于正确的位置)。这样划分一次后产生两个区间,再分别对这两个区间做同样的事。

        假设对序列7,15,8,54,2,6,9进行快速排序,以第一个数7作为基准数,分别设两个指针left、right,left指向基准数后面一个数,right指向最后一个数。

    1、从右边开始,找到第一个比基准数小的数(这里为6),用right标记位置

    2、从左边开始,找到第一个比基准数大的数(这里为15),用left标记位置,注意,right不能越过left的位置,若相交,跳到第4步

    3、交换left与right对应的值,right-1,left+1

    4、重复上面的步骤,直到left=right,将基准数与right标记的数交换位置,第一轮交换结束

    接下来对小于基准数的部分和大于基准数的部分都做这个操作。

    Java代码(引自最通俗易懂的快速排序算法详解 - yugenhai - 博客园

    public static int Partition(int[] a, int p, int r) {

            int x = a[r - 1];

            int i = p - 1;

            int temp;

            for (int j = p; j <= r - 1; j++) {

                if (a[j - 1] <= x) {

                    // 交换(a[j-1],a[i-1]);

                    i++;

                    temp = a[j - 1];

                    a[j - 1] = a[i - 1];

                    a[i - 1] = temp;

                }

            }

            // 交换(a[r-1,a[i+1-1]);

            temp = a[r - 1];

            a[r - 1] = a[i + 1 - 1];

            a[i + 1 - 1] = temp;

            return i + 1;

        }

        public static void QuickSort(int[] a,int p,int r){

            if(p < r) {

                int q = Partition(a, p, r);

                QuickSort(a, p, q-1);

                QuickSort(a, q + 1, r);

            }

        }

        // main方法中将数组传入排序方法中处理,之后打印新的数组

        public static void main(String[] stra) {

            int[] a = { 7, 10, 3, 5, 4, 6, 2, 8, 1, 9 };

            QuickSort(a, 1, 10);

            for (int i = 0; i < a.length; i++)

                System.out.print(a[i]+" ");

        }

    5、二叉树的遍历

        前序遍历:根结点 ---> 左子树 ---> 右子树

        中序遍历:左子树--->根结点 ---> 右子树

        后序遍历:左子树 ---> 右子树 ---> 根结点

        已知3种遍历序列中任意两个,即可还原出二叉树。

    引自已知二叉树的前序遍历和中序遍历,如何得到它的后序遍历? - 经欢非常道 - 博客园

    利用以下几个特性:

    特性A,对于前序遍历,第一个肯定是根节点;

    特性B,对于后序遍历,最后一个肯定是根节点;

    特性C,利用前序或后序遍历,确定根节点,在中序遍历中,根节点的两边就可以分出左子树和右子树;

    特性D,对左子树和右子树分别做前面3点的分析和拆分,相当于做递归,我们就可以重建出完整的二叉树;

    我们以一个例子做一下这个过程,假设:

    前序遍历的顺序是: CABGHEDF

    中序遍历的顺序是: GHBACDEF

    第一步,我们根据特性A,可以得知根节点是C,然后,根据特性C,我们知道左子树是:GHBA,右子树是:DEF。

    第二步,取出左子树,左子树的前序遍历是:ABGH,中序遍历是:GHBA,根据特性A和C,得出左子树的父节点是A,并且A没有右子树。

    第三步,使用同样的方法,前序是BGH,中序是GHB,得出父节点是B,B的左子树是GH,且B没有右子树。

    第四步,GH的前序是GH,中序是GH,得出父节点是G,G没有左子树,右子树为H。

    第五步,回到右子树,它的前序是EDF,中序是DEF,依然根据特性A和C,得出父节点是E,左右节点是D和F。

    到此,我们得到了这棵完整的二叉树。因此,它的后序遍历就是:HGBADFEC。

    6、Java关键字synchronized

        synchronized关键字最主要有以下3种应用方式,下面分别介绍

    修饰实例方法,作用于当前实例加锁,进入同步代码前要获得 当前实例 的锁

        所谓的实例对象锁就是用synchronized修饰实例对象中的实例方法,注意是实例方法不包括静态方法

    修饰静态方法,作用于当前类对象加锁,进入同步代码前要获得 当前类对象 的锁

        当synchronized作用于静态方法时,其锁就是当前类的class对象锁。由于静态成员不专属于任何一个实例对象,是类成员,因此通过class对象锁可以控制静态成员的并发操作。需要注意的是如果一个线程A调用一个实例对象的非static synchronized 方法,而线程B需要调用这个实例对象所属类的静态 synchronized方法,是允许的,不会发生互斥现象,因为访问静态 synchronized 方法占用的锁是当前类的 class 对象,而访问非静态 synchronized 方法占用的锁是当前实例对象锁。

    修饰代码块,指定加锁对象,对给定对象加锁,进入同步代码库前要获得 给定对象 的锁

        除了使用关键字修饰实例方法和静态方法外,还可以使用同步代码块,在某些情况下,我们编写的方法体可能比较大,同时存在一些比较耗时的操作,而需要同步的代码又只有一小部分,如果直接对整个方法进行同步操作,可能会得不偿失,此时我们可以使用同步代码块的方式对需要同步的代码进行包裹,这样就无需对整个方法进行同步操作了。

    相关文章

      网友评论

          本文标题:2018-08-23网易测试开发工程师题目练习补充

          本文链接:https://www.haomeiwen.com/subject/smrpiftx.html