Life

Thursday, December 27, 2018

兼职

临近期末,学校业已结课。闲来无事,找个兼职挣点饭钱。
兼职内容就是帮这个公司把书画装进画框,挂起来调好位置,贴上标签,打好灯光之类的一系列工作。
前期准备工作一共做了五六天,装了大概二百张字画。

还有两天展览之后就是拍卖,然后我们再把字画取出来:)就完事啦----

其实还蛮辛苦的:-I


不过呢,做兼职挣钱是一方面,更多的还是接触到更多的人事物,见识到其他行业,了解它们的日常,最终开拓自身的视野。
版权声明
本博客所有的原创文章,作者皆保留版权。转载必须包含本声明,保持本文完整,并以超链接形式注明作者Leslie Tien和本文原始地址:
https://leslietien.blogspot.com/2018/12/blog-post_27.html

Tuesday, December 25, 2018

考研&工作

      考研,结束了。尽管我并不是考研大军的一员,但在这近一年的时间里,我看着我的室友为考研拼搏,努力,我置身其中,心中多少有些感受。
      回首近一年前,那时所有的我们都面临着一个问题,是找工作还是考研?考研的理由千千万,工作的理由也不少。历数我的三个考研室友,原因或觉得本科所学东西太少,找工作没优势,或觉得本专业不符合自己的喜好,跨考其他学校和专业。于是他们下定决心参加考研。就本人而言,这些原因当初我也考虑过的啊。我是真正喜欢这个专业,这个行业吗?似乎并不是。高考后填报志愿时我并没有选择此专业,换言之,我其实是调剂过来的。我专业课学的很好,足够支持我去找一个好工作吗?其实也不是。我专业课学的并不好,专业技术并不过关。那么我为什么没有选择去跨考一个自己中意的专业或者是考一个研究生继续深造提高技术水平呢?原因当然很多啦。人生哪能都随自己心意呢。其实说实话,我也不知道我喜欢做什么,或者我想从事什么行业,我并没有清晰的目标。那既然调到这里了,那就干下去吧。
      那又为什么没有考研深造呢?说服我自己的最大理由可能就是我懒吧。高考是一群人的狂欢,考研是一个人的战斗。高中时的我们一个班,一个年级在一起为高考奋斗,有一堆老师,家长在后面推着我前进。学校和老师为我们规划好复习的顺序,进度,为我们准备好月考,一模,二模,三模,我们就像新兵连的一群新兵,经过长时间训练,一次次演习,最终集体走向战场接受洗礼,人是社会动物,集体行动能有效减轻个人的畏惧心理。我们就那样走过来了。而考研呢,自己为自己规划进度,选购资料。无人敦促,鼓励,监督。一切靠自己。我认为自己不想,不愿,也不一定能坚持到最后。我畏惧了,我不想再过那样的生活,又一年。一直以来,我都敬佩选择考研的学生,他们都是勇士。
      当然,这只是一个方面。再有就是,我不想再向家里伸手了。无论学的如何,找的工作如何,我都想出去闯一闯。学习不一定非要在学校是吧。我廿二岁了,读了十几年书,我迫切的希望去体现自己的价值,实现经济独立。
再有可能就是本专业本科学历工作也可以,学校实力尚可,父母年纪不小了,等等的原因吧。

      于是最终我选择工作了。学习并不突出,能力也不强,我也不会好高骛远。看看面经,复习专业知识,看看项目,前后可能投了有30家公司?也许不至吧。最后也收到一个还算满意的offer。也许大学生涯就这样了吧。
      秋招告一段落,考研也落下帷幕。唯愿所有考研的有学上,找工作的有班上。敬所有不甘平凡的灵魂。
版权声明
本博客所有的原创文章,作者皆保留版权。转载必须包含本声明,保持本文完整,并以超链接形式注明作者Leslie Tien和本文原始地址:
https://leslietien.blogspot.com/2018/12/vs.html

Sunday, December 9, 2018

FAR:Long Sails完结感言

     周末放松时间,在steam弄了个新游戏体验一番:FAR:Long Sails。
花了不到四个小时完成主线通关。
       游戏的流程并不是特别长,难度也不大,不过游戏的剧情以及环境角色的刻画都非常不错,喜欢末日风格的玩家可以尝试一下这款游戏。
      回到游戏本身,这是一款废土蒸汽朋克风格的横版解密向游戏。在游戏里,你将控制一名身穿红衣的少年,操纵一辆比他大得多的蒸汽机车,一路走到游戏的最后。精致的画风和背景音乐,以至于游戏的每一帧都能做壁纸的存在;每一种音乐都能让人跌宕起伏,带耳机玩《FAR:Long Sails》,会让你更加沉浸在游戏里。
       一路上,你将获得不同的补给,有时是升级你的车的装备,有时是能够驱动机车的能源,有时是一些精致的小玩意儿,让你的旅途不在枯燥无味。当然,也少不了一路上机车的磨损和故障。一旦你赖以生存的车坏了,你的游戏也结束了。
       开局你将驾驶你在这末世的唯一依靠:一辆蒸汽机车,踏上未知的旅程。
      不久之后你将装上风帆,在有风的时候升起你的风帆前进可以节省燃料。
