013 数组的排序方法(升序、降序、冒泡排序法、快速排序法、选择排序法、直接插入排序法)

013 数组的排序方法(升序、降序、冒泡排序法、快速排序法、选择排序法、直接插入排序法)

首先要知道数组中的排序有升序和降序,(这就需要去好好看看数据结构的排序方法原理了)

排序方法对应的有冒泡排序法,快速排序法,选择排序法,直接插入排序法等方法

我们先搞明白这些排序方法的思想和基本原理,然后再去看代码应该怎么写。下面一一介绍。

(一)排序

(1)升序

使用 java.util.Arrays 类中的 sort() 方法对数组进行升序分为以下两步:

导入 java.util.Arrays 包。

使用 Arrays.sort(数组名) 语法对数组进行排序,排序规则是从小到大,即升序。

例1:假设在数组 scores 中存放了 5 名学生的成绩,现在要实现从低到高排列的功能。在这里使用 Arrays.sort() 方法来实现,具体代码如下:

public static void main(String[] args) {

// 定义含有5个元素的数组

double[] scores = new double[] { 78, 45, 85, 97, 87 };

System.out.println("排序前数组内容如下:");

// 对scores数组进行循环遍历

for (int i = 0; i < scores.length; i++) {

System.out.print(scores[i] + "\t");

}

System.out.println("\n排序后的数组内容如下:");

// 对数组进行排序

Arrays.sort(scores);

// 遍历排序后的数组

for (int j = 0; j < scores.length; j++) {

System.out.print(scores[j] + "\t");

}

}

如上述代码所示,要对一个数组进行升序排列,只需要调用 Arrays.sort() 方法即可。运行后的输出结果如下所示。

排序前数组内容如下:

78.0 45.0 85.0 97.0 87.0

排序后的数组内容如下:

45.0 78.0 85.0 87.0 97.0

(2)降序

使用 sort 实现降序有两种方法,简单了解即可。1)利用 Collections.reverseOrder() 方法(Collections 是一个包装类。大家可以学习《Java Collections类》一节详细了解):

public static void main(String[] args) {

Integer[] a = { 9, 8, 7, 2, 3, 4, 1, 0, 6, 5 }; // 数组类型为Integer

Arrays.sort(a, Collections.reverseOrder());

for (int arr : a) {

System.out.print(arr + " ");

}

}

输出结果如下:

9 8 7 6 5 4 3 2 1 0

2)实现 Comparator 接口的复写 compare() 方法,代码如下:

public class Test {

public static void main(String[] args) {

/*

* 注意,要想改变默认的排列顺序,不能使用基本类型(int,double,char)而要使用它们对应的类

*/

Integer[] a = { 9, 8, 7, 2, 3, 4, 1, 0, 6, 5 };

// 定义一个自定义类MyComparator的对象

Comparator cmp = new MyComparator();

Arrays.sort(a, cmp);

for (int arr : a) {

System.out.print(arr + " ");

}

}

}

// 实现Comparator接口

class MyComparator implements Comparator {

@Override

public int compare(Integer o1, Integer o2) {

/*

* 如果o1小于o2,我们就返回正值,如果o1大于o2我们就返回负值, 这样颠倒一下,就可以实现降序排序了,反之即可自定义升序排序了

*/

return o2 - o1;

}

}

输出结果如下所示。

9 8 7 6 5 4 3 2 1 0

注意:使用以上两种方法时,数组必须是包装类型,否则会编译不通过。

(二)排序方法

