zoukankan      html  css  js  c++  java
  • 2020.10.17 笔试题错题反思

    背景

    星期六下午前往了佛山南海参加某公司的笔试;有几道题我明显没有做出来的,在此复习,并重新更正一下。

    做了45分钟的笔试题,和面试官与HR各聊了30分钟

    面试官对我的评价是:工作时间不长,但基础较好,知识面也比较广;但安卓驱动岗位的基础薄弱(后续有待加强)。

    谢谢面试官对我的评价,这两年的主动学习没有白费。

    错题

    求stack的增长方向

    原题:设计一个函数,获知stack是向高地址增长还是低地址增长。

    思路:

    判断栈的增长需要依赖函数的调用,那么我需要实现2个函数,通过在一个函数中调用另外一个函数,根据各函数中变量的地址来判断增长方向。但是因为自己怀疑程序的内存分布都是随机的,因此这道题我最后放弃了作答。

    事后查阅了有关资料以及做了验证,发现我之前的思路是正确的。

    解答:

    #include <stdio.h>
    
    void * get_var_in_fun_address(void) {
        int i;
        static long long * p;
        p = (long long *)&i;
        return p;
    }
    
    void * check_if_stack_grow_up (void) {
        int var;
        long long * p1 = (long long *)&var;
        long long * p2 = get_var_in_fun_address();
        printf("%p : %p
    ", p1, p2);
        if( p1 - p2 > 0) { // 向下增长
            printf("Down
    ");
        }else {
            printf("UP
    ");
        }
    }
    
    int main(int argc, char *argv[])
    {
        check_if_stack_grow_up();
        return 0;
    }
    

    运行结果:

    0xffffcbfc : 0xffffcbbc
    Down
    

    优化:由于题目要求以一个函数完成这样的实现,考虑使用递归(多调用自身1次)或者传参辅助判断。原理都是类似的。

    反转一条单链表

    题目:反转一条单链表

    • 输入: 1->2->3->4->5->NULL
    • 输出: 5->4->3->2->1->NULL

    思路:完成链表各个结点之间的交换,注意保存下一个节点的地址。链表的操作(尤其是单链表)一直是我薄弱的地方,之前学习链表的时候,实现了删除、交换、插入等操作以后,就将其封装作为接口,没有再去深究其中的东西了。因此,这道题会错的原因很大程度上归咎于没有定期复习一些底层原理,以为会了的东西就没在去看了。

    解答:在网上学到了几种的解答思路。

    递归虽然简洁,但是应该避免使用(建议改为尾递归,或者自定义栈)。

    解法:头删再头插

    原理:在原有链表的基础上,依次将位于链表头部的节点摘下,然后采用从头部插入的方式生成一个新链表,则此链表即反转结果。

    #include <stdio.h>
    struct node {
            struct node *next;
    };
    
    struct node *reverseList(struct node* head) {
            struct node *newHead = NULL;
            struct node *node;
            while (head != NULL) {
                    //1. 对之前的链表做头删
                    node = head;
                    head = head->next;
                    //2. 对新链表做头插
                    node->next = newHead;
                    newHead = node;
            }
            return newHead;
    }
    
    int main(int argc, char *argv[])
    {
        int i;
        // 构造一条链表
        struct node  head;
        struct node  node[5];
        struct node  *p;
        head.next = &node[0];
        printf("%p
    ", &head);
        for (i = 0; i +1< 5; ++i) {
            node[i].next = &(node[i+1]);
            printf("%p->%p
    ", &node[i], node[i].next);
        }
    	// 反转,并打印结果
        p = reverseList(&head);
        while(p)
        {
            printf("%p
    ", p);
            p = p->next;
        }
        return 0;
    }
    

    解法:迭代反转链表

    从当前链表的首元节点开始,一直遍历至链表的最后一个节点,这期间会逐个改变所遍历到的节点的指针域,另其指向前一个节点。

    #include <stdio.h>
    struct node {
            struct node *next;
    };
    
    //迭代反转法,head 为无头节点链表的头指针
    struct node * reverse_iteration(struct node * head) {
        struct node * beg = NULL;
        struct node * mid = head;
        struct node * end = head->next;
            if (head == NULL || head->next == NULL) {
                    return head;
            }
    
        while (1)
        {
            //修改 mid 所指节点的指向
            mid->next = beg;
    
            if (end == NULL) { // 到尾部则退出
                break;
            }
    
            //整体向后移动 3 个指针
            beg = mid;
            mid = end;
            end = end->next;
        }
        //最后修改 head 头指针的指向
        head = mid;
        return head;
    }
    
    int main(int argc, char *argv[])
    {
        int i;
        // 构造一条链表
        struct node  head;
        struct node  node[5];
        struct node  *p;
        head.next = &node[0];
        printf("%p
    ", &head);
        for (i = 0; i +1< 5; ++i) {
            node[i].next = &(node[i+1]);
            printf("%p->%p
    ", &node[i], node[i].next);
        }
    	// 反转,并打印结果
        //p = reverseList_header_insert(&head);
        p = reverse_iteration(&head);
        while(p)
        {
            printf("%p
    ", p);
            p = p->next;
        }
    
        return 0;
    }
    

    根据遍历结果还原二叉树

    题目:二叉树中如何根据已知的两种遍历方法,求出第三种遍历的结果。

    思路:这道题我是之前复习数据结构的时候遇到的。关键在于,找到根节点。但这道题没有做出来的原因在于,我忘记了“中序遍历”、“后序遍历”这些定义对应树遍历顺序。

    TCP/UDP传输优缺点

    题目:TCP/UDP传输的优缺点。

    思路:之前理解错题意了。事后想起来题目应该想问的是TCP与UDP传输的优缺点。

    解答:

    • 优点:
      • TCP是面向连接的协议,安全可靠;
      • UDP使用简单,而且能够支持组播,广播,传输开销比TCP小(因为TCP需要握手)
    • 缺点:
      • TCP传输开销较大,容易被握手攻击
      • UDP是一种尽力传输,不可靠,需要额外的机制保证数据的有效性。

    OSI网络模型

    题目:OSI网络模型是怎么样的。

    思路:考察网络知识概念,我把TCP/IP与OSI分层混淆了,而且还记错了各层的顺序。之前整理过有关的博客,现在笔试题做成这样,真的很惭愧。

    解答:网络OSI七层模型及各层作用 与 TCP/IP

    RGMII与SGMII的区别

    题目:面试官询问过我的工作以后,问起我们在MAC中用了什么接口,我回答的是RGMII。但后续他抛出的这个问题,我确实没有详细去了解过。

    解答:连接PHY-MAC的接口:MII,RMII,SMII,GMII,RGMII,SGMII

    其他错题

    因为不小心而做错的题目。

  • 相关阅读:
    C++——"%"运算符
    九度教程第22题——今年暑假不AC(看尽量多的电视节目)
    C++标准模板库 ——堆栈使用
    .Net转Java自学之路—基础巩固篇十三(集合)
    .Net转Java自学之路—基础巩固篇十二(多线程)
    .Net转Java自学之路—基础巩固篇十(异常)
    .Net转Java自学之路—基础巩固篇九(Object、内部类)
    .Net转Java自学之路—基础巩固篇八—总结(封装、继承、多态)
    .Net转Java自学之路—基础巩固篇七(接口、多态)
    .Net转Java自学之路—基础巩固篇六(继承)
  • 原文地址:https://www.cnblogs.com/schips/p/13833680.html
Copyright © 2011-2022 走看看