升起你的帆,在朝阳的光辉中前行,此时游戏响起悠扬的音乐,似乎我们的小主人公心情不错。高耸的风力发电机仍孤独的旋转,这里都曾是人类活动的领域,如今只剩这些死物等待着后来者向他们诉说这里曾经的辉煌。


游戏中仅有两次的出现生物,一次是羊群,一次是几只小鸟。人类寻无踪迹,而少数动物在恶劣的环境里艰难生存,似乎昭示着新一轮的生物大繁荣。


       在游戏中,你会有一种浓重的压抑感,孤独的人儿,独自前行,随处可见的废墟,巨大的,破碎的,搁浅的轮船。




       令人印象深刻的一段剧情是主人公登上一座信号塔,调整接受频率,寂静的夜空下突然从收音机中传出了歌声,想象一下,一人在末世孤独求生,那压抑了许久的心情在突然听到同类的声音时彻底释放,那一刻你知道你并不孤单。



       在游戏的末尾,发生了火山喷发,我们的庇护所也断成两节,无力前行。挣扎着走到终点,竟是海岸。似乎末世类题材作品,像电影还有游戏,很喜欢将终点设在海边,就如同那句歌词“越过山丘,却发现无人等候”,历经千辛万苦,到头来也只得”望洋兴叹“,多么令人绝望啊。我们默默的点亮灯塔,在夕阳下迎着海风瑟瑟发抖,天色越来越暗,越来越黑,最终是死一般的沉寂。





        然而,于黑暗之中传来一阵悠扬的汽笛声~~
版权声明
本博客所有的原创文章,作者皆保留版权。转载必须包含本声明,保持本文完整,并以超链接形式注明作者Leslie Tien和本文原始地址:
https://leslietien.blogspot.com/2018/12/farlong-sails.html

Friday, December 7, 2018

读书人要站直

       近期北大校园暗流涌动,不甚太平~听闻北大校园内出现不明身份人士对北大学子进行殴打和绑架,学校保安队无所作为,后又有北大学生食堂内发传单意图扩散消息,声援同学遭到保安阻拦。事情最早的起因不过是学生参与声援深圳佳士工人维权活动罢了。
       似乎在学校和政府领导人看来,大学生应该埋头学习,做到“两耳不闻窗外事,一心只读圣贤书”即可,社会上的事情都与自己无关.。不该听,不该看,不该管,不该参与。甚至美名其曰“拉你一把”。
       知识分子,读书人自古以来皆以天下苍生为己任,心系国家,心系百姓。亦如屈原之“长太息以掩涕兮,哀民生之多艰”,范仲淹之“先天下之忧而忧,后天下之乐而乐”。中华民族悠长历史上,这样的“读书人”太多太多。岂知到了今日,读书求学只是为了求名,求利。培养大学生成为“精致的利己主义者”。好在还是有很多同学不甘如此,勇于发声,令人敬佩。
       前些天,还是北大,北京大学元培学院常务副院长李沉简,借戊戌变法、北京大学建校120年以及纪念前校长蔡元培的机会,发表一篇题为《挺直脊梁拒做犬儒》的文章,明言’高级知识分子里的无耻之徒丝毫不比普罗大众少’,‘自由是有骨气的人们付出沉重的代价换来的’,读来发人深省。

        挺直脊梁 拒做犬儒

