目录
一、引入
在Java中,数组是一项很重要的概念,不过既然是数组,最基本的数组就是数字组成的数组,自然就离不开数字的比较大小与排序,当然,数组排序的方式有很多,本篇主要研究数组的冒泡排序与插入排序。
二、冒泡排序(最大筛选排序法)
冒泡排序,顾名思义,是用气泡在液体中上升时逐渐变大的状态来命名的,十分形象,当然冒泡排序的执行原理也如此
假如给我们一个无序的数组:
int[] scores = { 23,24,15,76,21,14,20 };
如何实现排序?
既然是冒泡,一定会有一个最大元素的“上升”的过程,冒泡排序就是让当前元素与下一元素按要求比较,升序则将较大元素后移 (降序则将较小元素后移)。
(假设我们要升序)则需要实现下面代码:
for (int i = 0; i < scores.length - 1; i++) {
int current = scores[i];//将当前位置的元素先赋给current变量
int next = scores[i + 1];//将下一位置的元素赋给next变量
if (current > next) { //如果下一位置的元素的值大于当前位置的元素的值
scores[i] = next;//交换两个位置的元素
scores[i + 1] = current;
}
}
那我们知道,因为我们是边遍历边执行交换操作,所以循环执行完毕,最大的元素一定移到了最后的位置。而且其位置不会再变。
因为比它小的所有元素都要和它交换位置,但剩下的元素不一定已经变成有序的,但是由于剩余元素中最大元素一定会紧贴排在上一轮最大元素的前面。
以此类推,n个元素的数组只需进行n-1轮最大元素筛选,而且每轮只需要遍历剔除上一轮最大元素后剩下的元素。所以直接改写代码:
package array;
public class BubbleSort {
public static void main(String[] args) {
int[] scores = { 23,24,15,76,21,14,20 };
for (int times = 1; times <= scores.length - 1; times++) {
for (int i = 0; i < scores.length - times; i++) {
int current = scores[i];
int next = scores[i + 1];
if (current > next) {
scores[i] = next;
scores[i + 1] = current;
}
}
}
for (int i : scores) {
System.out.println(i);
}
}
}
执行结果:
三、插入排序
每循环一次都将一个待排序的元素所对应的数据按其顺序大小插入到前面已经排序的序列的合适位置,直到全部插入排序完为止,其难点在于如何在前面已经排好序的序列中找到合适的插入位置。该排序方法有很多,比如直接插入排序、二分插入排序、希尔排序等等。
一个数组一旦确定,那么其元素一定有有序与无序的部分,插入排序就是预先将数组按有序和无序的规律划分开,从下标为0开始依次扫描,当扫描到第一个无序元素时,将其与其之前的所有元素化为一个局部数组。然后将数组末尾的无序元素插入有序部分中。
int[] scores = {1,2,4,5,3,9,6,8,7};
像这样一个数组,从左往右看第一个无序元素是3,那么就要截取它和它之前的元素:
{1,2,4,5,3}
像这样,则我们只需将3(异端元素)拿出来,然后拿着3在有序部分找第一个比它大的元素4(临界元素),记录位置,把有序部分中从临界元素开始的往后的所有元素都往后平移一个位置,然后将异端元素插入到记录的临界元素的位置上(这里执行的是升序排序,降序则类比升序作个别相反操作)。
总结起来三步:
1.找位置:
package array;
public class InsertSort {
public static void main(String[] args) {
int[] scores = { 1, 2, 4, 5, 3 };
int i = 4;// 记录异端元素下标
int data = scores[i];// 记录异端元素
int j = 0;// 用来记录临界元素位置
// 1.找位置
for (; j < i; j++) {
if (scores[j] > data) {
break;
}
}
System.out.println(j);
}
}
2.做移动
package array;
public class InsertSort {
public static void main(String[] args) {
int[] scores = { 1, 2, 4, 5, 3 };
int i = 4;// 记录异端元素下标
int data = scores[i];// 记录异端元素
int j = 0;// 用来记录临界元素位置
// 1.找位置
for (; j < i; j++) {
if (scores[j] > data) {
break;
}
}
// 2.做移动
for (int k = i; k > j; k--) {
scores[k] = scores[k - 1];
}
for (int j2 = 0; j2 < scores.length; j2++) {
System.out.println(scores[j2]);
}
}
}
3.做插入
package array;
public class InsertSort {
public static void main(String[] args) {
int[] scores = { 1, 2, 4, 5, 3 };
int i = 4;// 记录异端元素下标
int data = scores[i];// 记录异端元素
int j = 0;// 用来记录临界元素位置
// 1.找位置
for (; j < i; j++) {
if (scores[j] > data) {
break;
}
}
// 2.做移动
for (int k = i; k > j; k--) {
scores[k] = scores[k - 1];
}
// 3.做插入
scores[j] = data;
for (int j2 = 0; j2 < scores.length; j2++) {
System.out.println(scores[j2]);
}
}
}
运行结果:
这里的仿佛不具有普遍性,我们还要完善,就是比一个不完全有序数组从第二个元素开始的每一个元素都看成一个异端元素,在上方代码的基础上再套一层循环,就能适用于任何无序数组了。
package array;
public class InsertSort {
public static void main(String[] args) {
int[] scores = { 12, 65, 13, 1, 32, 14, 7, 9, 42, 41, 57, 8 };
for (int i = 1; i < scores.length; i++) {
int data = scores[i];// 记录异端元素
int j = 0;// 用来记录临界元素位置
// 1.找位置
for (; j < i; j++) {
if (scores[j] > data) {
break;
}
}
// 2.做移动
for (int k = i; k > j; k--) {
scores[k] = scores[k - 1];
}
// 3.做插入
scores[j] = data;
}
for (int j2 = 0; j2 < scores.length; j2++) {
System.out.println(scores[j2]);
}
}
}
运行结果: