Java 实现经典排序算法的思路详解

数组排序问题

1.冒泡排序算法

冒泡排序(Bubble Sort) - 通过不断交换相邻元素的位置,逐步将最大或最小的元素"冒泡"到序列的两端。

思路:

冒泡排序算法的一趟原理如下:

  1. 相邻元素进行两两比较,如果前者大于后者,则交换,否则不变。

  2. 每一趟依次向后进行第1步,直到最后一个元素。

  3. 经过一趟的依次比较后的结果是,最后一个数是本趟比较中最大的数。所谓大数 "沉入水底" ,轻的气泡 "向上冒泡"。

  4. 继续重复1、2、3 步骤。每趟只比较到上一步剩下的部分即可(除去最后的已经 "沉到底部" 的元素)。

  5. 详细步骤如下:

冒泡排序 :比较次数(内层循环) 和 趟数(外层循环)

[7 3 2 1 9]:

每一趟 找出最大值放到最后

  • 总结规律:i<length-1 j<length-i-1
  • 第一趟:i=0 j<=3
  • 比较第一次:(j和j+1)
  • j=0:3 7 2 1 9
  • j=1:3 2 7 1 9
  • j=2:3 2 1 7 9
  • j=3:3 2 1 7 [9]
  • 第二趟:i=1 j<=2
  • j=0:2 3 1 7 9
  • j=1:2 1 3 7 9
  • j=2:2 1 3 [7 9]
  • 第三趟:i=2 j<=1
  • j=0:1 2 3 7 9
  • j=1:1 2 [3 7 9]
  • 第四趟:i=3 j<=0
  • j=0:1 [2 3 7 9]
  • 总结规律:i<length-1 j<length-i-1
  • 交换(j和j+1)

具体代码如下:

java 复制代码
	public static void maopao(){
		int[] arr = {7,3,12,1,0};
		for (int i = 0; i < arr.length-1; i++) {
			for (int j = 0; j < arr.length-i-1; j++) {
				if(arr[j]>arr[j+1]){
					int temp = arr[j];
					arr[j] = arr[j+1];
					arr[j+1] = temp;
				}				
			}
		}
		System.out.println(Arrays.toString(arr));
	}

2.选择排序算法:

选择排序(Selection Sort) - 每一轮在剩余未排序的元素中找到最小(或最大)的元素,放到已排序部分的末尾

思路:

选择排序每趟选择一个固定位置上的元素,向后逐一和此位置上的数进行比较,如果小于此位置上的数,则交换。

一趟结束后,此位置上的数就是当前排序序列中最小的元素了。

重复上面的步骤即可排序成功。

步骤举例:

  • 选择排序:每次拿i上的元素和后面的数一一比较
    • [3,6,9,2,7] i 和 j 比较+
    • 第一趟:i=0:[3] 6 9 2 7 | 1<=j<=4
    • j=1:[3] 6 9 2 7 --arr[i]=3和arr[j]=6比较
    • j=2:[3] 6 9 2 7 --arr[i]=3和arr[j]=9比较
    • j=3:[2] 6 9 3 7 --arr[i]=3和arr[j]=2比较
    • j=4:[2] 6 9 3 7 --arr[i]=2和arr[j]=7比较
    • 第二趟:i=1: 2[6]9 3 | 2<=j<=4
    • j=2:2[6]9 3 7 ---arr[i]=6和arr[j]=9比较
    • j=3:2[3]9 6 7 ---arr[i]=6和arr[j]=3比较---
    • j=4:2[3]9 6 7 ---arr[i]=3和arr[j]=7比较---
    • 第3趟:i=2: 2 3[9] 6 7 | 3<=j<=4
    • j=3:2 3 [6] 9 7 ---arr[i]=9和arr[j]=6比较---
    • j=4:2 3 [6] 9 7 ---arr[i]=6和arr[j]=7比较---
    • 第4趟:i=3: 2 3 6[9]7 | 4<=j<=4
    • j=4: 2 3 6[7]9 ---arr[i]=9和arr[j]=7比较---
