基本排序算法 (Java)

  • 经过几次笔试,发现自己的Java基础有些薄弱,基本的排序算法掌握的还不够熟练,需要多加学习总结。

1. 选择排序

思想: 给定一个整数数组,例 int[] a ={38,65,97,76,13,27,49},首先进行第一轮比较:遍历整个数组,选出最小的数字,以及该数字所在数组的下标,然后将该元素与数组的第一个元素进行交换。第二轮比较:比较范围为从数组的第二个元素开始,选择出最小的元素,并与数组的第二个元素交换位置... 多轮比较后直到待选择元素只剩下一个。此时该数组就是升序了。

时间复杂度:最好、最坏、平均都是O(n^2)
空间复杂度:O(1)
稳定性:不稳定的排序算法:例[2(1),5,3,2(2),1] 经过选择排序后变成[1,2(2),2(1),3,5]
当n较小时,排序效果较好

代码实现如下:

public static int[] selectSort(int[] a)
{
if(a.length==1)
return a;
if(a.length==0)
return null;
int i,j,index; //index记录最小值元素所在下标
int min;
for(i=0;i<a.length-1;i++)
{
index=i;
min=a[i];
for(j=i+1;j<a.length;j++)
{
if(a[j]<min)
{
min=a[j];
index=j;
}
}
a[index]=a[i];
a[i]=min;
}
return a;
}

2. 直接插入排序

思想:对于给定的一个整数数组,例如a ={38,65,97,76,13,27,49},假定第一个元素自成一个有序序列,其他的元素为无序序列。则按顺序从无序序列中挑出一个元素,插入到有序序列的末尾,然后对该有序序列重新排序,生成一个新的有序序列,然后再依次这样从无序序列中挑出元素,构建新的有序序列,直到最后一个元素插入到有序序列中并重新构建出最终的有序序列。

时间复杂度: 最好:O(n),最坏:O(n^2),平均:O(n^2)
空间复杂度:O(1)
稳定性:稳定
当大部分有序时,排序效果较好

代码实现如下:

public static int[] insertSort(int[] a)
{
if(a.length==1)
return a;
if(a.length==0)
return null;
int i,j,tmp;
for(i=1;i<a.length;i++)
{
tmp=a[i];//选出的待插入元素
j=i;
if(a[j-1]>tmp)
{
//当在有序序列中出现比待插入元素大的元素时,将该元素后移一位
//j代表待插入元素在有序序列中插入的位置下标
while(j>=1&&a[j-1]>tmp)
{
a[j]=a[j-1];
j--;
}
}
a[j]=tmp;
}
return a;
}

3.冒泡排序

思想:在冒泡排序中,对于给定的整形数组a={38,65,97,76,13,27,49},第一轮排序比较:从第一个元素开始,与其相邻的元素进行比较,若右边元素比左边元素大,则交换位置;然后继续从第二个元素开始进行比较,直到比较到倒数第二个元素。此时,数组中最后一个元素是最大的元素,然后再进行第二轮比较,比较范围是从当前数组第一个元素到倒数第三个元素,即找出第二大的元素,放到末尾...经过(a.length-1) 这里是6次比较后,得到了最终的升序排序结果。

时间复杂度:最好:O(n),最坏和平均都是:O(n^2)
空间复杂度:O(1)
稳定性:稳定
当n较小时,排序效果较好

代码如下:

public static int[] bubbleSort(int[] a)
{
int len=a.length,tmp;
if(len==0)
return null;
if(len==1)
return a;
for(int i=0;i<len;i++) //经过n-1次比较
for(int j=0;j<len-i-1;j++) //每次比较的范围是 a[0,n-i-1)
{
if(a[j]>a[j+1])
{
tmp=a[j];
a[j]=a[j+1];
a[j+1]=tmp;
}
}
return a;
}

4.归并排序

思想:归并排序,归是递归,并是合并。首先对给定的数组进行折半,直到折半成最小的子数组,比如只包含一个元素。然后再依次进行两两合并,合并时按照顺序进行排序,得到有序的子数组,再对这些子数组进行两两合并,直到生成最终的一个数组,即是有序的数组了。比如数组[2,6,1,0]先对其进行不断地折半,生成[2],[6],[1],[0]四个子数组,然后再对其进行两两合并,生成[2,6],[0,1]两个数组,然后再对这两个有序数组进行两两合并,最终生成[0,1,2,6]这个最终的有序数组。

时间复杂度:最好,最坏,平均都是O(nlog(n))
空间复杂度:O(n)
稳定性:稳定
当n数目较大时较好

代码如下:

