【DS】排序

本文详细介绍了七种常见的排序算法:直接选择排序、堆排序、冒泡排序、插入排序、希尔排序、快速排序和归并排序。通过概念解析和代码示例,帮助读者理解每种排序算法的工作原理及其在不同场景下的适用性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1、直接选择排序

按升序排序,假设下标为0的数为最大值(max=0),用指针j从下标为0处开始遍历,找到比array[max]的值大的时候,max就为较大数的下标值,并把这个值与最后一个值交换,共有几个数,按此规律循环几次,循环过程中,无序数组的范围是:[0,array.length-i],有序数组为[array.length-i,array.length],代码如下:
`

for(int i=0;i<array.length;i++){
        int max=0;
        for(int j=0;j<array.length-i;j++){
            if(array[j]>array[max]){
                max=j;
            }
        }
        int t=array[max];
        array[max]=array[array.length-1-i];
        array[array.length-1-i]=t;
    }
`

2、堆排序(以建大堆为例)

大堆性质:父结点的值大于子节点的值
父结点下标若为i,那么他的左孩子结点下标为:2i+1;右孩子结点下标为:2i+2;
子节点下标若为j,那么他的父结点下标为:(j-1)/ 2;

先将一组数建成完全二叉树,然后利用向下调整的方式建成大顶堆,因为是大顶堆,所以下标为0的地方是无序部分的最大值,将无序部分的第一个数和最后一个数交换位置,此时无序部分的最后一个数就有序部分的第一个数,再将交换后的第一个数进行向下调成变成新的大顶堆,以此循环

建大堆向下调整:

public static void adjustdown(int[] array,int size,int index){
       int max=2*index+1;
       while (max<size){
           while (max+1<size&&array[max+1]>array[max]){
               max=max+1;
           }
           if(array[index]>array[max]){
               break;
           }
           int t=array[max];
           array[max]=array[index];
           array[index]=t;
           
           index=max;
           max=2*index+1;
       }
       

堆排序:

public static void heapSort(int[] array){
       for(int i=(array.length-1-1)/2;i>=0;i--){
           adjustdown(array,array.length,i);
       }
       for(int j=0;j<array.length;j++){
           int t=array[0];
           array[0]=array[array.length-j-1];
           array[array.length-j-1]=t;
           adjustdown(array,array.length-j-1,0);
       }
   }

3、冒泡排序

假设一组数: 8 6 2 1 4 3 5
第一次排序是从下标j=0处开始比较,若array[j]>array[j+1],则交换两个值,然后j++
经过一次排序后,这组数为: 6 2 1 4 3 5 8
以此循环,第二次排序后: 2 1 4 3 5 6 8
第三次排序后: 1 2 3 4 5 6 8

public static void bubleSort(int[] array){
       for(int i=0;i<array.length;i++){
           for(int j=0;j<array.length-i-1;j++){
               if(array[j]>array[j+1]){
                   int t=array[j];
                   array[j]=array[j+1];
                   array[j+1]=t;
               }
           }
       }
   }

4、插入排序

从第一个元素开始,该元素可以认为已经被排序,
取出下一个元素,在已经排序的元素序列中从后向前扫描,
如果该元素(已排序)大于新元素,将该元素移到下一位置,
重复步骤3,直到找到已排序的元素小于或者等于新元素的位置,
将新元素插入到该位置后,
重复步骤2~5

public static void inSort(int[] array){
       for(int i=0;i<array.length;i++){
           int key=array[i];
           int j=i-1;
           for(;j>=0&&array[j]>key;j--){
               array[j+1]=array[j];
           }
           array[j+1]=key;
       }
   }

5、希尔排序

希尔排序是直接插入排序的升级版,他将一组数分成了gap个数为一组的,每组之间对应下标相同的数进行比较,一趟完了之后,再将数分成(gap/2)个数,再将每组对应下标相同的数进行比较,以此循环,直到gap=1后,排序 完成,第一次gap=array.length/2;
下图大概演示排序过程:

代码如下:

public static void inSortwithgap(int[] array,int gap){
       for(int i=0;i<array.length;i++){
           int key=array[i];
           int j=i-gap;
           for(;j>=0&&array[j]>key;j=j-gap){
               array[j+gap]=array[j];
           }
           array[j+gap]=key;
       }
   }
   public static void shellSort(int[] array){
       int gap=array.length;
       while (true){
           gap=gap/2;
           inSortwithgap(array,gap);
           if(gap==1){
               break;
           }
       }

   }

6、快速排序

快速排序就是找到一个基准值,基准值左边的数都比这个基准值小,右边都比基准值大,然后在将基准值左边和右边分别单独看成两个数组,再找出各自的基准值,遵循左边比基准值小,右边比基准值大的方式不断进行递归
快速排序代码如下:

public static void quickSortInner(int[] array,int left,int right){
        if(left>=right){
            return;
        }
        int p=parition(array,left,right);
        quickSortInner(array,left,p-1);
        quickSortInner(array,p+1,right);

    }


    public static void quickSort(int[] array){
        quickSortInner(array,0,array.length-1);
    }

找基准值并排序方式
1、hover法
定义基准值为数组最后一个数,一个从下标为0处开始,定义为begin指针,另一个从array.length-1处开始,定义为end指针,begin的左边都要小于等于基准值,end的右边都要大于等于基准值,若begin遍历数组过程中碰到比基准值大的,则停下,让end指针开始遍历,若end指针碰到比基准值小的,也停下,此时交换begin和end的两个数,以此循环,当不满足begin<end这个条件时,交换begin所指元素和基准值
代码如下:

 public static int parition(int[] array, int left, int right){
        int begin=left;
        int end=right;
        int p =array[right];
        while (begin<end){
            while (begin<end&&array[begin]<=p){
                begin++;
            }
            while (begin<end&&array[end]>=p){
                end--;
            }
            int t=array[begin];
            array[begin]=array[end];
            array[end]=t;
        }
        int e=array[begin];
        array[begin]=array[right];
        array[right]=e;

        return begin;
    }

2、挖坑法
挖坑法 与hover法相差不大,差别就在于,使用挖坑法时,当begin指针碰到比基准值大的数时,不是停下,而是将begin指针的值赋给end指针,在让end指针开始遍历,此时begin指针的位置是空的,当end指针碰到比基准值小的时候,将end指针的值赋给空着的begin指针,在让begin指针开始继续遍历,以此循环,最后begin和end指针相遇时,这个指针指向位置应该是空的,将基准值赋给begin指针(此时begin==end),这样就完成了基准值左边比基准值小,右边比基准值大的顺序
代码如下:

     public static int parition(int[] array,int left,int right){
         int begin=left;
         int end=right;
         int p=array[right];
         while (begin<end){
             while (begin<end&&array[begin]<=p){
                 begin++;
             }
             array[end]=array[begin];
             while (begin<end&&array[end]>=p){
                 end--;
             }
             array[begin]=array[end];
         }
         array[begin]=p;
         return begin;
     }

3、前后下标法
创建两个指针,一个指针找大于基准值的值,另一个指针找小于基准值的值
两个指针 分别为i和d;i和d都从left开始,基准值为最右边的数,让i开始遍历数组,遇到比基准值大的数就跳过(i++),遇到比基准值小的数就停下,如果array[i]和array[d]不相等的话就交换这两个值,然后让d++,直到i遍历完整个数组,最后将d指针指向的元素和最后一个元素交换,就完成了基准值左边比基准值小,右边比基准值大的顺序

public static int parition3(int[] array,int left,int right){
        int d=left;
        for(int i=left;i<right;i++){
            if(array[i]<array[right]){
                swap(array,d,i);
                d++;
            }
        }
        swap(array,d,right);
        return d;
    }

7、归并排序

1、把要排序区间平均切分为两部分
2、分治算法,对左右两个区间进行同样方式的排序
直到 size1 已经有序
size
0 区间没有数了
3、合并左右两个两个有序区间到一个有序区间(需要额外空间)

public static void merge(int[] array,int low,int mid,int high){
        int[] extra = new int[high-low];
        int i=low;//遍历array[low,mid)
        int j=mid;//遍历array[mid,high)
        int x=0;//遍历extra

        while(i<mid&&j<high){
            if(array[i]<array[j]){
                extra[x++]=array[i++];
            }else {
                extra[x++]=array[j++];
            }
        }

        while (i<mid){
            extra[x++]=array[i++];
        }
        while (j<high){
            extra[x++]=array[j++];
        }
        for(int k=low;k<high;k++){
            array[k]=extra[k-low];
        }
    }


    public static void mergeSortInner(int[] array,int low,int high){
        if(low>=high){
            return;
        }
        if(low==high-1){
            return;
        }
        //需要排序的区间array[low,high)

        //1、平均切分
        int mid=low+(high-low)/2;
        //2、分治两个小区间
        mergeSortInner(array,low,mid);
        mergeSortInner(array,mid,high);

        //左右两个小区间已经有序了
        merge(array,low,mid,high);

    }
    public static void mergeSort(int[] array){
        mergeSortInner(array,0,array.length);
    }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值