JAVA 十大排序算法(自用笔记)

本文详细讲解了排序算法的基础,包括冒泡、选择、插入和希尔排序的实现及其时间复杂度分析,重点介绍了如何通过时间复杂度估算算法效率,同时剖析了空间复杂度的概念。通过实例展示了快速排序和归并排序的技巧,以及空间换时间的策略。
摘要由CSDN通过智能技术生成

排序算法

一、排序算法一缆
在这里插入图片描述
二、算法的时间复杂度O(n^M)(算法(程序)的执行时间)

①、度量算法(程序)的执行时间的两种方法,已经时间频度

1)、事后统计的方法
这种方法可行,但是有两个问题,一是要想对设计的算法的运行性能进行评测,需要实际运行该程序,二是所得时间的统计量依赖于计算机的硬件、软件等环境因素,这种方式,要在同一计算机的相同状态下运行,才能比较那个算法速度更快。

2)、事前估算的方法
通过分析某个算法的时间复杂度来判断那个算法更优

3)、时间频度
一个算法花费的时间与算法中语句的执行次数成正比,哪个算法中语句执行次数多,它花费的时间就多,一个算法中语句执行次数称之为语句频度或者时间频度,记为T(n)

4)、计算时间复杂度时,可以忽略常数项、低次项,系数项,因为当数据量足够大时,它们已经起不到关键性的作用了。它们不会随n值的增大而增大

5)、如何计算时间复杂度以及时间复杂度需要注意的细节(来源于Car大佬的学习网址,里面的东西是真不错

三、算法的空间复杂度
1)、.类似于时间复杂度的讨论,一个算法的空间复杂度(Space Complexity)定义为该算法所耗费的存储空间,它也是问题规模n的函数。

2)、空间复杂度(Space Complexity)是对一个算法在运行过程中临时占用存储空间大小的量度。有的算法需要占用的临时工作单元数与解决问题的规模n有关,它随着n的增大而增大,当n较大时,将占用较多的存储单元,例如快速排序和归并排序算法就属于这种情况

3)、在做算法分析时,主要讨论的是时间复杂度。从用户使用体验上看,更看重的程序执行的速度。一些缓存产品(redis, memcache)和算法(基数排序)本质就是用空间换时间.

四、排序算法
在这里插入图片描述

① 冒泡排序(稳定,最坏时间复杂度O(n^2))
我都不想重写写遍,太常见,太基础,看这篇博客,有图解,有代码,有思路,很🆗的。
冒泡排序

② 简单选择排序(不稳定,最坏时间复杂度O(n^2),比冒泡排序要快,测试方法使用了事后统计法)

1)、基本思想,取出数组中最小的放到最前面,取出的数据不与下次做对比,最后就得出排序后的数组了。

2)、基于此思想的算法主要有简单选择排序、树型选择排序和堆排序。

3)、简单选择排序的的基本思路:从arr[1]arr[n]中选出最小,与arr[1]交换位置,在从arr[2]arr[n]中选出最小值,与arr[2]交换位置,以此类推。

4)、代码

/**
	 * 简单选择排序,时间复杂度:O(n2)
	 *虽然时间复杂度一样,但是比冒泡要快
	 * @param arr
	 * @return
	 */
	public static int[] selectSort(int arr[]) {
		for (int i = 0; i < arr.length - 1; i++) {
			int k = i;//拿到第一次遍历的值
			for (int j = k + 1; j < arr.length; j++) {//temp+1,temp的后一个值
				if (arr[j] < arr[k]) {//小于记录下最小值的位置
					k = j;
				}
			}
			//找到最小值,交换位置
			if (i != k) {
				int temp = arr[i];
				arr[i] = arr[k];
				arr[k] = temp;
			}
		}
		return arr;
	}

③ 简单插入排序
1)、基本思想:把待排序的列表看成一个有序列表和一个无序列表,开始时有序列表中只包含一个元素,无序列表中包含有n-1个元素,排序过程中,每次从无序表中取出第一个元素与有序表中的元素进行比较,将他插到合适的位置,使之变为有序列表

