数据结构——排序算法总结

版权声明:本文为博主原创文章,遵循 CC 4.0 by-sa 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/hk10066/article/details/82807665

1.冒泡排序

  • 基本原理

    1. 从第一个数据开始,与第二个数据相比较,如果第二个数据小于第一个数据,则交换两个数据的位置

    2. 指针由第一个数据移向第二个数据,第二个数据与第三个数据相比较,如果第三个数据小于第二个数据,则交换两个数据的位置

    3. 依此类推,完成第一轮排序。第一轮排序结束后,最大的元素被移到了最右面

    4. 依照上面的过程进行第二轮排序,将第二大的排在倒数第二的位置

    5. 重复上述过程,没排完一轮,比较次数就减少一次

    6. 共进行n-1轮排序

  • 编码思路:

    • 需要两层循环,第一层循环i表示排序的轮数,第二层循环j表示比较的次数

  • 冒泡排序算法总结

    • N个元素需要排序N-1轮

    • 第i轮需要比较N-i次

    • N个元素比较,需要比较n(n-1)/2次

    • 冒泡排序算法复杂度较高O(n*n)

//每轮排序结束把最大的放后面
    public static void bubbSort(int[] arr){
        if (arr == null){
            return;
        }
        for (int end = arr.length-1;end > 0;end--){//循环范围,每次范围会缩小
            for (int i = 0;i<end;i++){
                if (arr[i]>arr[i+1]){
                    swap(arr,i,i+1);
                }
            }
        }
    }


    //冒泡排序
    public void bubSort2(){
        for (int i=0;i<array.length-1;i++){//排序轮数
            for (int j=0;j<array.length-1-i;j++){//每轮比较次数
                if (array[j]>array[j+1]){
                    int temp = array[j+1];
                    array[j+1] = array[j];
                    array[j] = temp;
                }
            }
        }
    }

2.选择排序SelectionSort

  • 选择排序是对冒泡排序的改进,比较次数和冒泡排序相同,但是交换次数要小于冒泡排序,时间复杂度为O(n*n)

  • 基本原理

    1. 从第一个元素开始,分别与后面的元素向比较,找到最小的元素与第一个元素交换位置

    2. 从第二个元素开始,分别与后面的元素相比较,找到剩余元素中最小的元素,与第二个元素交换

    3. 重复上述步骤,直到所有的元素都排成由小到大为止

  • 编码思路:

    • 需要两次循环,第一层循环i表示每轮指针指向的位置,将最小值min初始化为第i个元素,第二层循环从j=i+1开始,分别与min比较,如果小于min,则更新min的值,内层循环结束后;交换min元素和第i个元素的位置。以此类推进行下一轮循环,直到i=length时停止循环。当i=length时,说明小的元素已经全部移到了左面,因此无需进行内层循环了

  • 选择排序总结

    1. N个元素需要排序N-1轮

    2. 第i轮需要比较N-i次

    3. N个元素排序,需要比较n(n-1)/2次

    4. 选择排序的算法复杂度仍为O(n*n)

    5. 相比于冒泡排序,选择排序的交换次数大大减少,因此速度要快于冒泡排序

   //每次都选择最小的
 public static void selectSort(int[] arr){
        if (arr == null){
            return;
        }
        for (int i=0;i<arr.length-1;i++){
            int minindex = i;//假定小的在i上
            for (int j=i+1;j<arr.length;j++){
                minindex = arr[j]<arr[minindex]?j:minindex;//条件为真取问号后面的
            }
            swap(arr,i,minindex);
        }
    }

3.插入排序

  • 插入排序是简单排序中最快的排序算法,虽然时间复杂度仍然为O(n*n),但是却比冒泡排序和选择排序快很多

  • 基本原理:

    1. 将指针指向某个元素,假设该元素左侧的元素全部有序,将该元素抽取出来,然后按照从右往左的顺序分别与其左边的元素比较,遇到比其大的元素便将元素右移,直到找到比该元素小的元素或者找到最左面发现其左侧的元素都比它大,停止

    2. 此时会出现一个空位,将该元素放入到空位中,此时该元素左侧的元素都比它小,右侧的元素都比它大

    3. 指针向后移动一位,重复上述过程。每操作一轮,左侧有序元素都增加一个,右侧无序元素都减少一个

  • 编码分析:

    • 需要两层循环,第一层循环index表示上述例子中的指针,即遍历从坐标为1开始的每一个元素;第二层循环从leftindex=index-1开始,leftindex--向左遍历,将每一个元素与i处的元素比较,直到j处的元素小于i出的元素或者leftindex<0;遍历从i到j的每一个元素使其右移,最后将index处的元素放到leftindex处的空位处

  • 插入排序总结:

    • 插入排序的速度约比冒泡排序快一倍(比较次数少一倍),比选择排序还要快一些,对于基本有序的数据,插入排序的速度会很快,是简单排序中效率最高的排序算法

  •     //插入排序
        public void InsertSort(){
            for (int index=1;index<array.length;index++){//外层向右的index,即作为比较对象的数据的index
                int temp = array[index];//用作比较的数据
                int leftindex = index-1;
                while (leftindex>=0&&array[leftindex]>temp){//当必到最左边或者遇到比temp小的数据时结束循环
                    array[leftindex+1] = array[leftindex];
                    leftindex--;
                }
                array[leftindex+1] = temp;//把temp放在空位置
            }
        }

     

