排序

排序算法:

  1. 内部排序:值将需要处理的数据加载到内存进行排序
    1. 插入排序
      1. 直接插入排序
      2. 希尔排序
    2. 选择排序
      1. 简单选择排序
      2. 堆排序
    3. 交换排序
      1. 冒泡排序
      2. 快速排序
    4. 归并排序
    5. 基数排序(桶排序)
  2. 外部排序:数据量过大,必须借助外存

算法时间复杂度:

  1. 时间频度:一个算法中的语句执行次数称为语句频度或时间频度T(n)

  2. 时间复杂度:O(1) <O(logn)<O(n)<O(nlogn)<O(n2)<O(n3)<O(nk)<O(2n)<O(n!)

    1. 常数阶O(1):无论代码多少行,只要没有循环就是常数阶

    2. 对数阶O(logn):

      int i = 1;
      while (i<n){
          i = i * 2;        //乘以2就是2为底的对数log2n
      }
      
    3. 线性阶O(n):

      for(int i = 0;i < n;i++){        //循环n次就是O(n)
          j = i;
          j++;
      }
      
    4. 线性对数阶O(nlogn):

      for(int i = 0;i < n;i++){        //循环n次就是n倍的对数阶
          while (i<n){
              i = i * 2;        //乘以2就是2为底的对数log2n
          }
      }
      
    5. 平方阶O(n^2):

      for(int i = 0;i < n;i++){        //循环n的平方次
          for(int j = 0;j < n;j++){       
      		
          }
      }
      

平均时间复杂度和最坏时间复杂度:

排序法平均时间最差时间备注
冒泡O(n^2)O(n^2)
交换O(n^2)O(n^2)
选择O(n^2)O(n^2)
插入O(n^2)O(n^2)
基数O(log_R^B)O(log_R^B)
希尔O(nlogn)O(n^s) 1<s<2
快速O(nlogn)O(n^2)
归并O(nlogn)O(nlogn)
O(nlogn)O(nlogn)

算法空间复杂度:该算法占用的存储空间
在这里插入图片描述

冒泡排序

从前向后,依次比较相邻元素的值,若发现逆序则交换,使值较大的元素依次向后移动。

优化:如果在某次排序过程中没有发生一次交换,说明已经排好序

import java.util.Arrays;
import java.util.Date;
import java.text.SimpleDateFormat;

class Eg415MathDemo 
{
	public static void main(String[] args) 
	{
		int[] a = {16,25,9,90,23};

		//排序之前的时间
		Date date1 = new Date();
		//原时间格式
		SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
		//格式化日期对象
		String str = simpleDateFormat.format(date1);
		System.out.println(str);

		//冒泡排序
		bubble(a);

		//排序之后的时间
		Date date2 = new Date();
		//格式化日期对象
		String str2 = simpleDateFormat.format(date1);
		System.out.println(str2);
	}

	public static void bubble(int[] a){
		System.out.println("排序之前的数组:");
		printArray(a);
		boolean flag = false;   //优化标识变量,标识是否发生交换
		for (int i = 0;i < a.length - 1 ;i++ )   //时间复杂度O(n^2)
		{
			for (int j = 0;j < a.length -1-i ;j++ )
			{
				if (a[j]>a[j+1])
				{
					flag = true;
					int temp = a[j+1];
					a[j+1] = a[j];
					a[j] = temp;
				}
			}
			if (flag = false)          //(优化)在一趟排序中,一次都没有交换过
			{
				break;
			}else
				flag = false;          //重置为false,进行下次判断
		}
		System.out.println("\n排序之后的数组:");
		//printArray(a);
		//System.out.println(arr2String(a));
		//第三种输出方式
		System.out.println(Arrays.toString(a));   //将数组转成字符串
	}

	public static void printArray(int[] arry){
		for (int i = 0;i < arry.length ;i++ )
		{
			System.out.print(arry[i]+"\t");
		}
	}
	
