Java中常用排序算法简单介绍及实现(有详细注释)



一、冒泡排序

  • 定义
    冒泡排序是指重复地遍历待排序的元素,依次比较两个相邻的元素,如果顺序(如从大到小、首字母从Z到A)错误就把他们交换过来。每次遍历都能使得一个位置的元素最终有序,遍历进行到没有相邻元素需要交换时结束。
  • 代码实现
    public int[] void bubbleSort(int arr[]){
        boolean flag=true;
        for(int i=0;i<arr.length-1;i++){
            flag=true;//该趟交换如果flag为true,表示没有元素交换,则数组已经有序,直接返回
            //每趟交换后会使得第i个位置的元素被确定下来。
            for(int j=arr.length-1;j>i;j--){
                if(arr[j]<arr[j-1]){//如果前一个元素大于后一个元素,进行交换
                   int temp=arr[j-1];
                    arr[j-1]=arr[j];
                    arr[j]=temp;
                    flag=false;//有元素交换
                }
            }
            if(flag){//没有元素交换,直接返回
                return arr;
            }
        }
        return arr;
    }

二、插入排序

  • 定义
    插入排序是指在待排序的元素中,假设前面n-1(其中n>=2)个数已经是排好顺序的,现将第n个数插到前面已经排好的序列中,然后找到合适自己的位置,使得插入第n个数的这个序列也是排好顺序的。按照此法对所有元素进行插入,直到整个序列排为有序。
  • 代码实现
    public int[] insertSort(int arr[]) {
        //i从i开始,即假设第0位已经有序
        for (int i = 1; i < arr.length; i++) {
            int insertValue = arr[i];//保存当前要插入的元素
            int insertIndex = i - 1;
            for (int j = insertIndex; j >= 0; j--) {
                if (insertValue <= arr[j]) {//如果要插入的元素小于下标为j的元素,下标为j的元素值后移一位
                    arr[j + 1] = arr[j];
                    if (j == 0) {//如果要插入的值比数组中第一个元素还小,就直接将要插入的值放入arr[0]
                        arr[j] = insertValue;
                    }
                } else {//如果arr[j]小于要插入的元素,则j+1位置就存放要插入的元素
                    arr[j + 1] = insertValue;
                    break;
                }
            }
        }
        return  arr;
    }

三、选择排序

  • 定义
    选择排序是指第一次从待排序的数据元素中选出最小(或最大)的一个元素,存放在序列的起始位置,然后再从剩余的未排序元素中寻找到最小(大)元素,然后放到已排序的序列的末尾。以此类推,直到全部待排序的数据元素的个数为零。
  • 代码实现
    public int[] selectSort(int arr[]){
        for(int i=0;i<arr.length-1;i++){
           int min=arr[i];//记录从i开始到数组结束的元素最小值(初始为arr[i])
            int count=i;//记录最小值的下标(初始为i)
            for(int j=i+1;j<arr.length;j++){//遍历i+1及之后元素
                if(min>arr[j]){//求得最小值及其下标
                    min=arr[j];
                    count=j;
                }
            }
            //将i位置的元素和count位置对应的元素进行交换(第i位元素比后面所有元素都小)
            arr[count]=arr[i];
            arr[i]=min;
        }
        return arr;
    }

四、希尔排序

  • 定义
    希尔排序是把记录按下标的一定增量分组,对每组使用直接插入排序算法排序;随着增量逐渐减少,每组包含的关键词越来越多,当增量减至 1 时,整个文件恰被分成一组,算法便终止。
  • 代码实现
    public  int[] shellSort(int arr[]) {
        for (int gap = arr.length / 2; gap > 0; gap /= 2) {//将要排序的元素分成gap组,直到gap为1时到达最后
            for(int i=gap;i<arr.length;i++){//假设每组的第一个元素已经有序(即i=gap前的)
                //对当前组进行插入排序(当前组的每个运算间隔是gap)
                int insertValue=arr[i];
                int insertIndex=i-gap;
                for(int j=insertIndex;j>=0;j-=gap){
                    if(insertValue<=arr[j]){
                        arr[j+gap]=arr[j];
                        if(j<gap){//说明达到当前组的第一个元素
                            arr[j]=insertValue;
                        }
                    }else{
                        arr[j+gap]=insertValue;
                        break;
                    }
                }
            }
        }
        return arr;
    }

五、合并排序

  • 定义
    合并排序法是将两个(或两个以上)有序表合并成一个新的有序表,即把待排序序列分为若干个子序列,每个子序列是有序的。然后再把有序子序列合并为整体有序序列。
  • 代码实现
  public  int[] 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);//分割后进行合并
            }
            return  arr;
    }
    public  void merge(int arr[],int left,int mid,int right,int temp[]){
        int i=left;
        int j=mid+1;
        int index=0;
        while(i<=mid&&j<=right){//左右两边从第一个元素开始比较大小,存入temp数组
            if(arr[i]<=arr[j]){//保证稳定性
                temp[index++]=arr[i++];
            }else{
                temp[index++]=arr[j++];
            }
        }
        if(i>mid){//如果左边部分全部存入temp
            while(j<=right){
                temp[index++]=arr[j++];
            }
        }
        if(j>right){//如果右边部分全部存入temp
            while(i<=mid){
                temp[index++]=arr[i++];
            }
        }
        index=0;
        //每次都只将temp里的当前merge所产生的值赋值给arr里的left-right位置
        for(int count=left;count<=right;count++){
            arr[count]=temp[index++];
        }
    }

