作者参加校招,在复习Java的同时,决定开一打系列博客。复习的同时,作者希望能留下材料,方便也服务一些新入门的小伙伴。
本系列文章从基础入手,由简单的功能函数开始,再扩展为类,包,项目结构等等。进一步延伸至Java编程的核心思想,封装,继承,多态。
文章从面向功能编程方法开始过渡,手写代码的同时,逐渐向小伙伴揭示Java的编程思想和面向对象编程方法。
提示:Java写代码前,需要Java环境和IDE集成环境,作者不赘述,希望小伙伴们提前准备好。
前些天,我细细思考了冒泡排序。 看着它安详的模样,我不禁想起了与它出生入死的兄弟们。 号称三大经典简单排序的它们,冒泡排序,直接插入排序,选择排序,如今也该团聚了。 我摸起手里的鼠标,决定,给它们写个家。
引导:Java是一门十分注重结构的语言,它的项目名称,包名和类名都具有属性分类的意义。
Java项目结构规范需要注意三点:
一般结构 项目{包/包{类}}。项目名称,单词首字母均需要大写。类名中,单词首字母均需要大写。包名中,单词字母均为小写,并且一般为一个单词。函数名中,第一个单词首字母小写,其余单词首字母大写。首先在项目结构src下,我们新建几个包,分别为swap,select,insert,并且新建两个类SelectSort,InsertSort。
规划结构,使得项目结构如图所示。
src目录是存放Java源代码的地方,我们通过包对不同的类进行区分整理。当然,包中有包也是非常常见,相当于对大概念进行细分。
例如:包名为高中,小包名有高一,高二,高三。
项目开始前,我们对概念抽象越好,包会越细,代码复用率会相当有保证。Java编程,力求一个类写完,它的结构也固定完毕。这是Java编程中一个小点,牵扯重要的原则——开闭原则。
不过,很明显的是,我们并没有很好的执行这一原则。因为,我们才刚刚上路,要从实践中出真章。
这一次,我们需要写两个函数。一个选择排序,一个插入排序。
有了上次冒泡排序的经验,我们依葫芦画瓢,依次分析两个函数的特点。
选择排序:每一轮开始,选择一个元素,并将其移动到合适的位置。
比如,每轮选择出最小的元素,将其下标记下,然后移动到未排序好的首部。
编写函数注意数组元素下标,外循环0 -> length-1顺序执行。
代码如下(示例):
public int[] selectSort1(int[] array) { int temp; total = 0; //外层循环,意味着排序次数 for (int i = 0; i < array.length - 1; i++) { //假设array[i]元素最小,记录下标 pos = i; //内层循环,意味着比较次数 for (int j = i; j < array.length; j++) { //下标设置为最小 if (array[j] < array[pos]) { pos = j; } } total++; //交换元素,将最小值移动到最前 temp = array[i]; array[i] = array[pos]; array[pos] = temp; } return array; }我们不难发现,每一次排序完成,数组中最小的元素到了数组的首端。而且每一次排序中,我们只交换一次数组元素。
仔细想想,选择排序为什么当下标不变时,不能确定排序完成?
插入排序:将首元素视为有序数组,顺序依次插入元素,最终原数组有序。
插入排序,相当于将新的元素插入到有序的数组中。每一次插入排序时,元素需要找到合适的位置。因此,有序数组元素在整个数组中会多次移动。
编写函数注意数组元素下标,外循环1 -> length顺序执行。
插入排序执行时,依旧每次排好一个元素。
代码如下(示例):
public int[] insertSort1(int[] array) { total = 0; //外循环,排序次数,从第二个元素开始 for (int i = 1; i < array.length; i++) { //选择合适位置 int j = i; //记录选中元素值 temp = array[j]; //位置选择循环判断条件 while(j > 0) { //判断合适位置的前一个元素值与选中元素值 if (array[j-1] > temp) { //元素后移 array[j] = array[j-1]; //选择位置前移 j--; } else { //当array[i-1]<temp时,意味着位置合适,跳出循环 break; } } total++; //选中元素值放入合适位置 array[j] = temp; } return array; }函数编程完毕,我们发现与冒泡函数相比,选择排序和插入排序,都没有能判断数组有序的标志。
为什么冒泡有标志,而选择和插入没有呢?
我们花三分钟思考一下,问题的原因。
冒泡排序代码如下(示例):
public int[] bubbleSort1(int[] array) { int temp = 0; for (int i = 0; i < array.length - 1; i++) { for (int j = 0; j < array.length - i - 1; j++) { if(array[j] > array[j+1]) { temp = array[j]; array[j] = array[j+1]; array[j+1] = temp; } } } return array; }冒泡排序中,数组元素的交换,是多次的。每一次排序时,都需要对元素依次进行两两对比。当条件符合时,元素进行交换。
那么,设数列S为a1,a2,a3,...,aN。
a2 > a1 且a3 > a2 一直到aN > aN-1时,数组才不需要交换。同时,通过数学归纳法,我们很容易得出数列S为递增数列。
而对于,选择排序和插入排序,一次只交换一个元素,自然就缺失判断排序完成的标志。
经过编码,我们有了三个不同的排序函数,是时候验证一下,我们的思路了。
我们在src下新建一个包test,在test包中新建一个SortTest类。
代码如下(示例):
package test; import insert.InsertSort; import select.SelectSort; import swap.BubbleSort; public class SortTest { public static void main(String[] args) { BubbleSort bubble = new BubbleSort(); SelectSort select = new SelectSort(); InsertSort insert = new InsertSort(); //执行测试 ... } }鼠标右键,敲击Run,我们来跑程序。
经过了我不懈的努力,终于建好了一个排序算法的家。 有些欣慰,也有些开心。 我们的Java,终于算是入门了。