Java实现8种排序算法的示例代码

 更新时间:2020年06月11日 14:54:07   转载 作者:Oxye  
这篇文章主要介绍了8种JAVA实现排序算法的示例代码,文中讲解非常细致,代码帮助大家更好的理解和学习,感兴趣的朋友可以了解下

冒泡排序 O(n2)

两个数比较大小,较大的数下沉,较小的数冒起来。

public static void bubbleSort(int[] a) {
    //临时变量
    int temp;
    //i是循环次数,也是冒泡的结果位置下标,5个数组循环5次
    for (int i = 0; i < a.length; i++) {
      //从最后向前面两两对比,j是比较中下标大的值
      for (int j = a.length - 1; j > i; j--) {
        //让小的数字排在前面
        if (a[j] < a[j - 1]) {
          temp = a[j];
          a[j] = a[j - 1];
          a[j - 1] = temp;
        }
      }
    }
  }

选择排序 O(n2)

在长度为N的无序数组中,第一次遍历n-1个数,找到最小的数值与第一个元素交换;
第二次遍历n-2个数,找到最小的数值与第二个元素交换;
。。。
第n-1次遍历,找到最小的数值与第n-1个元素交换,排序完成。

public static void selectSort(int[] a) {
    //临时变量
    int temp;
    //i是循环次数,也是选择交换的结果的位置下标,5个数组循环5次
    for (int i = 0; i < a.length; i++) {
      //最小值下标
      int min = i;
      for (int j = i + 1; j < a.length; j++) {
        if (a[min] > a[j]) {
          min = j;
        }
      }
      temp = a[i];
      a[i] = a[min];
      a[min] = temp;
    }
  }

插入排序 O(n2)

在要排序的一组数中,假定前n-1个数已经排好序,现在将第n个数插到前面的有序数列中,使得这n个数也是排好顺序的。如此反复循环,直到全部排好顺序。

public static void insertSort(int[] a) {
    int temp;
    //i是循环次数,也是插入的队列的长度,最后一位是a[i]
    //所以一开始a[0]是排好的一个队列,比较a.length-1次,最后一次循环是a[a.length-1]插入a[0]~a[a.length-2]
    for (int i = 0; i < a.length - 1; i++) {
      //a[j]是要插入的数字,从a[j]往a[0]比较
      for (int j = i + 1; j > 0; j--) {
        //如果插入的数小,交换位置
        if (a[j] < a[j - 1]) {
          temp = a[j];
          a[j] = a[j - 1];
          a[j - 1] = temp;
        } else {
          //因为默认a[0]~a[i]是排好的,a[i+1]比a[i]大的话,就不用比较后面了
          break;
        }
      }
    }
  }

希尔排序 O(n1.5)

在要排序的一组数中,根据某一增量分为若干子序列,并对子序列分别进行插入排序。
然后逐渐将增量减小,并重复上述过程。直至增量为1,此时数据序列基本有序,最后进行插入排序。

public static void shellSort(int[] a) {
    int temp;
    int d = a.length;
    for (; ; ) {
      d = d / 2;
      //根据差值分组为子序列
      for (int k = 0; k < d; k++) {
        //此时对每组数列进行插入排序,数组为a[k+d],a[k+2d]...a[k+n*d]
        for (int i = k + d; i < a.length; i += d) {
          // a[j]是要插入的数字,从a[j]往a[0]比较,跨度为d
          for (int j = i; j > k; j -= d) {
            //如果插入的数小,交换位置
            if (a[j] < a[j - d]) {
              temp = a[j];
              a[j] = a[j - d];
              a[j - d] = temp;
            } else {
              //因为默认a[0]~a[i]是排好的,a[i+1]比a[i]大的话,就不用比较后面了
              break;
            }
          }
        }
      }
      if (d == 1) {
        break;
      }
    }
  }

快速排序 O(N*logN)

先从数列中取出一个数作为base值;
将比这个数小的数全部放在它的左边,大于或等于它的数全部放在它的右边;
对左右两个小数列重复第二步,直至各区间只有1个数。

