java实现十大排序及使用场景

一、十大算法详解

1、直接插入排序

1.1、基本思想

在要排序的一组数中,假设前面(n-1)[n>=2] 个数已经是排好顺序的,现在要把第n个数插到前面的有序数中,使得这n个数也是排好顺序的。如此反复循环,直到全部排好顺序。

1.2、实例:在这里插入图片描述

1.3、用java实现

class insertSort{
	public insertSort(){
		int a[]={49,38,65,97,76,12,27,49};
		int temp=0;
		for(int i=1;i<a.length;i++){
			int j=i-1;
			temp=a[i];
			for(;j>=0&&temp<a[j];j--){
				a[j+1]=a[j];
			}
			a[j+1]=temp;
		}
		for(int i=0;i<a.length;i++){
			System.out.println(a[i]);
		}
	}
}

2、冒泡排序

2.1、基本思想:

在要排序的一组数中,对当前还未排好序的范围内的全部数,自上而下对相邻的两个数依次进行比较和调整,让较大的数往下沉,较小的往上冒。即:每当两相邻的数比较后发现它们的排序与排序要求相反时,就将它们互换。

3.2、实例:在这里插入图片描述

3.3、用java实现

class bubbleSort{
	public bubbleSort(){
		int a[]={49,38,65,97,76,12,27,49};
		int temp=0;
		for(int i=0;i<a.length-1;i++){
			for(int j=0;j<a.length-1-i;j++){
				if(a[j]>a[j+1]){
					temp=a[j+1];
					a[j+1]=a[j];
					a[j]=temp;
				}
			}

		}
		for(int i=0;i<a.length;i++){
			System.out.println(a[i]);
		}
	}
}

3、快速排序

3.1、基本思想:

选择一个基准元素,通常选择第一个元素或者最后一个元素,通过一趟扫描,将待排序列分成两部分,一部分比基准元素小,一部分大于等于基准元素,此时基准元素在其排好序后的正确位置,然后再用同样的方法递归地排序划分的两部分。

3.2、实例:

在这里插入图片描述

3.3、用java实现

class quickSort{
public static void main(String[] args){
	int a[]={49,38,65,97,76,12,27,49};
	if(a.length>0){
		quickSort(a,0,a.length-1);
	}
	
	for(int i=0;i<a.length;i++){
		System.out.println(a[i]);
	}
}

public static void quickSort(int[] list,int low,int high){
	if(low<high){
		int middle=getMiddle(list,low,high);
		quickSort(list,low,middle-1);
		quickSort(list,middle+1,high);
	}
}

public static int getMiddle(int[] list,int low,int high){
	int temp=list[low];
	while(low<high){
		while(low<high&&list[high]>=temp){
			high--;
		}
		list[low]=list[high];
		while(low<high&&list[low]<=temp){
			low++;
		}
		list[high]=list[low];
	}
	list[low]=temp;
	return low;
}
}

4、简单选择排序

4.1、基本思想:

在要排序的一组数中,选出最小的一个数与第一个位置的数交换;然后在剩下的数当中再找最小的与第二个位置的数交换,如此循环到倒数第二个数和最后一个数比较为止。

4.2、实例:在这里插入图片描述

4.3、用java实现

class sort{
	public static void swap(int arr[],int i,int j){
		int temp=arr[i];
		arr[i]=arr[j];
		arr[j]=temp;
	}
	public static void heapify(int tree[],int n,int i) {
		int c1=2*i+1;
		int c2=2*i+2;
		int max=i;
		if(c1<n&&tree[c1]>tree[max])
			max=c1;
		if(c2<n&&tree[c2]>tree[max])
			max=c2;
		if(max!=i){
			swap(tree,max,i);
			heapify(tree,n,max);
		}

	}

	public static void build_heap(int tree[],int n){
		int last_node=n-1;
		int parent=(last_node-1)/2;
		for(int i=parent;i>=0;i--){
			heapify(tree,n,i);
		}

	}