六、快速排序

  • 定义
    快速排序是指通过一趟排序将要排序的数据分割成独立的两部分,其中一部分的所有数据都比另外一部分的所有数据都要小,然后再按此方法对这两部分数据分别进行快速排序,整个排序过程可以递归进行,以此达到整个数据变成有序序列。
  • 代码实现
    public  int[] quickSort(int arr[],int left,int right){
        if(left<right){
            int j=Partition(arr,left,right);
            quickSort(arr,left,j-1);
            quickSort(arr,j+1,right);
        }
        return  arr;
    }

    public  int Partition(int arr[],int left,int right){
        int standard = arr[left];//以arr[left]为基准进行分割
        int i = left;
        int j = right;
        while (i < j) {
            //一定要先从右边开始,因为i会在大于基准点的位置停下,这样会导致最后的swapswap(arr, i, left)会将大于基准点的值放在左边
            while (j > i && arr[j] > standard) {//只要后面元素一直大于基准点,就一直前移
                j--;
            }
            while (i < j && arr[i] <= standard) {//只要前面元素一直小于等于基准点,就一直后移
                i++;
            }
            swap(arr, i, j);
        }
        swap(arr, i, left);
        return i;
    }
    private void swap(int[] arr, int i, int j) {
        int temp = arr[i];
        arr[i] = arr[j];
        arr[j] = temp;
    }

七、基数排序

  • 定义
    基数排序属于“分配式排序”,又称“桶子法”,顾名思义,它是透过键值的部份资讯,将要排序的元素分配至某些“桶”中,藉以达到排序的作用,基数排序法是属于稳定性的排序,其时间复杂度为O (nlog®m),其中r为所采取的基数,而m为堆数,在某些时候,基数排序法的效率高于其它的稳定性排序法。
  • 代码实现
    public  int[] radixSort(int arr[], int cur, int max){
        int m=(int)Math.pow(10,cur)/10;
        int bucket[][]=new int[10][arr.length];//桶,用于存放每位数相同的元素,桶的行下标即代表元素位数值(第一次代表个位,第二次代表十位,依次类推)
        int bucketCount[]=new int[10];//用于存放每个桶所需放的元素个数
        for(int i=0;i<arr.length;i++){//统计每个桶所放元素的个数
            int k=arr[i]/m%10;//得到该位上的数字
            bucket[k][bucketCount[k]]=arr[i];//将个位(依次类推)相同的元素放入对应桶中
            bucketCount[k]++;//该位为k的元素个数+1
        }
        int count=0;
        //按照该位数字对数组进行排序
        for(int i=0;i<10;i++){
            for(int j=0;j<bucketCount[i];j++){
                    arr[count++]=bucket[i][j];
            }
        }
        while(cur<max){//对十位,百位....继续进行排序
            cur++;
            radixSort(arr,cur,max);
        }
          return arr;
    }

八、堆排序

  • 定义
    堆排序是指利用堆这种数据结构所设计的一种排序算法。堆是一个近似完全二叉树的结构,并同时满足堆积的性质:即子结点的键值或索引总是小于(或者大于)它的父节点。
  • 代码实现
public int[] heapSort(int arr[]){
        //先把原数组转化成大顶堆
      for(int i=arr.length/2-1;i>=0;i--){
          adjustHeap(arr,i,arr.length);
      }
           for(int j=arr.length-1;j>0;j--){
               //交换,因为此时arr[0]是最大的,所以将它放在数组末尾
               int temp=arr[j];
               arr[j]=arr[0];
               arr[0]=temp;
               adjustHeap(arr,0,j);//arr[j]已经按照顺序排好,只要对0~j-1的数组进行调整
                                     //而且此时只要arr[0]为父节点的堆不满足大顶堆,因此只要对i=0进行调整即可。
           }
           return  arr;
    }

    /**
     * 功能:完成将以i结点对应的非叶子结点调整为大顶堆
     * @param arr    待调整的数组
     * @param i      表示非叶子结点在数组中的索引
     * @param length 要调整的数组范围,length是在逐渐减少
     */
    public static void adjustHeap(int arr[],int i,int length){
            int temp=arr[i];
            for(int k=2*i+1;k<length;k=2*k+1){
                if(k+1<length&&arr[k]<arr[k+1]){//如果存在右子节点且其值大于左子节点
                    k++;//k指向右子节点
                }
                if(arr[k]>temp){//如果孩子节点大于父节点
                    arr[i]=arr[k];//较大的值赋给当前结点
                    i=k;//i指向k,继续循环比较
                }else {
                    break;
                }
            }
           //当for循环结束后,我们已经将以i为父节点的数的最大值,放在了最顶(局部)
                  arr[i]=temp;//将temp值(即原先的父节点)放到调整后的位置
    }

九、各排序算法复杂度总结

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值