Java实现基本的排序算法

排序算法的基本分类

 1.插入排序

插入排序 时间复杂度是O(n^2) 不稳定
插入排序介绍:对于欲排序的元素以插入的方式寻找该元素的适当位置,以达到排序的目的
* 插入排序思想:把n个待排序的元素看成未一个有序表和一个无序表,开始时有序表中只包含一个元素,
*              无序表中取出第一个元素,把它的排序码一次与有序表中的排序码进行比较,
*              将它插入到有序表中的适当位置,使之成为新的有序表
* 插入排序的缺点:当需要插入的数是较小的数时,数据向后移动的次数明显增多
public static void insertSort(int[] array) {
        for (int i = 1; i < array.length; i++) {
            int insertValue = array[i];
            int insertIndex = i - 1;
            while (insertIndex >= 0 && insertValue < array[insertIndex]) {
                //将当前被比较过的有序表中的元素向后移动一位
                array[insertIndex + 1] = array[insertIndex];
                //继续往前找
                insertIndex--;
            }
            //如果待插入的数insertValue小于有序列表中的所有数,
            // 或者待插入的数大于当前数组下标为insertIndex的数
            //当退出循环时说明待插入的位置找到了,为insertIndex+1
            if (insertIndex + 1 != i) {
                array[insertIndex + 1] = insertValue;
            }
            //System.out.println("第"+(i+1)+"轮后的顺序是:"+ Arrays.toString(array));
        }
        System.out.println("插入排序后的顺序是:" + Arrays.toString(array));
    }

2.希尔排序

希尔排序 时间复杂度是O(n log n) 不稳定
希尔排序是简单插入排序的更高效版本,也称为缩小增量排序
* 希尔排序的思想:就是把记录数按下标的一定增量分组,对每组使用世界插入排序算法排序,
*               随着增量逐渐减少,每组包含的关键词越来越多,当增量减少至一时,
*                整个文件恰被分成一组,算法便终止
* 希尔排序时,对有序序列在插入时采用交换法,ShellSortExchange()
* 希尔排序时,对有序序列在插入时采用交换法,ShellSortMove()
public static void shellSortExchange(int[] array) {
        int temp = 0;//用于临时存放交换的元素
        int count = 0;//用于记录当前是第几轮排序
        //gap即数组被分为gap数个小组,
        for (int gap = array.length / 2; gap > 0; gap /= 2) {
            for (int i = gap; i < array.length; i++) {
                //按照插入排序的方法 遍历各个组中的所有元素,共有gap组
                for (int j = i - gap; j >= 0; j -= gap) {
                    //如果当前元素大于加上步长后的那个元素,说明交换
                    if (array[j] > array[j + gap]) {
                        temp = array[j];
                        array[j] = array[j + gap];
                        array[j + gap] = temp;
                    }
                }
            }
            // System.out.println("希尔排序第"+(++count)+"轮排序后的顺序是:"+Arrays.toString(array));
        }
        System.out.println("希尔交换式排序后的顺序是:" + Arrays.toString(array));
    }

public static void shellSortMove(int[] array) {
        //增量gap,并逐步缩小增量
        for (int gap = array.length / 2; gap > 0; gap /= 2) {
            //从第gap个元素,逐个对其所在的组进行直接插入排序
            for (int i = gap; i < array.length; i++) {
                int insertIndex = i;
                int insertValue = array[insertIndex];
                if (array[insertIndex] < array[insertIndex - gap]) {
                    while (insertIndex - gap >= 0 && insertValue < array[insertIndex - gap]) {
                        //移动
                        array[insertIndex] = array[insertIndex - gap];
                        insertIndex -= gap;
                    }
                    //当退出while后,就给insertValue找到了插入的位置
                    array[insertIndex] = insertValue;
                }
            }
        }
        System.out.println("希尔移位式排序后的顺序是:" + Arrays.toString(array));
    }

 3.选择排序