	public static void heap_sort(int tree[],int n){
		build_heap(tree,n);
		for(int i=n-1;i>=0;i--){
			swap(tree,i,0);
			heapify(tree,i,0);
		}
	}
	public static void main(String[] args){
		int a[]={49,38,65,97,76,12,27,49,78,34};
		int n=a.length;
		heap_sort(a,n);
		for(int i=0;i<n;i++){	

			System.out.println(a[i]);
		}
	}
}

5、堆排序

5.1、堆定义:

堆是具有以下性质的完全二叉树:每个父结点的值都大于或等于其左右孩子结点的值,称为大顶堆;或者每个父结点的值都小于或等于其左右孩子结点的值,称为小顶堆

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-f6ubkdV5-1587557129868)(E:\flyeat\我的小心得\数据结构\图片\大小顶堆.png)]

5.2、基本思想:

  1. 将无序序列构建成一个堆,根据升序降序需求选择大顶堆或小顶堆;
  2. 将堆顶元素与末尾元素交换,将最大元素"沉"到数组末端;
  3. 重新调整结构,使其满足堆定义,然后继续交换堆顶元素与当前末尾元素,反复执行调整+交换步骤,直到整个序列有序。

5.3、代码实现

public class selectSort{
	public static void swap(int arr[],int i,int j){
		int temp=arr[i];
		arr[i]=arr[j];
		a[j]=temp;
	}
    
	public static void heapify(int tree[],int n int i) {
		int c1=2*i+1;
		int c2=2*i+2;
		int max=i;
		if(c1<n&&tree[c1]>tree[max])
			max=c1;
		if(c2<n&&tree[c2]>tree[max])
			max=c2;
		if(max!=i){
			swap(tree,max,i);
			heapify(tree,n,max)
		}
	}

	public static void build_heap(int tree[],int n){
		int last_node=n-1;
		int parent=(last_node-1)/2;
		for(int i=parent;i>=0;i--){
			heapify(tree,n,i)
		}
	}

	public static void heap_sort(int tree[],int n){
		build_heap(tree,n);
		for(int i=n-1;i>=0;i--){
			swap(tree,i,0);
			heapify(tree,i,0);
		}
	}
    
	public static void main{
		int a[]={49,38,65,97,76,12,27,49,78,34};
		int n=a.length;
		heap_sort(a,n);
		
		for(int i=0;i<n;i++){
			System.out.println(a[i]);
		}
	}
    
}

6、二分法插入排序(折半插入排序)

6.1、 核心思想

二分法插入排序是在插入第i个元素时,对前面的0~i-1元素进行折半,先跟他们中间的那个元素比,如果小,则对前半再进行折半,否则对后半进行折半,直到left>right,然后再把第i个元素前1位与目标位置之间的所有元素后移,再把第i个元素放在目标位置上。

6.2、代码实现

class Sort{
    public static int[] binaryInsertSort(int[] a){
    	for(int i=0;i<a.length;i++){
    		int temp = a[i];
    		int low=0;
    		int high=i-1;
    		int mid=0;
    		while(low<=high){
    			mid=(low+high)/2;
    			if(temp<a[mid]){
    				high=mid-1;
    			}else{
    				low=mid+1;
    			}
    		}

    		for(int j=i-1;j>=low;j--){
    			a[j+1]=a[j];
    		}

    		if(low!=i){
    			a[low]=temp;
    		}
    	}
    	return a;
    }

	public static void main(String[] args){
		int a[]={49,38,65,97,76,12,27,49};
		a=binaryInsertSort(a);
		
		for(int i=0;i<a.length;i++){
			System.out.print(a[i]+" ");
		}
	}
}

7、希尔排序(缩小增量排序)

7.1 核心思想

核心思想:算法先将要排序的一组数按某个增量d(n/2,n为要排序数的个数)分成若干组,每组中记录的下标相差d.对每组中全部元素进行直接插入排序,然后再用一个较小的增量(d/2)对它进行分组,在每组中再进行直接插入排序。当增量减到1时,进行直接插入排序后,排序完成。