2)、代码:

	/**
	 * 插入排序
	 * 时间复杂度 O(n2)
	 */
	public static int[] insertSort(int[] arr){
		//从1开始与前面的值比较
		for (int i = 1; i < arr.length; i++) {
			int k=arr[i];//待插入的数
			int v=i-1;//待插入的前一个
			/**
			 * v>=0 保证在给 k找插入位置,不越界
			 * k<arr[v] 待插入的数,还没有找到位置
			 * 需要后移,满足条件表示k不能插在原来的位置,v需要后移给我们的k预留我i之,v--让k与v前面位置的值比较,v>=0防止越界
			 */
			while (v>=0 && k<arr[v]){
				arr[v+1]=arr[v];
				v--;
			}
			//退出while循环,说明位置找到看,放到当前v的后面一位,一位不满足条件是当前值大于v下标的值,所以在放在v的后一位。
			if (v+1!=i){
				arr[v+1]=k;
			}
		}
		return arr;
	}

④ 简单希尔排序插入排序的一种(交换法,不推荐使用)

	/**
	 * 希尔排序时,对有序序列在插入时采用交换法,并测试排序速度,速度比简单插入排序还慢
	 * @param arr
	 * @return
	 */
	public static  int[] ShellSort(int[] arr){
		//增量gap,并逐步缩小增量
		for (int gap = arr.length/2; gap >0 ; gap /=2) {
			int temp = 0;
			//将gap.length个数据分成gap.length/2组
			for (int i = gap; i < arr.length; i++) {
				//遍历各组中,所有的元素(共gap组),步长gap
				for (int j = i - gap; j >= gap; j -= gap) {
					//如果当前元素大于加上步长后的那个元素,说明交换
					if (arr[j] > arr[j + gap]) {
						temp = arr[j];
						arr[j] = arr[j + gap];
						arr[j + gap] = temp;
					}
				}
			}
		}
		return arr;
	}

⑤ 希尔排序(移动法

	/**
	 * 希尔排序时,对有序序列在插入时采用移动法,并测试排序速度,速度比简单插入排序快很多
	 * @param arr
	 * @return
	 */
	public static  int[] 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,找到位置
					arr[j]=temp;
				}
			}
		}
		return arr;
	}

⑦ 快速排序
1)、核心思想:快速排序

2)、代码

/**
	 * 快速排序
	 * @param array
	 */
	public static int[]  quickSort(int[] array) {
		int len;
		if(array == null
				|| (len = array.length) == 0
				|| len == 1) {
			return array;
		}
		sort(array, 0, len - 1);
		return array;
	}
	/**
	 * 快排核心算法,递归实现
	 * @param array
	 * @param left
	 * @param right
	 */
	public static void sort(int[] array, int left, int right) {
		if(left > right) {
			return;
		}
		// base中存放基准数
		int base = array[left];
		int i = left, j = right;
		while(i != j) {
			// 顺序很重要,先从右边开始往左找,直到找到比base值小的数
			while(array[j] >= base && i < j) {
				j--;
			}

			// 再从左往右边找,直到找到比base值大的数
			while(array[i] <= base && i < j) {
				i++;
			}

			// 上面的循环结束表示找到了位置或者(i>=j)了,交换两个数在数组中的位置
			if(i < j) {
				int tmp = array[i];
				array[i] = array[j];
				array[j] = tmp;
			}
		}

		// 将基准数放到中间的位置(基准数归位)
		array[left] = array[i];
		array[i] = base;

		// 递归,继续向基准的左右两边执行和上面同样的操作
		// i的索引处为上面已确定好的基准值的位置,无需再处理
		sort(array, left, i - 1);
		sort(array, i + 1, right);
	}

	public static int[] mergeSort(int[] a,int low,int high){
		int mid = (low+high)/2;
		if(low<high){
			mergeSort(a,low,mid);
			mergeSort(a,mid+1,high);
			//左右归并
			merge(a,low,mid,high);
		}
		return a;
	}

	public static void merge(int[] a, int low, int mid, int high) {
		int[] temp = new int[high-low+1];
		int i= low;
		int j = mid+1;
		int k=0;
		// 把较小的数先移到新数组中
		while(i<=mid && j<=high){
			if(a[i]<a[j]){
				temp[k++] = a[i++];
			}else{
				temp[k++] = a[j++];
			}
		}
		// 把左边剩余的数移入数组
		while(i<=mid){
			temp[k++] = a[i++];
		}
		// 把右边边剩余的数移入数组
		while(j<=high){
			temp[k++] = a[j++];
		}
		// 把新数组中的数覆盖nums数组
		for(int x=0;x<temp.length;x++){
			a[x+low] = temp[x];
		}
	}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值