排序算法包括 内部排序 和 外部排序,重点要掌握的是 八大内部排序算法:(这里假设从小到大排序)
分别是:冒泡排序、插入排序、选择排序、希尔排序、堆排序、快速排序、归并排序、基数排序
① 冒泡排序:
基本思路:在一趟排序中,从左到右扫描数组,如果发现相邻两个数中,前一个数比后一个数大,则交换两个数。第1趟排序的代码是:
for(int j = 0 ; j < arr.length - 1 - 0 ; j ++ ){
//如果后面的数比前面的数大,则交换
if(arr[j] > arr[j+1]){
int temp = arr[j];
arr[j] = arr[j+1];
arr[j+1] = temp ;
}
}
因为每趟排序确定一个数在最右端,因此要对以上操作进行循环执行,冒泡排序的代码为:
public static void bubbleSort(int arr[]){
int temp = 0 ;// 纯属用来完成交换两个数的操作
boolean flag = false ; //用来判断该趟排序是否进行了交换,如果没有进行交换,说明数列已经有序,
//可以直接退出循环了,这是优化冒泡排序的重要一步
for(int i = 0 ; i < arr.length - 1 ; i ++){ //最多进行(length-1)次排序
for(int j = 0 ; j < arr.length - 1 - i ; i ++) {
if(arr[j] < a[j+1]){
temp = arr[j];
arr[j] = arr[j+1];
arr[j+1] = temp ;
flag = true;
{
}
if(!flag) //若flag为false,说明一次交换也没有发生
break;
else flag = false; //如果进行了交换,说明还没有排序完成,重新配置flag,进入下一轮排序
}
}
② 简单选择排序:
基本思路:每一趟排序中,都选择出一个最小值,将其置于最左端,而最左端的坐标 每趟排序向右移一个单位。第1趟排序的代码为:
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;
}
}
//经历一趟for循环后,最小值以及坐标已经被min 和 minIndex 保存起来了
if(minIndex != 0){
arr[minIndex] = arr[0] ;
arr[0] = min;
}//将最小值元素和第一个元素交换位置
简单选择排序的代码为:
// 选择排序算法
public static void selectSort(int[] arr) {
for (int i = 0; i < arr.length; i++) {
int minIndex = i;//当前认定的最小值的下标
int min = arr[i];//当前认定的最小值
for (int j = 1 + i; j < arr.length; j++) {
if (min > arr[j]) {//只要出现更小的数,就把值赋给min
min = arr[j];
minIndex = j;//赋最小值的同时,还要把最小值的位置给记录下来
}
}
if (minIndex != i) {
arr[minIndex] = arr[i];
arr[i] = min;
System.out.printf("第%d次排序的序列为: \n", i);
System.out.println(Arrays.toString(arr));
}
}
}
③ 直接插入排序:
该排序将数列分为有序区和无序区,假设有序区在左边。每趟排序从无序区中取头一个元素放到有序区中适当的位置。寻找插入位置采用 移动法 ,即将待插入元素从 有序区最右端 开始,依次同每个元素比较,如果待插入元素 小于 当前元素,就将当前元素 向右移动一位。
第一趟排序的代码如下:
int insertVal = arr[1]; //此时无序区一个元素,有序区第一个元素即为数组的arr[1]
int insertIndex = 1 - 1 ;
while( insertIndex >= 0 && insertVal < arr[insertIndex] ){
arr[insertIndex + 1 ] = arr[insertIndex ]; //将当前元素后移一位
insertIndex -- ;//
}
if((insertIndex + 1) != 1 ){ //这个判断是减少一些不必要的插入
//即经过判断以后,发现元素应该插入的位置就是元素原来的位置
//这时候选择不插入。
arr[insertIndex + 1] = insertVal;
}
直接插入排序的代码如下:
// 直接插入排序
public static void insertSort(int[] arr) {
for (int i = 1; i < arr.length; i++) {
int insertVal = arr[i]; // 表示当前要插入到有序区去的数
int insertIndex = i - 1;
// 表示当前要插入的数应该在有序区的位置,是一个比较出来的值
// 初值为有序区最右端的值
/* 说明:
* 1、insertIndex >= 0 保证在给insertVal找插入位置不越界
* 2、insertVal < arr[insertIndex]表示当前还没找到插入位置,需要继续往前找
*/
while (insertIndex >= 0 && insertVal < arr[insertIndex]) {
arr[insertIndex + 1] = arr[insertIndex];
insertIndex--;
}
if((insertIndex + 1 )!= i){
arr[insertIndex + 1] = insertVal;
}
System.out.println("第"+i+"次输出的结果是:");
System.out.println(Arrays.toString(arr));
}
}
④ 希尔排序:(难点)
希尔排序要求,在每趟排序中对数组按照 固定间距 进行分组,在 组内 进行插入排序。但每趟排序后需要将 固定间距 减半。 以下颜色相同的数字为一组。
首先确定一个增量,用int gap表示,增量的值作为“大前提”。(在平常的for循环中我们喜欢i++,这时候我们的“大前提”就是gap=1,),在大前提的基础上,逐 组 进行插入排序。(一组一组地排)
希尔排序的第1趟代码:
//假设此时gap = 5;
for(int i = 5 ; i < arr.length ; i ++){
//以下的办法就是插入排序的办法,只是此时元素移动的单位为5
int temp = arr[i]; //要插入的数
int j = i - 5 ; //初始化插入的位置
while(j >= 0 && temp < arr[j]){
arr[j + 5] = arr[j]
j = j - 5;
}
if((j + 5) != i){
arr[j + 5] = temp ;
}
}
希尔排序的代码:
public static void shellSortMove(int[] arr) {
int count = 0;
// 增量gap不变
for (int gap = arr.length / 2; gap > 0; gap /= 2) {
// 以gap为增量的大前提
for (int i = gap; i < arr.length; i++) {
// 以下的做法就是插入排序的方法:
int temp = arr[i];// 当前要插入的数
int j = i - gap;// 插入的位置
while (j >= 0 && temp < arr[j]) {
arr[j + gap] = arr[j];
j -= gap;
}
if ((j + gap) != i) {
arr[j + gap] = temp;
}
}
count++;
System.out.printf("在分组为%d的情况下,第%d 次的排序情况为:\n", gap, count);
System.out.println(Arrays.toString(arr));
}
}