(1)冒泡排序法(http://c.biancheng.net/view/927.html)

基本原理:

比较相邻的元素。如果第一个比第二个大,就交换他们两个。

对每一对相邻元素做同样的工作,从开始第一对到结尾的最后一对。在这一点,最后的元素应该会是最大的数。

针对所有的元素重复以上的步骤,除了最后一个。

持续每次对越来越少的元素重复上面的步骤,直到没有任何一对数字需要比较。

优化:

针对问题:

数据的顺序排好之后,冒泡算法仍然会继续进行下一轮的比较,直到arr.length-1次,后面的比较没有意义的。

方案:

设置标志位flag,如果发生了交换flag设置为true;如果没有交换就设置为false。

这样当一轮比较结束后如果flag仍为false,即:这一轮没有发生交换,说明数据的顺序已经排好,没有必要继续进行下去。

特点:冒泡排序的算法比较简单,排序的结果稳定,但时间效率不太高。

例1:(http://c.biancheng.net/view/6506.html)

假设待排序序列为 (5,1,4,2,8),如果采用冒泡排序对其进行升序(由小到大)排序,则整个排序过程如下所示:1) 第一轮排序,此时整个序列中的元素都位于待排序序列,依次扫描每对相邻的元素,并对顺序不正确的元素对交换位置,整个过程如图 1 所示。

2) 第二轮排序,此时待排序序列只包含前 4 个元素,依次扫描每对相邻元素,对顺序不正确的元素对交换位置,整个过程如图 2 所示。

3) 第三轮排序,此时待排序序列包含前 3 个元素,依次扫描每对相邻元素,对顺序不正确的元素对交换位置,整个过程如图 3 所示。

4) 第四轮排序,此时待排序序列包含前 2 个元素,对其进行冒泡排序的整个过程如图 4 所示。

5) (优化后,这一步不需要了)当进行第五轮冒泡排序时,由于待排序序列中仅剩 1 个元素,无论再进行相邻元素的比较,因此直接将其并入已排序序列中,此时的序列就认定为已排序好的序列(如图 5 所示)

例 2

获取用户在控制台输入的 5 个成绩信息,将这些成绩保存到数组中,然后对数组应用冒泡排序,并输出排序后的结果,实现步骤如下。(1) 创建一个 Test24 类文件,在 main() 方法中开始编码。首先创建 Scanner 类的实例后声明 double 类型的 score 数组,然后接收用户在控制台输入的成绩,并保存到元素中。代码如下:

public static void main(String[] args) {

Scanner scan = new Scanner(System.in);

double[] score = new double[5];

for (int i = 0; i < score.length; i++) {

System.out.print("请输入第 " + (i + 1) + " 个成绩:");

score[i] = scan.nextDouble();

}

}

(2) 在对 score 数组排序之前,首先输出数组中各个元素的值。代码如下:

System.out.println("排序前的元素值:");

for(double val:score) {

System.out.print(val+"\t");

}

System.out.println();

(3) 通过冒泡排序方法实现对 score 数组的排序,在实现时需要借助一个临时变量。代码如下:

public static void main(String[] args) {

System.out.println("通过冒泡排序方法对数组进行排序:");

for (int i = 0; i < score.length - 1; i++) {

// 比较相邻两个元素,较大的数往后冒泡

for (int j = 0; j < score.length - 1 - i; j++) {

if (score[j] > score[j + 1]) {

double temp = score[j + 1]; // 把第一个元素值保存到临时变量中

score[j + 1] = score[j]; // 把第二个元素值转移到第一个元素变量中

score[j] = temp; // 把临时变量(第一个元素的原值)保存到第二个元素中

}

System.out.print(score[j] + " "); // 对排序后的数组元素进行输出

}

System.out.print("【");

for (int j = score.length - 1 - i; j < score.length; j++) {

System.out.print(score[j] + " ");

}

System.out.println("】");

}

}

(4) 运行前面的代码进行测试,如下所示。

请输入第 1 个成绩:77

请输入第 2 个成绩:90

请输入第 3 个成绩:68

请输入第 4 个成绩:59

请输入第 5 个成绩:80

排序前的元素值:

77.0 90.0 68.0 59.0 80.0

通过冒泡排序方法对数组进行排序:

77.0 68.0 59.0 80.0 【90.0 】

68.0 59.0 77.0 【80.0 90.0 】

59.0 68.0 【77.0 80.0 90.0 】

59.0 【68.0 77.0 80.0 90.0 】

