标签:java面试宝典
(1)float型数据定义必须加f后缀,否则编译不通过。例:
float f = 3.53457f;
(2)浮点数计算
System.out.println(( 3 - 2.6 == 0.4));
输出flase
级别 | 运算符 |
---|---|
第一级 | () [] . ++(后置) –(后置) |
第二级 | ++(前置) –(前置) +(一元加) -(一元减) !(一元逻辑非) |
第三级 | (type) new |
第四级 | × / % |
第五级 |
|
第六级 | << >> >>> |
第七级 | < <= > |
第八级 | <= instanceof |
第九级 | == != |
第十级 | & |
第十一级 | ^ |
第十二级 | | |
第十三级 | && |
第十四级 | || |
第十五级 | ?: |
第十六级 | = += == *= /= %= |
!> 算数运算符 > 比较运算符 > 位运算符(& ^ | 依次递减) > 逻辑运算符(除!运算)(! && ||依次递减)
要求:不使用乘除,for,while,if,else,switch,case等关键字及条件判断句
解析:
首先,为了相加需要循环,但是题意限制了循环,所以只能是递归了
其次,为了结束递归需要进行条件判断,而题意限制了条件判断,故要选择条件运算符来达到判断的目的。
public int fun(int n){
return n == 1 ? 1: fun(n-1)+n;
}
1、大小写转换
toLowerCase()和toUpperCase
2、字符串反转输出
使用split()或charAt()自己实现一个函数
3、equals和==
String str = "我是中国人";
String str1 = "我是中国人";
System.out.print(str1 == str);//输出true,但这里的true并不代表str1和str相等
4、判断字符串为空
字符串为空:null和length=0
(1)当为null时,可以使用==来判断,但是不能使用length(会出现异常)
(2)当为""时,可以使用length判断
5、格式化
日期
使用String.format()方法来格式化日期(主要是年【Y】月【m】日【d】星期【a】)
转换符 含义 显示方法
%td 一个月中的第几天 05
%te 同上 5
%tm 月 01
%ty 年 11
%tY 年 2011
%ta 指定语言环境的星期简称 Sun
%tA 指定语言环境的星期全称 Sunday
%tb 指定语言环境的月份简称 Jan
%tB 指定语言环境的月份全称 January
实例:
System.out.println("未格式化日期:" + date);
System.out.println("两位天:" + String.format("%td",date));
System.out.println("一位天:" + String.format("%te",date));
System.out.println("两位月:" + String.format("%tm",date));
System.out.println("年:" + String.format("%ty",date));
System.out.println("年全写:" + String.format("%tY",date));
System.out.println("默认语言环境星期简称:" + String.format("%ta",date));
System.out.println("默认语言环境星期全称:" + String.format("%tA",date));
System.out.println("默认语言环境月份简称:" + String.format("%tb",date));
System.out.println("默认语言环境月份全称:" + String.format("%tB",date));
System.out.println("指定语言环境星期简称:" + String.format(Locale.US,"%ta",date));
System.out.println("指定语言环境星期全称:" + String.format(Locale.US,"%tA",date));
System.out.println("指定语言环境月份简称:" + String.format(Locale.US,"%tb",date));
System.out.println("指定语言环境月份全称:" + String.format(Locale.US,"%tB",date));
---------- java ----------
未格式化日期:Tue May 26 19:50:28 CST 2015
两位天:26
一位天:26
两位月:05
年:15
年全写:2015
默认语言环境星期简称:星期二
默认语言环境星期全称:星期二
默认语言环境月份简称:五月
默认语言环境月份全称:五月
指定语言环境星期简称:Tue
指定语言环境星期全称:Tuesday
指定语言环境月份简称:May
指定语言环境月份全称:May
输出完成 (耗时 0 秒) - 正常终止
时间
时-分-秒-毫秒-毫微秒-时间戳
H-M-S-L-N-Q
转换符 含义 显示方式
%tH 小时 00~13
%tI 小时 01~12
%tk 小时 0~23
%tl 小时 1~12
%tM 分钟 00~59
%S 秒 00~60(60是支持闰秒所需要的一个特殊值)
%tL 毫秒 000~999
%tN 毫微秒 000000000~999999999
%tp 特定语言环境的上下午 am/pm
%tZ 时区 CST
%ts 时间戳(秒) 值在Long.MIN_VALUE和Long.MAX_VALUE/1000之间
%tQ 时间戳(毫秒) 值在Long.MIN_VALUE和Long.MAX_VALUE之间
实例
System.out.println("未格式化时间:" + date);
System.out.println("时间戳:" + date.getTime());
System.out.println("小时:" + String.format("%tH",date));
System.out.println("分钟:" + String.format("%tM",date));
System.out.println("秒:" + String.format("%tS",date));
System.out.println("毫秒:" + String.format("%tL",date));
System.out.println("毫微秒:" + String.format("%tN",date));
System.out.println("时间戳:" + String.format("%tQ",date));
实际观测到:毫微秒这个值没有用,一直和毫秒相等
日期时间组合
转换符 显示方式
%tR 11:18
%tT 11:18:40
%tr 11:18:40 AM
%tD 02/28/09
%tF 2009-02-28
=================DateFormat======================
此类提供了静态方法以获取DateFormat实例
getDateInstance()
getDateInstance(dateStyle)
getDateInstance(dateStyle,locale)
getDateTimeInstance()
getDateTimeInstance(dateStyle,timeStyle)
getDateTimeInstance(dateStyle,timeStyle,locale)
getInstance():获取SHORT风格的默认日期时间格式化器
SimpleDateFormat类
允许用户自定义日期时间格式化模式
public SimpleDateFormat(String pattern)
使用的格式化符:y,M,d,h,m,s,
通过上述格式化符可以自定义自己的模式
如:String pattern = "yyyy.MM.dd ‘at‘ hh:mm:ss"
=================================================
常规数据
%b/%B 格式化为boolean,null为false,其余为true
%c/%C
%s/%S
%d 十进制
%o 八进制
%x/%X 十六进制
%e/%E 科学计数法
%% 字面常量%
6、正则表达式
元字符 正则表达式中写法 意义
. . 任意字符
\d \\d 数字
\D \\D 非数字
\s \\s 空白字符
\S \\S 非空白字符
\w \\w 可用于标示符的字符(不包括$)
\W \\W 不可用于标示符的字符
matches方法
实例:
验证电话号码的有效性
String regex ="^\\d{3,4}-?\\d{8}";
if(text.matches(regex)){
System.out.println(text+"是合法号码");
}else{
System.out.println(text+"是非法号码");
}
验证IP地址合法
String regex = "^(1\\d{2}|2[0-4]\\d|25[0-5]|[1-9]\\d|[1-9])\\."
+
"(1\\d{2}|2[0-4]\\d|25[0-5]|[1-9]\\d|[1-9])\\."
+
"(1\\d{2}|2[0-4]\\d|25[0-5]|[1-9]\\d|[1-9])\\."
+
"(1\\d{2}|2[0-4]\\d|25[0-5]|[1-9]\\d|[1-9])$"
简述题
- 为何需要面向对象
在较早的软件开发中,一般会存在以下问题:
软件重用性差
软件的可维护性差
开发出来的软件不能满足用户的需求变化- 什么是面向对象
面向对象编程(Object Oriented Programming)简称OOP技术,是开发应用程序的一种新方法,新思想。程序时许多对象在计算机中相机表现自己,而对象则是一个个程序实体- 面向对象的三大特性
封装性、继承性、多态性- 类的概念
类是具有相同性质和功能的事物构成的几何体,是对现实事物的一种抽象描述- 类和对象的区别
类时抽象的概念,用于创建对象;对象是类的实例,是客观世界知识存在的实体- 抽象类与抽象方法的作用
关键字abstract用于定义抽象类和抽象方法。抽象类是一种不可以被实例化的类。抽象方法中一般有抽象方法(在声明方法时,加上abstract关键字),当然也可有具体实现。继承类只有实现抽象类的所有抽象方法后才能被实例化- 接口和接口继承
接口是把多个继承类中的公共对象抽象出来并封装这些公共对象的行为。从接口是为了继承而存在的,如果没有继承也就不需要接口的存在。接口继承描述了一个对象可以在什么时候被用来替代另一个对象。- java中如何模拟多重继承
使用接口- 接口和抽象类有何区别
接口中的所有方法必须是抽象的,并且不能指定方法的访问修饰符。抽象类中可以有方法的实现,也可以制定方法的访问修饰符- 方法的重写
重写是指重新实现基类的方法。在运行过程中,如果将子类创建的对象赋值给子类的引用或父类的引用,则无论通过哪个类型的引用都将是子类中重写的方法。
如果希望调用父类中的放安抚,则需要通过父类创建类的实例,然后通过该实例才能访问父类定义的方法。重写方法是实现多态性的一个重要表现。- final,finally,finalize
final:修饰符,
修饰类,表示该类不能继承
修饰变量,表示该变量一旦赋值之后就不能更改
修饰方法,表示该方法不能被重写
finally:用于异常处理,修饰一个代码块
finalize:Object类中定义的一个方法,可以被重写,用于回收资源- 类成员访问权限
private protected public default
本类 可见 可见 可见 可见
相同包中的其他类 不可见 可见 可见 可见
不同包中的其他类 不可见 不可见 可见 不可见
相同包中的子类 不可见 可见 可见 可见
不同包中的子类 不可见 可见 可见 不可见- 构造方法的作用
创建类的实例,初始化数据成员- 方法重载
在java中,一个类的内部可以定义多个同名的方法,但是它们的方法参数要有所不同。Object类中的相关问题
- equals()的要求
要求有以下特征
自反性;
对称性;
传递性;
一致性;
对于任何非空引用值x,x.equals(null)返回false
equals方法的声明
public bollean equals(Object o){}
equals的默认操作时检测两个对象是否具有相同的引用- clone()
clone()方法是用来完成对象的浅克隆,所谓浅克隆是说被克隆的对象的各个域都是基本类型,而不是引用类型。如果存在引用类型的域,则需要进行深克隆。
@Override
public T clone(){}
如果克隆的对象的域包括引用类型,则需要使用深克隆,反之使用Object提供的clone方法进行浅克隆- 有两种方式可以实现深克隆,其效率如何?
序列化和依次克隆各个可变的引用类型都可以实现深克隆。但是序列化不理想
序列化克隆对象
@Override
public Employee clone(){
Employee employee = null;
ByteArrayOutputStream baos = new ByteArrayOutputStream();
try{
ObjectOutputStream oos = new ObjectOutputStream(baos);
oos.writeObject(this);
oos.close();
}catch(IOException e){
e.printStackTrace();
}
ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
try{
//从字节数组中读取对象
ObjectInputStream ois = new ObjectInputStream(bais);
employee = (Employee) ois.readObject();
ois.close();
}catch(IOException ioe){
ioe.printStackTrace();
}catch(ClassNotFoundException cnfe){
cnfe.printStackTrace();
}
}
如果不重写方法,也不会出错。
public class Test extends Thread
{
public void start(){
System.out.println("Start...");
}
public static void main(String[] args)
{
Test test = new Test();
test.run();
}
}
输出结果为空
需要注意的是Runnable是接口,所以一定要写run方法
而且要注意不能写错,
public void run(){
....
}
线程的常见属性
ID,Name,Priority,Daemon
ID: 标识线程,getId()获取,不可修改
Name: 标识线程,主要为了程序员区分线程,有setter和getter
Priority: 表示线程的优先级,优先级范围1-10,有setter和getter
Daemon: 表示线程是否是守护线程。守护线程是为其他线程提供服务。如果系统中仅剩下守护线程,则虚拟机会退出。可以使用setDaemon()设置
jion()和yield()
yield为其他线程临时让出CPU时间
jion使一个线程等待另一个线程结束(实现插队效果)
注意:jion有必检异常InterruptedException
名词解释
数据: 描述事物的符号记录,它是数据库存储的基本对象。数据的种类包括数字,文字,图片,图像等
数据库: 长期存储于计算机中的,有组织的,可共享的数据集合。
数据库管理系统:数据库系统的核心软件,它需要在操作系统的支持下工作。主要功能包括:数据定义功能,数据操纵功能,数据库运行管理,数据库建立维护等。
数据库系统: 在计算机系统中引入数据库后的系统,包括了数据库,数据库管理系统
实体间联系
一对一 学生和学号
一对多 班级和学生
多对多 课程和学生
SQL语言和关系数据库的三级模式
SQL
|
--------------------------
| |
视图1 视图2 ----------外模式
| |
------------------ ---------------
| | | | |
基本表1 基本表2 基本表3 基本表4 基本表5 ----------模式
| | | | |
| ------ | | -------
| | | | |
存储文件 存储文件 存储文件 ----------内模式
视图对应外模式,基本表对应模式,存储文件对应内模式
控制台输出MYSQL版本和当前时间
version() ——-输出当前MYSQL版本
now() ——-输出当前时间
mysql> SELECT version(),now()
数据库 | 驱动程序类 | 来源 |
---|---|---|
Access | sun.jdbc.odbc.JdbcOdbcDriver | JDK中 |
MySql | com.mysql.jdbc.Driver | 下载MySql驱动包 |
Oracle | oracle.jdbc.driver.OracleDriver | 下载对应的驱动包 |
SQL Server | com.microsoft.sqlserver.jdbc.SQLServerDriver | 下载对应的驱动包 |
为了使用驱动包,需要将下载的驱动包添加到类路径下面
(2)创建Connection类型对象
Connection connection = DriverManager.getConnection(databaseURL,username,password);
数据库 | URL模式 |
---|---|
Access | jdbc:odbc:dataSource,Access不需要username,password参数 |
MySQL | jdbc:mysql://hostname/dbname |
Oracle | jdbc:oracle:thin:@hostname:port#:oracleDBSID (port#表示端口号,oracleDBSID是定位数据库的数据库名,) |
SQL Server | jdbc:sqlserver://hostname:port;DatabaseName=数据库名 |
(3)获得Statement类型对象
Statement statement = connection.createStatement()
(4)执行查询或者更新
可以使用executeUpdate()执行SQL DDL(数据定义语言)或更新语句
可以使用executeQuery()执行查询语句
(5)处理ResultSet类型对象
查询结果存在ResultSet中,可以使用next()移动游标到下一行,使用getXXX(XXX为数据类型)获取当前行的列值
(6)释放资源
connection.close()
========PreparedStatement============
Statement接口用于执行不含参数的静态SQL语句
PreparedStatement接口用于执行含有或不含有参数的预编译的SQL语句
Connection接口中的preparedStatement() 可以创建PreparedStatement对象
例:
Statement preparedStatement = connection.prepareStatement(“insert into Student (firstname,mi,lastname) values(?,?,?)”);
解释:
三个问号(?)是占位符,可以使用setX(index,value),来设置
如:
preparedStatement.setString(1,”Jack”);
preparedStatement.setString(2,”J”);
preparedStatement.setString(3,”JR”);
然后就可以直接调用preparedStatement.executeQuery()和preparedStatement.executeUpdate()方法来执行上述准备好的语句
=====================================
========CallableStatement============
CallableStatement接口为执行SQL存储进程而设计
这个进程可能会有IN,OUT或IN OUT参数
=====================================
层 | 解释 |
---|---|
应用层 | 用于规定应用进程在通信时所应遵循的协议。 |
表示层 | 对上层的数据进行转换,如对数据的加密解密,压缩和格式等进行转换,以确保数据能够在两个主机的应用层进行正确的传输 |
会话层 | 用于建立,管理,终止进程间的会话,该层通过在数据中插入校验点,从而可以保证数据的同步传输 |
传输层 | 根据通信子网的特性,对网络资源进行最佳的利用,该层通过可靠和不可靠两种方式以报文为单位在源主机与目标主机的会话层建立、维护、取消传输连接 |
网络层 | 用于选择合适的网间路由和交换节点,以保证数据能够在经过很多数据链路或经过很多通信子网的计算机之间及时的传送,路由器是该层的典型设备 |
数据链路层 | 以帧为单位,在相邻两个节点间的线路上无差错的传输数据,并且接收方在接收到一帧数据时,对所接受的数据进行检测,如果数据存在差错,就通知发送方重新发送这一帧数据。交换机是该层的典型设备 |
物理层 | 用于在物理介质上传输可靠的原始比特流,Hub是该层典型的应用 |
TCP/IP
OSI TCP/IP
应用层 ————
|
表示层 —————> 应用层
|
会话层 ————
传输层 —————> 传输层
网络层 —————> 网络互联层
数据链路层 ———–
|
物理层 ———————–> 主机网络层
1、算法特性
输入: 零个或多个输入
输出:一个或多个输出
有穷性:执行步骤和执行时间
确定性:算法中任何指令的含义是确定的
可行性:算法可以用计算机支持的操作来完成
2、算法就地工作是指空间复杂度为O(1),即常量空间,而不是O(0),即不需要申请新的内存空间
3、顺序表逆置
public static void main(String[] args)
{
int[] arr = {1,2,3,4,5,6};
System.out.println(Arrays.toString(arr));
reverse(arr);
System.out.println(Arrays.toString(arr));
}
public static void reverse(int[] arr){
int low = 0;
int high = arr.length - 1;
while(low < high){
arr[low] = arr[low] ^ arr[high];
arr[high] = arr[low] ^ arr[high];
arr[low] = arr[low] ^ arr[high];
low++;
high--;
}
}
4、数组奇偶调整算法
public static void adjust(int[] arr){
int low = 0;
int high = arr.length - 1;
while(low < high){
//从左边寻找偶数
while(arr[low] % 2 != 0){
low++;
}
//从右边寻找奇数
while(arr[high] % 2 == 0){
high--;
}
if(low < high){
int temp = arr[low];
arr[low] = arr[high];
arr[high] = temp;
}
}
}
5、删除同值元素的算法
从顺序表中删除所有值为x的元素,空间复杂度为O(1)
/*================系统数组拷贝函数===============
System.arraycopy(source,startIndex,destination,startIndex,length);
===============================================*/
public static void main(String[] args)
{
int[] arr = {1,2,3,2,4,5,6,2,4};
System.out.println(Arrays.toString(arr));
int count = deleteSame(arr,2);
int[] newArray = new int[arr.length - count];
System.arraycopy(arr,0,newArray,0,newArray.length);
System.out.println(Arrays.toString(newArray));
}
public static int deleteSame(int[] arr,int same){
int count = 0;//统计相同值的个数,用于决定删除元素后,后续元素移动的位数
for(int i = 0; i < arr.length ; i ++){
if(count > 0){
arr[i-count] = arr[i];
}
if(arr[i] == same){
count++;
}
}
return count;
}
6、括号匹配算法
/*================字符串转数组和stack操作======================
toCharArray()
Stack
push(o:E):E
pop():E
peek():E
empty():
Queue
offer(e:E):boolean
空时返回null
poll():E
获取并删除队列头,空时返回null
peek():E
获取但不删除队列头,空时返回null
空时返回异常
remove():E
获取并删除对列头,空时返回一个异常
element():E
获取但不删除队列头,空时返回一个异常
=============================================================*/
public static boolean match(String expression){
//表达式转换成数组
char[] arr = expression.toCharArray();
Stack<Character> stack = new Stack<Character>();
//将第一个括号进栈
stack.push(arr[0]);
//遍历数组,左括号进栈,右括号判断是否出栈以及是否匹配
for(int i = 1 ;i < arr.length; i ++){
if(arr[i] == ‘(‘ || arr[i] == ‘[‘ || arr[i] == ‘{‘){
//当前括号是左括号则进栈
stack.push(arr[i]);
}else{
//当前括号是右括号则需要判断
char c = stack.peek();
switch(arr[i]){
case ‘)‘:
if(c == ‘(‘){
//匹配删除栈顶元素
stack.pop();
}else{
//不匹配
return false;
}
break;
case ‘]‘:
if(c == ‘[‘){
//匹配删除栈顶元素
stack.pop();
}else{
//不匹配
return false;
}
break;
case ‘}‘:
if(c == ‘{‘){
//匹配删除栈顶元素
stack.pop();
}else{
//不匹配
return false;
}
break;
}
}
}
if(stack.empty()){
return true;
}else{
return false;
}
}
7、霍夫曼树
霍夫曼树是带权路径最小的二叉树,核心思想是每一个从节点的权值中选择两个最小的构造树,并将它们的和作为一个新的节点
8、查找算法
静态查找:查找过程中元素不发生变化;
动态查找:查找过程中元素发生增加删除等变化
适合静态查找的算法:顺序查找,折半查找,散列查找
适合动态查找的算法:二叉树排序查找,散列查找折半查找:
public static int search(int[] arr ,int key){
int low = 0;
int high = arr.length - 1;
while(low <= high){
int mid = (low + high)/2;
if(key < arr[mid]){
high = mid - 1;
}else if(key > arr[mid]){
low = mid + 1;
}else{
return mid;
}
}
return -1;
}
9、排序
public static void insertSort(int[] arr){
for(int i = 0 ; i < arr.length ; i ++){
int tmp = arr[i];
int j = 0;
for(j = i - 1; (j > -1) && (tmp < arr[j]) ; j --){
arr[j + 1] = arr[j];
}
arr[j + 1] = tmp;
}
}
public static void bubbleSort(int[] arr){
int length = arr.length - 1;
int tmp = 0;
boolean flag = false;
while(length != 0){
flag = false;
for(int i = 0; i < length ; i ++){
if(arr[i] > arr[i+1]){
tmp = arr[i];
arr[i] = arr[i+1];
arr[i+1] = tmp;
flag = true;
}
}
System.out.println("第"+(arr.length-length)+"趟:"+Arrays.toString(arr));
length--;
if(flag == false){
//这个过程中不曾出现数据交换的动作,说明数组已经是有序的了
break;
}
}
}
public static void selectSort(int[] arr){
int tmp = 0;
int index = 0;
for(int i = 0 ; i < arr.length ; i ++){
index = i;
//查找[i...length]中的最小值
for(int j = i + 1; j < arr.length; j ++){
if(arr[index] > arr[j]){
index = j;
}
}
//最小元素不是本身
if(index != i){
tmp = arr[index];
arr[index] = arr[i];
arr[i] = tmp;
}
}
}
public static void mergeSort(int[] list){
if(list.length > 1){
//合并左半部分
int[] leftHalf = new int[list.length/2];
System.arraycopy(list,0,leftHalf,0,list.length/2);
mergeSort(leftHalf);
//合并右半部分
int rightHalfLength = list.length - list.length / 2;
int[] rightHalf = new int[rightHalfLength];
System.arraycopy(list,list.length / 2,rightHalf,0,rightHalfLength);
mergeSort(rightHalf);
int[] temp = merge(leftHalf,rightHalf);
System.arraycopy(temp,0,list,0,temp.length);
}
}
public static int[] merge(int[] list1,int[] list2){
int[] temp = new int[list1.length + list2.length];
int pos1 = 0;//list1游标
int pos2 = 0;//list2游标
int pos3 = 0;//temp游标
while(pos1 < list1.length && pos2 < list2.length){
if(list1[pos1] < list2[pos2]){
temp[pos3++] = list1[pos1++];
}else if(list1[pos1] > list2[pos2]){
temp[pos3++] = list2[pos2++];
}else{
temp[pos3++] = list2[pos2++];
temp[pos3++] = list1[pos1++];
}
}
while(pos1 < list1.length){
temp[pos3++] = list1[pos1++];
}
while(pos2 < list2.length){
temp[pos3++] = list2[pos2++];
}
return temp;
}
public static void quickSort(int[] arr,int low,int high){
if(high > low){
int part = partition(arr,low,high);
//System.out.println("part="+part);
quickSort(arr,low,part - 1);
quickSort(arr,part+1,high);
}
}
//找寻分界点
public static int partition(int[] arr,int low , int high){
int first = low;
int pivot = arr[low];
low++;
while(high > low){
//从左边找比pivot大的数
while(low <= high && arr[low] <= pivot ){
low++;
}
//从右边找比pivot小或等于的数
while(high >= low && arr[high] > pivot ){
high--;
}
//交换
if(high > low){
int temp = arr[high];
arr[high] = arr[low];
arr[low] = temp;
}
}
//此时high = low - 1;
//且high之前的元素都小于等于pivot,low之后的元素都大于pivot
//System.out.println("low="+low+";high="+high+":"+Arrays.toString(arr));
if(high > first){
int temp = arr[high];
arr[high] = arr[first];
arr[first] = temp;
//System.out.println("part="+high+":"+Arrays.toString(arr));
return high;
}else{
//System.out.println("part="+high+":"+Arrays.toString(arr));
return first;
}
}
public static void heapSort(int arr[]){
//初始化堆
initHeap(arr);
//System.out.println("初始化堆:" + Arrays.toString(arr));
//记录排好序的元素数
int count = 0;
int len = arr.length - 1;
while(count < arr.length){
//删除堆顶元素
int temp = arr[0];
arr[0] = arr[len - count];
arr[len - count] = temp;
count++;
//调整堆
adjustHeap(arr,len-count + 1);
//System.out.println("count:" + count);
}
}
public static void adjustHeap(int[] arr,int size){
//删除堆顶元素后,调整堆顶的位置
int current = 0;
while(current < size){
int left = current * 2 + 1;
int right = current * 2 + 2;
if(left < size && right < size){
//左右节点都存在
if(!(arr[current] >= arr[left] && arr[current] >= arr[right])){
//需要进行调整堆顶
int index = left;
if(arr[left] < arr[right]){
//左节点小于右节点
index = right;
}
int temp = arr[current];
arr[current] = arr[index];
arr[index] = temp;
current = index;
}
}else if(left < size && right > size){
//左节点存在但右节点不存在
if(arr[current] < arr[left]){
int temp = arr[current];
arr[current] = arr[left];
arr[left] = temp;
current = left;
}
}else{
//左右节点都不存在
break;
}
}
//System.out.println("size=" + size+ " :" + Arrays.toString(arr));
}
public static void initHeap(int[] arr){
//从0计数,则位置i的节点,左孩子在位置2i+1处,右孩子在位置2i+2处,而父节点在(i-1)/2处
for(int i = 1 ; i < arr.length ; i ++){
int current = i;
while(current > 0){
int parent = (current - 1) / 2;
//孩子节点大于父节点,则交换位置
if(arr[current] > arr[parent]){
int temp = arr[current];
arr[current] = arr[parent];
arr[parent] = temp;
current = parent;
}else{
break;
}
}
}
}
基础
软件的特点
逻辑性 软件产品通常包含大量的逻辑关系,通过这些关系对数据进行分析处理,获得用户需要的结果
非消耗性 一旦软件编写完毕,就可以在很多计算机上进行安装,正常的使用不会对软件产生任何消耗
针对性 软件产品是为了满足某些特定人群而“定做”的
无形性 软件产品本身没有任何实体,它需要与硬件结合使用才能体现价值,常见的光盘,U盘等是其重要的载体
昂贵性 软件产品开发过程需要消耗大量的脑力劳动,因此价格昂贵
软件的生存周期
可行性分析和定制开发计划
需求分析
总体设计
详细设计
编码
测试
维护
瀑布模型
--→需求分析 --------> 需求说明书
| |
| ↓
---设计←--- --------> 设计说明书
| |
↓ |
--→编码---- --------> 代码清单
| |
| ↓
---测试←-- --------> 测试报告
| |
↓ |
维护---- --------> 维护报告
优势:
要求软件开发前明确其需求,依靠各个阶段的严格执行控制软件质量,这样可以避免后期修正不完善的需求所耗费的大量精力。适用于功能和性能明确、开发过程中无重大修改的软件
劣势:
大于大型系统,用户在开发前不能完全确定和表述程序的需求,因此开发过程中难免设计功能的增加,按照瀑布模型的特点,如果已经进入了编码阶段,在增加功能,会涉及大量的文档的修改。程序在开发过程中,用户看不见软件是什么样的,因此不能及时提出修改意见。
可行性研究
技术可行性
经济可行性
社会可行性
标签:java面试宝典
原文地址:http://blog.csdn.net/havedream_one/article/details/46402857