七大基于比较的排序算法(JAVA)

简介: 冒泡排序堆排序插入排序希尔排序归并排序快速排序选择排序 

排序算法的稳定性大小相同的元素在排序前后相对位置相同就称其为稳定的排序。

注:一个本身就是稳定的排序 是可以实现为不稳定的排序的 ;但是相反 一个本身就不稳定的排序 是不可能实现为稳定的排序的。

稳定的排序算法:插入排序 冒泡排序 归并排序

冒泡排序

时间复杂度: o(n^2)   如果加了优化  最好情况O(N)

空间复杂度:O(1)

稳定性: 稳定

publicstaticvoidbubbleSort(int[] array){
for (inti=0; i<array.length-1; i++) {
for (intj=0; j<array.length-1; j++) {
if (array[j] >array[j+1]) {
swap(array, j, j+1);
                }
            }
        }
    }
privatestaticvoidswap(int[] array, intminIndex, inti) {
inttmp=array[i];
array[i] =array[minIndex];
array[minIndex] =tmp;
    }

image.gif

优化:

publicstaticvoidbubbleSort(int[] array) {
for (inti=0; i<array.length-1; i++) {
booleanflg=false;
for (intj=0; j<array.length-1-i; j++) {
if(array[j] >array[j+1]) {
swap(array,j,j+1);
flg=true;
                }
            }
if(!flg) {
return;
            }
        }
    }

image.gif

堆排序

时间复杂度:O(n*logN)    N^1.3 -->

空间复杂度:O(1)

稳定性:不稳定

数据量非常 大的时候 堆排 一定比希尔快


