1.冒泡排序

最简单的排序实现,冒泡排序,是一种交换排序,它的基本思想是:两两比较相邻记录的关键字,如果反序则交换,直到没有反序的记录为止。

 //冒泡排序
private int[] bubbleSort(int[] arr) {
for (int i = 0; i < arr.length; i++)
for (int j = arr.length - 1; j > i; j--)
if (arr[j] < arr[j - 1]) {
swap(arr, j, j - 1);
}
return arr;
}

swap方法

 private void swap(int[] arr, int i, int j) {
int temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}

冒泡算法的优化(外部循环优化)

private int[] bubbleSort1(int[] arr) {
boolean flag = true;//加入flag指针,若在一次冒泡中,没有交换 则说明可以停止 减少运行时
for (int i = 0; i < arr.length && flag; i++) {
flag = false;
for (int j = arr.length - 1; j > i; j--) {
if (arr[j] < arr[j - 1]) {
swap(arr, j, j - 1);
flag = true;
}
}
}
return arr;
}

代码改动的关键就是在i变量的for循环中,增加了对flag是否为true的判断。经过这样的改进,冒泡排序在性能上就有了一些提升,可以避免因已经有序的情况下的无意义的循环判断。

优化2:

private int[] bubbleSort2(int[] arr) {
boolean flag = true;//加入flag指针,若在一次冒泡中,没有交换 则说明可以停止 减少运行时
int pos = 0;
int k = arr.length - 2;
for (int i = 0; i < arr.length && flag; i++) {
flag = false;
for (int j = arr.length - 1; j > k; j--) {
if (arr[j] < arr[j - 1]) {
swap(arr, j, j - 1);
flag = true;
pos = i;
}
k = pos;
}
}
return arr;
}

冒泡排序的复杂度。当最好情况,也就是要排序的表本身就是有序的,那么我们要比较次数,根据改进后的代码,可以判断出就是n-1次比较,没有数据交换,时间复杂度也就是O(n).当最坏情况,即待排序表是逆序的情况,此时需要比较1+2+3+.....+(n-1) = n(n-1)/2次,并作等数量级的移动记录。因此,总的时间复杂度为O(n2)。


2.简单选择排序

基本思想:每一趟(例如第i趟)在n-i(i=1,2,...,n-1)个记录中选取关键字最小的记录作为有序序列的第i个记录,直到第n-1趟做完,待排序元素只剩1个,就不用再选了。

private int[] selectSort(int[] arr) {
int min;
for (int i = 0; i < arr.length - 1; i++) {//共进行n-1趟
min = i;//记录最小元素位置
for (int j = i + 1; j < arr.length; j++) {
if (arr[j] < arr[min]) {
min = j;//更新最小元素
}
}
if (min != i) {
swap(arr, i, min);
}
}
return arr;
}


简单选择排序的思想很简单,代码也很清晰就不多加赘述。

复杂度: 从简单选择排序的过程来看,它最大的特点就是交换移动数据次数相当少,这样也就节约了相应的时间,分析它的时间复杂度发现,无论最好最差情况,其比较次数都是一样多的,第i趟排序需要进行 n-1 次关键字的比较,此时需要比较n-1+n-2+...+1 = n(n-1)/2次。而对于交换次数而言,当最好情况,交换次数为0,最差情况,也就是逆序时,交换次数n-1次,基于最终的排序时间是比较与交换次数的综合,因此总的时间复杂度依然为O(n2).

应该说,尽管与冒泡排序同为O(n2),但简单选择排序的性能上还是要略由于冒泡排序的。

3.直接插入排序

基本思想:将一个记录插入到已经排序的有序表中,从而得到一个新的、记录数增1的有序表

private int[] insertSort(int[] arr) {
int temp = 0;
int j = 0;
for (int i = 1; i < arr.length; i++) {
temp = arr[i];
for (j = i; j > 0 && temp < arr[j-1]; j--) {
arr[j] = arr[j - 1];// 假如temp比前面的值小,则将前面的值后移
}
arr[j] = temp;
}
return arr;
}

复杂度分析:从控件上来看,它只需要一个记录的辅助空间。时间复杂度,O(n2)但是性能比简单选择排序和冒泡排序要好一些。

4.希尔排序(缩小增量排序)

基本思想:先将整个待排序的记录序列分割成为若干子序列分别进行直接插入排序,待整个序列中的记录“基本有序”时,再对全体记录进行依次直接插入排序。

private int[] shellSort(int[] arr) {
int j;
int temp = 0;
//每次将步长缩小为1/2
for (int d = arr.length / 2; d > 0; d /= 2) {
for (int i = d; i < arr.length; i++) {
temp = arr[i];
for (j = i; j >= d; j -= d) {
if (temp < arr[j - d]) {
arr[j] = arr[j - d];
} else {
break;
}
}
arr[j] = temp;
}
}
return arr;
}

时间复杂度O(n^1.5)

5.堆排序

