本人在传统软件公司工作了三年,在大学又学习了一年多了。现在,又面临着再次找工作。之前谁说的“最好的稳定,是上一份工作失去之后,马上就能找到下一份。”曾有一段时间深以为然,可是真的要找个合适的确实不那么容易啊!本人现希望谋得一份Java中级工程师的职位,望大家能推荐一下。
面试的这个公司是同学推荐去的,因此也省了很多事情。主要谈一下技术面试,虽然他们主要开发语言是PHP,但是面试过程中倒是没怎么涉及到PHP的问题。主要还是一些基本的知识,现将主要的内容总结如下:
============================华丽分割线============================================
1.介绍cookie和session的区别,怎么获取与使用?(这个问题比较开放,可深可浅,现在将这里涉及的主要问题总计如下答案)
答:
- 一、cookie机制和session机制的区别
cookie机制采用的是在客户端保持状态的方式,而session机制采用的是在服务器端保持状态的方式。
同时我们也看到,由于服务器端保持状态的方案在客户端也需要保存一个标识,所以session机制可能需要借助于cookie机制来达到保存标识的目的,但实际上还有其他选择。
- 二、会话cookie和持久cookie的区别
如果不设置过期时间,则表示这个cookie生命周期为浏览器会话期间,只要关闭浏览器窗口,cookie就消失了。这种生命期为浏览会话期的cookie被称为会话cookie。会话cookie一般不保存在硬盘上而是保存在内存里。
如果设置了过期时间,浏览器就会把cookie保存到硬盘上,关闭后再次打开浏览器,这些cookie依然有效直到超过设定的过期时间。
存储在硬盘上的cookie可以在不同的浏览器进程间共享,比如两个IE窗口。而对于保存在内存的cookie,不同的浏览器有不同的处理方式。
- 三、如何利用实现自动登录
当用户在某个网站注册后,就会收到一个惟一用户ID的cookie。客户后来重新连接时,这个用户ID会自动返回,服务器对它进行检查,确定它是否为注册用户且选择了自动登录,从而使用户务需给出明确的用户名和密码,就可以访问服务器上的资源。
- 四、如何根据用户的爱好定制站点
网站可以使用cookie记录用户的意愿。对于简单的设置,网站可以直接将页面的设置存储在cookie中完成定制。然而对于更复杂的定制,网站只需仅将一个惟一的标识符发送给用户,由服务器端的数据库存储每个标识符对应的页面设置。
- 五、cookie的发送
1.创建Cookie对象
2.设置最大时效
3.将Cookie放入到HTTP响应报头
如果你创建了一个cookie,并将他发送到浏览器,默认情况下它是一个会话级别的cookie:存储在浏览器的内存中,用户退出浏览器之后被删除。如果你希望浏览器将该cookie存储在磁盘上,则需要使用maxAge,并给出一个以秒为单位的时间。将最大时效设为0则是命令浏览器删除该cookie。
发送cookie需要使用HttpServletResponse的addCookie方法,将cookie插入到一个Set-Cookie HTTP请求报头中。由于这个方法并不修改任何之前指定的Set-Cookie报头,而是创建新的报头,因此我们将这个方法称为是addCookie,而非setCookie。同样要记住响应报头必须在任何文档内容发送到客户端之前设置。
- 六、cookie的读取
1.调用request.getCookie
要获取有浏览器发送来的cookie,需要调用HttpServletRequest的getCookies方法,这个调用返回Cookie对象的数组,对应由HTTP请求中Cookie报头输入的值。
2.对数组进行循环,调用每个cookie的getName方法,直到找到感兴趣的cookie为止
cookie与你的主机(域)相关,而非你的servlet或JSP页面。因而,尽管你的servlet可能只发送了单个cookie,你也可能会得到许多不相关的cookie。
例如:
String cookieName = “userID”; Cookie cookies[] = request.getCookies(); if (cookies!=null){ for(int i=0;i<cookies.length;i++){ Cookie cookie = cookies[i]; if (cookieName.equals(cookie.getName())){ doSomethingWith(cookie.getValue()); } } }
- 七、如何使用cookie检测初访者
A.调用HttpServletRequest.getCookies()获取Cookie数组
B.在循环中检索指定名字的cookie是否存在以及对应的值是否正确
C.如果是则退出循环并设置区别标识
D.根据区别标识判断用户是否为初访者从而进行不同的操作
- 八、使用cookie检测初访者的常见错误
不能仅仅因为cookie数组中不存在在特定的数据项就认为用户是个初访者。如果cookie数组为null,客户可能是一个初访者,也可能是由于用户将cookie删除或禁用造成的结果。但是,如果数组非null,也不过是显示客户曾经到过你的网站或域,并不能说明他们曾经访问过你的servlet。其它servlet、JSP页面以及非Java Web应用都可以设置cookie,依据路径的设置,其中的任何cookie都有可能返回给用户的浏览器。
正确的做法是判断cookie数组是否为空且是否存在指定的Cookie对象且值正确。
- 九、使用cookie属性的注意问题
属性是从服务器发送到浏览器的报头的一部分;但它们不属于由浏览器返回给服务器的报头。
因此除了名称和值之外,cookie属性只适用于从服务器输出到客户端的cookie;服务器端来自于浏览器的cookie并没有设置这些属性。
因而不要期望通过request.getCookies得到的cookie中可以使用这个属性。这意味着,你不能仅仅通过设置cookie的最大时效,发出它,在随后的输入数组中查找适当的cookie,读取它的值,修改它并将它存回Cookie,从而实现不断改变的cookie值。
- 十、如何使用cookie记录各个用户的访问计数
1.获取cookie数组中专门用于统计用户访问次数的cookie的值
2.将值转换成int型
3.将值加1并用原来的名称重新创建一个Cookie对象
4.重新设置最大时效
5.将新的cookie输出
- 十一、session在不同环境下的不同含义
session,中文经常翻译为会话,其本来的含义是指有始有终的一系列动作/消息,比如打电话是从拿起电话拨号到挂断电话这中间的一系列过程可以称之为一个session。
然而当session一词与网络协议相关联时,它又往往隐含了“面向连接”和/或“保持状态”这样两个含义。
session在Web开发环境下的语义又有了新的扩展,它的含义是指一类用来在客户端与服务器端之间保持状态的解决方案。有时候Session也用来指这种解决方案的存储结构。
- 十二、session的机制
session机制是一种服务器端的机制,服务器使用一种类似于散列表的结构(也可能就是使用散列表)来保存信息。
但程序需要为某个客户端的请求创建一个session的时候,服务器首先检查这个客户端的请求里是否包含了一个session标识-称为session id,如果已经包含一个session id则说明以前已经为此客户创建过session,服务器就按照session id把这个session检索出来使用(如果检索不到,可能会新建一个,这种情况可能出现在服务端已经删除了该用户对应的session对象,但用户人为地在请求的URL后面附加上一个JSESSION的参数)。
如果客户请求不包含session id,则为此客户创建一个session并且生成一个与此session相关联的session id,这个session id将在本次响应中返回给客户端保存。
- 十三、保存session id的几种方式【问到这个层面】
A.保存session id的方式可以采用cookie,这样在交互过程中浏览器可以自动的按照规则把这个标识发送给服务器。
B.由于cookie可以被人为的禁止,必须有其它的机制以便在cookie被禁止时仍然能够把session id传递回服务器,经常采用的一种技术叫做URL重写,就是把session id附加在URL路径的后面,附加的方式也有两种,一种是作为URL路径的附加信息,另一种是作为查询字符串附加在URL后面。网络在整个交互过程中始终保持状态,就必须在每个客户端可能请求的路径后面都包含这个session id。
C.另一种技术叫做表单隐藏字段。就是服务器会自动修改表单,添加一个隐藏字段,以便在表单提交时能够把session id传递回服务器。
- 十四、session什么时候被创建
一个常见的错误是以为session在有客户端访问时就被创建,然而事实是直到某server端程序(如Servlet)调用HttpServletRequest.getSession(true)这样的语句时才会被创建。
- 十五、session何时被删除
session在下列情况下被删除:
A.程序调用HttpSession.invalidate()
B.距离上一次收到客户端发送的session id时间间隔超过了session的最大有效时间
C.服务器进程被停止
再次注意关闭浏览器只会使存储在客户端浏览器内存中的session cookie失效,不会使服务器端的session对象失效。
- 十六、URL重写有什么缺点
对所有的URL使用URL重写,包括超链接,form的action,和重定向的URL。每个引用你的站点的URL,以及那些返回给用户的URL(即使通过间接手段,比如服务器重定向中的Location字段)都要添加额外的信息。
这意味着在你的站点上不能有任何静态的HTML页面(至少静态页面中不能有任何链接到站点动态页面的链接)。因此,每个页面都必须使用servlet或JSP动态生成。即使所有的页面都动态生成,如果用户离开了会话并通过书签或链接再次回来,会话的信息都会丢失,因为存储下来的链接含有错误的标识信息-该URL后面的SESSION ID已经过期了。
- 十七、使用隐藏的表单域有什么缺点
仅当每个页面都是有表单提交而动态生成时,才能使用这种方法。单击常规的<A HREF..>超文本链接并不产生表单提交,因此隐藏的表单域不能支持通常的会话跟踪,只能用于一系列特定的操作中,比如在线商店的结账过程
- 十八、会话跟踪的基本步骤
1.访问与当前请求相关的会话对象
2.查找与会话相关的信息
3.存储会话信息
4.废弃会话数据
- 十九、getSession()/getSession(true)、getSession(false)的区别
getSession()/getSession(true):当session存在时返回该session,否则新建一个session并返回该对象
getSession(false):当session存在时返回该session,否则不会新建session,返回null
- 二十、如何将信息于会话关联起来
setAttribute会替换任何之前设定的值;如果想要在不提供任何代替的情况下移除某个值,则应使用removeAttribute。这个方法会触发所有实现了HttpSessionBindingListener接口的值的valueUnbound
方法。
- 二十一、会话属性的类型有什么限制吗
通常会话属性的类型只要是Object就可以了。除了null或基本类型,如int,double,boolean。
如果要使用基本类型的值作为属性,必须将其转换为相应的封装类对象
- 二十二、如何废弃会话数据
A.只移除自己编写的servlet创建的数据:
调用removeAttribute(“key”)将指定键关联的值废弃
B.删除整个会话(在当前Web应用中):
调用invalidate,将整个会话废弃掉。这样做会丢失该用户的所有会话数据,而非仅仅由我们
servlet或JSP页面创建的会话数据
C.将用户从系统中注销并删除所有属于他(或她)的会话
调用logOut,将客户从Web服务器中注销,同时废弃所有与该用户相关联的会话(每个Web应用至多一个)。这个操作有可能影响到服务器上多个不同的Web应用
- 二十三、使用isNew来判断用户是否为新旧用户的错误做法
public boolean isNew()方法如果会话尚未和客户程序(浏览器)发生任何联系,则这个方法返回true,这一般是因为会话是新建的,不是由输入的客户请求所引起的。
但如果isNew返回false,只不过是说明他之前曾经访问该Web应用,并不代表他们曾访问过我们的servlet或JSP页面。
因为session是与用户相关的,在用户之前访问的每一个页面都有可能创建了会话。因此isNew为false只能说用户之前访问过该Web应用,session可以是当前页面创建,也可能是由用户之前访问过的页面创建的。
正确的做法是判断某个session中是否存在某个特定的key且其value是否正确
- 二十四、Cookie的过期和Session的超时有什么区别
会话的超时由服务器来维护,它不同于Cookie的失效日期。首先,会话一般基于驻留内存的cookie
不是持续性的cookie,因而也就没有截至日期。即使截取到JSESSIONID cookie,并为它设定一个失效日期发送出去。浏览器会话和服务器会话也会截然不同。
- 二十五、session cookie和session对象的生命周期是一样的吗
当用户关闭了浏览器虽然session cookie已经消失,但session对象仍然保存在服务器端
- 二十六、是否只要关闭浏览器,session就消失了
程序一般都是在用户做log off的时候发个指令去删除session,然而浏览器从来不会主动在关闭之前通知服务器它将要被关闭,因此服务器根本不会有机会知道浏览器已经关闭。服务器会一直保留这个会话对象直到它处于非活动状态超过设定的间隔为止。
之所以会有这种错误的认识,是因为大部分session机制都使用会话cookie来保存session id,而关闭浏览器后这个session id就消失了,再次连接到服务器时也就无法找到原来的session。
如果服务器设置的cookie被保存到硬盘上,或者使用某种手段改写浏览器发出的HTTP请求报头,把原来的session id发送到服务器,则再次打开浏览器仍然能够找到原来的session。恰恰是由于关闭浏览器不会导致session被删除,迫使服务器为session设置了一个失效时间,当距离客户上一次使用session的时间超过了这个失效时间时,服务器就可以认为客户端已经停止了活动,才会把session删除以节省存储空间。
由此我们可以得出如下结论:
关闭浏览器,只会是浏览器端内存里的session cookie消失,但不会使保存在服务器端的session对象消失,同样也不会使已经保存到硬盘上的持久化cookie消失。
- 二十七、打开两个浏览器窗口访问应用程序会使用同一个session还是不同的session
通常session cookie是不能跨窗口使用的,当你新开了一个浏览器窗口进入相同页面时,系统会赋予你一个新的session id,这样我们信息共享的目的就达不到了。
此时我们可以先把session id保存在persistent cookie中(通过设置session的最大有效时间),然后在新窗口中读出来,就可以得到上一个窗口的session id了,这样通过session cookie和persistent cookie的结合我们就可以实现了跨窗口的会话跟踪。
- 二十八、如何使用会话显示每个客户的访问次数
由于客户的访问次数是一个整型的变量,但session的属性类型中不能使用int,double,boolean等基本类型的变量,所以我们要用到这些基本类型的封装类型对象作为session对象中属性的值
但像Integer是一种不可修改(Immutable)的数据结构:构建后就不能更改。这意味着每个请求都必须创建新的Integer对象,之后使用setAttribute来代替之前存在的老的属性的值。例如:
HttpSession session = request.getSession(); SomeImmutalbeClass value = (SomeImmutableClass)session.getAttribute(“SomeIdentifier”); if (value= =null){ value = new SomeImmutableClass(…); // 新创建一个不可更改对象 }else{ value = new SomeImmutableClass(calculatedFrom(value)); // 对value重新计算后创建新的对象 } session.setAttribute(“someIdentifier”,value); // 使用新创建的对象覆盖原来的老的对象
- 二十九、如何使用会话累计用户的数据
使用可变的数据结构,比如数组、List、Map或含有可写字段的应用程序专有的数据结构。通过这种方式,除非首次分配对象,否则不需要调用setAttribute。例如
HttpSession session = request.getSession(); SomeMutableClass value = (SomeMutableClass)session.getAttribute(“someIdentifier”); if(value = = null){ value = new SomeMutableClass(…); session.setAttribute(“someIdentifier”,value); }else{ value.updateInternalAttribute(…); // 如果已经存在该对象则更新其属性而不需重新设置属性 }
- 三十、不可更改对象和可更改对象在会话数据更新时的不同处理
不可更改对象因为一旦创建之后就不能更改,所以每次要修改会话中属性的值的时候,都需要调用setAttribute(“someIdentifier”,newValue)来代替原有的属性的值,否则属性的值不会被更新可更改对象因为其自身一般提供了修改自身属性的方法,所以每次要修改会话中属性的值的时候,只要调用该可更改对象的相关修改自身属性的方法就可以了。这意味着我们就不需要调用setAttribute方法了。
=====================================华丽分割线=============================================
2.二叉树遍历的各种变种问题。(问的是二叉树结点求和)
答:虽然数据结构用C++表述的话比较方便,之前学习的时候多用C++写成。现在,要应聘Java工程师,因此,将这些都由JAVA实现。
二叉树简单介绍:
二叉树是树形结构的一个重要类型。许多实际问题抽象出来的数据结构往往是二叉树的形式,即使是一般的树也能简单地转换为二叉树,而且二叉树的存储结构及其算法都较为简单,因此二叉树显得特别重要。
二叉树(BinaryTree)是n(n≥0)个结点的有限集,它或者是空集(n=0),或者由一个根结点及两棵互不相交的、分别称作这个根的左子树和右子树的二叉树组成。
这个定义是递归的。由于左、右子树也是二叉树, 因此子树也可为空树。
二叉树的遍历
对于二叉树来讲最主要、最基本的运算是遍历。
遍历二叉树 是指以一定的次序访问二叉树中的每个结点。所谓 访问结点 是指对结点进行各种操作的简称。例如,查询结点数据域的内容,或输出它的值,或找出结点位置,或是执行对结点的其他操作。遍历二叉树的过程实质是把二叉树的结点进行线性排列的过程。假设遍历二叉树时访问结点的操作就是输出结点数据域的值,那么遍历的结果得到一个线性序列。
从二叉树的递归定义可知,一棵非空的二叉树由根结点及左、右子树这三个基本部分组成。因此,在任一给定结点上,可以按某种次序执行三个操作:
(1)访问结点本身(N),
(2)遍历该结点的左子树(L),
(3)遍历该结点的右子树(R)。
具体实现如下:(包括数据的构造,二叉树递归遍历,非递归遍历,以及变种问题的解决方案。也可以重构之后,直接作为库函数使用)
/** * 二叉树的递归遍历,非递归遍历,已经衍生出来的其他问题。 */ package com.algorithm.Tree; import java.util.LinkedList; import java.util.List; import java.util.Stack; /** * @author Administrator */ public class BinaryTree { private int data[]={1,2,3,5,9,8,5}; private static List<TreeNode> nodeList=null; /** * 创建B树 */ public void createBTree(){ nodeList = new LinkedList<BinaryTree.TreeNode>(); for(int nodeIndex=0;nodeIndex<data.length;nodeIndex++){ nodeList.add(new TreeNode(data[nodeIndex])); } //create as the binary tree. for(int parentIndex=0;parentIndex<data.length/2-1;parentIndex++){ nodeList.get(parentIndex).leftTree=nodeList.get(parentIndex*2+1); nodeList.get(parentIndex).rightTree=nodeList.get(parentIndex*2+2); } int lastParentIndex = data.length / 2 - 1; // 左孩子 nodeList.get(lastParentIndex).leftTree = nodeList .get(lastParentIndex * 2 + 1); if (data.length % 2 == 1) { nodeList.get(lastParentIndex).rightTree = nodeList .get(lastParentIndex * 2 + 2); } } /** * 中序遍历 * @param treeNode */ public void inOrderTraverse(TreeNode treeNode) { if (treeNode == null) return; inOrderTraverse(treeNode.leftTree); visit(treeNode); inOrderTraverse(treeNode.rightTree); } /** * 递归实现树的求和。 * @param treeNode * @return */ public int sum(TreeNode treeNode){ int sum=0; if(treeNode == null){ sum=0; }else{ sum+=treeNode.getData(); sum+=sum(treeNode.leftTree); sum+=sum(treeNode.rightTree); } return sum; } /** * 非递归实现中序遍历 * @param treeNode */ public void noRecInOrder(TreeNode treeNode){ Stack<BinaryTree.TreeNode> stack=new Stack<BinaryTree.TreeNode>(); while(treeNode!=null||stack.size()>0){ while(treeNode!=null){ stack.push(treeNode); treeNode=treeNode.leftTree; } if(stack.size()>0){ treeNode=stack.pop(); visit(treeNode); treeNode=treeNode.rightTree; } } } public int noRecSum(TreeNode treeNode){ int sum=0; Stack<BinaryTree.TreeNode> stack=new Stack<BinaryTree.TreeNode>(); while(treeNode!=null||stack.size()>0){ while(treeNode!=null){ stack.push(treeNode); treeNode=treeNode.leftTree; } if(stack.size()>0){ treeNode=stack.pop(); sum+=treeNode.getData(); treeNode=treeNode.rightTree; } } return sum; } private void visit(TreeNode treeNode){ treeNode.setVisted(true); System.out.print(treeNode.getData()+" "); } public static void main(String[] args) { BinaryTree bt=new BinaryTree(); bt.createBTree(); bt.inOrderTraverse(nodeList.get(0)); System.out.println("\n+++++++++++++"); System.out.println(bt.sum(nodeList.get(0))); System.out.println("\n+++++++++++++"); bt.noRecInOrder(nodeList.get(0)); System.out.println("\n+++++++++++++"); System.out.println(bt.noRecSum(nodeList.get(0))); } /** * 内部内,主要构造为树的节点。 */ private static class TreeNode{ private TreeNode leftTree; private TreeNode rightTree; private int data; private boolean isVisted=false;//是否已经访问标识 TreeNode(int newData){ this.leftTree=null; this.rightTree=null; this.data = newData; this.setVisted(false); } public int getData(){ return data; } @SuppressWarnings("unused") public boolean isVisted() { return isVisted; } public void setVisted(boolean isVisted) { this.isVisted = isVisted; } } }
http://www.cnblogs.com/accipiter/p/5135823.html
首先,感谢大家的浏览,还有朋友给推荐工作,由于本人目前在北京,且年后本人在北京还有部分课程需要上,因此现在不便于远行前往深圳,广州等地。还是非常感谢大家!
今天主要是把之前的工具,做了一些设置与调整,工欲善其事,必先利其器嘛。主要涉及到Eclipse设置,maven使用(之前工作都是使用自有构建工具,现在用开源,开源工具功能大而全,但是,往往也坑比较多),git工具的使用(以前工作一直使用SVN,版本管理以后稍作介绍),Mysql安装使用(之前工作一直使用oracle,关于这一部分以后做详加使用说明)。下面还是接昨天的,把面试涉及到的东西写完整。
====================================华丽分割线===========================================
1.索引的使用,联合索引的使用,是否索引越多越好?
答:[以oracle为例]索引好比是一本书前面的目录,能加快数据库表的查询速度。索引分为聚簇索引和非聚簇索引两种,聚簇索引 是按照数据存放的物理位置为顺序的,而非聚簇索引就不一样了;聚簇索引能提高多行检索的速度,而非聚簇索引对于单行的检索很快。
用的最多也最好的是B-tree索引,它主要是避免了大量数据的排序操作。
数据库中存储数据的基础单位就是页,数据库的页大小和操作系统类似,是指存放数据时,每一块的大小。比如一个1M的数据存放在数据库中时, 需要大概12块页来存放。如果是在操作系统上安装的数据库,最好将数据库页大小设置为操作系统页大小的倍数,才是最佳设置。数据库可以将数据从逻辑上分成页,磁盘的I/O操作就是在页级执行。
- 96字节大小的标头,存储统计信息,包括页码、页类型、页的可用空间以及拥有该页的对象的分配单元 ID。数据库页类型主要分如下三类:
- 数据页,除了大型对象的数据列之外的数据存储页,比如int,float,varchar等。
- 索引页,存放索引的条目。
- 大型对象数据类型,比如text,image,nvarchar(max)等。
- 一个区包含8个页,它是管理空间的单位,分为如下两类
- 统一区,由单个对象所有。
- 混合区,最多可由八个对象共享
知道了区以及页的概念,再看下数据表和这两者之间的联系, 表包含一个或多个分区,每个分区在一个堆或一个聚集索引结构中包含数据行。
索引中的底层节点称为叶节点。根节点与叶节点之间的任何索引级别统称为中间级。在聚集索引中,叶节点包含基础表的数据页。根节点和中间级节点包含存有索引行的索引页。每个索引行包含一个键值和一个指针,该指针指向 B -树上的某一中间级页或叶级索引中的某个数据行。每级索引中的页均被链接在双向链接列表中。
非聚集索引与聚集索引之间的显著差别在于以下两点:
- 基础表的数据行不按非聚集键的顺序排序和存储。
- 非聚集索引的叶层是由索引页而不是由数据页组成。
索引的优点:正确的索引会大大提高数据查询,对结果进行排序、分组的操作效率。
索引的缺点:
1.创建索引需要额外的磁盘空间,索引最大一般为表大小的1.2倍左右。
2.在表数据修改时,例如增加,删除,更新,都需要维护索引表,这是需要系统开销的。
3.不合理的索引设计非但不能利于系统,反而会使系统性能下降。例如我们在一个创建有非聚集索引的列上做范围查询,此列的索引不会起到任何的优化效果,反而由于数据的修改而需要维护索引表,从而影响了对数据修改的性能。
什么字段不适合创建索引?
1.不经常使用的列,这种索引带来缺点远大于带来的优点。
2.逻辑性的字段,例如性别字段等等,匹配的记录太多,和全表扫描比起来差不多。
3.字段内容特别大的字段,例如大字段等,这会大大增大索引所占用的空间以及索引维护时的速度。
4.涉及到计算的列,或者是需要利用数据库函数进行加工处理的列不应当创建索引。
联合索引:
1.查询条件中出现联合索引第一列,或者全部,则能利用联合索引.
2.条件列中只要条件相连在一起,无论前后,都会利用上联合索引.
3.查询条件中没有出现联合索引的第一列,而出现联合索引的第二列,或者第三列,都不会利用联合索引查询.
单一列索引:
1.只要条件列中出现索引列,无论在什么位置,都能利用索引查询.
另外,实际使用过程中,经常遇到索引丢失的情况,这种情况一般需要重建索引,有的涉及到复杂业务查询的语句,需要优化查询,对于具体的SQL,可能由于优化的原因,有不是理想的执行计划。
======================================华丽分割线==========================================
2.实现二路归并排序(面试是要求画出图)
答:二路归并理解起来比较容易,主要是利用分治法。但是,具体代码还是要下一些功夫。
归并排序其实要做两件事:
1.分解——将序列每次折半划分。
2.合并——将划分后的序列段两两合并后排序。
合并的规则:
在每次合并过程中,都是对两个有序的序列段进行合并,然后排序。这两个有序序列段分别为 arr[low, mid] 和 arr[mid+1, high]。先将他们合并到一个局部的暂存数组tmparr中,待合并完成后再将tmparr复制回R中。这里称 arr[low, mid] 第一段,arr[mid+1, high] 为第二段。每次从两个段中取出一个记录进行关键字的比较,将较小者放入tmparr中。最后将各段中余下的部分直接复制到tmparr中。经过这样的过程,tmparr已经是一个有序的序列,再将其复制回arr中,一次合并排序就完成了。
注意,若子表个数为奇数,则最后一个子表无须和其他子表归并(即本趟处理轮空):若子表个数为偶数,则要注意到最后一对子表中后一个子表区间的上限为n-1。
/** * @FileName MergeSort.java * @Package com.algorithm.sort * @Description TODO[what the file to do] * @Author ali blog:http://www.cnblogs.com/accipiter * @Date 上午1:06:31 * @Version V1.0.1 */ package com.algorithm.sort; /** * @ClassName MergeSort * @Description TODO * @Date 下午11:14:51 */ public class MergeSort { /** * @Title Merge * @Description TODO * @param arr * @param low * @param mid * @param high * @Return void * @Throws * @user Administrator */ public void Merge(int[] arr, int low, int mid, int high) { int i = low; // i是第一段序列的起始 int j = mid + 1; // j是第二段序列的起始 int k = 0; // k是临时存放合并序列的起始 int[] tmparr = new int[high - low + 1]; // tmparr是临时合并序列 while (i <= mid && j <= high) { if (arr[i] <= arr[j]) { tmparr[k++] = arr[i++]; } else { tmparr[k++] = arr[j++]; } } while (i <= mid) { tmparr[k++] = arr[i++]; } while (j <= high) { tmparr[k++] = arr[j++]; } for (k = 0, i = low; i <= high; i++, k++) { arr[i] = tmparr[k]; } } /** * @Title MergeStep * @Description TODO * @param arr * @param len * @param length * @Return void * @Throws * @user Administrator */ public void MergeStep(int[] arr, int len, int length) { int i = 0; for (i = 0; i + 2 * len - 1 < length; i = i + 2 * len) { Merge(arr, i, i + len - 1, i + 2 * len - 1); } if (i + len - 1 < length) { Merge(arr, i, i + len - 1, length - 1); } } /** * @Title sort * @Description TODO * @param list * @return * @Return int[] * @Throws * @user Administrator */ public int[] sort(int[] list) { for (int len = 1; len < list.length; len = 2 * len) { MergeStep(list, len, list.length); System.out.print("len = " + len + ":\t"); this.printAll(list); } return list; } /** * @Title printAll * @Description TODO * @param list * @Return void * @Throws * @user Administrator */ public void printAll(int[] list) { for (int value : list) { System.out.print(value + "\t"); } System.out.println(); } public static void main(String[] args) { int[] array = { 8, 1, 7, 3, 1, 2, 6, 9, 5}; MergeSort merge = new MergeSort(); System.out.print("排序前:\t\t"); merge.printAll(array); merge.sort(array); System.out.print("排序后:\t\t"); merge.printAll(array); } }
http://www.cnblogs.com/accipiter/p/5138162.html
转载于:https://www.cnblogs.com/softidea/p/5138969.html
发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/109172.html原文链接:https://javaforall.cn
【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛
【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...