java 复制代码
/**
	 * 总结:
	 * i--0~length-1
	 * j--i+1~length-1
	 * 比较:
	 * i和j
	 */
	public static void selorder(int[] arr){
//		int[] arr = {3,6,9,2,7};
		for (int i = 0; i < arr.length-1; i++) {
			for (int j = i+1; j <= arr.length-1; j++) {
				if(arr[i]>arr[j]){
					int temp = arr[i];
					arr[i] = arr[j];
					arr[j] = temp;
				}
			}
		}
		//System.out.println(Arrays.toString(arr));
	}

3.插入排序算法:

插入排序(Insertion Sort) - 将每个元素按其正确位置插入已排序的部分,保持已排序部分始终有序

思路:

插入排序思路:

从第二个位置上开始,每次选择一个位置上元素,和前面的数逐一比较,如果小于前面的数,则前面数后移,直到大于前面的数,则停止移动,插入位置。这样每趟走完之后,前面的已经插入的序列一定是有序。

就如生活中的起扑克牌一样,每起一张都会插入手中,但是插入后,手中的牌一直是有序的。

步骤举例

  • 插入排序
    • 第一趟:假设第一个元素是有序的,从第二个开始和前面有序的序列中插入到合适位置
    • 第一趟:[9] (2) 1 7 4 3 6
    • 第一次:[2 9] 1 7 4 3 6
    • 第二趟:[2 9] (1) 7 4 3 6
    • 第一次:2 1 9 7 4 3 6
    • 第二次:1 2 9 7 4 3 6
    • 第三趟:[1 2 9] (7) 4 3 6
    • 第一次:...
    • 插入排序每一趟的结果是保证前面的是有序的序列。
java 复制代码
	public static void insertOrder() {
		int[] arr = {9,8,7,6,5,4,3,2};
		for (int i = 1; i < arr.length; i++) {
			int insert = arr[i];
			for (int j = i; j > 0; j--) {
				//前面的数大于已经选择插入的数,则后移
				if(arr[j-1]>insert) {
					arr[j] = arr[j-1];
					arr[j-1] = insert;
				}else {
					arr[j] = insert;
					break;
				}
			}
		}
		System.out.println("排序后:"+Arrays.toString(arr));
	}

4.快速排序算法

快速排序(Quick Sort) - 使用分治策略,选取一个基准元素,将数组划分为两部分,左边的元素都小于基准,右边的元素都大于基准,然后递归地对左右两边进行快速排序

思路:

需要使用到递归

每次选择一个元素,通过一趟的过程,前后比较,从而找到自己的合适位置,即此位置前的都比次数小,此位置之后的,都比次数大。

然后再对已经分割的两部分,重复递归使用相同的方法来找每个数的位置。递归嵌套即可完成排序。

步骤举例

  • 快速排序
    • 初始数组:4 6 9 7 8 1 3
    • 开始选择第一数,分别和对称其他位置上的数比较,找到合适位置
    • 第一趟:和最后一位的3比较后结果为: 【4】 6 9 7 8 1 3
      • 第一次: 3 6 9 7 8 1 [4 ]
      • 第二次: 3 [4 ] 9 7 8 1 6
      • 第三次: 3 1 9 7 8 [4 ] 6
      • 第四次:3 1 [4 ] 7 8 9 6
      • 第五次:3 1 [4 ] 7 8 9 6 和8比较 不要交换,所以和第四次一致
      • 第六次:3 1 [4 ] 7 8 9 6 同上
      • 注意:第一趟完成后,我们可以看到,4 所在位置之前的都比4小,之后的都比4大
      • 下面再分别对于前后两部分使用相同的思路进行交换即可
    • 第二趟:3 1 [4 ] 7 8 9 6
      • 第一次:{1 3 } 4 {6 8 9 7} 说明:这里同时找前面一组中1的位置,和后面一组中7的位置
      • 第二次:{1 3 } 4 {6 7 9 8}
      • 第三次:{1 3 } 4 {6 7 9 8}
      • 第二趟结束
    • 第三趟:1 3 4 6 7{ 9 8}
      • 第一次:1 3 4 6 7{ 8 9}
java 复制代码
package com;

import java.util.Arrays;