(2)快速排序法(http://c.biancheng.net/view/929.html)

基本原理:

(1)首先设定一个分界值,通过该分界值将数组分成左右两部分。

(2)将大于或等于分界值的数据集中到数组右边,小于分界值的数据集中到数组的左边。此时,左边部分中各元素都小于或等于分界值,而右边部分中各元素都大于或等于分界值。

(3)然后,左边和右边的数据可以独立排序。对于左侧的数组数据,又可以取一个分界值,将该部分数据分成左右两部分,同样在左边放置较小值,右边放置较大值。右侧的数组数据也可以做类似处理。

(4)重复上述过程,可以看出,这是一个递归定义。通过递归将左侧部分排好序后,再递归排好右侧部分的顺序。当左、右两个部分各数据排序完成后,整个数组的排序也就完成了。

例1:利用快速排序法对一数组进行排序

(1) 声明静态的 getMiddle() 方法,该方法需要返回一个 int 类型的参数值,在该方法中传入 3 个参数。代码如下:

public static int getMiddle(int[] list, int low, int high) {

int tmp = list[low]; // 数组的第一个值作为中轴(分界点或关键数据)

while (low < high) {

while (low < high && list[high] > tmp) {

high--;

}

list[low] = list[high]; // 比中轴小的记录移到低端

while (low < high && list[low] < tmp) {

low++;

}

list[high] = list[low]; // 比中轴大的记录移到高端

}

list[low] = tmp; // 中轴记录到尾

return low; // 返回中轴的位置

}

(2) 创建静态的 unckSort() 方法,在该方法中判断 low 参数是否小于 high 参数,如果是则调用 getMiddle() 方法,将数组一分为二,并且调用自身的方法进行递归排序。代码如下

public static void unckSort(int[] list,int low,int high) {

if(low < high) {

int middle = getMiddle(list,low,high); // 将list数组一分为二

unckSort(list,low,middle-1); // 对低字表进行递归排序

unckSort(list,middle+1,high); // 对高字表进行递归排序

}

}

(3) 声明静态的 quick() 方法,在该方法中判断传入的数组是否为空,如果不为空,则调用 unckSort() 方法进行排序。代码如下:

public static void quick(int[] str) {

if(str.length > 0) {

// 查看数组是否为空

unckSort(str,0,str.length-1);

}

}

(4) 在 main() 方法中声明 int 类型的 number 数组,接着输出该数组中的元素。然后调用自定义的 quick() 方法进行排序,排序后重新输出数组中的元素。代码如下:

int[] number={13,15,24,99,14,11,1,2,3};

System.out.println("排序前:");

for(int val:number) {

System.out.print(val+" ");

}

quick(number);

System.out.println("\n排序后:");

for(int val:number) {

System.out.print(val +" ");

}

运行前面的代码进行测试,输出结果如下:

排序前:

13 15 24 99 14 11 1 2 3

排序后:

1 2 3 11 13 14 15 24 99

(3)选择排序法

工作原理:每一次从待排序的数据元素中选出最小(或最大)的一个元素,存放在序列的起始位置,然后,再从剩余未排序元素中继续寻找最小(大)元素,然后放到已排序序列的末尾。以此类推,直到全部待排序的数据元素排完。

类别

常见的选择排序可以分为直接选择排序(Straight selection sort)、树形选择排序(Tree-type selection sort)以及堆排序(Heap sort)。

(1)直接选择排序。①基本思想。实现思想是每步从排序记录中选出排序码最小(最大)的记录,放在已排序记录序列的最后(前);②算法特点。直接选择排序算法n个记录的文件的直接选择排序可经过n-1趟直接选择排序得到有序结果。

(2)树形选择排序。①基本思想。其实现思想是保存先前比较的结果以减少比较次数,是一种不稳定的排序方法。首先对n个记录的关键字进行两两比较,然后在n/2个较小者之间再进行两两比较,如此重复,直至选出最小的记录为止。

(3)堆排序。①基本思想。堆排序是一种树形选择排序,是对直接选择排序的有效改进;②算法描述。从算法描述来看,堆排序需要两个过程,即建立堆和堆顶与堆的最后一个元素交换位置。所以堆排序有两个函数组成,一是建堆的渗透函数,二是反复调用渗透函数实现排序的函数;③算法特点。堆排序可通过树形结构保存部分比较结果,可减少比较次数。但由于建初始堆所需的比较次数较多,所以堆排序不适宜于记录数较少的文件。

例1:使用选择排序法重新对 number(该数组中的元素依次是 13、15、 24、99、4 和 1) 中的元素进行排序。

//第一趟选择排序

13、15、24、1、4、99

//第二趟选择排序

13、15、4、1、24、99

//第三趟选择排序

13、1、4、15、24、99

//第四趟选择排序

4、1、13、15、24、99

//第五趟选择排序

1、4、13、15、24、99

例2:代码。利用选择排序方法通过编程的方式实现对 number 数组的排序,并输出已排序的数组元素。

int[] number = {13,15,24,99,4,1};

String end = "\n";

int index;

for (int i = 1;i < number.length;i++) {

index = 0;

for(int j = 1;j <= number.length-i;j++) {

if (number[j] > number[index]) {

index = j; // 查找最大值

}

}

end = number[index] + " " + end; // 定位已排好的数组元素

int temp = number[number.length-i];

number[number.length-1] = number[index];

number[index] = temp;

System.out.print("【");

for (int j = 0;j < number.length-i;j++) {

System.out.print(number[j]+" ");

}

System.out.print("】"+end);

}

结果:

【13 15 24 1 4 】99

【13 15 4 1 】24 99

【13 1 4 】15 24 99

【4 1 】13 15 24 99

【1 】4 13 15 24 99

(4)直接插入排序法

基本思想:将 n 个有序数存放在数组 a 中,要插入的数为 x,首先确定 x 插在数组中的位置 p,然后将 p 之后的元素都向后移一个位置,空出 a(p),将 x 放入 a(p),这样可实现插入 x 后仍然有序。

例 1:本例子通过直接插入的方法对上述例子中的 number 数组进行排序。创建一个 Test27 类文件,在 main() 方法中开始编码,具体实现代码如下:

public static void main(String[] args) {

int[] number = { 13, 15, 24, 99, 4, 1 };

System.out.println("排序前:");

for (int val : number) { // 遍历数组元素

System.out.print(val + " "); // 输出数组元素

}

int temp, j;

for (int i = 1; i < number.length; i++) {

temp = number[i];

for (j = i - 1; j >= 0 && number[j] > temp; j--) {

number[j + 1] = number[j];

}

number[j + 1] = temp;

}

System.out.println("\n排序后:");

for (int val : number) { // 遍历数组元素

System.out.print(val + " "); // 输出数组元素

}

}

运行结果:

排序前:

13 15 24 99 4 1

排序后:

1 4 13 15 24 99

相关推荐

獭形狸尾兽
beat365中国在线体育

獭形狸尾兽

📅 06-29 👁️ 8622
獭形狸尾兽
beat365中国在线体育

獭形狸尾兽

📅 06-29 👁️ 8622
惠威音响
beat365中国在线体育

惠威音响

📅 07-02 👁️ 8180
第二七则
365买球官网入口

第二七则

📅 06-30 👁️ 1616
隔的成语
365买球官网入口

隔的成语

📅 07-01 👁️ 3068
小米4手机尺寸详解:长度、宽度、厚度及全面解析
beat365中国在线体育

小米4手机尺寸详解:长度、宽度、厚度及全面解析

📅 07-04 👁️ 4064
枪神纪WIKI
365买球官网入口

枪神纪WIKI

📅 07-02 👁️ 7333
如何查看手机相机像素
365bet网站

如何查看手机相机像素

📅 06-28 👁️ 7525
史上最简单💯成功红豆沙/豆沙馅/蜜红豆馅做法,无油可无糖,糖尿病控血糖减肥,高压锅版