戊戌变法、北大建校一百二十年,我们纪念蔡元培校长。在中国近代史上,元培先生当之无愧是现代教育之父。他留给我们的“兼容并包,思想自由”是北大的精神火炬,代代相传。蔡校长在人们的印象里总是一个谦谦君子式的思想领袖。其实蔡校长的另外一个侧面同样是万世师表,那就是一个挺直脊梁、拒绝做犬儒的男子汉。
早年的元培先生为了反抗清朝,一介书生却豁出命来组织训练暗杀团,意图刺杀清朝的官员。在后面的几十年里,他只认真理,不畏强权,在北大校长的任上曾先后八次辞职以示抗议:1917年抗议张勋复辟清朝而辞职;1919年5月营救被捕学生而辞职;1919年底和1920年1月支持北京市教职员为薪酬抗议政府而辞职;1922年8月/9月两次为政府侮辱校长/拖欠教育经费而辞职;1923年抗议教育总长践踏人权和司法独立而辞职;1926年抗议政府镇压学生而辞职。 从这个意义上看,元培先生的“兼容并包,思想自由”是付出了极大的个人牺牲才使得当时的北大空前活跃——既有全盘西化的胡适、也有追求共产主义的陈独秀李大钊毛泽东、甚至还有天天嚷着复辟清朝的拖辫子的辜鸿铭。各种思想在这里产生和碰撞。
Freedom is never free. 自由从来不是天上掉下来的,而是有骨气的人们付出沉重的代价换来的,其中北大的先人多有这样的典范:胡适一辈子敢于批评蒋介石和国民党专制;马寅初坚持自己的学术观点,在批判之下拒不认错;林昭在疯狂的文革年代毫不退缩,只身和反人类的罪恶斗争到底,直至被枪杀。北大之所以成为中国神圣的殿堂,不仅因为她有思想,更因为她有为了理念不惜付出一切的师生。
可是我们也要清醒客观地看到,上下五千年的历史,有脊梁的毕竟是少数,更多的是软骨头甚至为虎作伥:抗日战争里,中国创了人类历史上“伪军比占领军多”的记录;在大跃进、文革中,究竟有多少人是“受蒙蔽”,有多少人是精明地昧着良心、为自保而诬陷同事、为加官进爵而落井下石?
不仅民间“人在屋檐下不得不低头”,“好死不如赖活着”之类犬儒的生活教条深入人心,高级知识分子里的无耻之徒丝毫不比普罗大众少。上古就有在“指鹿为马”的当口曲意奉承、吮痈舐痔的臣子;当代有郭沫若这样满腹诗书的墙头草;更可怕的是像经过加州理工学院最良好科学训练的钱学森也连篇累牍地在报纸上为“亩产十几万斤”这样尽人皆知、笑掉大牙的谎言摇旗呐喊,而且还舔着脸发“钱学森之问”——殊不知我们没有科学、人文社科大师的第一原因就是我们的教育系统性地培养精明乖巧的撒谎者,而不是真理的捍卫者:这和知识无关,和人格有关。
这样的犬儒和无耻何以盛行?除了人性中固有的懦弱和卑微,社会几千年来对敢言者的持续绞杀当属首要原因。从文字狱到株连十族,当敢于“一士之谔谔”的人被消灭的时候,负淘汰的结果自然剩下的是“千士之诺诺”。在这种千年严酷的条件下,人们甚至被剥夺了保持沉默的权利,而被强迫加入谄媚奉承的大合唱。
不过,在漫长的历史中总有火种还顽强地燃烧。在北大,蔡元培、马寅初、胡适、林昭……承载着北大人的傲骨,公民的尊严。我们即使做不到振臂一呼,以笔为旗与懦弱卑微做不妥协的抗争,也至少做到不出卖人的起码尊严和思想独立。北大人、元培人当共勉。
Where there is darkness,may we bring light
Where there is despair, may we bring hope
Where there is doubt, may we bring faith
Where there is hatred, may we bring love
戊戌双甲子,诸君拒做犬儒,
北大一二〇,师生挺直脊梁。
李沉简
2018.2.28
北京大学 朗润园
版权声明
本博客所有的原创文章,作者皆保留版权。转载必须包含本声明,保持本文完整,并以超链接形式注明作者Leslie Tien和本文原始地址:
https://leslietien.blogspot.com/2018/12/120-19171919519191920119228919231926.html

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

Sunday, September 30, 2018

希尔排序

基本概念

希尔排序是一种基于插入排序的快速排序算法,希尔排序的时间复杂度和其增量序列有关系,并无确定值。希尔排序的空间复杂度是O(1),即属于就地排序,希尔排序属于不稳定的排序。

算法思想

将无序数组分割为若干个子序列,子序列不是逐段分割的,而是相隔特定的步长的子序列,对各个子序列进行插入排序;然后再选择一个更小的步长,再将数组分割为多个子序列进行排序……最后选择步长为1,即使用直接插入排序,使最终数组成为有序。

算法描述

我们用一个例子来描述希尔排序的过程:
给出一无序数组:5, 3, 6, 2, 1, 7, 9, 8, 0, 4
取步长为5,将数组划分为5个子数组。为使读者明白,在这里采用[下标]-值的形式表示:
第一个子数组:[0]-5 , [5]-7
第二个子数组:[1]-3 , [6]-9
第三个子数组:[2]-6 , [7]-8
第四个子数组:[3]-2 , [8]-0
第五个子数组:[4]-1 , [9]-4
对这五个数组分别进行插入排序,排序后的结果:
[0]-5 , [5]-7
[1]-3 , [6]-9
[2]-6 , [7]-8
[3]-0 , [8]-2
[4]-1 , [9]-4
合并起来就是: 5,3,6,0,1,7,9,8,2,4
第二次取步长为5-1=4,可划分为四个子数组:
第一个子数组:[0]-5 , [4]-1 , [8]-2
第二个子数组:[1]-3 , [5]-7 , [9]-4
第三个子数组:[2]-6 , [6]-9
第四个子数组:[3]-0 , [7]-8
再次对每个子数组进行插入排序,排序结果:
[0]-1 , [4]-2 , [8]-5
[1]-3 , [5]-4 , [9]-7
[2]-6 , [6]-9
[3]-0 , [7]-8
合并后为:1,3,6,0,2,4,9,8,5,7
依次类推
第三次取步长为3,排序后为:0 ,2 ,4, 1, 3 ,5, 7 ,8 ,6 ,9 
第四次取步长为2,排序后为:0 ,1 ,3 ,2, 4 ,5 ,6, 8, 7, 9 
第五次取步长为1,排序后为:0 ,1 ,2, 3 ,4 ,5 ,6 ,7 ,8 ,9