4.希尔排序

  • 希尔排序属于插入类排序,是将整个有序序列分割成若干小的子序列分别进行插入排序

  • 基本原理:

    • 希尔排序通过将比较的全部元素分为几个区域来提升插入排序的性能。这样可以让一个元素可以一次性地朝最终位置前进一大步。然后算法再取越来越小的步长进行排序,算法的最后一步就是普通的插入排序,但是到了这步,需排序的数据几乎是已排好的了(此时插入排序较快

    • 步长的选择是希尔排序的重要部分。只要最终步长为1任何步长序列都可以工作(且步长要小于数组长度)。算法最开始以一定的步长进行排序。然后会继续以一定步长进行排序,最终算法以步长为1进行排序。当步长为1时,算法变为插入排序,这就保证了数据一定会被排序

  •     //希尔排序
        public void ShellSort(){
            int d = array.length;
            while (true){
                d=d/2;
                for (int x=0;x<d;x++){
                    for (int i=x+d;i< array.length;i=i+d){
                        int temp = array[i];
                        int j;
                        for (j=i-d;j>=0&&array[j]>temp;j=j-d){
                            array[j+d]=array[j];
                        }
                        array[j+d]=temp;
                    }
                }
                if (d==1){
                    break;
                }
            }
        }

     

5.归并排序

  • O(nlogN)

  • 归并排序 (merge sort) 是一类与插入排序、交换排序、选择排序不同的另一种排序方法。归并的含义是将两个或两个以上的有序表合并成一个新的有序表,

  • 将两个或者两个以上的有序表合并成一个新的有序表,即把待排序的序列分成若干个子序列,每个序列是有序的,然后把有序序列合并成整体有序序列

  • 是一种稳定排序方式

    public static void Sort(int[] arr,int L,int R){
        if (L==R){
            return;
        }
        int mid = (L+R)/2;//中点
        Sort(arr,L,mid);//  T(N/2)
        Sort(arr,mid+1,R);//  T(N/2)
        mergeSort(arr,L,mid,R);//  O(N)
        //T(N) = 2(N/2)+O(N)
    }

    public static void mergeSort(int[] arr,int L,int mid,int R){
        int[] help = new int[R-L+1];//新建辅助数组
        int i = 0;//辅助数组的i
        int p1 = L;
        int p2 = mid+1;
        while (p1<=mid&&p2<=R){
            //每次都要移动放置
            help[i++] = arr[p1]<arr[p2] ? arr[p1++] : arr[p2++];
        }
        //两个必有且只有一个越界
        while (p1<=mid){
            help[i++] = arr[p1++];
        }
        while (p2<=R){
            help[i++] = arr[p2++];
        }
        //拷贝回去
        for (i = 0;i<help.length;i++){
            arr[L+i] = help[i];
        }
    }

6.快速排序

  • 算法思路:

    1. 设置两个变量i、j,排序开始的时候:i=0,j=N-1

    2. 以第一个数组元素作为关键数据,赋值给key,即key=A[0]

    3. 从j开始向前搜索,即由后开始向前搜索(j--),找到第一个小于key的值A[j],将A[j]和A[i]互换

    4. 从i开始向后搜索,即由前开始向后搜索(i++),找到第一个大于key的A[i],将A[i]和A[j]互换

    5. 重复第3、4步,直到i=j; (3,4步中,没找到符合条件的值,即3中A[j]不小于key,4中A[i]不大于key的时候改变j、i的值,使得j=j-1,i=i+1,直至找到为止。找到符合条件的值,进行交换的时候i, j指针位置不变。另外,i==j这一过程一定正好是i+或j-完成的时候,此时令循环结束)

  •     //经典快排
    public static int Partition(int[] a, int p, int r) {
            int x = a[r - 1];
            int i = p - 1;
            int temp;
            for (int j = p; j <= r - 1; j++) {
                if (a[j - 1] <= x) {
                    // 交换(a[j-1],a[i-1]);
                    i++;
                    temp = a[j - 1];
                    a[j - 1] = a[i - 1];
                    a[i - 1] = temp;
                }
            }
                    //交换(a[r-1,a[i+1-1]);
            temp = a[r - 1];
            a[r - 1] = a[i + 1 - 1];
            a[i + 1 - 1] = temp;
            return i + 1;
        }
    
        public static void QuickSort(int[] a, int p, int r) {
            if (p < r) {
                int q = Partition(a, p, r);
                QuickSort(a, p, q - 1);
                QuickSort(a, q + 1, r);
            }
        }

     

  • //随机快排算法
        public static void quickSort(int[] arr,int L,int R){
    
            if (L<R){
                //随机快排添加代码,即在L到R位置上随机一个值和R交换,作为指定值
                swap(arr,L+(int)(Math.random()*(R-L+1)),R);
                int[] p = patrition(arr,L,R);//记录边界,后续递归区域选择,左边完了处理右边
                quickSort(arr,L,p[0]-1);
                quickSort(arr,p[1]+1,R);
            }
        }
    
        private static int[] patrition(int[] arr, int L, int R) {
    
            int Less = L-1;
            int more = R;
            while (L<R){
                if (arr[L]<arr[R]){  //比较   小于·部分·扩大
                    swap(arr,++Less,L++);
                }else if (arr[L]>arr[R]){
                    swap(arr,--more,L);
                }else {
                    L++;
                }
            }
            swap(arr,more,R);//将后边存放x区域的x和大于x部分的区域交换,即=x的部分++
            return new int[] {Less+1,more};//两个长度的数组
        }

     

展开阅读全文

没有更多推荐了,返回首页