排序算法Java代码

本文详细介绍了几种常见的排序算法,包括选择排序、快速排序、冒泡排序和堆排序,以及归并排序的过程。这些算法在不同的场景下有不同的效率表现,如选择排序的时间复杂度为O(n^2),而快速排序平均情况下为O(n*logn)。通过理解这些排序算法,可以更好地优化程序性能。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一 算法简介

  1. 大O表示法
O(n)——n表示操作数。表示的最糟情况下的运行时间
常见:
O(1),也叫常量时间
O(log n),也叫对数时间,这样的算法包括二分查找。
O(n),也叫线性时间,这样的算法包括简单查找。
O(n * log n),这样的算法包括快速排序——一种速度较快的排序算法。
O(n^2),这样的算法包括选择排序——一种速度较慢的排序算法。
O(n!),这样的算法包括旅行商问题的解决方案——一种非常慢的算法。

二.算法复杂度与稳定性

在这里插入图片描述

二 选择排序

1.0索引开始,依次和后面的元素比较大小,小的往前放。第一次完毕后,最小值出现在最小索引处
2.每轮比较完毕后,下一轮会比该轮少比较一个元素
3.一共需要len-1public static void SelectSort(int[] arr){
	for(int i = 0;i < arr.length-1;i++){
		for(int j = i+1; j < arr.length; j++){
			if(arr[j]<arr[i]){
				int temp = arr[j];
				arr[j] = arr[i];
				arr[i] = temp;
			} 
		}
	}
}

三 快速排序

(1) 选择数组的第一个元素为基准值。
(2) 首尾元素同时依次与基准值比较,最终将数组分成两个子数组:小于基准值的元素和大于基准值的元素。
(3) 对这两个子数组进行以上操作。
***先比较大的那边!!
public static void quickSort(int[] arr, int left, int right) {
	if (left< right) {
		int middle = getMiddle(arr, left, right);
        quickSort(arr, left, middle - 1);
        quickSort(arr, middle + 1, right);
    }
}
public int getMiddle(int[] nums,int left,int right){
        int temp = nums[left];
        int j = left;
        for(int i = left+1;i<=right;i++){
            if(nums[i]<temp){
                // j 的初值为 left,先右移,再交换,小于 temp 的元素都被交换到前面
                j++;
                swap(nums,i,j);
            }
        }
        // 在之前遍历的过程中,满足 nums[left + 1..j] < temp,并且 nums(j..i) >= temp
        swap(nums,left,j);
        // 交换以后 nums[left..j - 1] < temp, nums[j] = temp, nums[j + 1..right] >= temp
        return j;        
    }
 private void swap(int[] nums,int left,int right){
        int tep = nums[left];
        nums[left] = nums[right];
        nums[right] = tep;
}

四. 冒泡排序

/*
1.相邻元素两两比较,大的往后交换。第一轮完毕后,最大值出现在最大索引处
2.每轮比较完毕后,下一轮会比该轮少比较一个元素
3.一共需要len-1轮
*/
private static void bubbleSort(int[] arr) {
    for (int i = 0; i < arr.length - 1; i++) {
        //控制比较轮数
        for (int j = 0; j < arr.length - 1 - i; j++) {
            //因为有j+1,所以上面循环控制条件中j < arr.length - 1 - i中的减一是为了控制越界
            if (arr[j] > arr[j + 1]) {
                int temp = arr[j];
                arr[j] = arr[j + 1];
                arr[j + 1] = temp;
            }
        }
    }
}

五 堆排序

  • 堆是具有以下性质的完全二叉树:每个结点的值都大于或等于其左右孩子结点的值,称为大顶堆;或者每个结点的值都小于或等于其左右孩子结点的值,称为小顶堆。
  • 堆排序的基本思想是:将待排序序列构造成一个大顶堆,此时,整个序列的最大值就是堆顶的根节点将其与末尾元素进行交换,此时末尾就为最大值。然后将剩余n-1个元素重新构造成一个堆,这样会得到n个元素的次小值。如此反复执行,便能得到一个有序序列了
步骤一 构造初始堆。将给定无序序列构造成一个大顶堆(一般升序采用大顶堆,降序采用小顶堆)。
步骤二 从最后一个非叶子结点开始(叶结点自然不用调整,最后一个非叶子结点 arr.length/2-1),从左至右,从下至上进行调整。
步骤三 找到第二个非叶节,重复步骤二 ......
步骤四 将堆顶元素与最后的叶子节点元素交换,待调整的长度改为n-1,重复以上操作
import java.util.Arrays;
public static void heapsort(int []arr){
        //1.构建大顶堆
        for(int i=arr.length/2-1;i>=0;i--){
            //从最后一个非叶子结点从下至上,从右至左调整结构
            adjustHeap(arr,i,arr.length);
        }
        //2.调整堆结构+交换堆顶元素与末尾元素
        for(int j=arr.length-1;j>0;j--){
            swap(arr,0,j);//将堆顶元素与末尾元素进行交换
            adjustHeap(arr,0,j);//重新对堆进行调整
        }
 
}
 
    /**
     * 调整大顶堆(仅是调整过程,建立在大顶堆已构建的基础上)
     * @param arr
     * @param i 调整的根节点
     * @param length 此时需要调整的数组的长度
     */  
    public static void adjustHeap(int []arr,int i,int length){
        int temp = arr[i];//先取出当前元素i
        for(int k=i*2+1;k<length;k=k*2+1){//从i结点的左子结点开始,也就是2i+1处开始
            if(k+1<length && arr[k]<arr[k+1]){//如果左子结点小于右子结点,k指向右子结点
                k++;
            }
            if(arr[k] >temp){//如果子节点大于父节点,将子节点值赋给父节点(不用进行交换)
                arr[i] = arr[k];
                i = k;
            }else{
                break;
            }
        }
        arr[i] = temp;//将temp值放到最终的位置
    }
 
    /**
     * 交换元素
     * @param arr
     * @param a
     * @param b
     */
    public static void swap(int []arr,int a ,int b){
        int temp=arr[a];
        arr[a] = arr[b];
        arr[b] = temp;
    }
}

归并排序

public static void mergesort(int[] arr) {
        // 在排序前,先建好一个长度等于原数组长度的临时数组,避免递归中频繁开辟空间
		int[] temp = new int[arr.length];
		sort(arr, 0, arr.length - 1, temp);
	}
 
private static void sort(int[] arr, int left, int right, int[] temp) {
		if (left < right) {
			int mid = (left + right) / 2;
			sort(arr, left, mid, temp);// 左边归并排序,使得左子序列有序
			sort(arr, mid + 1, right, temp);// 右边归并排序,使得右子序列有序
			merge(arr, left, mid, right, temp);// 将两个有序子数组合并操作
		}
	}
 
private static void merge(int[] arr, int left, int mid, int right,
			int[] temp) {
		int i = left;// 左序列指针
		int j = mid + 1;// 右序列指针
		int t = 0;// 临时数组指针
		//下面代码就像归并两个已经排好序的列表一样!
		while (i <= mid && j <= right) {
			if (arr[i] <= arr[j]) {
				temp[t++] = arr[i++];
			} else {
				temp[t++] = arr[j++];
			}
		}
		while (i <= mid) {// 将左边剩余元素填充进temp中
			temp[t++] = arr[i++];
		}
		while (j <= right) {// 将右序列剩余元素填充进temp中
			temp[t++] = arr[j++];
		}
		t = 0;
		// 将temp中的元素全部拷贝到原数组中
		while (left <= right) {
			arr[left++] = temp[t++];
		}
	}
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值