算法实现



package test;
/**
 * Title:ShellSort
 * Description:希尔排序
 * @author LeslieTian
 * @date   2018-9-29 下午5:06:59
 * @version 1.0
 */
public class ShellSort {
    public  static void shellSort(int[] arr){
     int h = arr.length/2;//初始步长取排序数组长度的一半
     if(h==0){
      return;
     }
     while(h>=1){
      for(int i = h; i < arr.length;i++){
       for(int j = i; j >= h && arr[j] < arr[j-h];j -= h){
        swap(arr,j,j-h);
       }
      }
      System.out.print("步长为" +h+ ": ");//输出一次循环后的数组
      for(int word : arr){
       System.out.print(word + " ");
      }
      System.out.println("\n");
      h -= 1;
     }//while
    }//method-shellSort
    
    public static void swap(int arr[],int x,int y){
     int temp;
     temp = arr[x];
     arr[x] = arr[y];
     arr[y] = temp;
    }
 
 public static void main(String[] args) {
       int arr[]= {5,3,6,2,1,7,9,8,0,4} ;
       shellSort(arr);
 }
}
运行结果:

步长为5: 5 3 6 0 1 7 9 8 2 4 

步长为4: 1 3 6 0 2 4 9 8 5 7 

步长为3: 0 2 4 1 3 5 7 8 6 9 

步长为2: 0 1 3 2 4 5 6 8 7 9 

步长为1: 0 1 2 3 4 5 6 7 8 9
版权声明
本博客所有的原创文章,作者皆保留版权。转载必须包含本声明,保持本文完整,并以超链接形式注明作者Leslie Tien和本文原始地址:
https://leslietien.blogspot.com/2018/12/blog-post_7.html

Friday, September 28, 2018

HashMap与TreeMap有什么区别?

先说相同点:
都实现了Map接口。
HashMap、TreeMap都是非线程安全的。顺便提一下HashTable,它是线程安全的,全,它支持线程的同步,即任一时刻只有一个线程能写Hashtable,然而,这也导致了Hashtable在写入时会比较慢。

不同点:
在性能上,HashMap:适用于在Map中插入、删除和定位元素。TreeMap:适用于按自然顺序或自定义顺序遍历键(key)。 TreeMap能够把它保存的记录根据键排序,默认是按升序排序,也可以指定排序的比较器。当用Iteraor遍历TreeMap时,得到的记录是排过序的。
TreeMap的键和值都不能为空。HashMap最多只允许一条记录的键为Null;允许多条记录的值为 Null。
看一个例子:

package test;

import java.util.Map;
import java.util.TreeMap;

public class TreeMapTest {
      public static void main(String[] args) {
        Map tree = new TreeMap();
        int [] a={9,8,7,6,5,4,3,2,1,0};
        for(int i=0; i<10 i<10;i++){
            tree.put(a[i],i );
        }
        for(Integer key:tree.keySet()){
            System.out.print(tree.get(key) + " ");
        }
     }
}
输出结果是:

9 8 7 6 5 4 3 2 1 0
可以发现,TreeMap把它保存的记录按照键进行了排序,并且是按升序排序。
版权声明
本博客所有的原创文章,作者皆保留版权。转载必须包含本声明,保持本文完整,并以超链接形式注明作者Leslie Tien和本文原始地址:
https://leslietien.blogspot.com/2018/12/hashmaptreemap.html

Monday, September 24, 2018

java基本原则

java设计模式中应当遵循的基本原则:

<单一职责原则>我们把职责定义为系统变化的原因。所以在定义类,接口,方法的时候,如果有多余一个的动机去改变这个类,接口,方法,那么说明定义的类,接口,方法多余一个职责。单一职责原则宗旨是每个接口、类的功能,只能用来做专门的事,做到功能单一。

<开放封闭原则>一个模块、类、方法在扩展性方面应该是开放的而在更改性方面应该是封闭的。 开放封闭原则体现在若要在已有系统基础上进行需求拓展时,通过添加新类或者新代码来实现,对已有代码做到最少修改,甚至是零修改。这就要求开发人员对程序中频繁变化的地方进行抽象,即对变化的修改关闭。对于变化的不确定性,可通过继承的使用,抽象类的运用来随时扩展。