基本思想:堆排序(heap sort)就是利用堆进行排序的方法。将待排序的序列构造成一个堆。此时,整个序列的最大值就是堆顶的根节点。将它移走(其实就是将其与堆数组的末尾元素蒋欢,此时元素末尾就是最大值),然后将剩余的n-1个序列重新构造成一个堆,这样就会得到n个元素中的次大值。如此反复执行,便能得到一个有序序列了。

按照这个思想来做,那么实际会有两个问题:

  1. 如何由一个无需序列构建成一个堆?
  2. 如何再输出堆顶元素后,调整生于元素成为一个新的堆?
 private int[] heapSort(int[] arr) {
int i;
for (i = arr.length / 2; i >= 0; i--) {//把arr构建成大顶堆
heapAdjust(arr, i, arr.length - 1);
}
for (i = arr.length - 1; i >= 0; i--) {
swap(arr, 0, i);//将堆顶元素和当前未经排序子序列的最后一个记录交换
heapAdjust(arr, 0, i - 1);//重新调整大顶堆
}
return arr;
} private void heapAdjust(int[] arr, int s, int m) {
//已知arr[s...m]中记录的关键字除了arr[s]之外均满足堆的定义
//本函数调整arr[s]的关键字,使arr[s...m]成为一个大顶堆
int temp, j;
temp = arr[s];
for (j = 2 * s; j <= m; j *= 2) {//沿关键字较大的孩子节点往下筛选
if (j < m && arr[j] < arr[j + 1]) {
++j;//j为关键字中较大的记录的下标
}
if (temp >= arr[j]) {
break;//应插入在位置s上
}
arr[s] = arr[j];
s = j;
}
arr[s] = temp;//插入
}

时间复杂度O(nlogn)不适合待排序序列较少的情况

6.归并排序

归并排序(merging sort)是将两个(或两个以上)有序表合并成一个新的有序表,即把待排序序列分为若干个子序列,每个子序列是有序的。然后再把有序子序列合并为整体有序序列。

private int[] mergeSort(int[] arr) {
return mSort(arr, 0, arr.length - 1);
} private int[] mSort(int[] arr, int low, int high) {
int mid = (low + high) / 2;
if (low < high) {
//左边
mSort(arr, low, mid);
//右边
mSort(arr, mid + 1, high);
//左右归并
merge(arr, low, mid, high);
}
return arr;
} private void merge(int[] arr, int low, int mid, int high) {
int[] temp = new int[high - low + 1];
int i = low;// 左指针
int j = mid + 1;// 右指针
int k = 0;
// 把较小的数先移到新数组中
while (i <= mid && j <= high) {
if (arr[i] < arr[j]) {
temp[k++] = arr[i++];
} else {
temp[k++] = arr[j++];
}
}
// 把左边剩余的数移入数组
while (i <= mid) {
temp[k++] = arr[i++];
}
// 把右边边剩余的数移入数组
while (j <= high) {
temp[k++] = arr[j++];
}
// 把新数组中的数覆盖nums数组
if (temp.length >= 0) System.arraycopy(temp, 0, arr, low, temp.length);
}

时间复杂度O(nlogn)

7.快速排序

基本思想:分治

private int[] quickSort(int[] arr) {
return qSort(arr, 0, arr.length - 1);
} private int[] qSort(int[] arr, int low, int high) {
if (low < high) {
int pivotPos = partition(arr, low, high);//划分
qSort(arr, low, pivotPos - 1);
qSort(arr, pivotPos + 1, high);
}
return arr;
} private int partition(int[] arr, int low, int high) {//一趟排序过程
int pivot = arr[low];//将当前表的第一个元素作为枢轴值,对表进行划分
while (low < high) {//循环跳出条件
while (low < high && arr[high] >= pivot) --high;
arr[low] = arr[high];//将比pivot小的移到左侧
while (low < high && arr[low] <= pivot) ++low;
arr[high] = arr[low];//将比pivot大的移到右侧
}
arr[low] = pivot;//枢轴元素存放到最终位置
return low;//返回枢轴的最终位置
}

时间复杂度O(nlogn)

快速排序在序列中元素很少时,效率将比较低,不如插入排序,因此一般在序列中元素很少时使用插入排序,这样可以提高整体效率。

