Java实现八大排序算法

JAVA排序

1、冒泡排序

实现原理: 从序列左边开始比较相邻位置两个元素的大小,如果前一个大于后一个值就交换位置,这样较大的元素经过交换就慢慢’浮动’到序列的右端。

  • 如果有n个数据进行排序,总共需要比较n-1次
  • 每一次比较完毕,下一次的比较就会少一个数据参与

    代码实现:
import java.util.Arrays;

public class Test {
    public static void main(String[] args) {
        //定义一个数组
        int[] arr = {7, 6, 18, 5, 4, 3};
        System.out.println("排序前:" + Arrays.toString(arr));

        // 冒泡排序
        // 外层循环控制比较的轮数
        for (int i = 0; i < arr.length - 1; i++) {
            // 内层循环控制比较的次数
            for (int j = 0;j<arr.length-1-i;j++){
                // 比较判断 arr[j]与arr[j+1]
                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、选择排序

选择排序概述

实现原理:从待排序的数据中寻找最小值,将其与序列最左边的数字进行交换。

  • 如果有n个数据进行排序,总共需要比较n-1轮
  • 每一轮比较完毕,下一轮的比较就会少一个数据参与
public static int [] selectSort(int [] arr){
        int length = arr.length;
        int temp,minIndex;
        for (int i = 0; i < length-1; i++) {
            minIndex = i;  
            for (int j = i+1; j < length ; j++) {
                if (arr[minIndex] > arr[j]){ //如果当前最小值元素大于 其它元素
                    minIndex = j;             // ,就将其它元素下标给 minIndex
                }
            }
            temp = arr[i];
            arr[i] = arr[minIndex];
            arr[minIndex] = temp;
        }
        return arr;
    }

3、插入排序

实现原理:默认第一个元素为已排序元素,取出下一个元素,在已排序队列中从后向前扫描,如果该元素(已排序元素)大于新元素,就将该元素移动到后一位置,重复此操作,直至已排序队列的元素小于或等于该元素停止。

public  static int[] insertSort(int [] array){
//        插入排序:从第一个元素开始,该元素默认已经被排序,取出下一个元素,在已经排序的序列中
//从后向前扫描,如果该元素 大于新元素,将该元素移动到下一位置,重复以上步骤.
        int preIndex,current;
        for (int i = 1,j = array.length ; i < j; i++) {
            preIndex = i - 1;
            current = array[i];
            while (preIndex >= 0 && array[preIndex] > current){
                array[preIndex+1] = array[preIndex];
                preIndex--;
            }
            array[preIndex + 1] =  current;
        }
        return array;
}

以上三种排序时间复杂度为O(n^2)

常见几种java排序算法

4、归并排序

归并排序,简单的说把一串数,从中平等分为两份,再把两份再细分,直到不能细分为止,这就是分而治之的分的步骤。再从最小的单元,两两合并,合并的规则是将其按从小到大的顺序放到一个临时数组中,再把这个临时数组替换原数组相应位置,这就是治。图解如下:

java排队机 java排列算法_算法

public static void mergeSort(int[] a,int s,int e){
    int m = (s + e) / 2;
    if (s < e){
      mergeSort(a,s,m);
      mergeSort(a,m+1,e);
      //归并
      merge(a,s,m,e);
    }
}

private static void merge(int[] a, int s, int m, int e) {
    //初始化一个从起始s到终止e的一个数组
    int[] temp = new int[(e - s) + 1];
    //左起始指针
    int l = s;
    //右起始指针
    int r = m+1;
    int i = 0;
    //将s-e这段数据在逻辑上一分为二,l-m为一个左边的数组,r-e为一个右边的数组,两边都是有序的
    //从两边的第一个指针开始遍历,将其中小的那个值放在temp数组中
    while (l <= m && r <= e){
      if (a[l] < a[r]){
        temp[i++] = a[l++];
      }else{
        temp[i++] = a[r++];
      }
    }

    //将两个数组剩余的数放到temp中
    while (l <= m){
      temp[i++] = a[l++];
    }
    while (r <= e){
      temp[i++] = a[r++];
    }
    
    //将temp数组覆盖原数组
    for (int n = 0; n < temp.length; n++) {
      a[s+n] = temp[n];
    }
}

5、分治排序法,快速排序法

简单的说, 就是设置一个标准值, 将大于这个值的放到右边(不管排序), 将小于这个值的放到左边(不管排序), 那么这样只是区分了左小右大, 没有排序, 没关系, 左右两边再重复这个步骤.直到不能分了为止.
详细说就是:

1、选择待排数列的首部第一个元素为基准元素x,设置两指针,分别指向数列首尾部位置,假设两指针分别设为i和j。
2、每次遍历的过程是这样的,首先从右到左遍历指针j所指向的元素,直到j指向的元素值小于基准元素x时,停止遍历,将其放到i的位置(因为i的值已经拷贝成了基准x腾出了位置)
3、 i往右挪一步, i++,接着轮到指针i从左到右遍历,直到i所指向的元素值大于基准元素x时,停止遍历,将其放到j的位置(因为上面一步j的值已经占用到了i的位置,腾出位置了)
4、 依此类推,两边轮流遍历, 直到指针i与指针j相等或者大于(实际肯定是i==j)时,停止外部循环。此时必定左边都是比x小的, 右边是比x大的.
5、最后直接将基准元素x直接放置于指针i所指向的位置即可
6、 完成分区操作, 从i的位置一分为二, 左边和右边再递归执行上面的操作. 层层细分

接下来,我们通过示图来展示上述分区算法思路的过程:

java排队机 java排列算法_数组_02

public class QuickSort {

    public static void sort(int[] arr,int begin,int end) {
        //先定义两个参数接收排序起始值和结束值
        int a = begin;
        int b = end;
        //先判断a是否大于b

        if (a >= b) {
            //没必要排序
            return;
        }
        //基准数,默认设置为第一个值
        int x = arr[a];

        //循环
        while (a < b) {
            //从后往前找,找到一个比基准数x小的值,赋给arr[a]
            //如果a和b的逻辑正确--a<b ,并且最后一个值arr[b]>x,就一直往下找,直到找到后面的值大于x
            while (a < b && arr[b] >= x) {
                b--;
            }
            //跳出循环,两种情况,一是a和b的逻辑不对了,a>=b,这时候排序结束.二是在后面找到了比x小的值
            if (a < b) {
                //将这时候找到的arr[b]放到最前面arr[a]
                arr[a] = arr[b];
                //排序的起始位置后移一位
                a++;
            }

            //从前往后找,找到一个比基准数x大的值,放在最后面arr[b]
            while (a < b && arr[a] <= x) {
                a++;
            }
            if (a < b) {
                arr[b] = arr[a];
                //排序的终止位置前移一位
                b--;
            }
        }
        //跳出循环 a < b的逻辑不成立了,a==b重合了,此时将x赋值回去arr[a]
        arr[a] = x;
        //调用递归函数,再细分再排序
        sort(arr,begin,a-1);
        sort(arr,a+1,end);
    }
}

分别对1k,1w,10w,20w大小的随机数组排序,结果如下:
得到综合结果是:
速度: 快速排序>>归并排序>>>>>插入排序>>选择排序>>冒泡排序
并且可以看到,选择排序,冒泡排序在数据量越来越大的情况下,耗时已经呈指数型上涨,而不是倍数上涨,在50w的时候已经需要足足5分钟以上

6、希尔排序

希尔排序视频 插入排序的算法复杂度为O(n2),但如果序列为正序可提高到O(n),而且直接插入排序算法比较简单,希尔排序利用这两点得到了一种改进后的插入排序。

希尔排序,也称 递减增量排序算法,是插入排序的一种更高效的改进版本。希尔排序是 非稳定排序算法。

希尔排序:将无序数组分割为若干个子序列,子序列不是逐段分割的,而是相隔特定的增量的子序列,对各个子序列进行插入排序;然后再选择一个更小的增量,再将数组分割为多个子序列进行排序…最后选择增量为1,即使用直接插入排序,使最终数组成为有序。
增量的选择:在每趟的排序过程都有一个增量,至少满足一个规则 增量关系 d[1] > d[2] > d[3] >…> d[t] = 1 (t趟排序);根据增量序列的选取其时间复杂度也会有变化,这个不少论文进行了研究,在此处就不再深究; 本文采用首选增量为n/2,以此递推,每次增量为原先的1/2,直到增量为1;

java排队机 java排列算法_java排队机_03

/********************************************************
*函数名称:ShellInsert
*参数说明:pDataArray 无序数组;
*          d          增量大小
*		   iDataNum为无序数据个数
*说明:    希尔按增量d的插入排序
*********************************************************/
void ShellInsert(int* pDataArray, int d, int iDataNum)
{
	for (int i = d; i < iDataNum; i += 1)    //从第2个数据开始插入
	{
		int j = i - d;
		int temp = pDataArray[i];    //记录要插入的数据
		while (j >= 0 && pDataArray[j] > temp)    //从后向前,找到比其小的数的位置
		{
			pDataArray[j+d] = pDataArray[j];    //向后挪动
			j -= d;
		}
 
		if (j != i - d)    //存在比其小的数
			pDataArray[j+d] = temp;
	}
}
 
/********************************************************
*函数名称:ShellSort
*参数说明:pDataArray 无序数组;
*		   iDataNum为无序数据个数
*说明:    希尔排序
*********************************************************/
void ShellSort(int* pDataArray, int iDataNum)
{
	int d = iDataNum / 2;    //初始增量设为数组长度的一半
	while(d >= 1)
	{
		ShellInsert(pDataArray, d, iDataNum);
		d = d / 2;    //每次增量变为上次的二分之一
	}
}

希尔排序中对于增量序列的选择十分重要,直接影响到希尔排序的性能。我们上面选择的增量序列{n/2,(n/2)/2…1}(希尔增量),其最坏时间复杂度依然为O(n2),一些经过优化的增量序列如Hibbard经过复杂证明可使得最坏时间复杂度为O(n3/2)。

java排队机 java排列算法_排序算法_04