<里氏替换原则>保证子类可以替换它的父类。对于一组具有类似属性,方法,变量的类。我们可以提取公共属性,方法,变量做为一个基类(抽象类或者类),使这一组类继承基类,重写虚方法。现在这些继承的类和基类的关系符合替换原则。

<依赖倒置原则>面向接口编程,依赖于抽象而不依赖于具体。通过接口或者抽象类提供依赖关系。写代码时用到具体类时,不与具体类交互,而与具体类的上层接口交互。

<接口分离原则>模块间要通过抽象接口隔离开,而不是通过具体的类强耦合起来。

<迪米特原则>又叫最少知识原则; 对象与对象之间应该使用尽可能少的方法来关联,避免千丝万缕的关系;  低耦合; 类知道其他类应尽量少; 类可以访问其他类的方法或者属性也应尽量少。

       总之,六大设计原则是代码设计的基本原则。设计原则规范了开发人员如何去设计和实现代码,来提高程序的规范性、可读性、扩展性和维护性。
      更多参考资料:
版权声明
本博客所有的原创文章,作者皆保留版权。转载必须包含本声明,保持本文完整,并以超链接形式注明作者Leslie Tien和本文原始地址:
https://leslietien.blogspot.com/2018/12/java_6.html

Saturday, September 22, 2018

JDK的bin目录下都有哪些内容?


这是java的JDK的bin目录下的一部分,可以看到有很多*.exe,他们都是开发工具执行文件。这些工具是JDK的基础,用这些工具来编写应用程序。平时我们用不到这么多,在这里简单归纳整理一些常见的exe文件的用途:
  1. javac.exe:Java编译器,将Java源代码换成字节代码,即.class文件。在DOS命令行编译java文件会用到此命令。
  2. java.exe:这个应该是最熟悉的了,Java解释器,应用程序启动器。直接从类文件执行Java应用程序代码 。
  3. javadoc.exe:根据Java源代码及其说明语句生成的HTML文档。
  4. jdb.exe:Java调试器,可以逐行地执行程序、设置断点和检查变量。
  5. jar.exe:多用途的存档及压缩工具,是个java应用程序,可将多个文件合并为单个JAR归档文件。
  6. javap.exe:Java反汇编器,显示编译类文件中的可访问功能和数据,同时显示字节代码含义。
  7. javah.exe:头文件生成器,javah程序创建C头文件和存根文件,这些是把本地C成员函数包入java 所需要的。被创建的头文件给出了有关java类的信息,这些信息是C成员函数与java类交换数据所必需的。存根文件将用来创建将定义java对象的结构与java对象本身数据相联系的C文件。
  8. extcheck.exe:扩展检测工具,主要用于检测指定jar文件与当前已安装的Java SDK扩展之间是否存在版本冲突。
  9. javaw.exe:Java运行工具,用于运行.class字节码文件或.jar文件,但不会显示控制台输出信息,适用于运行图形化程序。
  10. javaws.exe:Java Web Start,使您可以从Web下载和运行Java应用程序,下载、安装、运行、更新Java应用程序都非常简单方便。
  11. jcmd.exe:Java 命令行(Java Command),用于向正在运行的JVM发送诊断命令请求。
  12. jconsole.exe:图形化用户界面的监测工具,主要用于监测并显示运行于Java平台上的应用程序的性能和资源占用等信息。
如有纰漏,请不吝赐教,谢谢!
版权声明
本博客所有的原创文章,作者皆保留版权。转载必须包含本声明,保持本文完整,并以超链接形式注明作者Leslie Tien和本文原始地址:
https://leslietien.blogspot.com/2018/12/jdkbin.html

Wednesday, September 5, 2018

排序算法

常用排序算法归纳
评价排序算法好坏的标准:
1.执行时间和所需的辅助空间。
2.算法本身的复杂程度。

排序稳定性时间复杂度空间复杂度
气泡排序(bubble sort)稳定最差、平均为O(n²),最好为O(n)1
插入排序(insertion sort)稳定最差、平均为O(n²),最好为O(n)1
归并排序(merge sort)稳定最差、平均和最好都是O(nlog n)O(n)
二叉树排序(Binary tree sort)稳定O(nlog n)O(n)
选择排序(selection sort)不稳定最差、平均都是O(n²)1
堆排序(heapsort)不稳定最差、平均和最好都是O(nlog n)1
快速排序(quicksort)不稳定平均是O(n log n),最坏情况O(n²)O(log n)
版权声明
本博客所有的原创文章,作者皆保留版权。转载必须包含本声明,保持本文完整,并以超链接形式注明作者Leslie Tien和本文原始地址:
https://leslietien.blogspot.com/2018/12/blog-post.html

Thursday, June 28, 2018

