zoukankan      html  css  js  c++  java
  • 2012.09.10阿里笔试

    投了个内推,在南大旧的就业中心技术沙龙和面试

    9.10号晚笔试题

    1、正则表达式,邮件合法性检测,给出正则表达式规则,让写正确的正则表达式

    2、统计英文文章单词个数,并按出现顺序打印出来,自己设计数据结构和算法

    1、解答: 以下是一个不区分大小写的正则表达式:/^[a-z]([a-z0-9]*[-_]?[a-z0-9]+)*@([a-z0-9]*[-_]?[a-z0-9]+)+[.][a-z]{2,3}([.][a-z]{2})?$/i;
    2、解答:

    步骤1:从头开始读取每一个字符,用char *c来引用,遇到一个空格或者标点符号,一个单词结束;

    步骤2:输出单词该单词,对这个单词进行hash处理:hash(*c)%1000,存入一个hashmap中,对应的<key,value>是单词和单词出现的次数;

    步骤3:读取第2个单词,hash取模后判断是否在hashmap中,如果在,则对应的value加1,不在则输出,并存入到hashmap中;

    步骤4;重复上述三个步骤,直到读取到文章末尾。

    另,9.6的笔试题

    1、设计一个分布式消息系统

    2、求无向图的环的个数

    9.12面试

    1、面试官自己介绍,再让我自我介绍 2、说说自认为学的最好的一门课(楼主选了数据结构,面试官简历上标记) 3、说一下所有数据结构的特点;栈和队列的差别,数组和链表的差别

    解答:

    ①从数据的逻辑结构分,数据结构分为线性结构和非线性结构。线性结构又分为一般的线性表、受限线性表和线性表推广。其中受限线性表包括栈、队列和串。线性表推广包括数组和广义表。非线性表包括集合、树形结构和图状结构。其中树形结构分为一般树和二叉树,图分为有向图和无向图。

    线性表:线性表是具有相同类型的n(n>=0)个数据元素的有限序列。

    线性表有两种表示形式:顺序表和链表。顺序表是用一组地址连续的存储单元,依次存储线性表中数据元素;链表不要求逻辑上相邻的两个元素逻辑上也相邻,它是通过“链”建立起数据元素之间的逻辑关系。

    串: 串(或字符串),是由零个或多个字符组成的有穷序列。

    树:树是N(N>=0)个结点的有限集合,N=0时,称为空树。在任意一棵非空树中应满足:1)有且仅有一个特定的称为根的结点;2)当N>1时,其余结点可分为m(m>0)个互不相交的有限集合T1、T2,···,Tm,其中每一个集合本身又是一棵树,并且称为根结点的子树。显然树的定义是递归的,是一种递归的数据结构。

    图:由顶点集以及边集合组成的数据结构。

    ②栈:只允许在一端进行插入和删除的线性表,后进先出;队列:在一端进行插入,另一端删除的线性表,先进先出。

    ③数组是用一组地址连续的存储单元,依次存储线性表中数据元素,通过下标就能迅速访问数组中的任意元素,但同时插入、删除就比较麻烦;链表访问元素需要遍历,时间复杂度高,插入删除只要操作操作指针就行。

    4、给10分钟写一个队列的出队入队操作

     用C语言以及链式存储实现。

    Queue.h文件:

    //第一种结构定义方法
    //typedef struct node  
    //{  
    //    int data;  
    //    struct node *next;  
    //}Node,*PNode; 
    
    //第二章结构定义方法
    typedef struct node *PNode;
    typedef struct node  
    {  
        int data;  
        PNode next;
    }Node;
    
    typedef struct{
    	PNode front;
    	PNode rear;
    	int size;
    }Queue;
    
    //构造一个空队列
    Queue *InitQueue();
    
    //销毁一个队列
    void DestroyQueue(Queue *pqueue);
    
    //清空一个队列
    void ClearQueue(Queue *pqueue);
    
    //判断队列是否为空
    int IsEmpty(Queue *pqueue);
    
    //返回队列大小
    int GetSize(Queue *pqueue);
    
    //返回队头元素
    PNode GETFront(Queue *pqueue,int *item);
    
    //返回队尾元素
    PNode GETRear(Queue *pqueue,int *item);
    
    //将新元素入队
    PNode EnQueue(Queue *pqueue,int item);
    
    //将新元素出队
    PNode DeQueue(Queue *pqueue,int *item);
    

     Queue.c文件:

    #include "Queue.h"
    #include <malloc.h>
    #include <stdio.h>
    
    //构造一个空队列
    Queue *InitQueue(){
    	Queue *queue = (Queue *)malloc(sizeof(Queue));
    	if(queue != NULL){
    		queue->front = NULL;
    		queue->rear = NULL;
    		queue->size = 0;
    	}
    
    	return queue;
    }
    
    //判断队列是否为空
    int IsEmpty(Queue *pqueue){
    	if(pqueue->front == NULL && pqueue->rear == NULL)
    		return 1;
    	else 
    		return 0;
    }
    
    
    //返回队列大小
    int GetSize(Queue *pqueue){
    	return pqueue->size;
    }
    
    //返回队头元素
    PNode GETFront(Queue *pqueue,int *item){
    	if(IsEmpty(pqueue)!=1&&item!=NULL)  
        {  
           *item = pqueue->front->data;  
        }  
        return pqueue->front;  
    }
    
    //返回队尾元素
    PNode GETRear(Queue *pqueue,int *item){
    	if(IsEmpty(pqueue)!=1&&item!=NULL)  
        {  
           *item = pqueue->rear->data;  
        }  
        return pqueue->rear;   
    }
    
    //将新元素入队
    PNode EnQueue(Queue *pqueue,int item){
    	PNode node = (PNode)malloc(sizeof(item));
    	if(node != NULL){
    		node->data = item;
    		node->next = NULL;
    		if(IsEmpty(pqueue)){
    			//如果队列为空
    			pqueue->front = node;
    		}else{
    			pqueue->rear->next = node;
    		}
    		pqueue->rear = node;
    		pqueue->size++;
    	}
    	return node;
    }
    
    //将新元素出队
    PNode DeQueue(Queue *pqueue,int *item){
    	PNode node = pqueue->front;
    	if(IsEmpty(pqueue)!=1 && node != NULL){
    		pqueue->front = node->next;
    		free(node);
    		pqueue->size--;
    		if(pqueue->size == 0)
    			pqueue->rear = NULL;
    
    	}
    	return pqueue->front;
    }
    
    /**测试**/
    void print(int i)
    {
    	printf("该节点元素为%d
    ",i);
    }
    main()
    {
    	Queue *pq = InitQueue();
    	int i,item;
    	printf("0-9依次入队并输出如下:
    ");
    	for(i=0;i<10;i++)
    	{
    		EnQueue(pq,i);
    		GETRear(pq,&item);
    		printf("%d ",item);
    	}
    
    	
    }
    

      

    5、多线程死锁写个示例

    多线程死锁的四个必要条件:

    4.1、互斥使用(资源独占)
    一个资源每次只能给一个进程使用
    4.2、不可强占(不可剥夺)
        资源申请者不能强行的从资源占有者手中夺取资源,资源只能由占有者自愿释放
    4.3、请求和保持(部分分配,占有申请)
    一个进程在申请新的资源的同时保持对原有资源的占有(只有这样才是动态申请,动态分配)
    4.4、循环等待
    存在一个进程等待队列
    {P1 , P2 , … , Pn},
    其中P1等待P2占有的资源,P2等待P3占有的资源,…,Pn等待P1占有的资源,形成一个进程等待环路

    实际例子:

    package com.damlab.fz;
    
    public class DeadLock {
        public static void main(String[] args) {
            Resource r1= new Resource();
            Resource r2= new Resource();
            //每个线程都拥有r1,r2两个对象
            Thread myTh1 = new MyThread1(r1,r2);
            Thread myTh2 = new MyThread2(r1,r2);
            myTh1.start();
            myTh2.start();
        }
    }
    
    class Resource{
        private int i;
    }
    
    class MyThread1 extends Thread{
        private Resource r1,r2;
        public MyThread1(Resource r1, Resource r2) {
            this.r1 = r1;
            this.r2 = r2;
        }
    
        @Override
        public void run() {
            while(true){
            //先获得r1的锁,再获得r2的锁    
            synchronized (r1) {
                System.out.println("1号线程获取了r1的锁");
                synchronized (r2) {
                    System.out.println("1号线程获取了r2的锁");
                }
            }
            }
        }
        
    }
    
    class MyThread2 extends Thread{
        private Resource r1,r2;
        public MyThread2(Resource r1, Resource r2) {
            this.r1 = r1;
            this.r2 = r2;
        }
    
        @Override
        public void run() {
            while(true){
            //先获得r2的锁,再获得r1的锁
            synchronized (r2) {
                System.out.println("2号线程获取了r2的锁");
                synchronized (r1) {
                    System.out.println("2号线程获取了r1的锁");
                }
            }
            }
        }
        
    }

    6、TCPIP有哪几种状态

    解答:其实就是TCP通过三次握手进行连接和通过四次握手释放连接的过程中,TCP有几种状态。

    详见http://blog.sina.com.cn/s/blog_6a2787d40102uwte.html

    7、词法分析和语法分析作用是什么

    解答:编译过程包括词法分析,语法分析,语义检查,代码生成,代码优化。

    词法分析:分析由字符组成的单词是否合法,如果没有问题的话,则产生一个单词流。

    语法分析:分析由单词组成的句子是否合法,如果没有问题的话,则产生一个语法树。

    8、一亿个数存在一个大文件里,现在给出一个数,怎么判断这数是否在文件里

    解答:遍历这一亿个数,用bit-map存储这一亿个数,对应的bit位置为1,只需要约10^8/8byte=12.5Mb的内存存储空间。根据给出的数,通过位运算查找该数对应的位置上是否为1,如果是则表明该数在文件里,否则不在文件中。

    9、最有成就感的项目

    10、对比java和c++;c++的内存管理是怎么做的

    解答:
    1.
    Java中对内存的分配是动态的,它采用面向对象的机制,采用运算符new为每个对象分配内存空间,而且,实际内存还会随程序运行情况而改变.程序运行中,每个, Java系统自动对内存进行扫描,对长期不用的空间作为”垃圾”进行收集,使得系统资源得到更充分地利用.按照这种机制,程序员不必关注内存管理问题,这使Java程序的编写变得简单明了,并且避免了了由于内存管理方面的差错而导致系统出问题.而C语言通过malloc()和free()这两个库函数来分别实现分配内在和释放内存空间的,C++语言中则通过运算符new和delete来分配和释放内存.在C和C++这仲机制中,程序员必须非常仔细地处理内存的使用问题.一方面,如果对己释放的内存再作释放或者对未曾分配的内存作释放,都会造成死机;而另一方面,如果对长期不用的或不再使用的内存不释放,则会浪费系统资源,甚至因此造成资源枯竭.
    • Java不在所有类之外定义全局变量,而是在某个类中定义一种公用静态的变量来完成全局变量的功能.
    • Java不用goto语句,而是用try-catch-finally异常处理语句来代替goto语句处理出错的功能.
    • Java不支持头文件,面C和C++语言中都用头文件来定义类的原型,全局变量,库函数等,这种采用头文件的结构使得系统的运行维护相当繁杂.
    • Java不支持宏定义,而是使用关键字final来定义常量,在C++中则采用宏定义来实现常量定义,这不得于程序的可读性.
    • Java对每种数据类型都分配固定长度.比如,在Java中,int类型总是32位的,而在C和C++中,对于不同的平台,同一个数据类型分配不同的字节数,同样是int类型,在PC机中为二字节即16位,而在VAX-11中,则为32位.这使得C语言造成不可移植性,而Java则具有跨平台性(平台无关性).
    • 类型转换不同.在C和C++中,可通过指针进行任意的类型转换,常常带来不安全性,而在Java中,运行时系统对对象的处理要进行类型相容性检查,以防止不安全的转换.
    • 结构和联合的处理.在C和C++中,结构和联合的所有成员均为公有,这就带来了安全性问题,而在Java中根本就不包含结构和联合,所有的内容都封装在类里面
    • Java不再使用指针.指针是C和C++中最灵活,也最容易产生错误的数据类型.由指针所进行的内存地址操作常会造成不可预知的错误,同时通过指针对某个内存地址进行显式类型转换后,可以访问一个C++中的私有成员,从而破坏安全性.而Java对指针进行完全地控制,程序员不能直接进行任何指针操作.
       

    C++内存管理:详见http://www.cnblogs.com/lancidie/archive/2011/08/05/2128318.html

  • 相关阅读:
    eclipse中如何修改编码格式
    如何让Div中的Table居中
    EL表达式和标准标签库
    jQuery获取option的一些常用方法
    第三十五章——过滤器和监听器
    第三十四章——java web的注册登录和留言板的制作
    关于九大内置对象的补充——application
    第三十三章——javaweb初识和九大内置对象
    学习记录
    从 HTTP 到 HTTPS 再到 HSTS
  • 原文地址:https://www.cnblogs.com/hzhtracy/p/4454317.html
Copyright © 2011-2022 走看看