🧡数据结构与算法🧡从零到有系列《八》各种排序算法

137 阅读4分钟

这是我参与8月更文挑战的第20天,活动详情查看:8月更文挑战

上一篇说到了数据结构与算法中的基础排序和冒泡排序。今天这篇文章主要内容:

  1. 快速排序
  2. 插入排序
  3. 选择排序
  4. 希尔排序
  5. 归并排序

快速排序

1. 介绍

快速排序是对冒泡排序的一种改进。通过一趟排序将要排序的数据分割成独立的两部分,其中一部分的所有数据都比另一部分所有的数据都要小,然后再按此方法对这两部分数据分别进行快速排序,整个排序过程可以递归进行,以此达到整个数据变成有序序列  

2. 示意图

image.png

3. 代码实现

/**

 * author:韩国庆

 * date:2021/3/9 16:53

 * version:1.0

 */

public class QuickSort {

 

    public static void main(String[] args) {

        int[] arrays = new int[]{2,9,4,7,3,1,6,5};

        sort(arrays,0,arrays.length-1);

        System.out.println(Arrays.toString(arrays));

 

    }

    public static void sort(int[] arrays,int left,int right){

        int l = left;//左下标

        int r = right;//右下标

 

        int pivot = arrays[(left+right)/2];//中间值

        int temp = 0;

        /**

         * 循环的目的是让比pivot小的值放在左边,比pivot大的值放在右边

         */

        while (l<r){

            //在pivot左边找到大于等于pivot值,再退出

            while (arrays[l]<pivot){

                l+=1;

            }

            /**

             * 在pivot右边找小于等于pivot值,再退出
             
             */

            while (arrays[r]>pivot){

                r-=1;

            }

 

            /**

             * 如果 l>=r说明左边全部是小于pivot的值,右边全部是大于pivot的值

             */

            if (l>=r){

                break;

            }

            /**

             * 交换位置

             */

            temp = arrays[l];

            arrays[l] = arrays[r];

            arrays[r] = temp;

            /**

             * 交换后发现arrays[l] == piovt值,则r--;

             */

            if (arrays[l]==pivot){

                r-=1;

            }

            /**

             * 交换后发现arrays[r] == piovt值,则l++;

             */

            if (arrays[r] == pivot){

                l+=1;

            }
            
            /**

             * 如果l==r 必须l++,r--,否则出现溢栈

             */

            if (l==r){

                l+=1;

                r-=1;

            }

 

            if (left<r){

                sort(arrays,left,r);

            }

            if (right>l){

                sort(arrays,l,right);

            }

        }

 

    }

}

插入排序

1. 介绍

插入排序属于内部排序,是对于排序的元素以插入的方式寻找该元素的适当位置,已达到排序的目的。

2. 示意图

image.png

3. 代码实现

/**

 * author:韩国庆

 * date:2021/3/12 14:44

 * version:1.0

 */

public class InsertSort {

 

    public static void main(String[] args) {

 

        int[] arrays = new int[]{2,6,4,1,3,7,5};

        sort(arrays);

 

        System.out.println(Arrays.toString(arrays));

 

 

    }
    public static void sort(int[] arrays){

 

        int[] arr = arrays;

        int temp;

        for (int i=1;i<arr.length;i++){

            System.out.println("第  "+i+"  次");

            for (int j=i;j>=1;j--){

                if (arr[j]<arr[j-1]){

                    temp = arr[j];

                    arr[j] = arr[j-1];

                    arr[j-1] = temp;

                }else {

                    break;

                }

            }

        }

 

 

    }

 

}

选择排序

1. 介绍

选择排序也属于内部排序法,是从欲排序的数据中按指定的规则选择某一个元素,再以规则交换位置后达到的排序目的。

它的工作原理是:

第一次从待排序的数据元素中选出最小(或最大)的一个元素,存放在序列的起始位置,然后再从剩余的未排序元素中寻找到最小(大)元素,然后放到已排序的序列的末尾。以此类推,直到全部待排序的数据元素的个数为零。选择排序是不稳定的排序方法。  

2. 示意图

image.png

3.源码实现

/**

 * author:韩国庆

 * date:2021/3/12 15:02
 * version:1.0

 */

public class SelectSort {

 

    public static void main(String[] args) {

 

        int[] arrays = new int[]{2,6,4,1,3,7,5};

        sort(arrays);

 

        System.out.println(Arrays.toString(arrays));

 

    }

 

    public static void sort(int[] arrays){

        for (int i=0;i<arrays.length;i++){

            System.out.println("   "+i);

            int index = i;

            for (int j=arrays.length-1;j>i;j--){

                if (arrays[j]<arrays[index]){

                    index = j;

                    int temp = 0;

                    temp = arrays[j];

                    arrays[j] = arrays[i];

                    arrays[i] = temp;

                }

            }

        }

    }

}

希尔排序

1. 介绍

