文章目录
前言
跟着B站的尚硅谷学习数据结构与算法,语言为java,目前是第九个代码内容——排序
课程传送门:尚硅谷——排序算法2.0
一、冒泡排序
1.基本介绍
冒泡排序(Bubble Sorting)的基本思想是:通过对待排序序列从前向后(从下标较小的元素开始),依次比较相邻元素的值,若发现逆序交换,使值较大的元素逐渐从前移向后部,就像水底下的水泡一样逐渐往上冒。
因为排序的过程中,各元素不断接近自己的位置,如果一趟比较下来没有进行交换,就说明序列有序,因此要在排序过程中设置一个标志 flag 判断元素是否进行过交换。从而减少不必要的比较。(这里说的优化,可以在冒泡排序写好后,再进行)
2.应用实例
我们举一个具体的案例来说明冒泡法,我们将五个无序的数: 3、9、-1、10、20
冒泡排序规则:
1)一共进行数组的 大小-1 次大的循环
2)每一趟排序的次数再逐渐的减少
3)如果发现再某次排序中,没有发生一次交换,可以提前结束冒泡排序,这就是优化。
使用冒泡排序法将其排成一个从小到大的有序数列。
package com.sort;
import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Date;
public class BubbleSort {
public static void main(String[] args) {
int arr[] = {3,9,-1,10,20};
//为了容量理解,我们把冒泡排序的演变过程展示给大家
//测试
System.out.println("排序前");
System.out.println(Arrays.toString(arr));
bubbleSort(arr);
System.out.println("排序后");
System.out.println(Arrays.toString(arr));
}
public static void bubbleSort(int arr[]){
//第一场排序,就是将最大的数排在最后
int temp = 0;
boolean flag = false;
for (int i = 0; i < arr.length-1; i++){
for (int j = 0; j < arr.length - 1 - i; j++){
//如果前面的数比后面的数大,则交换
if (arr[j] > arr[j+1]){
flag = true;
temp = arr[j];
arr[j] = arr[j+1];
arr[j+1] = temp;
}
}
System.out.println("第" + (i+1) + "趟排序后的数组");
System.out.println(Arrays.toString(arr));
if (!flag){
break;
}else {
flag = false;
}
}
}
}
3.速度测试
package com.sort;
import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Date;
public class BubbleSort {
public static void main(String[] args) {
int[] arr = new int[80000];
for (int i = 0; i < 80000; i++){
arr[i] = (int)(Math.random() * 8000000);
}
Date data1 = new Date();
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-mm-dd HH:mm:ss");
String date1Str = simpleDateFormat.format(data1);
System.out.println("排序前的时间是 = " + date1Str);
bubbleSort(arr);
Date data2 = new Date();
String date2Str = simpleDateFormat.format(data2);
System.out.println("排序后的时间是 = " + date2Str);
}
public static void bubbleSort(int arr[]){
//第一场排序,就是将最大的数排在最后
int temp = 0;
boolean flag = false;
for (int i = 0; i < arr.length-1; i++){
for (int j = 0; j < arr.length - 1 - i; j++){
//如果前面的数比后面的数大,则交换
if (arr[j] > arr[j+1]){
flag = true;
temp = arr[j];
arr[j] = arr[j+1];
arr[j+1] = temp;
}
}
if (!flag){
break;
}else {
flag = false;
}
}
}
}
二、选择排序
1.基本介绍
选择排序(select sorting)也是一种简单的排序方法。它的基本思路是:第一次从 arr[0]~arr[n-1] 中选取最小值,与 arr[0] 交换,第二次从 arr[1]~arr[n-1] 中选取最小值,与 arr[1] 交换,第三次从 arr[2]~arr[n-1] 中选取最小值,与 arr[2] 交换,…,第 i 次从 arr[i]~arr[n-1] 中选取最小值,与 arr[i] 交换。总共经过 n-1 次,得到一个按排序码从小到大排序的有序列表。
2.应用实例
有一群牛,颜值分别是101,34,119,1 请使用选择排序从低到高进行排序[ 101, 34, 119, 1]
选择排序规则:
1.选择排序一共有数组大小-1 轮排序
2.每 1 轮排序,又是一个循环
-先假定当前的这个数是最小数
-然后和后面的每一个数作比较,如果发现有当前数更小的数,就重新确定最小数,并得到下标
-当遍历到数组的最后时,就得到本轮最小数和下标
-交换(代码)
package com.sort;
import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Date;
public class SelectSort {
public static void main(String[] args) {
int[] arr = {101,34,119,1,-1,2,5,778};
System.out.println("排序前");
System.out.println(Arrays.toString(arr));
selectSort(arr);
System.out.println("排序后");
System.out.println(Arrays.toString(arr));
}
//选择排序
public static void selectSort(int[] arr){
//在推导的过程中,有所规律
for (int i = 0; i < arr.length; i++){
int minIndex = i;
int min = arr[i];
for (int j = i + 1; j < arr.length;j++){
if (min > arr[j]){
min = arr[j];
minIndex = j;
}
}
//将最小值放在arr[0],即交换
if (minIndex != i){
arr[minIndex] = arr[i];
arr[i] = min;
}
System.out.println("第"+ i +"轮后");
System.out.println(Arrays.toString(arr));
}
//使用逐步推导的方式来,讲解选择排序
//第一轮
//原始数组: 101 34 119 1
//第一轮排序: 1 34 119 101
//算法:先简单后复杂,就是把一个复杂的算法,拆分成简单的问题
// //第一轮
// int minIndex = 0;
// int min = arr[0];
// for (int j = 0 + 1; j < arr.length;j++){
// if (min > arr[j]){
// min = arr[j];
// minIndex = j;
// }
// }
//
// //将最小值放在arr[0],即交换
// if (minIndex != 0){
// arr[minIndex] = arr[0];
// arr[0] = min;
// }
//
// System.out.println("第一轮后");
// System.out.println(Arrays.toString(arr));
//
// //第二轮
// minIndex = 1;
// min = arr[1];
// for (int j = 1 + 1; j < arr.length;j++){
// if (min > arr[j]){
// min = arr[j];
// minIndex = j;
// }
// }
//
// //将最小值放在arr[0],即交换
// if (minIndex != 1){
// arr[minIndex] = arr[1];
// arr[1] = min;
// }
//
//
// System.out.println("第二轮后");
// System.out.println(Arrays.toString(arr));
//
// //第三轮
// minIndex = 2;
// min = arr[2];
// for (int j = 2 + 1; j < arr.length;j++){
// if (min > arr[j]){
// min = arr[j];
// minIndex = j;
// }
// }
//
// //将最小值放在arr[0],即交换
// if (minIndex != 2){
// arr[minIndex] = arr[2];
// arr[2] = min;
// }
//
//
// System.out.println("第三轮后");
// System.out.println(Arrays.toString(arr));
}
}
3.速度测试
package com.sort;
import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Date;
public class SelectSort {
public static void main(String[] args) {
int[] arr = new int[80000];
for (int i = 0; i < 80000; i++){
arr[i] = (int)(Math.random() * 8000000);
}
Date data1 = new Date();
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-mm-dd HH:mm:ss");
String date1Str = simpleDateFormat.format(data1);
System.out.println("排序前的时间是 = " + date1Str);
selectSort(arr);
Date data2 = new Date();
String date2Str = simpleDateFormat.format(data2);
System.out.println("排序后的时间是 = " + date2Str);
}
//选择排序
public static void selectSort(int[] arr){
//在推导的过程中,有所规律
for (int i = 0; i < arr.length; i++) {
int minIndex = i;
int min = arr[i];
for (int j = i + 1; j < arr.length; j++) {
if (min > arr[j]) {
min = arr[j];
minIndex = j;
}
}
//将最小值放在arr[0],即交换
if (minIndex != i) {
arr[minIndex] = arr[i];
arr[i] = min;
}
}
}
}
三、插入排序
插入式排序属于内部排序法,是对于排序的元素以插入的方式找寻该元素的适当位置,以达到排序的目的。
1.基本介绍
插入排序(Insertion Sorting)的基本思想是:把 n 个待排序的元素看成为一个有序表和一个无序表,开始时有序表中只包含一个元素,无序表中包含 n-1 个元素,排序过程中每次从无序表中取出第一个元素,把它的排序码依次与有序表元素的排序码进行比较,将它插入到有序表中的适当位置,使之称为新的有序表。
2.应用实例
有一群小牛,考试成绩分别是:101,34,119,1 请从小到大排序
ppackage com.sort;
import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Date;
public class InsertSort {
public static void main(String[] args) {
int[] arr = {101,34,119,1};
insertSort(arr);
}
//插入排序
public static void insertSort(int[] arr){
//使用逐步推导的方法来讲解,便于理解
for (int i = 0; i < arr.length; i++){
int insertVal = arr[i];
int insertIndex = i - 1;
while (insertIndex >= 0 && insertVal < arr[insertIndex]){
arr[insertIndex + 1] = arr[insertIndex];
insertIndex--;
}
//当退出while循环时,说明插入的位置找到, insertIndex + 1
if (insertIndex + 1 != i){
arr[insertIndex + 1] = insertVal;
}
System.out.println("第" + i + "轮排序");
System.out.println(Arrays.toString(arr));
}
//第一轮{101,34,119,1} => {34,101,119,1}
//定义待插入的数
// int insertVal = arr[1];
// int insertIndex = 1 - 1;
//
// //说明
// //1.insertIndex >= 0 保证在给insertVal找插入值的时候不越界
// //2.insertVal < arr[insertIndex] 待插入的数,还没有找到插入位置
// //3.就需要持 arr[insertIndex] 后移
// while (insertIndex >= 0 && insertVal < arr[insertIndex]){
// arr[insertIndex + 1] = arr[insertIndex];
// insertIndex--;
// }
// //当退出while循环时,说明插入的位置找到, insertIndex + 1
// arr[insertIndex + 1] = insertVal;
//
// System.out.println("第一轮排序");
// System.out.println(Arrays.toString(arr));
//
// //第二轮
// insertVal = arr[2];
// insertIndex = 2 - 1;
//
// while (insertIndex >= 0 && insertVal < arr[insertIndex]){
// arr[insertIndex + 1] = arr[insertIndex];
// insertIndex--;
// }
// //当退出while循环时,说明插入的位置找到, insertIndex + 1
// arr[insertIndex + 1] = insertVal;
//
// System.out.println("第二轮排序");
// System.out.println(Arrays.toString(arr));
//
// //第三轮
// insertVal = arr[3];
// insertIndex = 3 - 1;
//
// while (insertIndex >= 0 && insertVal < arr[insertIndex]){
// arr[insertIndex + 1] = arr[insertIndex];
// insertIndex--;
// }
// //当退出while循环时,说明插入的位置找到, insertIndex + 1
// arr[insertIndex + 1] = insertVal;
//
// System.out.println("第三轮排序");
// System.out.println(Arrays.toString(arr));
}
}
3.速度测试
package com.sort;
import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Date;
public class InsertSort {
public static void main(String[] args) {
int[] arr = new int[80000];
for (int i = 0; i < 80000; i++){
arr[i] = (int)(Math.random() * 8000000);
}
Date data1 = new Date();
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-mm-dd HH:mm:ss");
String date1Str = simpleDateFormat.format(data1);
System.out.println("排序前的时间是 = " + date1Str);
insertSort(arr);
Date data2 = new Date();
String date2Str = simpleDateFormat.format(data2);
System.out.println("排序后的时间是 = " + date2Str);
}
//插入排序
public static void insertSort(int[] arr){
//使用逐步推导的方法来讲解,便于理解
for (int i = 0; i < arr.length; i++){
int insertVal = arr[i];
int insertIndex = i - 1;
while (insertIndex >= 0 && insertVal < arr[insertIndex]){
arr[insertIndex + 1] = arr[insertIndex];
insertIndex--;
}
//当退出while循环时,说明插入的位置找到, insertIndex + 1
if (insertIndex + 1 != i){
arr[insertIndex + 1] = insertVal;
}
}
}
}
四、希尔排序
希尔排序是希尔(DonaldShell)于 1959 年提出的一种排序算法,希尔排序也是一种插入排序,它是简单插入排序经过改进之后的一种更高效的版本,也称为缩小增量排序。
1.基本介绍
希尔是把记录按下标的一定增量分组,对每组使用直接插入排序算法排序;随着增量逐渐减少,每组包含的关键词越来越多,当增量减至 1 时,整个文件给分成一组,算法便终止。
2.应用实例
有一群小牛,考试成绩分别是 {8,9,1,7,2,3,5,4,6,0} 请从小到大排序,请分别使用
1)希尔排序时,对有序序列在插入时采用交换法,并测试排序速度
2)希尔排序时,对有序列表在插入时采用移动法,并测试排序速度
1)交换法
package com.sort;
import java.util.Arrays;
public class ShellSort {
public static void main(String[] args) {
int[] arr = {8,9,1,7,2,3,5,4,6,0};
shellSort(arr);
}
public static void shellSort(int[] arr){
int temp = 0;
//根据规律可得
for (int gap = arr.length / 2; gap > 0; gap /= 2){
for (int i = gap; i < arr.length; i++){
//遍历各组中所有的元素(共arr.length / 2组)
for (int j = i - gap; j >= 0; j -= gap){
//如果当前元素大于加上步长后的那个元素,说明交换
if (arr[j] > arr[j+gap]){
temp = arr[j];
arr[j] = arr[j+gap];
arr[j+gap] = temp;
}
}
}
System.out.println("希尔排序第 " + gap + " 轮后 = " + Arrays.toString(arr));
}
// //第一轮
// //将10个数分成五份
// for (int i = 5; i < arr.length; i++){
// //遍历各组中所有的元素(共五组,每组两个元素)
// for (int j = i -5; j >= 0; j-=5){
// //如果当前元素大于加上步长后的那个元素,说明交换
// if (arr[j] > arr[j+5]){
// temp = arr[j];
// arr[j] = arr[j+5];
// arr[j+5] = temp;
// }
// }
// }
// System.out.println("希尔排序第一轮后 = " + Arrays.toString(arr));
//
// //第2轮
// //将10个数分成2份
// for (int i = 2; i < arr.length; i++){
// //遍历各组中所有的元素(共五组,每组两个元素)
// for (int j = i -2; j >= 0; j -= 2){
// //如果当前元素大于加上步长后的那个元素,说明交换
// if (arr[j] > arr[j+2]){
// temp = arr[j];
// arr[j] = arr[j+2];
// arr[j+2] = temp;
// }
// }
// }
// System.out.println("希尔排序第二轮后 = " + Arrays.toString(arr));
//
// //第3轮
// //将10个数分成3份
// for (int i = 1; i < arr.length; i++){
// //遍历各组中所有的元素(共五组,每组两个元素)
// for (int j = i - 1; j >= 0; j -= 1){
// //如果当前元素大于加上步长后的那个元素,说明交换
// if (arr[j] > arr[j+1]){
// temp = arr[j];
// arr[j] = arr[j+1];
// arr[j+1] = temp;
// }
// }
// }
// System.out.println("希尔排序第三轮后 = " + Arrays.toString(arr));
}
}
2)移动法
package com.sort;
import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Date;
public class ShellSort {
public static void main(String[] args) {
int[] arr = {8,9,1,7,2,3,5,4,6,0};
// shellSort(arr);
shellSort2(arr);
}
//对交换式的希尔排序进行优化 -> 移位法
public static void shellSort2(int[] arr){
//增量gap,并逐步缩小
for (int gap = arr.length / 2; gap > 0; gap /= 2){
//从第gap个元素,逐个对其所在的组进行直接插入排序
for (int i = gap; i < arr.length; i++){
int j = i;
int temp = arr[j];
if (arr[j] < arr[j-gap]){
while(j - gap >= 0 && temp < arr[j - gap]){
//移动
arr[j] = arr[j-gap];
j -= gap;
}
//当退出while后,就给temp找到插入的位置
arr[j] = temp;
}
}
System.out.println("希尔排序第 " + gap + " 轮后 = " + Arrays.toString(arr));
}
}
}
3.速度测试
1)交换法
package com.sort;
import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Date;
public class ShellSort {
public static void main(String[] args) {
int[] arr = new int[80000];
for (int i = 0; i < 80000; i++){
arr[i] = (int)(Math.random() * 8000000);
}
Date data1 = new Date();
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-mm-dd HH:mm:ss");
String date1Str = simpleDateFormat.format(data1);
System.out.println("排序前的时间是 = " + date1Str);
shellSort(arr);
Date data2 = new Date();
String date2Str = simpleDateFormat.format(data2);
System.out.println("排序后的时间是 = " + date2Str);
}
public static void shellSort(int[] arr){
int temp = 0;
//根据规律可得
for (int gap = arr.length / 2; gap > 0; gap /= 2){
for (int i = gap; i < arr.length; i++){
//遍历各组中所有的元素(共arr.length / 2组)
for (int j = i - gap; j >= 0; j -= gap){
//如果当前元素大于加上步长后的那个元素,说明交换
if (arr[j] > arr[j+gap]){
temp = arr[j];
arr[j] = arr[j+gap];
arr[j+gap] = temp;
}
}
}
}
}
}
2)移动法
package com.sort;
import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Date;
public class ShellSort {
public static void main(String[] args) {
// int[] arr = {8,9,1,7,2,3,5,4,6,0};
int[] arr = new int[80000];
for (int i = 0; i < 80000; i++){
arr[i] = (int)(Math.random() * 8000000);
}
Date data1 = new Date();
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-mm-dd HH:mm:ss");
String date1Str = simpleDateFormat.format(data1);
System.out.println("排序前的时间是 = " + date1Str);
// shellSort(arr);
shellSort2(arr);
Date data2 = new Date();
String date2Str = simpleDateFormat.format(data2);
System.out.println("排序后的时间是 = " + date2Str);
}
public static void shellSort(int[] arr){
int temp = 0;
//根据规律可得
for (int gap = arr.length / 2; gap > 0; gap /= 2){
for (int i = gap; i < arr.length; i++){
//遍历各组中所有的元素(共arr.length / 2组)
for (int j = i - gap; j >= 0; j -= gap){
//如果当前元素大于加上步长后的那个元素,说明交换
if (arr[j] > arr[j+gap]){
temp = arr[j];
arr[j] = arr[j+gap];
arr[j+gap] = temp;
}
}
}
// System.out.println("希尔排序第 " + gap + " 轮后 = " + Arrays.toString(arr));
}
}
//对交换式的希尔排序进行优化 -> 移位法
public static void shellSort2(int[] arr){
//增量gap,并逐步缩小
for (int gap = arr.length / 2; gap > 0; gap /= 2){
//从第gap个元素,逐个对其所在的组进行直接插入排序
for (int i = gap; i < arr.length; i++){
int j = i;
int temp = arr[j];
if (arr[j] < arr[j-gap]){
while(j - gap >= 0 && temp < arr[j - gap]){
//移动
arr[j] = arr[j-gap];
j -= gap;
}
//当退出while后,就给temp找到插入的位置
arr[j] = temp;
}
}
//System.out.println("希尔排序第 " + gap + " 轮后 = " + Arrays.toString(arr));
}
}
}
总结
以上就是本章要讲的内容,本文仅仅简单复述了老师讲课的文本内容,内容有误麻烦联系。