Life

Wednesday, October 31, 2018

两个栈实现一个队列

如何用两个栈实现一个队列?
思路:
入栈:元素进入stack1;
出栈:
若stack2为空,stack1 不为空,将stack1所有元素出栈进入stack2,stack2从栈顶出栈;
若stack2不为空,则stack2栈顶出栈。
java代码实现示例:
package test;

import java.util.Stack;
/**
 * Title:StackToQueue
 * Description:两个栈实现一个队列
 * @author LeslieTian
 * @date   2018-10-30 下午8:18:43
 * @version 1.0
 */
public class StackToQueue {
    Stack stack1 = new Stack();
    Stack stack2 = new Stack();
    
    public static void main(String[] args) {
  StackToQueue s = new StackToQueue();
  s.add(3);
  s.add(4);
  s.add(5);
  System.out.println(s.delect());
  System.out.println(s.delect());
  System.out.println(s.delect());
  System.out.println(s.delect());
 }
    /**
     * 队列入队
     * @param x
     */
    public void add(int x){
     stack1.push(x);
    }
    /**
     * 队列出队
     */
    public int delect(){
     if((stack2.size()+stack1.size())!=0){//队列不为空
      if(stack2.isEmpty()){//stack2为空,stack1不为空
       //stack to stack2
       stack1Tostack2();
       return stack2.pop();
      }else{//stack2不为空
       return stack2.pop();
      }
     }
     else {//队列为空
      System.out.println("队列为空!");
      return -1; 
  }
    }
    public void stack1Tostack2(){//stack1 元素倒入stack2中
     while(!stack1.isEmpty()){
      stack2.push(stack1.pop());
     }
    }
}
输出:
3
4
5
队列为空!
-1
版权声明
本博客所有的原创文章,作者皆保留版权。转载必须包含本声明,保持本文完整,并以超链接形式注明作者Leslie Tien和本文原始地址:
https://leslietien.blogspot.com/2018/10/blog-post_30.html

Saturday, October 20, 2018

数据库数据的隔离级别

在MySQL数据库中,支持四种隔离级别:

① Serializable (串行化):可避免脏读、不可重复读、幻读的发生。
② Repeatable read (可重复读):可避免脏读、不可重复读的发生。
③ Read committed (读已提交):可避免脏读的发生。
④ Read uncommitted (读未提交):最低级别,任何情况都无法保证。

      四种隔离级别最高的是Serializable级别,最低的是Read uncommitted级别,当然级别越高,执行效率就越低。
      MySQL数据库支持上面四种隔离级别,默认的为Repeatable read (可重复读);而Oracle数据库只支持Serializable (串行化)级别和Read committed (读已提交)这两种级别,其中默认的为Read committed级别。
版权声明
本博客所有的原创文章,作者皆保留版权。转载必须包含本声明,保持本文完整,并以超链接形式注明作者Leslie Tien和本文原始地址:
https://leslietien.blogspot.com/2018/10/blog-post_19.html

Monday, October 15, 2018

ArrayList和LinkedList的add方法都是向尾部追加元素,谁更快?

      在看到这个问题时 ,我的第一反应就是LinkedList要快。通常我们所知道的关于ArrayList和LinkedList的区别就在与它们的实现方式不同导致的性能不同,ArrayList随即访问快,插入删除慢;LinkedList随即访问慢,插入删除快。
      不过经过更细致深入的学习后,对两者有了更深的理解。
ArrayList:内部使用数组的形式实现了存储,实现了RandomAccess接口,利用数组的下标进行元素的访问,因此对元素的随机访问速度非常快。但在从ArrayList中插入和删除元素时,移动变更位置之后的所有元素,所以插入和删除较慢。
但是,如果修改位置越靠前,需要位移的元素越多,开销越大,相反,修改位置越靠后的话,开销就越小了,如果在最后面进行插入,那就不需要进行位移;
LinkedList:内部使用双向链表的结构实现存储,LinkedList内部有一个header属性,用来标识起始位置,LinkedList的第一个单元和最后一个单元都会指向header,因此形成了一个双向的链表结构。也正因为这样,LinkedList的随机访问速度惨不忍睹,因为无论你要访问哪一个元素,都需要从header起步正向或反向(根据元素的位置进行的优化)的进行元素遍历。
      对ArrayList和LinkedList塞入上万个元素,或在指定位置连续插入元素。指定位置从头部开始逐步后移,ArrayList消耗的时间越来越短;
LinkedList插入元素是需要先进行元素的查找定位,然后才能进行首尾链接的拆分、重新指向新元素的,然而LinkedList的遍历有多低效,大家也是清楚明白的。
package test;

import java.util.ArrayList;
import java.util.LinkedList;
/**
 * 
 * Title:AddTime
 * Description:arraylist和linkedlist添加元素速度对比
 * @author LeslieTian
 * @date   2018-10-14 下午5:12:32
 * @version 1.0
 */
public class AddTime {
    public static void main(String[] args) {
  ArrayList arrayList = new ArrayList();
  LinkedList linkedList = new LinkedList();
  
  long ArrStart = System.currentTimeMillis();//获取ArrayList循环开始前时间
  for(int i=0;i<10000;i++){
   arrayList.add(i);
  }
  long ArrEnd = System.currentTimeMillis();//获取ArrayList循环结束的时间
  
  long LinkStart = System.currentTimeMillis();//获取LinkedList循环开始前时间
  for(int j = 0;j<10000;j++){
   linkedList.add(j);
  }
  long LinkEnd = System.currentTimeMillis();//获取LinkedList循环结束的时间
  
  if((ArrEnd-ArrStart)>(LinkEnd-LinkStart)){//时间对比
   System.out.println("ArrayList慢");
  }else {
   System.out.println("LinkedList慢");
  }
 }
}
输出:
LinkedList慢
所以说ArrayList对越靠近尾部的元素进行增删时效率其实要比LinkedList要高。
版权声明
本博客所有的原创文章,作者皆保留版权。转载必须包含本声明,保持本文完整,并以超链接形式注明作者Leslie Tien和本文原始地址:
https://leslietien.blogspot.com/2018/10/arraylistlinkedlistadd.html