public static int[] num = {38,65,97,76,13,27,49};
public static void MergeSort(int[] a,int[] array_tmp,int p,int q,int r)
{
int i,j,k,l_end,r_end;
l_end=q+1;
r_end=r+1;
for(i=p,k=p;i<l_end;i++,k++)
array_tmp[i]=a[k];
for(j=q+1,k=q+1;j<r_end;j++,k++)
array_tmp[j]=a[k];
for(k=p,i=p,j=q+1;i<l_end&&j<r_end;k++) //执行完一次循环以后,k会自动加一,然后执行条件判断
{
if(array_tmp[i]<=array_tmp[j]) //这样便是稳定的排序了
{
a[k]=array_tmp[i];
i++;
}
else
{
a[k]=array_tmp[j];
j++;
}
}
if(i<l_end)
{
for(;i<q+1;i++,k++)
a[k]=array_tmp[i];
}
if(j<r_end)
{
for(;j<r+1;j++,k++)
a[k]=array_tmp[j];
}
} public static void Merge(int[] a,int[] array_tmp,int p,int r)
{
if(p<r)
{
int q=(p+r)/2;
Merge(a,array_tmp,p,q);
Merge(a,array_tmp,q+1,r);
MergeSort(a,array_tmp,p,q,r);
}
} public static void main(String[] args)
{
int[] array_tmp = new int[num.length];//使用的辅助空间大小为n
Merge(num,array_tmp,0,num.length-1);
for(int i:num)
System.out.print(i+" ");
}

5.快速排序

思想:快速排序采用分而治之的思想,对于一个给定的数组,还是以a{38,65,97,76,13,27,49}为例,先是随机选取其中的一个数(可以是选择数组中的第一个元素,也可以是数组中的最后一个元素,还可以从左、右、中间随机数中选择大小取中的值)作为一个基准值,然后将该数组分成左右两个部分,左边的数字都比基准数字小,右边的数字都比基准数字大,此时该基准数字的位置就是其在排序后数组中的最终位置。然后对左右两边的子无序数组,再进行上述的排序过程,通过不断地拆分,直到所有元素都找到了其真正所属的位置下标,排序结束。

时间复杂度:最坏:O(n^2) [ 当每次进行选取的基准关键字都是最小的或者最大的,使得区间划分的结果一边为空,此时比较次数是1+2+3+...+n-1=n(n-1)/2即n^2 ],最好和平均:O(nlog(n)) 快速排序的平均性能是最好的
空间复杂度:O(log(n)) [ 快速排序需要一个栈空间来实现递归,当情况最好时,栈空间的大小为 log(n)+1,当情况最坏时,栈空间大小为n,平均空间复杂度为 O(log(n)) ]
稳定性:不稳定
当n较大时,排序效果较好

代码如下:

public static void QuickSort(int[] a,int start,int end)
{
if(start>=end) //一定要记得加上递归结束条件,否则会造成 StackOverflowError错误
return;
int i,j,index;
index=a[start];
i=start;
j=end;
while(i<j)
{
while(i<j&&a[j]>=index)
j--;
if(i<j)
a[i++]=a[j];
while(i<j&&a[i]<index)
i++;
if(i<j)
a[j--]=a[i];
}
a[i]=index;
QuickSort(a,start,i-1);
QuickSort(a,i+1,end);
}

6.希尔排序

思想:希尔排序也称为“缩小增量排序”,其基本思想是通过选定一个 步长序列,比如T{t1,t2,...ti...tn}。步长序列一般是逐渐缩小的,即前面的步长要比后面的步长要大。当选定步长序列以后,对每一个步长ti,根据步长将给定待排序数组分成多个子序列。比如待排序数组
a={12,11,10,9,8,7,6,5,4,3,2,1},步长此时为ti=3。则根据步长将数组a分成{12,9,6,3}、{11,8,5,2}、{10,7,4,1}这三个子序列。然后对这三个子序列进行直接插入排序,得到排序结果后再依照步长序列中后面的步长再进行直接插入排序。最后的步长tn一般取为1,也就是最后一次是将所有元素看成一组进行直接插入排序,此时一般来说整个数组基本有序,所需要的交换次数很少。

时间复杂度:最好是:O(n) 最坏:O(n^s) (1<s<2) 平均:O(nlog(n))
空间复杂度:O(1)
稳定性:不稳定
希尔排序属于插入排序的一种

代码如下:

public static void ShellSort(int[] a)
{
int len=a.length;
int i,j,tmp;
int h;//h为步长
for(h=len/2;h>0;h=h/2)
{
for(i=h;i<len;i++)
{
tmp=a[i];
for(j=i-h;j>=0;j-=h)
{
if(tmp<a[j])
a[j+h]=a[j];
else break;
}
a[j+h]=tmp;
}
}
}