7.2 演示图在这里插入图片描述

7.3、代码实现

class Sort{
    public static int[] shellSort(int[] a){
    	int d = a.length / 2;
        int temp=0;
        while (true) {
            d/=2;
            for (int i=0;i<d;i++) {
               for (int j=i;j+d<a.length;j+=d) {
                  for(int n=i;n+d<a.length;n+=d){  
                      if (a[n]>a[n+d]) {
                          temp = a[n];
                          a[n] = a[n + d];
                          a[n + d] = temp;
                      }
                   }
               }
            }
            if (d == 1)
                break;
        }
        return a;
    }

	public static void main(String[] args){
		int a[]={49,38,65,97,76,12,27,49,1};
		a=shellSort(a);
		
		for(int i=0;i<a.length;i++){
			System.out.print(a[i]+" ");
		}
	}
}

8 、归并排序

8.1 核心思想

基本思想是:归并排序(MERGE-SORT)是利用归并的思想实现的排序方法,该算法采用经典的分治(divide-and-conquer)策略(分治法将问题分(divide)成一些小的问题然后递归求解,而治(conquer)的阶段则将分的阶段得到的各答案”修补”在一起,即分而治之)。
  细化来说,归并排序现将长度为n的无序序列看成是n个长度为1的有序子序列,首先做两两合并,得到n/2个长度为2的有序子序列,再做两两合并…不断重复这个过程,最终可以得到一个长度为n的有序序列。

8.2 演示图

在这里插入图片描述

在这里插入图片描述

8.2代码实现

class Sort{
    public static void mergeSort(int[] a,int left,int right){
    	if(left<right){
    		int middle=(left+right)/2;
    		mergeSort(a,left,middle);
    		mergeSort(a,middle+1,right);
    		merge(a,left,middle,right);
    	}
    }

    public static void merge(int[] a,int left,int middle,int right){
    	int tempArry[]=new int[a.length];
    	int rightStart=middle+1;
    	int leftPos=left;
    	int temp=left;
    	while(left<=middle&&rightStart<=right){
    		if(a[left]<=a[rightStart]){
    			tempArry[temp++]=a[left++];
    		}else {
    			tempArry[temp++]=a[rightStart++];
    		}
    	}

    	while(left<=middle){
    		tempArry[temp++]=a[left++];
    	}

    	while(rightStart<=right){
    		tempArry[temp++]=a[rightStart++];
    	}

    	while(leftPos<=right){
    		a[leftPos]=tempArry[leftPos++];
    	}

    }

	public static void main(String[] args){
		int a[]={49,38,65,97,76,12,27,49};
		mergeSort(a,0,a.length-1);
		
		for(int i:a){
			System.out.print(i+" ");
		}
	}
}

9 基数排序

9.1 核心思想

基本思想是:将所有待比较数值(正整数)统一为同样的数位长度,数位较短的数前面补零。然后,从最低位开始,依次进行一次排序。这样从最低位排序一直到最高位排序完成以后,数列就变成一个有序序列。

基数排序的实现方法分为两种:MSD和LSD。
MSD:最高位优先法(Most Significant Digit First),先比较最高位,最高位分到一个桶中的,再按照第二位进行分桶…,知道分到最后一位,然后再从最小的桶中逐层向上,把元素都拿出来,即完成排序。
LSD:最低位优先法(Least Significant Digit First),先比较最低位,也就是个位,进行分桶,分桶过程中分到一个桶中的数据直接追加到桶中即可,无需排序。然后将所有同种的元素按桶的顺序拿出,重新组成序列,然后比较十位,进行分桶…直到比较到最高位,重新组成序列即可完成排序。

9.2 演示图(LSD为例)在这里插入图片描述

9.3代码实现(LSD为例)

import java.util.List;
import java.util.ArrayList;