希尔排序(Shell's Sort)是插入排序的一种又称“缩小增量排序”(Diminishing Increment Sort),是插入排序算法的一种更高效的改进版本。希尔排序是非稳定排序算法。该方法因 D.L.Shell 于 1959 年提出而得名。

希尔排序是把记录按下标的一定增量分组,对每组使用直接插入排序算法排序;随着增量逐渐减少,每组包含的关键词越来越多,当增量减至 1 时,整个文件恰被分成一组,算法便终止。

2. 示意图:

image.png

image.png

image.png

3. 源码实现

/**

 * author:韩国庆

 * date:2021/3/13 15:12

 * version:1.0

 */

public class ShellSort {

 

    public static void main(String[] args) {

        int[] array = {7,3,2,5,9,4,8,1,6};

       // shellSort(array); //交换法

        shellSort2(array);//移动法

    }
    /**

     * 交换方式

     * @param arrays

     */

    public static void shellSort(int[] arrays){

        int temp = 0;

        int count = 0;

 

        for (int gap = arrays.length/2;gap>0;gap/=2){

            for (int i=gap;i<arrays.length;i++){

                for (int j=i-gap;j>=0;j-=gap){

                    if (arrays[j]>arrays[j+gap]){

                        temp=arrays[j];

                        arrays[j] = arrays[j+gap];

                        arrays[j+gap] = temp;

                    }

                }

            }

            System.out.println("第"+(++count)+"轮  =  "+ Arrays.toString(arrays));

        }

    }

 

    /**

     * 移位法

     */

    public static void shellSort2(int[] arrays){

        for (int gap=arrays.length/2;gap>0;gap/=2){

            for (int i=gap;i<arrays.length;i++){

                int j=i;
                int temp = arrays[j];

                if (arrays[j]<arrays[j-gap]){

                    while (j-gap>=0 && temp<arrays[j-gap]){

                        //移动

                        arrays[j] = arrays[j-gap];

                        j-=gap;

                    }

                    arrays[j] = temp;

                }

            }

        }

 

        System.out.println(Arrays.toString(arrays));

    }

}

归并排序

1. 介绍

归并排序(Merge Sort)是建立在归并操作上的一种有效,稳定的排序算法,该算法是采用分治法(Divide and Conquer)的一个非常典型的应用。将已有序的子序列合并,得到完全有序的序列;即先使每个子序列有序,再使子序列段间有序。若将两个有序表合并成一个有序表,称为二路归并。

2. 示意图

image.png

我们需要将两个已经有序的子序列合并成一个有序序列,比如上图最后一次合并,将[2,4,5,6]和[1,3,7,8]已经有序的子序列合并最终序列[1,2,3,4,5,6,7,8]

image.png

3. 源码实现

/**

 * author:韩国庆

 * date:2021/3/15 14:29

 * version:1.0

 */

public class MergetSort {

 

    public static void main(String[] args) {

        int[] arrays = {8,4,7,2,3,6,1,5};

 

        /**

         * 定义一个临时数组

         */

        int[] temp = new int[arrays.length];

        mSort(arrays,0,arrays.length-1,temp);

        System.out.println(Arrays.toString(arrays));

    }

 

    public static void mSort(int[] array,int left,int right,int[] temp){

        if (left<right){

            int mid = (left+right)/2;

 

            /**

             * 向左进行分解

             */

            mSort(array,left,mid,temp);
            /**

             * 向右分解

             */

            mSort(array,mid+1,right,temp);

 

            /**

             * 合并

             */

            sort(array,left,right,mid,temp);

        }

    }

 

    public static void sort(int[] arrays,int left,int right,int mid,int[] temp){

        /**

         * 初始化i,指向左边序列的初始索引值

         */

        int i = left;

        /**

         * 初始化j,指向左边序列初始值

         */

        int j = mid+1;

 

        /**

         * 初始化 t,指向数组的当前索引

         */

        int t = 0;

 

        /**

         * 先把左右两边的数据按照有序序列方式填充到temp数组中

         * 直至左右两边的有序序列,有一边处理完毕为止
         */

        while (i<=mid && j<=right){

 

            /**

             * 如果左边的有序序列的当前元素小于等于右边有序序列的当前元素,即让左边的当前元素填充到temp数组中

             然后 t++,i++

             */

            if (arrays[i]<=arrays[j]){

                temp[t] = arrays[i];

                t+=1;

                i+=1;

            }else {

                temp[t] = arrays[j];

                t+=1;

                j+=1;

            }

        }

        /**

         * 把剩余数据的一边的数据一次全部填充到temp;

         */

        while (i<=mid){

            temp[t] = arrays[i];

            t+=1;

            i+=1;

        }

 

        while (j<=right){

            temp[t] = arrays[j];

            t+=1;
            
            j+=1;

        }

 

        /**

         * 将temp数组中的元素拷贝至arrays数组中。这里不是每次拷贝所有的元素

         */

        t=0;

        int tempIndex = left;

        while (tempIndex<=right){

            arrays[tempIndex] = temp[t];

            t+=1;

            tempIndex +=1;

        }

    }

}