【排序算法】java实现的更多相关文章

  1. 八大排序算法Java

    目录(?)[-] 概述 插入排序直接插入排序Straight Insertion Sort 插入排序希尔排序Shells Sort 选择排序简单选择排序Simple Selection Sort 选择 ...

  2. 八大排序算法Java实现

    本文对常见的排序算法进行了总结. 常见排序算法如下: 直接插入排序 希尔排序 简单选择排序 堆排序 冒泡排序 快速排序 归并排序 基数排序 它们都属于内部排序,也就是只考虑数据量较小仅需要使用内存的排 ...

  3. 排序算法(Java实现)

    这几天一直在看严蔚敏老师的那本<数据结构>那本书.之前第一次学懵懵逼逼,当再次看的时候,发觉写的是非常详细,非常的好. 那就把相关的排序算法用我熟悉的Java语言记录下来了.以下排序算法是 ...

  4. 6种基础排序算法java源码+图文解析[面试宝典]

    一.概述 作为一个合格的程序员,算法是必备技能,特此总结6大基础算法.java版强烈推荐<算法第四版>非常适合入手,所有算法网上可以找到源码下载. PS:本文讲解算法分三步:1.思想2.图 ...

  5. 排序算法Java版,以及各自的复杂度,以及由堆排序产生的top K问题

    常用的排序算法包括: 冒泡排序:每次在无序队列里将相邻两个数依次进行比较,将小数调换到前面, 逐次比较,直至将最大的数移到最后.最将剩下的N-1个数继续比较,将次大数移至倒数第二.依此规律,直至比较结 ...

  6. 九大排序算法Java实现

    之前学习数据结构与算法时花了三天时间整理九大排序算法,并采用Java语言来实现,今天第一次写博客,刚好可以把这些东西从总结的文档中拿出来与大家分享一下,同时作为自己以后的备忘录. 1.排序算法时间复杂 ...

  7. 排序系列 之 希尔排序算法 —— Java实现

    基本思想: 希尔排序的实质就是分组插入排序,又称缩小增量法. 将整个无序序列分割成若干个子序列(由相隔某个“增量”的元素组成的)分别进行直接插入排序,然后依次缩减增量再进行排序,待整个序列中的元素基本 ...

  8. 十大基础排序算法[java源码+动静双图解析+性能分析]

    一.概述 作为一个合格的程序员,算法是必备技能,特此总结十大基础排序算法.java版源码实现,强烈推荐<算法第四版>非常适合入手,所有算法网上可以找到源码下载. PS:本文讲解算法分三步: ...

  9. 排序算法Java代码实现(一)—— 选择排序

    以下几篇随笔都是记录的我实现八大排序的代码,主要是贴出代码吧,讲解什么的都没有,主要是为了方便我自己复习,哈哈,如果看不明白,也不要说我坑哦! 本片分为两部分代码: 常用方法封装 排序算法里需要频繁使 ...

  10. 【排序算法】希尔排序算法 Java实现

    希尔排序算法是按其设计者希尔(Donald Shell)的名字命名,该算法由1959年公布,是插入排序的一种更高效的改进版本. 希尔排序是基于插入排序的以下两点性质而提出改进方法的: 插入排序在对几乎 ...

随机推荐

  1. IAR配置ICF到项目的实现方法

    以STM8为例: 将项目使用的MCU型号的icf文件拷贝到项目里面,icf一般放在 C:\Program Files\IAR Systems\Embedded Workbench 6.5\stm8\c ...

  2. hadoop中namenode启动失败

    jps发现namenode启动失败 每次开机都要重新格式化一下namenode才可以 其实问题出现自tmp文件上,因为每次开机就会被清空,所以现在我们配置一个tmp文件目录. 如果之前没有配置过,默认 ...

  3. Invalid bound statement (not found): com.up.sell.mapper.system.H5operationMapper.

    springboot + mybatis项目,出现这样的错误原因就是mapper类的名字和xml的id不对应或者是忘记写了,仔细检查一下吧

  4. mybatis异常:There is no getter for property named 'xxx' in 'xxx'

    在使用mybatis查询的时候出现了下面的异常: org.apache.ibatis.reflection.ReflectionException: There is no getter for pr ...

  5. 转载: keepalived工作原理和配置说明

    转自:http://outofmemory.cn/wiki/keepalived-configuration keepalived是什么 keepalived是集群管理中保证集群高可用的一个服务软件, ...

  6. iOS笔记059 - 网络总结

    网络 基本概念 客户端:client 服务器:server 请求:request 响应:response 过程 客户端 -> 发送请求 -> 服务器(连接数据库) 服务器 -> 发送 ...

  7. 【Python】python内置函数、列表生成式、生成器

    一.内置函数 1 print(all([1,2,3,4]))#判断可迭代的对象里面的值是否都为真 2 print(any([0,1,2,3,4]))#判断可迭代的对象里面的值是否有一个为真 3 pri ...

  8. 用Jenkins自动化搭建测试环境

    1-1 课程介绍 2-1 Jenkins安装 2-2 Jenkins插件 2-3 Jenkins基础设置 3-1 Linux系统准备 3-2 安装Java环境 3-3 安装并配置Git 3-4 安装并 ...

  9. Python全栈工程师(异常(高级)、运算符重载)

    ParisGabriel              每天坚持手写  一天一篇  决定坚持几年 为了梦想为了信仰    开局一张图 Python人工智能从入门到精通 对象的属性管理函数: getattr ...

  10. CodeForces-999D Equalize the Remainders

    题目链接 https://vjudge.net/problem/CodeForces-999D 题面 Description You are given an array consisting of ...