public class QuickSort {
	public static void quickSort(int[] arr,int low,int high){
        int i,j,temp,t;
        if(low>high){
            return;
        }
        i=low;
        j=high;
        //temp就是基准位
        temp = arr[low];
 
        while (i<j) {
            //先看右边,依次往左递减
            while (temp<=arr[j]&&i<j) {
                j--;
            }
            //再看左边,依次往右递增
            while (temp>=arr[i]&&i<j) {
                i++;
            }
            //如果满足条件则交换
            if (i<j) {
                t = arr[j];
                arr[j] = arr[i];
                arr[i] = t;
            }
 
        }
        //最后将基准为与i和j相等位置的数字交换
         arr[low] = arr[i];
         arr[i] = temp;
        //递归调用左半数组
        quickSort(arr, low, j-1);
        //递归调用右半数组
        quickSort(arr, j+1, high);
    }
 
 
    public static void main(String[] args){
        int[] arr = {10,7,2,4,7,62,3,4,2,1,8,9,19};
        quickSort(arr, 0, arr.length-1);
        System.out.println(Arrays.toString(arr));
    }

}

5. 希尔排序

希尔排序(Shell Sort) - 是插入排序的一种优化版本,通过定义一个间隔序列来分组元素,使得不同组内的元素相对较远,从而减少整体的交换次数。

以下是一个简单的 Java 语言实现希尔排序的示例。在这个例子中,我将展示一种基于经典希尔排序算法思想的实现,其中采用的是Hibbard增量序列(即增量每次都为前一次的一半,直到增量为1)。

java 复制代码
public class ShellSort {
    /**
     * 希尔排序(Hibbard增量序列)
     *
     * @param arr 待排序的整数数组
     */
    public static void shellSort(int[] arr) {
        // 获取数组长度
        int n = arr.length;

        // 开始时设定一个较大的步长(通常是n/2,这里简化为直接使用常量)
        int gap = n / 2;
        
        while (gap > 0) {
            // 按照当前步长进行插入排序
            for (int i = gap; i < n; i++) {
                // 将arr[i]插入到arr[i-gap], arr[i-2*gap]...已经排序好的序列中
                int temp = arr[i];
                int j;
                for (j = i; j >= gap && arr[j - gap] > temp; j -= gap) {
                    arr[j] = arr[j - gap];
                }
                // 插入元素
                arr[j] = temp;
            }

            // 缩小增量
            gap /= 2; // 或者 gap = (gap == 2) ? 1 : gap / 2; 这种方式可以防止gap变为0
        }
    }

    public static void main(String[] args) {
        int[] arr = {5, 1, 7, 3, 1, 6, 9, 4};
        shellSort(arr);
        // 输出排序后的数组
        for (int num : arr) {
            System.out.print(num + " ");
        }
    }
}

这段代码首先设置了一个初始步长(gap),然后在每一次循环中,都会对所有按照步长分组的子序列进行插入排序。随着步长逐渐减小至1,整个数组就被分成了越来越多的小组,最终实现全局有序。当步长减小到1时,实际上就是执行了一次完整的插入排序,此时数组已经是有序的了。

相关推荐
秋夫人3 分钟前
B+树(B+TREE)索引
数据结构·算法
kinlon.liu4 分钟前
零信任安全架构--持续验证
java·安全·安全架构·mfa·持续验证
王哲晓25 分钟前
Linux通过yum安装Docker
java·linux·docker
java66666888830 分钟前
如何在Java中实现高效的对象映射:Dozer与MapStruct的比较与优化
java·开发语言
Violet永存31 分钟前
源码分析:LinkedList
java·开发语言
执键行天涯31 分钟前
【经验帖】JAVA中同方法,两次调用Mybatis,一次更新,一次查询,同一事务,第一次修改对第二次的可见性如何
java·数据库·mybatis
梦想科研社39 分钟前
【无人机设计与控制】四旋翼无人机俯仰姿态保持模糊PID控制(带说明报告)
开发语言·算法·数学建模·matlab·无人机
Milo_K40 分钟前
今日 leetCode 15.三数之和
算法·leetcode
Darling_0044 分钟前
LeetCode_sql_day28(1767.寻找没有被执行的任务对)
sql·算法·leetcode
AlexMercer10121 小时前
【C++】二、数据类型 (同C)
c语言·开发语言·数据结构·c++·笔记·算法