Re0:Java编程系列
作者参加校招,在复习Java的同时,决定开一打系列博客。复习的同时,作者希望能留下材料,方便也服务一些新入门的小伙伴。
本系列文章从基础入手,由简单的功能函数开始,再扩展为类,包,项目结构等等。进一步延伸至Java编程的核心思想,封装,继承,多态。
文章从面向功能编程方法
开始过渡,手写代码的同时,逐渐向小伙伴揭示Java的编程思想和面向对象编程方法
。
提示:Java写代码前,需要Java环境和IDE集成环境,作者不赘述,希望小伙伴们提前准备好。
前言
前些天,我细细思考了冒泡排序。
看着它安详的模样,我不禁想起了与它出生入死的兄弟们。
号称三大经典简单排序的它们,冒泡排序,直接插入排序,选择排序,如今也该团聚了。
我摸起手里的鼠标,决定,给它们写个家。
一、项目结构?包?类?
引导:Java是一门十分注重结构的语言,它的项目名称,包名和类名都具有属性分类的意义。
Java项目结构规范需要注意三点:
- 一般结构
项目
{包/包
{类
}}。 - 项目名称,单词首字母均需要大写。类名中,单词首字母均需要大写。
- 包名中,单词字母均为小写,并且一般为一个单词。函数名中,第一个单词首字母小写,其余单词首字母大写。
首先在项目结构src
下,我们新建几个包,分别为swap
,select
,insert
,并且新建两个类SelectSort
,InsertSort
。
规划结构,使得项目结构如图所示。
src
目录是存放Java源代码的地方,我们通过包对不同的类进行区分整理。当然,包中有包也是非常常见,相当于对大概念进行细分。
例如:包名为高中,小包名有高一,高二,高三。
项目开始前,我们对概念抽象越好,包会越细,代码复用率会相当有保证。Java编程,力求一个类写完,它的结构也固定完毕。这是Java编程中一个小点,牵扯重要的原则——开闭原则。
不过,很明显的是,我们并没有很好的执行这一原则。因为,我们才刚刚上路,要从实践中出真章。
二、开始敲码!
1.编程思路
这一次,我们需要写两个函数。一个选择排序,一个插入排序。
有了上次冒泡排序的经验,我们依葫芦画瓢,依次分析两个函数的特点。
选择排序:每一轮开始,选择一个元素,并将其移动到合适的位置。
比如,每轮选择出最小的元素,将其下标记下,然后移动到未排序好的首部。
编写函数注意数组元素下标,外循环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;
}
2.对比思路
函数编程完毕,我们发现与冒泡函数相比,选择排序和插入排序,都没有能判断数组有序的标志。
为什么冒泡有标志,而选择和插入没有呢?
我们花三分钟思考一下,问题的原因。
- 冒泡排序
代码如下(示例):
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为递增数列。
而对于,选择排序和插入排序,一次只交换一个元素,自然就缺失判断排序完成的标志。
3.验证思路
经过编码,我们有了三个不同的排序函数,是时候验证一下,我们的思路了。
我们在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,终于算是入门了。