堆排序的原理:

    1. 用一个大根堆的堆顶元素和最后一个元素交换
    2. 使数组长度减一
    3. 在重新将堆调整为大根堆

    image.gif

    publicstaticvoidheapSort(int[] array){
    createHeap(array);
    for (inti=0; i<array.length-1; i++) {
    swap(array, 0, array.length-1-i);
    shiftDown(array, 0, array.length-1-i);
            }
        }
    privatestaticvoidcreateHeap(int[] array) {
    for (inti= (array.length-1-1)/2; i>=0; i--) {
    shiftDown(array, i, array.length);
            }
        }
    privatestaticvoidshiftDown(int[] array, inti, intlength) {//length个元素intchild=i*2+1;
    while (child<length) {
    if (child+1<length&&array[child] <array[child+1]) {
    child++;
                }
    if (array[child] >array[i]) {
    swap(array, child, i);
    i=child;
                }else {
    break;
                }
    child=i*2+1;
            }
        }
    privatestaticvoidswap(int[] array, intminIndex, inti) {
    inttmp=array[i];
    array[i] =array[minIndex];
    array[minIndex] =tmp;
        }

    image.gif

    插入排序

    时间复杂度:

           最好情况:数据完全有序的时候 O(N)

           最坏情况:数据完全逆序的时候 O(N^2)

    空间复杂度:O(1)

    稳定性:稳定

    插入排序的原理

      1. 从左边第一位开始挨个令其成为关键码
      2. 从左到右把待排序的记录按其关键码值的大小逐个插入到左边已经排好序的有序序列中
      3. 直到所有的记录插入完为止,得到一个新的有序序列
      publicstaticvoidinsertSort(int[] array){
      for (inti=1; i<array.length; i++) {
      inttmp=array[i];
      intj=i-1;
      for (; j>=0 ; j--) {
      //如果此处改为array[j] >= tmp就会变成不稳定排序if (array[j] >tmp) {
      array[j+1] =array[j];
                      }else{
      break;
                      }
                  }
      array[j+1] =tmp;
              }
          }

      image.gif

      希尔排序

      时间复杂度:

                  约等于:n^1.3 - n^1.5

      复杂度:O(1)

      稳定性:不稳定

      希尔排序其实就是对插入排序的一种优化

      基本原理:

        1. 先按照步长将数组分为若干组
        2. 对每组进行插入排序
        3. 减小步长重复以上步骤

        image.png

        publicstaticvoidshellSort(int[] array){
        intgap=array.length;
        while (gap>1) {
        gap=gap/2;
        shell(array, gap);
                }
            }
        privatestaticvoidshell(int[] array, intgap) {
        for (inti=gap; i<array.length; i++) {
        inttmp=array[i];
        intj=i-gap;
        for (; j>=0; j-=gap) {
        if (array[j] >tmp) {
        array[j+gap] =array[j];
                        }else {
        break;
                        }
                    }
        array[j+gap] =tmp;
                }
            }

        image.gif

        归并排序


        时间复杂度: 0(N*logN)

        空间复杂度:O(n)

        稳定性: 稳定


        归并排序是建立在归并操作上的一种有效的排序算法,该算法是采用分治法的一个非常典型的应用。将已有序的子序列合并,得到完全有序的序列;即先使每个子序列有序,再使子序列段间有序。

        publicvoidmergerSort(int[] nums, intleft, intright) {//right:数组长度减一if (left>=right) {
        return;
                }
        intmid= (left+right) /2;
        mergerSort(nums, left, mid);
        mergerSort(nums, mid+1, right);
        merger(nums, left, mid, right);
            }
        privatevoidmerger(int[] nums, intleft, intmid, intright) {
        int[] tmp=newint[right-left+1];
        inti=0;
        intl=left;
        intr=mid+1;
        while (l<=mid&&r<=right) {
        if (nums[l] <nums[r]) {
        tmp[i++] =nums[l++];
                    }else {
        tmp[i++] =nums[r++];
                    }
                }
        while (l<=mid) {
        tmp[i++] =nums[l++];
                }
        while (r<=right) {
        tmp[i++] =nums[r++];
                }
        i=0;
        for (intj=0; j<tmp.length; j++) {
        nums[left++] =tmp[j];
                }
            }

        image.gif

        快速排序

        时间复杂度:

               最好情况:O(N*logN)   满二叉树/完全二叉树

               最坏情况:O(N^2) 单分支的树

        空间复杂度:

               最好情况:O(logN)   满二叉树/完全二叉树

               最坏情况:O(N)   单 分支的树

        稳定性:不稳定

        快速排序基本原理

          1. 任取待排序元素序列中的某元素作为基准值
          2. 按照该排序码将待排序集合分割成两子序列,左子序列中所有元素均小于基准值,右子序列中所有元素均大于基准值
          3. 每个子序列重复该过程,直到所有元素都排列在相应位置上为止

          有Hoare法   挖坑版法  前后指针法

          这里只介绍Hoare法

          publicstaticvoidquickSort(int[] array){
          quick(array, 0, array.length-1);
              }
          privatestaticvoidquick(int[] array, intleft, intright) {
          if (left>=right) {
          return;
                  }
          intIndex=findSwap(array, left, right);
          quick(array, left, Index-1);
          quick(array, Index+1, right);
              }
          privatestaticintfindSwap(int[] array, intleft, intright) {
          intkey=array[left];
          intkeyIndex=left;
          while (left<right) {
          //必须right先走//如果是left先走,两个相遇的地方一定比key大while (left<right&&array[right] >=key) {
          right--;
                      }
          while (left<right&&array[left] <=key) {
          left++;
                      }
          swap(array, right, left);
                  }
          if (left==right) {
          swap(array, keyIndex, left);
                  }
          returnleft;
              }
          privatestaticvoidswap(int[] array, intminIndex, inti) {
          inttmp=array[i];
          array[i] =array[minIndex];
          array[minIndex] =tmp;
              }

          image.gif

          优化

          利用三数取中法来避免单分支树的形成(尽量降低树的高度)

          publicint[] sortArray(int[] nums) {
          //快速排序quickSort(nums, 0, nums.length-1);
          returnnums;
              }
          privatevoidquickSort(int[] nums, intleft, intright) {
          if (left>=right) {
          return;
                  }
          //三数取中法swap(nums, left, threeNumMid(nums, left, right));
          //也可以在这里加一个判断当左右之间的数据个数小于一定值然后调用插入排序//因为在排序过程中数组会趋近于有序所以插入排序的效率会很快intpivot=quick(nums, left, right);
          quickSort(nums, left, pivot-1);
          quickSort(nums, pivot+1, right);
              }
          privateintthreeNumMid(int[] nums, intleft, intright) {
          intmid= (left+right) /2;
          if (nums[left] >nums[right]) {
          if (nums[mid] >nums[left]) {
          returnleft;
                      }elseif (nums[mid] <nums[right]) {
          returnright;
                      }else {
          returnmid;
                      }
                  }else {
          if (nums[mid] <nums[left]) {
          returnleft;
                      }elseif (nums[mid] >nums[right]) {
          returnright;
                      }else {
          returnmid;
                      }
                  }
              }
          privateintquick(int[] nums, intleft, intright) {
          intindex=left;
          intkey=nums[left];
          while (left<right) {
          while (left<right&&nums[right] >=key) {
          right--;
                      }
          while (left<right&&nums[left] <=key) {
          left++;
                      }
          swap(nums, right, left);
                  }
          swap(nums, index, left);
          returnleft;
              }
          privatevoidswap(int[] nums, intleft, intright) {
          inttmp=nums[left];
          nums[left] =nums[right];
          nums[right] =tmp;
              }

          image.gif

          选择排序

          时间复杂度:O(n^2)

          空间复杂度:O(1)

          稳定性:不稳定的排序

          选择排序基本原理:

            1. 从左至右每一次从待排序的数据元素中选出最小(或最大)的一个元素
            2. 将其放在待排序元素的起始位置,已有序元素的最后边
            3. 重复上述步骤直到全部待排序的数据元素排完 。
            publicstaticvoidselectSort(int[] array){
            for (inti=0; i<array.length; i++) {
            intminIndex=i;
            for (intj=i+1; j<array.length; j++) {
            if (array[minIndex] >array[j]) {
            minIndex=j;
                            }
                        }
            swap(array, minIndex, i);
                    }
                }
            privatestaticvoidswap(int[] array, intminIndex, inti) {
            inttmp=array[i];
            array[i] =array[minIndex];
            array[minIndex] =tmp;
                }

            image.gif

            目录
            相关文章
            |
            1月前
            |
            存储 人工智能 算法
            数据结构与算法细节篇之最短路径问题:Dijkstra和Floyd算法详细描述,java语言实现。
            这篇文章详细介绍了Dijkstra和Floyd算法,这两种算法分别用于解决单源和多源最短路径问题,并且提供了Java语言的实现代码。
            74 3
            数据结构与算法细节篇之最短路径问题:Dijkstra和Floyd算法详细描述,java语言实现。
            |
            3月前
            |
            搜索推荐 算法 Java
            手写快排:教你用Java写出高效排序算法!
            快速排序(QuickSort)是经典的排序算法之一,基于分治思想,平均时间复杂度为O(n log n),广泛应用于各种场合。在这篇文章中,我们将手写一个Java版本的快速排序,从基础实现到优化策略,并逐步解析代码背后的逻辑。
            157 1
            |
            1月前
            |
            算法 Java 数据中心
            探讨面试常见问题雪花算法、时钟回拨问题,java中优雅的实现方式
            【10月更文挑战第2天】在大数据量系统中,分布式ID生成是一个关键问题。为了保证在分布式环境下生成的ID唯一、有序且高效,业界提出了多种解决方案,其中雪花算法(Snowflake Algorithm)是一种广泛应用的分布式ID生成算法。本文将详细介绍雪花算法的原理、实现及其处理时钟回拨问题的方法,并提供Java代码示例。
            74 2
            |
            3月前
            |
            算法 Java
            LeetCode经典算法题:矩阵中省份数量经典题目+三角形最大周长java多种解法详解
            LeetCode经典算法题:矩阵中省份数量经典题目+三角形最大周长java多种解法详解
            52 6
            |
            3月前
            |
            搜索推荐 算法 Java
            经典排序算法之-----选择排序(Java实现)
            这篇文章通过Java代码示例详细解释了选择排序算法的实现过程,包括算法的基本思想、核心代码、辅助函数以及测试结果,展示了如何通过选择排序对数组进行升序排列。
            经典排序算法之-----选择排序(Java实现)
            |
            3月前
            |
            搜索推荐 算法 Java
            |
            3月前
            |
            存储 算法 Java
            LeetCode经典算法题:打家劫舍java详解
            LeetCode经典算法题:打家劫舍java详解
            70 2
            |
            3月前
            |
            人工智能 算法 Java
            LeetCode经典算法题:井字游戏+优势洗牌+Dota2参议院java解法
            LeetCode经典算法题:井字游戏+优势洗牌+Dota2参议院java解法
            50 1
            |
            3月前
            |
            存储 算法 Java
            LeetCode经典算法题:预测赢家+香槟塔java解法
            LeetCode经典算法题:预测赢家+香槟塔java解法
            61 1
            |
            3月前
            |
            数据采集 搜索推荐 算法
            【高手进阶】Java排序算法:从零到精通——揭秘冒泡、快速、归并排序的原理与实战应用,让你的代码效率飙升!
            【8月更文挑战第21天】Java排序算法是编程基础的重要部分,在算法设计与分析及实际开发中不可或缺。本文介绍内部排序算法,包括简单的冒泡排序及其逐步优化至高效的快速排序和稳定的归并排序,并提供了每种算法的Java实现示例。此外,还探讨了排序算法在电子商务、搜索引擎和数据分析等领域的广泛应用,帮助读者更好地理解和应用这些算法。
            44 0
            下一篇
            无影云桌面