【嵌入式学习——知识点总结】面试题汇总(2)

11.堆和栈的区别
(1)管理方式不同。栈由操作系统自动分配释放,无需我们手动控制;堆的申请和释放工作由程序员控制,容易产生内存泄漏;

(2)空间大小不同。每个进程拥有的栈的大小要远远小于堆的大小。理论上,程序员可申请的堆大小为虚拟内存的大小,进程栈的大小 64bits 的 Windows 默认 1MB,64bits 的 Linux 默认 10MB;

(3)生长方向不同。堆的生长方向向上,内存地址由低到高;栈的生长方向向下,内存地址由高到低。

(4)分配方式不同。堆都是动态分配的,没有静态分配的堆。栈有2种分配方式:静态分配和动态分配。静态分配是由操作系统完成的,比如局部变量的分配。动态分配由alloca函数进行分配,但是栈的动态分配和堆是不同的,他的动态分配是由操作系统进行释放,无需我们手工实现。

(5)分配效率不同。栈由操作系统自动分配,会在硬件层级对栈提供支持:分配专门的寄存器存放栈的地址,压栈出栈都有专门的指令执行,这就决定了栈的效率比较高。堆则是由C/C++提供的库函数或运算符来完成申请与管理,实现机制较为复杂,频繁的内存申请容易产生内存碎片。显然,堆的效率比栈要低得多

6)存放内容不同。栈存放的内容,是函数返回地址、相关参数、局部变量和寄存器内容等。当主函数调用另外一个函数的时候,要对当前函数执行断点进行保存,需要使用栈来实现,首先入栈的是主函数下一条语句的地址,即扩展指针寄存器的内容(EIP),然后是当前栈帧的底部地址,即扩展基址指针寄存器内容(EBP),再然后是被调函数的实参等,一般情况下是按照从右向左的顺序入栈,之后是被调函数的局部变量,注意静态变量是存放在数据段或者BSS段,是不入栈的。出栈的顺序正好相反,最终栈顶指向主函数下一条语句的地址,主程序又从该地址开始执行。堆,一般情况堆顶使用一个字节的空间来存放堆的大小,而堆中具体存放内容是由程序员来填充的。

12.链表和数组的区别
数组是最基本的数据结构,所开辟的内存空间是连续的,且内存大小一经确定之后便无法再更改;
优点:查找速度快,因为开辟的内存空间是连续的,
缺点:浪费内存,缺乏弹性(不能根据当前实际需求更改大小);增添和删除的效率低。因为数组的大小在一开始就确定,无法更改,在后续想要添加或者删除数据,不能直接往里面添加或者删除索引,取而代之的方法是:先复制原有的数组,根据添加或者删除的数据再增加或减小数组长度,再往新的数组中添加或删除数据。

链表,存储数据的内存不需要连续的,链表中的数据可以存储在内存的任何地方,这是因为链表中的每个数据都存储了下一个链表的地址,从而使离散的内存空间联系在一起,能合理的利用内存。每个链表包含多个节点,每个节点又包含数据域和引用域。
缺点:查找元素麻烦,如果要查找链表中的一个元素,需要从第一个元素开始,依次往下,直到找到需要的元素位置。
优点:添加和删除元素十分方便。只需要知道修改前一个元素指向的地址即可。

13.栈和队列的异同
1.栈和队列的相同点
(1)都是线性结构。
(2)插入操作都是限定在表尾进行。(栈的栈顶,队列的队尾)
(3)都可以通过顺序存储结构和链式存储结构实现。
(4)插入和删除的时间复杂度都是O(1),在空间复杂度上两者也一样。
(5)多链栈和多链队列的管理模式可以相同。
2.栈和队列的不同点
(1)删除元素的位置不同,栈的操作在表尾进行,队列的删除操作在表头进行。
(2)应用场景:常见的栈的应用场景有括号问题的求解,表达式的转换和求值,函数调用和递归实现,深度优先搜索遍历等;常见的队列的应用场景包括计算机系统中各种资源的管理,消息缓冲器的管理和广度优先遍历、还可用于实现打印机打印的冲突以及多个客户访问服务器的文件时,满足先来先服务的原则等。
(3)顺序栈能够实现多栈空间共享,而顺序队列不能。

14.树的表示方法

  • 树状表示法
  • 文氏图标表示法
  • 凹入表示法
  • 括号表示法

15.DFS(深度优先遍历)和BFS(广度优先遍历)的区别

  • 深度优先遍历:从图中一个未访问的顶点 V 开始,沿着一条路一直走到底,然后从这条路尽头的节点回退到上一个节点,再从另一条路开始走到底…,不断递归重复此过程,直到所有的顶点都遍历完成,它的特点是不撞南墙不回头,先走完一条路,再换一条路继续走。
  • 从图的一个未遍历的节点出发,先遍历这个节点的相邻节点,再依次遍历每个相邻节点的相邻节点。

16.怎么判断一个链表中是否有环的存在
快慢指针:首先创建两个指针1和2,同时指向这个链表的头节点。然后开始一个大循环,在循环体中,让指针1每次向下移动一个节点,让指针2每次向下移动两个节点,然后比较两个指针指向的节点是否相同。如果相同,则判断出链表有环,如果不同,则继续下一次循环。

17.链表的逆序
主要思路:先输出除了当前节点外的节点,然后输出当前节点。
1-2-3-4-5-6-7 输出为 2-3-4-5-6-7 然后输出 1。同理 2-3-4-5-6-7 输出 3-4-5-6-7 然后输出2.

 	/**
     * 插入法 逆序
     */
    private void reverse3(Node head) {
        if (head == null || head.next == null) {
            return;
        }
        Node cur = null;
        Node next = null;
        // 当前从第二个开始 2
        cur = head.next.next;
        // 第一个节点变为尾
        head.next.next = null;
        while (cur != null) {
            next = cur.next;
            cur.next = head.next;
            head.next = cur;
            cur = next;
        }
    }

18.memset、memcpy、strcpy的区别

  • 复制内容不同,strcpy只能复制字符串,而memcpy可以复制任一内容,比如整形、结构体等。所以在复制字符串时会用strcpy(因为效率原因),而复制其他类型数据一般会用memcpy。

  • 从参数可以看出复制方法也不尽相同。strcpy不需要指定特定长度,遇到“\0”才会结束,所以使用不当容易造成溢出。memcpy则是根据第三个参数决定复制长度。

  • memset函数的原型:memset(void *s, int ch,size_t n);将s中当前位置后面的n个字节用 ch 替换并返回 s,作用是在一段内存块中填充某个给定的值,它是对较大的结构体或数组进行清零的一种快速操作。

19.排序算法的稳定性

排序前后两个相等的数相对位置不变,则算法稳定。
各排序算法的稳定性:

  • 堆排序、快速排序、希尔排序、直接选择排序不是稳定的排序算法;

  • 基数排序、冒泡排序、直接插入排序、折半插入排序、归并排序是稳定的排序算法。

20.Shell的第一行是什么,有什么作用

#!/bin/bash

第一行的内容指定了shell脚本解释器的路径,而且这个指定路径只能放在文件的第一行;第一行写错或者不写时,系统会有一个默认的解释器进行解释。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值