String-StringBuffer-StringBuilder

String、StringBuffer、StringBuilder之间有什么区别呢?
先说一说String和StringBuffer的不同之处。
String 类型和 StringBuffer 类型的主要性能区别其实在于 String 是不可变的对象,因此在每次对 String 类型进行改变的时候其实都等同于生成了一个新的 String 对象,然后将指针指向新的 String 对象,所以经常改变内容的字符串最好不要用 String ,因为每次生成对象都会对系统性能产生影响。
而如果是使用 StringBuffer 类则结果就不一样了,每次结果都会对 StringBuffer 对象本身进行操作,而不是生成新的对象,再改变对象引用。
所以在一般情况下推荐使用 StringBuffer ,特别是字符串对象经常改变的情况下。而在某些特别情况下,String 对象的字符串拼接其实是被 JVM 解释成了 StringBuffer 对象的拼接,所以这些时候 String 对象的速度并不会比StringBuffer 对象慢,而特别是以下的字符串对象生成中, String 效率是远要比 StringBuffer 快的。
String S1 = “This is only a” + “ simple” + “ test”;
StringBuffer Sb = new StringBuilder(“This is only a”).append(“ simple”).append(“ test”);
你会惊讶的发现,生成 String S1 对象的速度简直太快了,
而这个时候 StringBuffer 居然速度上根本一点都不占优势。其实这是 JVM对String类进行的优化处理,在JVM眼里,这句生成 String S1 对象的代码相当于

String S1 = “This is only a simple test”;
       StringBuffer是Synchronized的,即线程安全的。如果要频繁对字符串内容进行修改,出于效率考虑最好使用 StringBuffer,如果想转成 String 类型,可以调用 StringBuffer 的 toString() 方法。
      StringBuffer 上的主要操作是 append 和 insert 方法,可重载这些方法,以接受任意类型的数据。每个方法都能有效地将给定的数据转换成字符串,然后将该字符串的字符追加或插入到字符串缓冲区中。
      append 方法始终将这些字符添加到缓冲区的末端; insert 方法则在指定的点添加字符。 例如,如果 z 引用一个当前内容是 start 的字符串缓冲区对象,则此方法调用 z.append(“le”) 会使字符串缓冲区包含 startle ,而 z.insert(4, “le”) 将更改字符串缓冲区,使之包含 starlet 。
      再看StringBuilder。java.lang.StringBuilder是一个可变的字符序列,是5.0新增的。此类提供一个与 StringBuffer 兼容的 API,但不保证同步。该类被设计用作 StringBuffer 的一个简易替换,用在字符串缓冲区被单个线程使用的时候(这种情况很普遍)。如果可能,建议优先采用该类,因为在大多数实现中,它比 StringBuffer 要快。两者的方法基本相同。
      因此,在大部分情况下,StringBuilder > StringBuffer。这主要是由于前者不需要考虑线程安全。
总结一下:
  1. 1>如果要操作少量的数据,用String ;单线程操作大量数据,用StringBuilder ;多线程操作大量数据,用StringBuffer。
  2. 2>不要使用String类的”+”来进行频繁的拼接,因为那样的性能极差的,应该使用StringBuffer或StringBuilder类,这在Java的优化上是一条比较重要的原则。
  3. 3>为了获得更好的性能,在构造 StringBuffer 或 StringBuilder 时应尽可能指定它们的容量。当然,如果你操作的字符串长度(length)不超过 16 个字符就不用了,当不指定容量(capacity)时默认构造一个容量为16的对象。不指定容量会显著降低性能。
  4. 4>StringBuilder 一般使用在方法内部来完成类似 + 功能,因为是线程不安全的,所以用完以后可以丢弃。StringBuffer 主要用在全局变量中。
  5. 5>相同情况下使用 StringBuilder 相比使用 StringBuffer 仅能获得 10%~15% 左右的性能提升,但却要冒多线程不安全的风险。而在现实的模块化编程中,负责某一模块的程序员不一定能清晰地判断该模块是否会放入多线程的环境中运行,因此:除非确定系统的瓶颈是在 StringBuffer 上,并且确定你的模块不会运行在多线程模式下,才可以采用 StringBuilder;否则还是用 StringBuffer。
版权声明
本博客所有的原创文章,作者皆保留版权。转载必须包含本声明,保持本文完整,并以超链接形式注明作者Leslie Tien和本文原始地址:
https://leslietien.blogspot.com/2018/12/string-stringbuffer-stringbuilder.html

Monday, June 11, 2018

sleep()与wait()的区别

1.

这两个方法来自不同的类.分别是:sleep来自Thread类,和wait来自Object类。

2.