7.堆排序

思想:对于给定的数组序列,例如a={38,65,97,76,13,27,49},初始时先将其看作一棵顺序存储的二叉树,即a[0]为根节点,a[1]、a[2]为其左右子节点。然后将该树调整成为一个小顶堆,然后将堆中的最后一个元素a[n-1]与堆顶元素(即二叉树的根节点,也是最小的元素)进行交换。接着将前n-1个元素重新调整成一个小顶堆,再将堆顶元素与该堆中的最后一个元素a[n-2]进行交换,得到次最小元素,重复上述过程,直到调整的堆中只剩下一个元素为止,该元素即为数组中的最大元素。此时该数组就变成了降序数组了。

时间复杂度:最坏、最好、平均都是O(nlog(n))
空间复杂度:O(1)
稳定性:不稳定
当n较大时,排序效果较好

代码如下:

public static void sift(int[] a,int low,int high){
int i=low,j=2*i+1;
int tmp;
while(j<=high) //判断a[i]是不是父节点,若a[i]是父节点,则2*i小于high
{
if((j<high)&&(a[j]>a[j+1])) //如果存在右孩子,且左孩子小于右孩子,则指向右孩子
j++;
if(a[i]>a[j])
{ tmp=a[i];
a[i]=a[j];
a[j]=tmp;
i=j;
j=2*i+1;
}
else //别忘记 break 终止,否则会一直循环下去
break;
}
}
public static void main(String[] args)
{
int[] a = {2,5,8,6,1,4,7};
int n = a.length-1;
int i,tmp;
//构建初始堆
for(i=n/2-1;i>=0;i--)
sift(a,i,n);
for(i=n;i>=1;i--)
{
tmp=a[i];
a[i]=a[0];
a[0]=tmp;
sift(a,0,i-1);
}
for(int m:a)
System.out.println(m); //此时数组a为降序有序
}

文章内容主要参考《Java面试宝典》数据结构与算法章节,感谢作者的精彩讲解。

基本排序算法(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. java 代码

    java 里的 pandas tablesaw DataFrame 再有就是 spark 了 java 代码规范 Java8特性详解 lambda表达式 Stream Sonar 规则检测 sprin ...

  2. (二)初探Maven之设置代理和阿里云镜像

    引言:           在许多公司,可能因为安全性的要求配置了代理服务器,用户无法直接访问外网,所以在项目中使用Maven必须设置好代理才能下载依赖.           并且直接从中央仓库下载依 ...

  3. 基于Gecko内核的简单浏览器实现

    分享一个基于Gecko内核的简单浏览器实现过程. 项目需要需要开发一个简单浏览器,由于被访问的网页中有大量Apng做的动画,使用IE内核的webbrowser不能播放,使用基于WebKit和Cefsh ...

  4. UTF-8字符C2A0引起的问题

    今天遇到一个问题: 网页上的一段文字中有几个空格,把这段文字当作文件名称保存为一个windows系统下的文件后,文件名中本来是空格的地方变成了问号,另外一个C#程序打开这个文件,也提示找不到文件. 初 ...

  5. python基本面试题

    https://www.cnblogs.com/changwentao/p/9432166.html

  6. (二)ORB描述子提取源码思路与实现

    ORBSLAM2中ORB特征提取的特点 ORBSLAM2中通过对OpenCV中的ORB特征点提取类进行修改,对图像进行分块提取,而后划分节点,使得每个节点中保存的特征点性能是该节点所有特征点中最好的. ...

  7. 关于vscode插件 的一些体验

    一 vsCode git 首先vscode 继承了 git 在使用git前 先手动创建一个文件夹  用来clone已有项目 然后将 clone下来的项目放入工作区 右上角的小转转就是 pull文件 更 ...

  8. 软件测试面试必问--bug交互流程

    目前市场主要用的bug管理工具:禅道.jira.QC.bugfree等,当然也有自己公司开发的. 不过不管哪一种工具,核心交互流程都是差不多的,只是字段的名称不一样而已,参考如下两张示意图: 这是前几 ...

  9. Qt+mpg123+openal播放MP3流

    #ifndef PLAYSTREAM_H #define PLAYSTREAM_H #include <QObject> #include "../libMPG123/mpg12 ...

  10. webpack : 无法将“webpack”项识别为 cmdlet、函数、脚本文件或可运行程序的名称

    全局安装webpack npm install -g webpack 把node_global加入到环境变量