五、语言相关问题

告诉我你的首选语言的三个最坏的缺陷

  • Python语言
    • 动态
    • 弱类型
    • 运行速度限制

什么是栈?什么是堆?

  • 栈(Stack)在中文中又被称为堆栈,但其实堆和栈是两个数据结构,中文语境下要注意区分,同时也要注意在讨论***数据结构***和***计算机内存***时的堆与栈有一定的区别,堆的区别比较明显

  • 栈为标准的LIFO后进先出,经典操作即push和pop

  • 堆(Heap)通常是一个可以被看做一棵树数组对象,堆总是一棵完全树(其节点序号能与相应的最大满二叉树完全对应)。通常说的堆是指二叉堆,属于二叉树的一种。所有节点都比后续节点大/小的堆叫最大/小堆

    • 结构(完全树二叉树示例,节点序号为数组下标)
    graph TB
    0 --> 1
    0 --> 2
    1 --> 3
    1 --> 4
    2 --> 5
    2 --> 6
    3 --> 7
    
    • 堆操作
    操作 说明
    build 创建一个空堆
    insert 向堆中插入一个新的元素
    update 将新元素提升使其匹配堆的性质
    delete 删除堆顶元素
    get 获取堆顶元素
    heapify 删除堆顶元素后使之再次符合堆的数据结构关系
  • 堆与栈都是可以被认为是一种特殊结构的数组,即是说可以通过数组配合相应的限制可以实现这两数据结构(当然还有链表的部分性质)

  • 对一般的运行程序来说,通常都是用来存储对象的,而通常用于运行程序

    • 栈本身后进先出的数据结构与函数调用,嵌套运行的结构相符,因此用于运行程序,而通常局部的、临时的变量分配也都在栈上
    • 注意堆在计算机内存中的结构与数据结构的堆有很大区别。以C++为例,堆空间通常是不连续的,结构更接近链表而不是数组,受物理内存限制,效率要比栈得多
    • 基于两者特性,再综合一下程序运行所需内容:编译好的二进制代码、对象、(静态)变量、常量等,就不难理解Java(程序计数器,方法区,虚拟机栈,本地方法栈,Java堆)或C++(堆区,栈区,全局静态区,常量区,程序代码区)中的内存划分依据了
  • 协议栈(Protocol Stack)的“栈”的概念与上述的基本没有太大关系,不做详细介绍


七、代码版本管理相关问题

能描述下什么是GithubFlow和GitFlow工作流吗?

  • 这两种都是基于分支,为协同开发而创造的工作流。除了主干分支,其他分支主要用于功能开发、修复bug等等,基本上新分支完成其任务后会合并到主干分支,主干分支的核心目的是发布与部署

  • GitFlow的特性适用于版本发布,一般来说有master和develop两个主要分支,辅助分支包括hotfix、feature、release等等,develop分支是主要开发分支,开发完成后合并到此分支,发布成功后合并到master分支

  • GithubFlow的特征则适用于“敏捷开发”等,即随时修改完代码随时发布的流程模式,没有develop分支,但是若考虑到代码合并进master分支与线上发布未必在同一时间(例如对master主干代码的大规模回归测试,到指定日期才发布等)

  • 各处常见的资料介绍经常将Pull Request放到GithubFlow中介绍,但实际上Pull Request可以跟包括这两者在内的其他各种诸如ForKing工作流一起协作

  • PS:there is no difference in the GitHub flow between a hotfix and a very small feature.

  • 这两种工作流模式都是针对单一仓库的,而ForKing工作流在于其分布式工作的特性,即每个开发者在自己的仓库、自己的分支上完成相应开发,其明显的优势是项目维护者可以接受任何开发者的提交,但无需给他正式代码库的写权限


九、逻辑和算法相关问题?

写一段有栈溢出的代码

  • 内存溢出(参考java):栈溢出(StackOverFlow)、堆溢出(OutOfMemoryError)。结合堆与栈通常在程序中的用法,堆用于分配对象,那么只要永不停息的分配新对象不回收自然会堆溢出;而栈如果作为函数调用栈则深度有限,那么只要不断深入调用(最经典操作:无限递归),自然会栈溢出

  • 栈溢出:

public void sofMethod(){
    depth ++ ;
    sofMethod();
}
  • 堆溢出:
public void sofMethod(){
    List<byte[]> list = new ArrayList<>();
    int i=0;
    while(true){
        list.add(new byte[5*1024*1024]);
        System.out.println("分配次数:"+(++i));
    }
}

写一段有内存泄漏(Memory Leak)的示例代码

  • 注意区分内存溢出和内存泄漏,关键在于溢出(Overflow)泄漏(Leak) 两个概念要区别开来,同样概念适用于栈/堆溢出等
#include <stdio.h>
int main() {
    char *c;
    c=(char*)malloc(256*sizeof(char));
    //这里分配的内存没有回收,且后续无法控制,虽然程序不会崩溃,但符合定义
    c=(char*)malloc(256*sizeof(char));
    return 0;
}

Written with StackEdit.