最主要是sleep方法没有释放锁,而wait方法释放了锁,使得其他线程可以使用同步控制块或者方法。
sleep不出让系统资源,sleep方法只让出了CPU,而并不会释放同步资源锁,sleep() 是static静态的方法,他不能改变对象的机锁,当一个synchronized块中调用了sleep() 方法,
线程虽然进入休眠,但是对象的机锁没有被释放,其他线程依然无法访问这个对象;
wait是进入线程等待池等待,出让系统资源,其他线程可以占用CPU。一般wait不会加时间限制,因为如果wait线程的运行资源不够,
再出来也没用,要等待其他线程调用notify/notifyAll唤醒等待池中的所有线程,
才会进入就绪队列等待OS分配系统资源。sleep(milliseconds)可以用时间指定使它自动唤醒过来,
如果时间不到只能调用interrupt()强行打断。

3.

使用范围:wait,notify和notifyAll只能在同步控制方法或者同步控制块里面使用,
而sleep可以在任何地方使用
synchronized(x){
x.notify()
//或者wait()
}

4.

sleep必须捕获异常,而wait,notify和notifyAll不需要捕获异常
版权声明
本博客所有的原创文章,作者皆保留版权。转载必须包含本声明,保持本文完整,并以超链接形式注明作者Leslie Tien和本文原始地址:
https://leslietien.blogspot.com/2018/12/sleepwait.html

Saturday, May 26, 2018

常见HTTP状态码

      当浏览者访问一个网页时,浏览者的浏览器会向网页所在服务器发出请求。当浏览器接收并显示网页前,此网页所在的服务器会返回一个包含HTTP状态码的信息头(server header)用以响应浏览器的请求。
下面是常见的HTTP状态码:

2**:成功,操作被成功接收并处理

3**:重定向,需要进一步的操作以完成请求

4**:客户端错误,请求包含语法错误或无法完成请求

5**:服务器错误,服务器在处理请求的过程中发生了错误

  1. 200:ok,请求成功。一般用于GET与POST请求。
  2. 202:Accepted,已接受。已经接受请求,但未处理完成。
  3. 301:永久移动。请求的资源已被永久的移动到新URI,返回信息会包括新的URI,浏览器会自动定向到新URI。今后任何新的请求都应使用新的URI代替。
  4. 302:临时移动。与301类似。但资源只是临时被移动。客户端应继续使用原有URI。
  5. 303:查看其它地址。与301类似。使用GET和POST请求查看。
  6. 304:未修改。所请求的资源未修改,服务器返回此状态码时,不会返回任何资源。客户端通常会缓存访问过的资源,通过提供一个头信息指出客户端希望只返回在指定日期之后修改的资源。
  7. 305:使用代理。所请求的资源必须通过代理访问。
  8. 307:临时重定向。与302类似。使用GET请求重定向。
  9. 400:客户端请求的语法错误,服务器无法理解。
  10. 403:服务器理解请求客户端的请求,但是拒绝执行此请求。
  11. 404:服务器无法根据客户端的请求找到资源(网页)。通过此代码,网站设计人员可设置”您所请求的资源无法找到”的个性页面。
  12. 500:服务器内部错误,无法完成请求。
  13. 503:由于超载或系统维护,服务器暂时的无法处理客户端的请求。延时的长度可包含在服务器的Retry-After头信息中。
版权声明
本博客所有的原创文章,作者皆保留版权。转载必须包含本声明,保持本文完整,并以超链接形式注明作者Leslie Tien和本文原始地址:
https://leslietien.blogspot.com/2018/12/http.html

Friday, May 18, 2018

Java容器类库

Java容器类库一共两种主要类型:Collection , Map。
Collection和Map的区别在于容器内每个“槽”所存储的元素的个数不同。
Collection类型中,每个“槽”只有一个元素;Map类型中,持有key-value关联(键-值对)。
所有的java容器类都可以自动调整自己的尺寸。

Collection类的子类:
     List:将以特定次序存储元素,所以取出来的顺序可能和放入顺序不同。允许元素重复。
           ArrayList:擅长随机访问元素,但在List中间插入、删除、移动元素较慢。
           LinkedList:插入、删除、移动元素方便,随机访问元素差。
           Vector

     Set:每个值只能保存一个对象,不能含有重复的元素。
           HashSet:使用散列函数
           TreeSet:使用红黑树
           LinkedHashSet:使用链表结合散列函数

     Queue:先进先出的容器

Map类:
      HaspMap
      HashTable
      TreeMap
版权声明
本博客所有的原创文章,作者皆保留版权。转载必须包含本声明,保持本文完整,并以超链接形式注明作者Leslie Tien和本文原始地址:
https://leslietien.blogspot.com/2018/05/java.html

Wednesday, April 11, 2018

Java抽象类和接口的区别

      抽象类和接口都用于实现抽象,可以声明抽象方法。 抽象类和接口都不能被实例化。但是在下面给出的抽象类和接口之间有许多区别。