public void quickSort(int a[], int l, int r) {
    //左边必须大于右边
    if (l >= r) {
      return;
    }
    int i = l;
    int j = r;
    //选择第一个数为基准
    int base = a[l];
    while (i < j) {
      //从右向左找第一个小于base的值,如果大于左移一位,直到找到小值或者i/j重合
      while (i < j && a[j] > base) {
        j--;
      }
      //从左向右找第一个大于base的值,如果小于右移一位,直到找到大值或者i/j重合
      while (i < j && a[i] < base) {
        i++;
      }
      //交换
      if (i < j) {
        int temp = a[j];
        a[j] = a[i];
        a[i] = temp;
      }
    }
    //将基准值放到i右移到的位置
    a[i] = base;
    //将i左边和i右边分别排序
    quickSort(a, l, i - 1);//递归调用
    quickSort(a, i + 1, r);//递归调用
  }

归并排序 O(N*logN)

归并排序是建立在归并操作上的一种有效的排序算法。该算法是采用分治法的一个非常典型的应用。
首先考虑下如何将2个有序数列合并。
这个非常简单,只要从比较2个数列的第一个数,谁小就先取谁,取了后就在对应数列中删除这个数。
然后再进行比较,如果有数列为空,那直接将另一个数列的数据依次取出即可。

private static void mergeSort(int[] a, int first, int last, int temp[]) {
    if (first < last) {
      //中间值
      int middle = (first + last) / 2;
      //左半部分排序
      mergeSort(a, first, middle, temp);
      //右半部分排序
      mergeSort(a, middle + 1, last, temp);
      //合并左右部分
      mergeArray(a, first, middle, last, temp);
    }
  }

  private static void mergeArray(int a[], int first, int middle, int end, int temp[]) {
    int i = first;
    int m = middle;
    int j = middle + 1;
    int n = end;
    int k = 0;
    while (i <= m && j <= n) {
      if (a[i] <= a[j]) {
        temp[k] = a[i];
        k++;
        i++;
      } else {
        temp[k] = a[j];
        k++;
        j++;
      }
    }
    while (i <= m) {
      temp[k] = a[i];
      k++;
      i++;
    }
    while (j <= n) {
      temp[k] = a[j];
      k++;
      j++;
    }
    for (int r = 0; r < k; r++) {
      a[first + r] = temp[r];
    }
  }

堆排序 O(N*logN)

利用堆这种数据结构所设计的一种排序算法。堆是一个近似完全二叉树的结构,并同时满足堆积的性质:即子结点的键值或索引总是小于(或者大于)它的父节点。

public static void heapSort(int a[]) {
    //堆顶最大值和数组最后(叶节点)交换 长度-1 次
    for (int i = a.length - 1; i > 0; i--) {
      //构建大顶堆(最大堆)
      buildHeap(a, i);
      //堆顶最大值和数组最后(叶节点)交换
      swap(a, 0, i);
    }
  }

  //构建大顶堆(最大堆)
  public static void buildHeap(int a[], int lastIndex) {
    //排最后的非叶节点为 长度/2-1,从第i检查到堆顶第0项,上浮大值
    for (int i = (lastIndex + 1) / 2 - 1; i >= 0; i--) {
      //必定存在的左叶节点,不一定存在的右叶节点
      int left = i * 2 + 1;
      int right = i * 2 + 2;
      //max为左右叶节点中的最大值
      int max = left;
      if (right <= lastIndex) {
        if (a[left] < a[right]) {
          max = right;
        }
      }
      //上浮大值
      if (a[i] < a[max]) {
        swap(a, i, max);
      }
    }
  }

  //交换值
  public static void swap(int a[], int i, int j) {
    int temp = a[i];
    a[i] = a[j];
    a[j] = temp;
  }

基数排序 O(d(n+r))

【d代表关键字有d位,n代表n个记录,r代表r个空队列】
基数排序(radix sort),相对于常见的比较排序,基数排序是一种分配式排序,即通过将所有数字分配到应在的位置最后再覆盖到原数组完成排序的过程。