选择排序 时间复杂度是O(n^2) 不稳定
* 选择排序介绍:选择式排序是从欲排序的数据中,按指定的规则选出某一元素,再依规定交换位置后达到选择排序的目的
* 选择排序思想:第一次从arr[0]~ar[n-1]中选取最小值与arr[0]交换,
*              第i次从arr[i-1]~arr[n-1]中选最小值与arr[i-1]交换,
*              第n-1次从arr[i-2]~arr[n-1]中选最小值与arr[n-2]交换,
*              得到一个按从小到大排序的有序序列
public static void selectSort(int[] array) {
        for (int i = 0; i < array.length; i++) {
            int minIndex = i;//每次存放找到的最小值的下标
            int min = array[i];//存放最小值
            for (int j = i + 1; j < array.length; j++) {
                if (min > array[j]) {
                    min = array[j];//重置min
                    minIndex = j;//重置minIndex
                }
            }
            //将最小值与当前遍历到的值交换
            if (minIndex != i) {
                array[minIndex] = array[i];
                array[i] = min;
            }
            //System.out.println("第"+(i++)+"轮后");
        }
        System.out.println("选择排序排序后的顺序是:" + Arrays.toString(array));
    }

 4.冒泡排序

冒泡排序 时间复杂度是O(n^2) 稳定
冒泡排序思想:通过对待排序序列从前向后,依次比较相邻元素的值,
*              如发现逆序则交换,使值较大的元素从前移动到后面,
*              就像水底下的气泡一样组件向上冒
* 冒泡排序优化:如果一趟比较下来没有进行过交换,说明序列有序,
*              因此再排序过程中设置一个标志flag,判单是否进行过交换,
*              从而减少不必要的比较
 public static void bubbleSort(int[] array) {
        for (int i = 0; i < array.length - 1; i++) {//这里注意 -1因为每趟排序都是把最大的数交换到了当前排序数的最后面
            int temp = 0;
            boolean flag = true;
            for (int j = 0; j < array.length - 1 - i; j++) {
                if (array[j] > array[j + 1]) {
                    temp = array[j];
                    array[j] = array[j + 1];
                    array[j + 1] = temp;
                    flag = false;
                }
            }
            //System.out.println("第"+(i+1)+"趟排序后端数组:"+Arrays.toString(array));
            if (flag = true) {
                //代表没有发生交换,数组有序,就不用交换了
                break;
            }
        }
        System.out.println("冒泡排序排序后的顺序是:" + Arrays.toString(array));
    }

5.快速排序

快速排序 时间复杂度是O(n log n) 不稳定
* 快速排序是对冒泡排序的一种改进,也属于交换排序
* 快速排序思想:通过一趟排序将要排序的数据分割成独立的两部分,
*              其中一部分的所有数据都比另外一部分的所有数据都要小,
*              然后再按照此方法对这两部分数据分别进行快速排序,整个排序过程可以递归进行,
*              以此达到整个数据编程有序序列
public static void quickSort(int[] array, int left, int right) {
        int l = left;//左下标
        int r = right;//右下标
        int pivot = array[(left + right) / 2];//中轴值
        int temp = 0;//临时变量
        //while循环的目的是让比pivot值小的都在pivot的左边,比pivot值大的都在pivot的右边
        while (l < r) {
            //从左向右找大于pivot值
            while (array[l] < pivot) {
                l += 1;
            }
            //从右向左找小于pivot的值
            while (array[r] > pivot) {
                r -= 1;
            }
            //左右两边的值符合规则
            if (l >= r) {
                break;
            }

            //交换找到的值
            temp = array[l];
            array[l] = array[r];
            array[r] = temp;

            //如果arr[l]==pivot 前移 r--
            if (pivot == array[l]) {
                r--;
            }
            //如果arr[r]==pivot 后移 l++
            if (pivot == array[r]) {
                l++;
            }
        }
        if (l == r) {
            //防止栈溢出
            l += 1;
            r -= 1;
        }
        //向左递归
        if(left<r){
            quickSort(array,left,r);
        }
        //向右递归
        if(l<right){
            quickSort(array,l,right);
        }

    }

6.桶排序

