排序算法总结

本文总结了基本的排序算法,包括选择排序,插入排序,冒泡排序,快速排序,堆排序,归并排序,以及,计数排序和基数排序。前六种排序算法是基于比较算法,时间复杂度的下界为o(nlgn),后两种不是基于比较的排序算法,时间复杂度为线性o(n)。
一、堆排序
堆排序的过程是先初始化一个大顶堆,然后堆顶与最后元素交换位置,交换之后再调整为大顶堆。时间复杂度o(nlgn),不稳定排序。
packageheap;
/**
*@authortyp
*
*/
publicclassHeapSort{
/**
*初始化时候,建立一个堆
*
*@parama
*/
publicvoidbuildHeap(int[]a){
intn=a.length;
for(inti=n/2-1;i>=0;--i){//(n/2-1),就是最后一个有子节点的元素
heapify(a,i,n-1);//从底往上,不断调整,直到整个数组变成堆
}
}
/**
*完成从a[i]开始对堆的调整
*
*@parama
*@parami
*@paramj
*/
publicvoidheapify(int[]a,inti,intj){//j代表待排序列的元素个数
intleft=i*2+1;
intright=i*2+2;
if(left>j){//没有左子树,那么(也不会有右子树),递归停止
return;
}
intlarge=left;//large是左子树和右子树中的较大者
if(right<=j&&a[left]<a[right]){
large=right;
}
if(a[i]<a[large]){//若根元素比large小,交换根和large
swap(a,i,large);
heapify(a,large,j);//此时large树又可能不是堆了,那就迭代实现large树成堆
}
}
/**
*堆排序
*
*@parama
*/
publicvoidheapSort(inta[]){
buildHeap(a);
intsize=a.length;
//每次去第一个元素,即最大元素,与最后元素交换位置。
for(inti=0;i<size;i++){
swap(a,0,(size-i-1));
heapify(a,0,size-i-2);
}
}
publicvoidswap(int[]a,inti,intj){
intt=a[i];
a[i]=a[j];
a[j]=t;
}
publicstaticvoidmain(String[]args){
inta[]={2,5,1,7,9,4,6,0};
HeapSorthSort=newHeapSort();
hSort.heapSort(a);
for(inti=0;i<a.length;i++){
System.out.println(a[i]);
}
}
}
非递归的heapify,只改动一处,见红色语句
publicvoidheapify(int[]a,inti,intj){
while(true){
intleft=i*2+1;
intright=i*2+2;
if(left>j){//没有左子树,那么(也不会有右子树),递归停止
break;
}
intlarge=left;//large是左子树和右子树中的较大者
if(right<=j&&a[left]<a[right]){
large=right;
}
if(a[i]<a[large]){//若根元素比large小,交换根和large
swap(a,i,large);
i=large;//此处将i值改为large传回,可以代替下面递归语句
//heapify(a,large,j);//此时large树又可能不是堆了,那就迭代实现large树成堆
}else{
break;//若根元素比large大,则不需要调整,跳出循环体
}
}
}
二、快速排序
快速排序基于分治策略,是由一趟趟的排序组成。选取一个元素为基准元素,经过交换操作,使得该基准元素左边的元素都小于基准元素,右边的元素都大于基准元素,这样就完成了一趟排序。然后递归基准元素左右两部分。最好时间复杂度o(nlgn),最坏时间复杂度o(n2)。不稳定排序。
packagequicksort;
/**
*@authortyp
*
*/
publicclassQuickSort{
staticint[]quickSort(inta[],intstart,intend){
inti,j;
i=start;
j=end;
intkey=a[start];//取key为序列的第一个元素
while(i<j){//整个while循环完成一趟排序
while(i<j&&key<=a[j])
//右侧扫描
j--;
if(i<j){//找出第一个比key小的,交换位置
a[i]=a[j];
}
while(i<j&&a[i]<key)
//左侧扫描
i++;
if(i<j){//找出第一个比key大的,交换位置
a[j]=a[i];
}
}
a[i]=key;//注意这步赋值操作,将最后的元素赋key
if(i-start>1){
quickSort(a,0,i-1);//递归调用,把key前面的完成排序
}
if(end-j>1){
quickSort(a,j+1,end);//递归调用,把key后面的完成排序
}
returna;
}
publicstaticvoidmain(String[]args){
inta[]={6,5,4,3,2,1};
intb[]=quickSort(a,0,5);
for(intitem:b){
System.out.println(item);
}
}
}
三、插入排序
不断地将后续元素插入到前面已经排好序的元素中。时间复杂度o(n2),稳定排序。
packageinsertsort;
/**
*@authortyp
*
*/
publicclassInsertSort{
staticvoidinsertSort(inta[]){
inti,j;
for(i=1;i<a.length;i++){
intkey=a[i];//key的引入,减少交换次数
for(j=i;j>0&&a[j-1]>key;j--){
a[j]=a[j-1];
}
a[j]=key;
}
}
publicstaticvoidmain(String[]args){
inta[]={6,5,4,3,2,1};
insertSort(a);
for(inti=0;i<a.length;i++){
System.out.println(a[i]);
}
}
}
四、选择排序
第i次循环将选出第i大的元素排列到i位置时间复杂度o(n2),不稳定。
packageselectsort;
/**
*@authortyp
*
*/
publicclassSelectSort{
staticvoidselectSort(inta[]){
intsize=a.length,k,tmp;
for(inti=0;i<size-1;i++){
k=i;//用k来记录每次最小的数的位置
for(intj=i;j<size;j++){
if(a[j]<a[k]){
k=j;
}
}
if(k!=i){
tmp=a[i];
a[i]=a[k];
a[k]=tmp;
}
}
}
publicstaticvoidmain(String[]args){
inta[]={6,5,4,3,2,1};
selectSort(a);
for(inti=0;i<a.length;i++){
System.out.println(a[i]);
}
}
}
五、归并排序
对有序的两个序列进行两两合并,最小的有序序列只含有单个元素。时间复杂度o(nlgn)。稳定排序。
packagemergesort;
/**
*@authortyp
*
*/
publicclassMergeSort{
/**
*递归实现归并排序,调用merge函数(合并两个有序集)
*
*@parama
*@paramb
*@paramlow
*@paramhigh
*/
staticvoidmergeSort(inta[],intb[],intlow,inthigh){
intmid=(low+high)/2;
if(low<high){
mergeSort(a,b,low,mid);
mergeSort(a,b,mid+1,high);
merge(a,b,low,mid,high);//合并两个有序集
}
}
/**
*合并两个有序集
*
*@parama
*@paramb
*@parammin
*@parammid
*@parammax
*/
staticvoidmerge(inta[],intb[],intmin,intmid,intmax){
inti=min,j=mid+1,k=min;
while(i<=mid&&j<=max){
if(a[i]<a[j])
b[k++]=a[i++];
else
b[k++]=a[j++];
}
while(i<=mid){
b[k++]=a[i++];
}
while(j<=max){
b[k++]=a[j++];
}
for(intm=min;m<=max;m++){
a[m]=b[m];
}
}
publicstaticvoidmain(String[]args){
inta[]={5,2,7,1,9,4,6,0};
intb[]=newint[a.length];
intsize=a.length;
mergeSort(a,b,0,size-1);
for(inti=0;i<size;i++){
System.out.println(a[i]);
}
}
}
六、冒泡排序
第i趟排序,使得第i小的元素排到i处,时间复杂度o(n2)。稳定排序。
packagebubblesort;
/**
*@authortyp
*
*/
publicclassBubbleSort{
/**
*冒泡排序
*
*@parama
*/
staticvoidbubbleSort(inta[]){
intsize=a.length;
for(inti=1;i<size;i++){
for(intj=0;j<size-i;j++){
if(a[j]>a[j+1]){
swap(a,j);
}
}
}
}
/**
*交换a[j]和a[j+1]
*
*@parama
*@paramj
*/
staticvoidswap(inta[],intj){
inttmp;
tmp=a[j];
a[j]=a[j+1];
a[j+1]=tmp;
}
publicstaticvoidmain(String[]args){
inta[]={5,2,7,1,9,4,6,0};
bubbleSort(a);
for(inti=0;i<a.length;i++){
System.out.println(a[i]);
}
}
}
七、计数排序
可以在线性时间内完成排序,要求序列的取值小于某个自然数k。时间复杂度o(n),稳定排序。
packagecountsort;
/**
*计数排序,数组的取值范围为0-k,没输入一个元素x,确定小于x的元素的个数,直接将x放到输出数组的指定位置
*
*@authortyp
*
*/
publicclassCountSort{
staticvoidcountSort(inta[],intk){
intc[]=newint[k];//c[i]存放数组a中小于等于i的元素的个数
intb[]=newint[a.length];//b用于存放排好序的a的元素。
for(inti=0;i<a.length;i++){//c[i]为数组a中值等于i的元素的个数
c[a[i]]=c[a[i]]+1;
}
for(inti=1;i<k;i++){//c[i]为数组a中值小于等于i的元素的个数
c[i]=c[i]+c[i-1];
}
for(inti=a.length-1;i>=0;i--){//b中存放排好序的a的元素。为保证排序稳定性,从大到小循环
intindex1=a[i];
intindex2=c[a[i]]-1;
b[index2]=a[i];//(a中的每个元素在b中的位置已经定下了,在c中保存着,即a[i]应该放在b中的c[a[i]]-1处)
c[index1]-=1;
}
for(inti=0;i<b.length;i++){//将排好序的数组b赋值给数组a
a[i]=b[i];
}
}
publicstaticvoidmain(String[]args){
intk=10;//代表数组的最大值为k
inta[]={3,1,4,4,2,1,7,8};
countSort(a,k);
for(inti=0;i<a.length;i++){
System.out.println(a[i]);
}
}
}
八、基数排序
通过对元素由低位到高位的按位排序,实现整体的排序。每次的位排序要求排序是稳定的,通常调用计数排序作为基数排序位排序算法。可以实现线性时间o(n)。稳定
packageradixsort;
/**
*基数排序,通过对序列元素每一位的排序,最终形成元素的排序,并不对元素直接进行大小比较。
*该基数排序中,用到的中间排序算法(对位的排序算法)为计数排序
*
*@authortyp
*
*/
publicclassRadixSort{
/**
*被调函数-完成计数排序
*@parama
*@paramk
*@paramnum
*/
staticvoidcountSort(inta[],intk,intnum){
intc[]=newint[k];//c[i]存放数组a中小于等于i的元素的个数
intb[]=newint[a.length];//b用于存放排好序的a的元素。
for(inti=0;i<a.length;i++){//c[i]为数组a中元素的相应位数值等于i的元素的个数
intindex=a[i]/num%10;//index为a[i]的某位
c[index]=c[index]+1;
}
for(inti=1;i<k;i++){//c[i]为数组a中值小于等于i的元素的个数
c[i]=c[i]+c[i-1];
}
for(inti=a.length-1;i>=0;i--){//b中存放排好序的a的元素。
intindex1=a[i]/num%10;
intindex2=c[a[i]/num%10];
b[index2-1]=a[i];//(a中的每个元素在b中的位置已经定下了,在c中保存着,即a[i]应该放在b中的c[a[i]]-1处)
c[index1]-=1;
}
for(inti=0;i<b.length;i++){//将排好序的数组b赋值给数组a
a[i]=b[i];
}
}
/**
*基数排序的主调函数
*@parama
*@paramk
*@paramnum
*/
staticvoidradixSort(inta[],intk,intnum){
for(inti=0;i<num;i++){
countSort(a,k,(int)Math.pow(10,i));//对a中元素的每一位都调用一次计数排序,且由低位到高位
}
}
publicstaticvoidmain(String[]args){
intk=9;//代表数组的最大值为k
intnum=3;//表示a数组中数据的最大位数
inta[]={23,231,524,114,332,121,227,448};
radixSort(a,k,num);
for(inti=0;i<a.length;i++){
System.out.println(a[i]);
}
}
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值