@SuppressWarnings("unchecked")
class Sort{
    public static void basicSort(int[] array){
    	int max=0;
    	int digit=10;//0-9
    	int times=0;
        //获得最大值
    	for(int num:array){
    		if(max<num)
    			max=num;
    	}

        //获取最大值位数
    	while(max>0){
    		max/=10;
    		times++;
    	}

        //建立10个集合(0-9)
    	List<ArrayList> baseList=new ArrayList<ArrayList>();
    	for(int i=0;i<digit;i++){
    		ArrayList list1=new ArrayList<>();
    		baseList.add(list1);
    	}

        //进行times次分配和收集;
    	for(int i=0;i<times;i++){
    		for(int j=0;j<array.length;j++){
                 // 获取对应的位的值(pow是平方,i为0是个位,i为1是10位,i为2是百位)
    			int x=array[j]%(int)Math.pow(10,i+1)/(int)Math.pow(10,i);
    			ArrayList list2=baseList.get(x);
    			list2.add(array[j]);
    		}
            
    		int count=0;
            
            //收集队列元素;
    		for(int j=0;j<digit;j++){
    			while(baseList.get(j).size()>0){
    				ArrayList<Integer> list3=baseList.get(j);
    				array[count]=list3.get(0);
    				list3.remove(0);
    				count++;
    			}
    		}
    	}
    }

	public static void main(String[] args){
		int a[]={49,38,65,97,76,12,27,49};
		basicSort(a);
		
		for(int i:a){
			System.out.print(i+" ");
		}
	}
}

10、桶排序

二、总结

在这里插入图片描述

1 稳定性

(1)稳定:冒泡排序、插入排序、二分插入排序、归并排序和基数排序。
(2)不稳定:选择排序、快速排序、希尔排序、堆排序。

2 平均时间复杂度

(1)O(n^2):直接插入排序,简单选择排序,冒泡排序、二分插入排序。
(2)O(nlogn):快速排序,归并排序,希尔排序,堆排序。快排是最好的, 其次是归并和希尔,堆排序在数据量很大时效果明显。
(3)在数据规模较小时(9W内):直接插入排序,简单选择排序差不多。当数据较大时:冒泡排序算法的时间代价最高。性能为O(n^2)的算法基本上是相邻元素进行比较,基本上都是稳定的。

3 排序算法的选择

3.1 数据规模较小(9W内)
(1)直接插入排序、冒泡排序:待排序列基本有序的情况下,对稳定性有要求
(2)直接选择排序:待排序列无序,对稳定性不作要求

3.2 数据规模很大
(1)归并排序:序列本身基本有序,对稳定性有要求空间允许下。
(2)快速排序:序列本身无序。完全可以用内存空间,对稳定性没有要求,此时要付出log(n)的额外空间。 (3)堆排序:对稳定性没有要求,所需的辅助空间少于快速排序

3.3 基数排序 (稳定) (1)在某个数字可能很大的时候,基数排序没有任何性能上的优势,还会浪费非常多的内存。 (2)一组数,这组数的最大值不是很大,更加准确的说,是要排序的对象的数目 和排序对象的最大值之间相差不多。比如,这组数 1 4 5 2 2,要排序对象的数目是 5 ,排序对象的最大值也是 5. 这样的情况很适合。

3.4 希尔排序 (不稳定) (1)对于中等大小的数组它的运行时间是可以接受的。 它的代码量很小,且不需要使用额外的内存空间。虽然有更加高效的算法,但除了对于很大的 N,它们可能只会比希尔排序快两倍(可能还达不到),而且更复杂。如果你需要 解决一个排序问题而又没有系统排序函数可用,可以先用希尔排序,然后再考虑是否值得将它替换为更加复杂的排序算法。 (2)希尔排序是对直接插入排序的一种优化,可以用于大型的数组,希尔排序比插入排序和选择排序要快的多,并且数组越大,优势越大。

  • 6
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值