桶排序 时间复杂度O(n+k) 稳定
* 桶排序思想:将数据 分组放到桶中,递归排序桶中的数据,
*            当桶中的bucketSize为1时将数据加入到返回集合中,bucketSize为大桶中每个小桶的大小
*            当桶中的bucketCount为1时 将bucketSize的值减1.bucketCount为大桶中小桶的个数
 public static List<Integer> bucketSort(List<Integer> list, int bucketSize){
        //递归的出口
        if(list==null||list.size()<2){
            return list;
        }
        //遍历list找到最大与最小的值
        int max=list.get(0);
        int min=list.get(0);

        for (int num: list) {
            if(num<min){
                min=num;
            }
            if(num>max){
                max=num;
            }
        }

        //定义返回结果集
        List<Integer> retList = new ArrayList<Integer>();

        //求出bucketCount
        int bucketCount=(max-min)/bucketSize+1;

        //定义大桶
        List<List<Integer>> buckets = new ArrayList<>(bucketCount);
        //初始化小桶
        for (int i = 0; i < bucketCount; i++) {
            buckets.add(new ArrayList<>());
        }
        //遍历原始的集合将数据放入到桶中
        for (int i = 0; i < list.size(); i++) {
            int value=list.get(i);
            int index=(value-min) /bucketSize;
            buckets.get(index).add(value);
        }
        //依次将桶中的数据进行排序
        for (int i = 0; i < buckets.size(); i++) {
            if(bucketSize==1){
                //说明要么只有一个元素,要么桶中的元素都相同
                for (int j = 0; j < buckets.get(i).size(); j++) {
                    retList.add(buckets.get(i).get(j));
                }
            }else {
                if(bucketCount==1){
                    bucketSize--;
                }
                //当bucketSize不等于1说明存在两个以上不同种类的数据
                //将小桶中的集合看成原集合再次遍历
                List<Integer> temp = bucketSort(buckets.get(i), bucketSize);
                //依次将递归返回的集合存放到结果集中
                for (Integer num : temp) {
                    retList.add(num);
                }
            }
        }
        return retList;
    }

7.归并排序

归并排序 时间复杂度O(n log n) 稳定
* 归并排序介绍:一开始先把数组从中间划分成两个子数组,一直递归地把子数组划分成跟小的数组,
*              直到子数组里面只有一个元素,才开始排序
* 归并排序思想:把一个复杂问题分成两个或多个相同或相似的子问题,然后把子问题分成更小的子问题,
*              直到子问题可以简单的直接请求,最原问题的解就是子问题的合并,
*              归并排序将分治的思想体现得淋漓尽致
 public static void mergeSort(Integer[] array, int lo, int hi){
        //判断是否只剩下最后一个元素
        if(lo>=hi){
            return;
        }
        //从中间将数组分成两部分
        int mid=lo+(hi-lo)/2;
        //分别递归的将左右两半排好序
        mergeSort(array,lo,mid);
        mergeSort(array,mid+1,hi);
        //将排好序的两半合并
        merge(array,lo,mid,hi);
    }
private static void merge(Integer[] array, int lo, int mid, int hi) {
        //复制一份原来的数组
        Integer[] copy=array.clone();

        //定义k指针表示从什么位置开始修改原来的数组
        int k=lo;
        //i指针表示左半边的起始位置
        int i=lo;
        //j指针表示右半边的起始位置
        int j=mid+1;
        while (k<hi){
            if(i>mid){
                //当左半边的数都处理完毕,只需要将右半边的数逐个拷贝过去
                array[k++]=copy[j++];
            }else if(j>hi){
                //当右半边的数都处理完毕,只需要将左半边的数逐个拷贝过去
                array[k++]=copy[i++];
            }else if(copy[j]<copy[i]){
                //当右半边的数小于左半边的数,将右半边的数拷贝,j指针向后移动一位
                array[k++]=copy[j++];
            }else {
                //当左半边的数小于右半边的数,将左半边的数拷贝,i指针向后移动一位
                array[k++]=copy[i++];
            }
        }
    }

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值