抽象类接口
抽象类可以有抽象和非抽象方法。接口只能有抽象方法。 从Java 8开始,它也可以有默认和静态方法。
抽象类不支持多重继承。接口支持多继承。
抽象类可以有final非final,静态和非静态变量。接口只有静态和final变量。
抽象类可以提供接口的实现。接口不能提供抽象类的实现。
abstract关键字用来声明抽象类。interface关键字用于声明接口。
简单地说,抽象类实现了部分抽象(0到100%),而接口实现了完全抽象(100%)。
版权声明
本博客所有的原创文章,作者皆保留版权。转载必须包含本声明,保持本文完整,并以超链接形式注明作者Leslie Tien和本文原始地址:
https://leslietien.blogspot.com/2018/04/java.html

Friday, April 6, 2018

vultr服务器被墙检测与迁移教程

        有时候因为某些不可知的原因,你的服务器的IP可能会被“墙”。尽管这种可能性很小, 但是一旦发生,网站进不去,梯子用不了,有些小白就不知道如何是好了。
        我的服务器也是经常被墙,自己已经进行过多次数据迁移,对这个流程还是比较熟悉的。 在这里我就教给大家如果vultr的服务器被墙,如何利用快照功能进行服务器数据迁移。
        首先,是要检测你的服务器IP是不是被墙了,如何判断自己的服务器IP被墙呢?被“墙”的表现会有两种,第一种是ping IP 不通,数据包全部丢失。可以去这里www.ipip.net进行ping检测。 第二种是ping IP 正常,但是服务器访问不了,用xshell连不上。 但是我们基本遇到的情况都是第二种,包括我自己。所以 我要具体讲的是第二种现象如何判断。 如果国内外都可以 Ping,那么此时无法判断出是否已经被封了,还需要进行下一步端口扫描测试。 后面需要用到机器的 IP 地址和 SSH 连接端口,IP 地址大家都知道,SSH 连接端口默认是 22 端口, 如果大家没有手动更改过此端口,那么下文中需要填写 SSH 连接端口时填写 22 即可。

1.国内端口测试

首先前往国内端口扫描站,(http://tool.chinaz.com/port) 输入IP地址和SSH端口号,点击查询,下面会显示端口状态,如果显示此 SSH 连接端口为关闭状态,那么说明此 IP 可能已经被封了, 但是确切的答案还需要进行后面的国外测试才能得出;而如果显示此 SSH 连接端口为开启状态,那么就说明此 IP 地址并没有被封。


2.国外端口测试

前往国外端口扫描站(https://www.yougetsignal.com/tools/open-ports/) 填入机器的 IP 地址,然后输入 SSH 连接端口,然后点击 Check 按钮继续。 如果显示此 SSH 连接端口为开启状态,加上前面检测到的此 SSH 连接端口在国内为关闭状态,此时完全可以确定此 IP 已经被封! 而如果显示此 SSH 连接端口依旧为关闭状态,那么就检查下机器是不是在正常运行以及端口是否填写错误。

如果经过测试你的IP确实是被墙了,那么恭喜你下面的教程会帮到你。

vultr服务器提供快照功能, 进行数据迁移非常方便。
进去vultr官网,登录你的账户,点一下服务器,会跳转至你的服务器的详细信息。在这个信息页面我请大家做一件事,就是新建一个记事本,将password复制下来(小眼睛旁是复制图标),保存在记事本里,这个非常重要,下面我会讲。


点击snapshots进去快照页面。有个Take Snapshot(创建快照的意思)按钮,点击一下就会自动开始创建快照。 Label框可以填入标记语言避免与以前的快照混淆。

创建快照的过程大概需要二三十分钟。 在这段时间里你可以去创建你的新服务器。 这这里要注意的是你的新服务器分配好之后记得先去检查一下端口是否开放, 因为有可能给你分配的新IP依然是被封的。一个不行多开几个,一个一个去试。
当你确认这个新IP的服务器没有问题时,就可以进入下面的数据还原阶段了。
同样的步骤,点击你的新服务器,点击snapshots按钮,但现在不是创建快照了, 而是下面的重装快照。在你刚备份的快照最右边有Restore Snapshot的小图标,点击它进行数据还原操作。


这段时间同样大概会花费三十分钟左右,在这段时间你的服务器是关闭的。数据恢复后服务器自动重启。
注意,快照恢复后,当你用xshell连接新服务器时所用的密码是你的旧服务器的密码(快照的原因),所以我前面请大家用记事本保存下来。 你的旧服务器的密码要妥善保管,当你以后再次进行数据迁移时,迁移后的连接密码都是它。

最后,当一切都确认无误后,你就可以把你的旧服务器摧毁了。

版权声明
本博客所有的原创文章,作者皆保留版权。转载必须包含本声明,保持本文完整,并以超链接形式注明作者Leslie Tien和本文原始地址:
https://leslietien.blogspot.com/2018/12/vultr.html