	//第二种输出数组模式
	public static String arr2String(int[] arry) {
		StringBuilder sb = new StringBuilder();
		sb.append("[");
		for (int i = 0;i < arry.length;i++ )
		{
			if (i == arry.length - 1)           //最后一个
			{
				sb.append(arry[i]).append("]");
			}else
				sb.append(arry[i]).append(",");
		}
		return sb.toString();             //将StringBuilder类型转换为String类型
	}
}

选择排序

class Eg418SelectionSort 
{
	public static void main(String[] args) 
	{
		System.out.println("排序之前的数组:");
		int[] pData = {67,88,99,15,3,56,1,78,63};
		print(pData);
		System.out.println("\n排序之后的数组:");
		selectionSort(pData,pData.length);
		print(pData);
	}

	public static void print(int[] c){
		for (int i = 0;i < c.length ;i++ )
		{
			System.out.print(c[i]+"\t");
		}
	}

	public static void selectionSort(int[] data,int size){
		int i = 0,j = 0,min = 0;      //min假设为最小值数组元素的下标值
		for (i=0;i < size -1  ;i++ )
		{
			min = i;
			for (j = i + 1;j < size ;j++ )
			{
				if (data[j] < data[min])        //把大的往后移
				{
					min = j;
				}
			}
			swap(data,min,i);
		}
	}

	public static void swap(int[] x,int c,int d){
		int temp = x[d];
		x[d] = x[c];
		x[c] = temp;
	}
}

选择排序时间会比冒泡排序短

插入排序

把待排序的数组看成一个有序表和一个无序表,开始时有序表只有一个元素(第一个元素),无序表中有n-1个元素。每次从无序表中取一个元素和有序表进行比较,插入到有序表的位置。

import java.util.Arrays;

class InsertSort 
{
	public static void main(String[] args) 
	{
		int[] arr ={34,1,23,2};
		System.out.println("排序之前的数组;");
		System.out.println(Arrays.toString(arr));   //将数组转成字符串
		insertSort(arr);

	}

	public static void insertSort(int[] arr){
		for (int i = 1;i < arr.length ;i++ )  //从1开始,因为从第二个元素开始与前一个比较
		{
			int indexval = arr[i];       //记录当前与前面元素相比较的值
			int index = i -1;           //当前元素前面数的下标
			while (index >= 0 && indexval < arr[index])           //当前元素比前一个元素小
			{
				arr[index+1] = arr[index];        //把前一个元素向后移
				index--;             //index向前移继续与前面的数字(有序的)相比较
			}
			arr[index+1] = indexval;    //因为while循环中index--,所以需要加1,将元素赋值到新的位置
		}
		System.out.println("排序之后的数组;");
		System.out.println(Arrays.toString(arr));
	}
}

希尔排序

希尔排序是对插入排序的改进,分组缩小增量排序
在这里插入图片描述

import java.util.Arrays;

class ShellSort 
{
	public static void main(String[] args) 
	{
		int[] arr = {8,9,1,7,2,3,5,4,6,0};
		System.out.println(Arrays.toString(arr));
		shell2(arr);
	}

	//希尔排序交换式(效率低)
	public static void shell(int[] arr){
		int temp = 0;   //用于交换数据
		int count = 0;  //用于统计分组的数目
		for (int gap = arr.length/2;gap>0 ;gap/=2 )       //每一次分组,组数为gap
		{
			for(int i = gap;i<arr.length;i++){           //遍历各个组共gap组
				for(int j = i-gap;j >=0;j -= gap){        //遍历组中的元素,步长为gap
					if (arr[j] > arr[j+gap])               //如果当前元素大于加上步长后的元素要交换
					{
						temp = arr[j+gap];
						arr[j+gap] = arr[j];
						arr[j] = temp;
					}
				}
			}
			System.out.println("第"+(++count)+"轮:"+Arrays.toString(arr));
		}
	}