public static void radixSort(int[] a) {
    //位数
    int digit = 1;
    //作为排序后数组的新下标
    int newIndex = 0;
    //供基数排序使用的二维数组,第一维度固定10位0~9,第二维度根据下标依次存放每次基数排序的结果
    int[][] container = new int[10][a.length];
    //第一维度每个数组的内容计数,最少为10,防止数组全是个位数时越界,例如五位数组最大值为8,counter.length=5 ,counter[8]就越界
    int counterLength = 10;
    if (a.length > 10) {
      counterLength = a.length;
    }
    int[] counter = new int[counterLength];
    //算出数组中最大的值,用来确定最大位
    int max = a[0];
    int maxDigit = 0;
    for (int i = 0; i < a.length; i++) {
      if (a[i] > max) {
        max = a[i];
      }
    }
    while (max > 0) {
      max /= 10;
      maxDigit++;
    }
    //对每位进行排序
    while (digit <= maxDigit) {
      //对每个数值该位取余,container[remainder],并计数该位置上数值的下标counter[remainder]
      for (int num : a) {
        int remainder = (num / digit) % 10;
        container[remainder][counter[remainder]] = num;
        counter[remainder]++;
      }
      //将上一步放入容器的数值依次覆盖到远数组中
      for (int i = 0; i < 10; i++) {
        for (int j = 0; j < counter[i]; j++) {
          a[newIndex] = container[i][j];
          newIndex++;
        }
        counter[i] = 0;
      }
      digit *= 10;
      newIndex = 0;
    }
  }

以上就是Java实现8种排序算法的示例代码的详细内容,更多关于Java实现8种排序算法的资料请关注脚本之家其它相关文章!

相关文章

  • 解析SpringSecurity自定义登录验证成功与失败的结果处理问题

    解析SpringSecurity自定义登录验证成功与失败的结果处理问题

    这篇文章主要介绍了SpringSecurity系列之自定义登录验证成功与失败的结果处理问题,本文通过实例给大家讲解的非常详细,具有一定的参考借鉴价值,需要的朋友可以参考下
    2019-11-11
  • Mybatis懒加载的实现

    Mybatis懒加载的实现

    这篇文章主要介绍了Mybatis懒加载的实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-07-07
  • java反射机制示例

    java反射机制示例

    这篇文章主要介绍了java反射机制示例,需要的朋友可以参考下
    2014-04-04
  • 两种java文件上传实例讲解

    两种java文件上传实例讲解

    这篇文章主要为大家详细介绍了两种java文件上传实例,一种是附件上传,另一种是上传简历功能,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2016-06-06
  • JAVA中list,set,数组之间的转换详解

    JAVA中list,set,数组之间的转换详解

    以下是对JAVA中list,set,数组之间的转换进行了详细的分析介绍,需要的朋友可以过来参考下
    2013-09-09
  • 使用Prometheus+Grafana的方法监控Springboot应用教程详解

    使用Prometheus+Grafana的方法监控Springboot应用教程详解

    这篇文章主要介绍了用Prometheus+Grafana的方法监控Springboot应用,本文通过实例代码详解给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2020-03-03
  • 15道非常经典的Java面试题 附详细答案

    15道非常经典的Java面试题 附详细答案

    这篇文章主要为大家推荐了15道非常经典的Java面试题,附详细答案,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2016-10-10
  • Java用Arrays.asList初始化ArrayList实例方法

    Java用Arrays.asList初始化ArrayList实例方法

    在本篇文章里小编给大家分享的是关于Java中使用Arrays.asList初始化ArrayList的知识点内容,需要的朋友们参考下。
    2019-10-10
  • Mybatis RowBounds 限制查询条数的实现代码

    Mybatis RowBounds 限制查询条数的实现代码

    Oracle 数据库查询增加RowBounds限制查询条数,默认是0到1000条。下面给大家分享Mybatis RowBounds 限制查询条数的实现代码,需要的朋友参考下吧
    2016-11-11
  • Java容器类源码详解 Deque与ArrayDeque

    Java容器类源码详解 Deque与ArrayDeque

    这篇文章主要介绍了Java容器类源码详解 Deque与ArrayDeque,Deque 接口继承自 Queue接口,但 Deque 支持同时从两端添加或移除元素,因此又被成为双端队列。,需要的朋友可以参考下
    2019-06-06

最新评论