static{}静态代码块

在最近的笔试过程中遇到一个关于静态代码块的题,代码大概是下面这样的:



package test;
/**
 * 
 * Title:A
 * Description:static 静态块
 * @author LeslieTian
 * @date   2018-10-14 下午4:52:11
 * @version 1.0
 */
class A{
 static{
  System.out.println("A.static");
 }
 public A() {
  System.out.println("A");
 }
}
class B extends A{
 static {
  System.out.println("B.static");
 }
 public B(){
  System.out.println("B");
 }
}

public class Static {
    public static void main(String[] args) {
  new B();
  new B();
 }
}
运行的结果是:

A.static
B.static
A
B
A
B
为什么会出现这样的结果呢?
static{}(即static块),会在类被加载的时候执行且仅会被执行一次,所以在类A与类B加载时执行static块输出
A.static
B.static
但是之后的创建类B的实例化对象时实例化了两个,只输出打印了一个,这是因为在虚拟机的生命周期中一个类只被加载一次;又因为static{}是伴随类加载执行的,所以,不管你new多少次对象实例,static{}都只执行一次。
另外,输出打印 ABAB 是因为子类在构造是会先执行父类的无参构造函数,又因为实例化两次,所以输出两次AB。
版权声明
本博客所有的原创文章,作者皆保留版权。转载必须包含本声明,保持本文完整,并以超链接形式注明作者Leslie Tien和本文原始地址:
https://leslietien.blogspot.com/2018/10/static.html

Friday, October 12, 2018

自动类型提升

java中使用二元操作符进行运算是会进行自动类型提升。
具体为:
如果两个操作数其中有一个是double类型,另一个操作就会转换为double类型。
  否则,如果其中一个操作数是float类型,另一个将会转换为float类型。
  否则,如果其中一个操作数是long类型,另一个会转换为long类型。
  否则,两个操作数都转换为int类型。
看例子:

  byte a = 5;
  byte b = 4;
  int c = a+b;//自动类型提升
  a+=b;//自加没有自动类型提升问题
  
  char char1 = 4;
  char char2 = 4;
  char cadd = (char) (char1 + char2);//自动类型提升
  char1 += char2;//自加没有自动类型提升问题
  
  short s = 4;
  short t = 5;
  int con = (s + t) ;//自动类型提升
  s += t;//自加没有自动类型提升问题

                byte bt = 1;
  char ch = 5;
  short sh = 5;
  int   i = 6;
  long  l =5l;
  float f = 6.6f;
  double j = 5.7;

                long add = l + i ;  //long + int 结果为long型
  long add2 = l + sh ;//long + short 结果为long型
  float add3 = l + f; //long + float 结果为float型
  double add4 = l + j;//long + double 结果为double型
  
  float add5 = i + f; //int + float 结果为float型
  double add6 = i + j;//int + double  结果为double型
        
                int add7 = i + ch;
  int add8 = i + sh;
  int add9 = i + bt;//int +(byte,short,char) 结果为int型
但是有一点要注意,final修饰的byte, short, char变量相加后不会被自动提升。

  final char fch = 5;
  final char fch1 = 6;
  char fch2 = fch + fch1;//类型没有提升
版权声明
本博客所有的原创文章,作者皆保留版权。转载必须包含本声明,保持本文完整,并以超链接形式注明作者Leslie Tien和本文原始地址:
https://leslietien.blogspot.com/2018/10/blog-post.html

Wednesday, October 10, 2018

基本数据类型转换

        java允许除布尔类型之外的所有其他基本数据类型之间的相互转换。
      类型转换有两种基本方式。把某种类型的值转换为取值范围更广的类型,此时执行的是放大转换(widening conversion)。放大转换是隐式类型转换,也叫作自动类型转换, 由系统自动完成.是从存储范围小的类型转到存储范围大的类型。
      另一种方式是缩小转换(narrowing conversion)。把一个值转换为取值范围小的类型执行的是缩小转换。缩小转换是显示类型转换也叫作强制类型转换,此时可能会丢失精度。
这里要注意的是,byte可以隐式类型转换到short类型,但是需要强制类型转换到char类型。同时,short和char类型之间的类型转换也需要强制类型转换。

byte bt = 1;
char ch = 5;
short sh = 5;
ch = (char) bt;//byte转char需要强制转换
sh = bt;       //byte 转short是隐式转换
sh = (short) ch;//short 与 char 之间转换也是强制转换
ch = (char) sh;

我们知道char和short类型都占两个字节,为什么会出现这种情况呢?实际上虽然都是占两字节,但是表示的范围却不一样。
byte表示的范围是-2ˆ7~2ˆ7-1
char表示的范围是0~2ˆ16-1;
short表示的范围是-2ˆ15~2ˆ15-1
通过这几个范围我们就可以明白为什么byte转short是隐式转换,转char就要是显式转换。因为byte的表示范围在short表示范围内,但不再char的表示范围内。
char和short表示的范围不同,所以它们之间需要强制转换。
版权声明
本博客所有的原创文章,作者皆保留版权。转载必须包含本声明,保持本文完整,并以超链接形式注明作者Leslie Tien和本文原始地址:
https://leslietien.blogspot.com/2018/12/blog-post_94.html