	//希尔排序移位法(效率高)
	public static void shell2(int[] arr){
		int count = 0;
		for (int gap = arr.length/2;gap>0 ;gap/=2 )
		{
			for(int i=gap;i<arr.length;i++){
				//插入排序
				int indexval = arr[i];       //记录当前与前面元素相比较的值
				int index = i -gap;           //当前元素前面数的下标
				if (arr[i] < arr[index])    
				{
					while (index >= 0 && indexval < arr[index])           //当前元素比前一个元素小
					{
						arr[index+gap] = arr[index];        //把前一个元素向后移
						index -=gap;             //index向前移继续与前面的数字(有序的)相比较
					}
					arr[index+gap] = indexval;    //因为while循环中index-gap,所以需要加gap,将元素赋值到新的位置
				}
			}
			System.out.println("第"+(++count)+"轮:"+Arrays.toString(arr));
		}
	}
}
//输出
[8, 9, 1, 7, 2, 3, 5, 4, 6, 0]1轮:[3, 5, 1, 6, 0, 8, 9, 4, 7, 2]2轮:[0, 2, 1, 4, 3, 5, 7, 6, 9, 8]3轮:[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

快速排序

import java.util.Arrays;

class QuickSort 
{
	public static void main(String[] args) 
	{
		int[] arr = {55,44,33,22,11};
		quickSort(arr,0,arr.length-1);
		System.out.println(Arrays.toString(arr));
	}

	public static void quickSort(int[] arr,int left,int right){
		int l = left;
		int r = right;
		int pivot = arr[(left + right)/2];      //中轴值
		int temp = 0;    //用于交换
		while (l < r)           //让比pivot小的值放到左边,比pivot大的放到右边
		{
			while (arr[l] < pivot)      //找比pivot大的,直到找到就退出
			{
				l += 1;    //将l向左移
			}
			while (arr[r] > pivot)       //找比pivot小的,找到就退出
			{
				r -= 1;     //将r向右移
			}			
			if (l >= r)        //必须要有这行,否则数组下标越界
			{
				break;
			}
			//交换
			temp = arr[r];
			arr[r] = arr[l];
			arr[l] = temp;
			//如果交换后发现arr[l] == pivot,那么就将r--才能不断将=pivot的到最后靠近pivot,下一轮可以将该值放右边,避免死循环
			if (arr[l] == pivot)
			{
				r -= 1;
			}
			if (arr[r] == pivot)   //反之
			{
				l += 1;
			}

		}
		//如果l == r;必须l++,r--,否职栈溢出
		if (l == r)
		{
			l += 1;
			r -= 1;
		}
		//向左递归
		if(left < r){
			quickSort(arr,left,r);
		}
		//向右递归
		if(right > l){
			quickSort(arr,l,right);
		}
	}
}

归并排序

采用归并思想实现排序,使用分治算法
在这里插入图片描述
在这里插入图片描述

package calculate;

import java.util.Arrays;

public class MergeSort {

	public static void main(String[] args) {
		int[] arr = {8,4,5,7,1,3,6,2};         //merge7次
		int[] temp = new int[arr.length];
		mergeSort(arr, 0, arr.length-1, temp);
		
		System.out.println(Arrays.toString(arr));
	}
	
	//分+合
	public static void mergeSort(int[] arr,int left,int right,int[] temp) {
		if (left < right) {
			int mid = (left + right)/2;
			//向左递归分解
			mergeSort(arr, left, mid, temp);
			//向右递归分解
			mergeSort(arr, mid+1, right, temp);
			//合并
			merge(arr, left, mid, right, temp);
		}
		
	}
	
	//合并
	/**
	 * @param arr 排序的原始数组
	 * @param left 左边有序的序列的初始索引
	 * @param mid  中间索引
	 * @param right  右边索引
	 * @param temp   中转数组
	 */
	public static void merge(int[] arr,int left,int mid,int right,int[] temp) {
		int i = left;   //初始化i,左边有序序列的初始索引
		int j = mid + 1;    //右边序列初始索引(mid在左边序列的最后一个)
		int t = 0;           //t是指向temp数组的当前索引,列号
		
		//1.先把左右两边的数据(有序)按照规则填充到temp,直到左右两边有一边数据处理完毕为止
		while (i <= mid && j <= right) {
			//如果左边有序序列当前元素小于等于右边序列的当前元素
			//将当前元素拷贝到temp数组,然后t后移,i后移
			if (arr[i] < arr[j]) {
				temp[t] = arr[i];
				t += 1;
				i += 1;
			}else {//反之,将右边序列当前元素填充到temp数组
				temp[t] = arr[j];
				t += 1;
				j += 1;
			}
		}
		
		//2.把有剩余的数据一边依次全部填充到temp
		while (i <= mid) {      //说明左边存在剩余元素
			temp[t] = arr[i];
			t += 1;
			i += 1;
		}
		while (j <= right) {      //说明右边存在剩余元素
			temp[t] = arr[j];
			t += 1;
			j += 1;
		}
		
		//3.将temp数组的元素拷贝到arr,并不是每次拷贝所有的
		t = 0;
		int templeft = left;
		//第一次合并templeft = 0,right = 1,如图中4和8
		//第二次合并templeft = 2,right = 3,如图中5和7
		//第三次合并templeft = 0,right = 3,如图中4,5,7,8
		//最后一次合并templeft = 0,right = 7
		while (templeft <= right) {    
			arr[templeft] = temp[t];
			t += 1;
			templeft += 1;
		}
	}

}

基数排序

基数排序属于分配式排序,桶排序的扩展,稳定性的排序(使用空间换时间)

将所有待比较数值统一为同样的数位长度,数位较短的数前面补零,然后从最低位开始,依次进行一次排序,这样从最低位排序一直到最高位排序完成,完成以后就是有序数列

负数就不用基数排序
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

package calculate;

import java.util.Arrays;

public class RadixSort {

	public static void main(String[] args) {
		int[] arr = {53,3,542,748,14,214};
		//第一轮对个位
		radix(arr);

	}

	//基数排序(使用空间换时间)
	public static void radix(int[] arr) {
		
		//根据前面推导出基数排序
		//1.得到数组中最大数的位数
		int max = arr[0];   //假设第一个数就是最大的
		for (int i = 1; i < arr.length; i++) {
			if (arr[i] > max) {
				max = arr[i];
			}
		}
		//最大数几位
		int maxLength = (max + "").length();     //转换为字符串

		//定义二维数组表示10个桶,每个桶是一维数组,防止数据溢出定成最大的
		int[][] bucket = new int[10][arr.length];
		
		//为了记录每个桶实际存放多少个数据,定义一个一维数组记录各个桶每次放入数据的个数
		int[] bucketElementCounts = new int[10];
		
		//循环轮数(k次循环,n为了取各个位)
		for (int k = 0,n=1; k < maxLength; k++,n *=10) {
			for (int i = 0; i < arr.length; i++) {
				//取出每个元素的位
				int digitOfElement = arr[i] /n %10;
				//放到对应的桶
				bucket[digitOfElement][bucketElementCounts[digitOfElement]] = arr[i];
				bucketElementCounts[digitOfElement]++;          //从0依次递增
			}
			//按照桶的顺序(一维数组的下标依次取出数据,放入原来数组)
			int index = 0;
			//遍历每一个桶,放入到原数组
			for (int i = 0; i < 10; i++) {
				//如果桶中有数据,才放入原数组
				if (bucketElementCounts[i] != 0) {      //有数据
					for (int j = 0; j < bucketElementCounts[i]; j++) {
						//取出元素放到arr
						arr[index] = bucket[i][j];
						index++;
					}
				}
				//每一轮排序后将bucketElementCounts[i]=0
				bucketElementCounts[i] = 0;
			}
			System.out.println("第"+(k+1)+"轮"+Arrays.toString(arr));
		}
		
	}
}
//输出1[542, 53, 3, 14, 214, 748]2[3, 14, 214, 542, 748, 53]3[3, 14, 53, 214, 542, 748]

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值