排序算法一:冒泡排序算法
基本思想:n个数比较n-1轮,第一轮有n个数,但是由于是两两比较,所以只用比较n-1次;第二轮由于前一轮结束后,最大(最小)的数已经方法第n-1位了,所以只用再比较剩下的n-1个数,要比较n-2次;以此类推,那么第i轮就要比较n-i次,所以代码为:
import java.util.Arrays;
public class Main {
public static void mP(int[]num,int size){
for(int i=1;i<size;++i){//轮数
boolean flag=true;//标志,因为可能中间哪一轮就已经有序了
for(int j=0;j<size-i;++j){//比较次数
if(num[j]>num[j+1]){
int tmp=num[j];
num[j]=num[j+1];
num[j+1]=tmp;
flag=false;
}
}
if(flag){
break;
}
}
}
public static void show(int[]num){
System.out.println(Arrays.toString(num));
}
public static void main(String[] args) {
int[]num=new int[]{2,8,1,5,6,7,3};
System.out.print("冒泡排序前:");
show(num);
System.out.print("冒泡排序后:");
mP(num,7);
show(num);
}
}
运行结果:
复杂度分析:
时间复杂度:O(N^2)
空间复杂度:O(1)
稳定性:稳定
排序算法二:选择排序
基本思想:和冒泡排序类似,只不过,不是每次比较完符合条件就交换了,而是把每一轮的最大值的下标记录下来,和第n-i个元素比较然后符合交换条件时再交换,也就是说,每一轮只交换一次。代码实现:
public class Main {
public static void xZ(int[]num,int size){
for(int i=1;i<size;++i){
int index=0;//默认记录最大值的位置,这样排出来是升序
for(int j=1;j<=size-i;++j){
if(num[index]<num[j]){//默认记录最大值的位置,这样排出来是升序
index=j;
}
}
int tmp=num[index];
num[index]=num[size-i];//和最后一个值进行交换
num[size-i]=tmp;
}
}
public static void show(int[]num){
System.out.println(Arrays.toString(num));
}
public static void main(String[] args) {
int[]num=new int[]{2,8,1,5,0,6,7,3,10};
System.out.print("选择排序前:");
show(num);
System.out.print("选择排序后:");
xZ(num,9);
show(num);
}
}
运行结果:
复杂度分析:
时间复杂度:O(N^2)
空间复杂度:O(1)
稳定性:不稳定
排序算法三:插入排序
基本思想:比较j下标的值与tmp保存的值的大小关系,如果要升序排列,那么就是j下标的值比tmp下标大的,就让num[j+1]=num[j],然后j–,直到j<0或者num[j]<num[j+1]的值为止,然后将tmp的值放到num[j+1]的位置,然后i++,每一次排序使得前i项有序。说白了就是给第tmp中存的i下标的值在前i个位置中找空位。
代码实现:
public class Main {
public static void insertSort(int[]num,int size){
for(int i=1;i<size;++i){
int tmp=num[i];
int j=i-1;
while(j>=0&&num[j]>tmp){
num[j+1]=num[j];
j--;
}
num[j+1]=tmp;
}
}
public static void show(int[]num){
System.out.println(Arrays.toString(num));
}
public static void main(String[] args) {
int[]num=new int[]{2,8,1,5,0,6,7,3,10};
System.out.print("插入排序前:");
show(num);
System.out.print("插入排序后:");
insertSort(num,9);
show(num);
}
}
运行结果:
时间复杂度:在数组有序的情况下为O(N),在几乎无序的情况下为O(N^2),例如升序排列的操作数组反而是降序排列的,那么就是实打实的O(N^2)了。
空间复杂度:O(1)
稳定性:稳定
排序算法四:希尔排序
基本思想:分组思想,在插入排序的逻辑思维上将数组按照不同的组长进行分组排序,也就是说,之前是让j=i-1,那么这次是让j=i-group,并且每次j向前走的时候不再是j–,而是j-=group,代码实现:
public class Main{
public static void xEr(int[]num,int size,int group){
for(int i=1;i<size;++i){
int tmp=num[i];
int j=i-group;
while(j>=0&&num[j]>tmp){
num[j+group]=num[j];
j-=group;
}
num[j+group]=tmp;
}
}
public static void show(int[]num){
System.out.println(Arrays.toString(num));
}
public static void main(String[] args) {
int[]num=new int[]{2,8,1,5,0,6,7,3,10};
int[]group=new int[]{5,3,1};//分组,5个一组、三个一组、一个一组
System.out.print("希尔排序前:");
show(num);
System.out.print("希尔排序后:");
for(int x:group){
xEr(num,9,x);
}
show(num);
}
}
运行结果:
复杂度分析:
时间复杂度:最优情况为O(N),最坏情况为O(N^2)
空间复杂度:O(1)
稳定性:不稳定
排序算法五:归并排序
基本思想:采用分治思想,将已有序的子序列合并,得到完全有序的序列;即先使每个子序列有序,再使子序列段间有序。若将两个有序表合并成一个有序表,称为二路归并。
代码实现:
递归版本:
public class Main {
public static void gb(int[]num,int start,int end){//递归版本
if(start>=end){
return;
}
int mid=(start+end)/2;
gb(num,start,mid);
gb(num,mid+1,end);
int[]index=new int[end-start+1];
int k=0;
int left1=mid+1;
int left2=start;
while(left2<=mid&&left1<=end){
if(num[left2]<num[left1]){
index[k++]=num[left2++];
}else{
index[k++]=num[left1++];
}
}
while(left2<=mid){
index[k++]=num[left2++];
}
while(left1<=end){
index[k++]=num[left1++];
}
for (int i = 0; i < k; i++) {
num[start+i]=index[i];
}
}
public static void show(int[]num){
System.out.println(Arrays.toString(num));
}
public static void main(String[] args) {
int[]num=new int[]{2,8,1,5,0,6,7,3,10};
System.out.print("归并排序前:");
show(num);
System.out.print("归并排序后:");
gb(num,0,8);
show(num);
}
}
运行结果:
非递归版本:
public class Main {
public static void gb2(int[]num,int index){//非递归
int left1=0;
int right1=index;
int left2=index+1;
int right2=left2+index>=num.length-1?num.length:left2+index;
while(left1<=right1&&left2<=right2&&right2<num.length){
int[]nn=new int[right2-left1+1];
int k=0;
int left=left1;
while(left1<=right1&&left2<=right2){
if(num[left1]<num[left2]){
nn[k++]=num[left1++];
} else{
nn[k++]=num[left2++];
}
}
while(left1<=right1){
nn[k++]=num[left1++];
}
while(left2<=right2){
nn[k++]=num[left2++];
}
for(int i=0;i<k;++i){
num[left+i]=nn[i];
}
left1=right2+1;
right1=left1+index;
left2=right1+1;
right2=left2+index>=num.length-1?num.length:left2+index;
}
}
public static void main(String[] args) {
int[]num=new int[]{2,8,1,5,0,6,7,3,10};
System.out.print("归并排序前:");
show(num);
System.out.print("归并排序后:");
for(int i=0;i<9;++i){
gb2(num,i);
}
show(num);
}
}
运行结果:
复杂度分析:
时间复杂度:O(n*logn)
空间复杂度:O(n)
稳定性:稳定
排序算法六:堆排序
基本思想:利用堆的特性,以升序为例,建立一个大根堆,交换堆顶元素与最后一个元素的位置,然后向下调整,也就是说自堆底向上,依次有序。代码实现:
import java.util.Arrays;
/**
* 堆排序
* **/
public class Main{
public static void adjustDown(int[]num,int parent,int size){//向下调整
int child=parent*2+1;
while(child<size){
if(child+1<size&&num[child+1]>num[child]){
child++;
}
if(num[parent]<num[child]){
int tmp=num[parent];
num[parent]=num[child];
num[child]=tmp;
}else{
break;
}
parent=child;
child=parent*2+1;
}
}
public static void adjustUp(int[]num,int child){//向上调整,建堆插入元素的时候用
int parent=(child-1)/2;
while(parent>0){
if(num[parent]<num[child]){
int tmp=num[parent];
num[parent]=num[child];
num[child]=tmp;
}else{
break;
}
child=parent;
parent=(child-1)/2;
}
}
public static void heapSort(int[]num,int size){
int len=size-1;
while(len>0){
int tmp=num[0];
num[0]=num[len];
num[len]=tmp;
adjustDown(num,0,len--);
}
}
public static void main(String[] args) {
int[]num=new int[]{1,18,800,7,0,6,5,40,3,2};
System.out.println("堆排之前:"+Arrays.toString(num));
for(int i=1;i<=10;++i){//构建大根堆
adjustDown(num,0,i);
adjustUp(num,i-1);
}
heapSort(num,10);
System.out.println("堆排之后:"+Arrays.toString(num));
}
}
运行结果:
复杂度分析:
时间复杂度:O(N*logn)
空间复杂度:O(1)
稳定性:稳定
排序算法七:快速排序
基本思想:分治思想,使当前第i个数的左边都是比它小的,右边都是比它大的,然后分别再处理两边,重复之前的操作。
代码实现:
递归实现:
import java.util.Arrays;
import java.util.Stack;
public class Main7 {
public static void quickSort(int[]num,int start,int end){//快排递归
if(start>=end){
return;
}
int left=start;
int right=end;
int tmp=num[start];
while(left<right){
while(right>left&&num[right]>=tmp){
right--;
}
num[left]=num[right];
while(right>left&&num[left]<=tmp){
left++;
}
num[right]=num[left];
}
num[left]=tmp;
quickSort(num,start,left-1);
quickSort(num,left+1,end);
}
public static void main(String[] args) {
int[]num=new int[]{1,9,8,7,0,6,5,4,3,2};
System.out.println("快排之前:"+ Arrays.toString(num));
quickSort(num,0,9);
System.out.println("快排之后:"+Arrays.toString(num));
}
}
运行结果:
非递归实现:
import java.util.Arrays;
import java.util.Stack;
public class Main7 {
public static void quickSort2(int[]num,int start,int end){
Stack<Integer>stack=new Stack<>();
stack.push(start);
stack.push(end);
while (!stack.isEmpty()){
end=stack.pop();
start=stack.pop();
int left=start;
int right=end;
int tmp=num[start];
while(left<right){
while(right>left&&num[right]>=tmp){
right--;
}
num[left]=num[right];
while(right>left&&num[left]<=tmp){
left++;
}
num[right]=num[left];
}
num[left]=tmp;
if(left-1>start){
stack.push(start);
stack.push(left-1);
}
if(left+1<end){
stack.push(left+1);
stack.push(end);
}
}
}
public static void main(String[] args) {
int[]num=new int[]{1,9,8,7,0,6,5,4,3,2};
System.out.println("快排之前:"+ Arrays.toString(num));
quickSort2(num,0,9);
System.out.println("快排之后:"+Arrays.toString(num));
}
}
运行结果:
复杂度分析:
时间复杂度:当非常无序的时候,时间复杂度为O(N),当接近有序的时候,时间复杂度为O(N^2)
空间复杂度:O(1)
稳定性:不稳定
排序算法八:基数排序
基本思想:按照从个位开始比较的顺序,依次入对应数字的桶,当全部个位全部遍历完之后,按照入桶的先后顺序,从0号桶开始,依次出桶,直到将最高位的数遍历完,由于每一位可能的取值为0~9,所以要创建10个桶,标号分别从0~9。
代码实现:
public class Main {
public static void cardinalSort(int[]num,int size,int maxSize){
ArrayList<ArrayList<Integer>>list=new ArrayList<>(10);
for(int i=0;i<10;++i){
list.add(new ArrayList<>());//必须这样,不然下面会越界
}
int k=0;
while(k<maxSize){
for(int i=0;i<size;++i){
int n=(num[i]/(int)Math.pow(10,k))%10;//取对应位的值
if(list.get(n)==null){//用list存数据切记要初始化,尤其是没插入数据时,因为list默
//认没插入数据时的容量为0,就算你设置了list的大小也是一样的
list.set(n,new ArrayList<>());
}
list.get(n).add(num[i]);
}
k++;
int t=0;
for(int i=0;i<10;++i){
if(list.get(i)!=null){
for(int x:list.get(i)){
num[t++]=x;
}
list.get(i).clear();
}
}
}
}
public static void main(String[] args) {
int[]num=new int[]{1,9,8,7,10,6,5,4,3,2};
System.out.println("基数排序之前:"+ Arrays.toString(num));
cardinalSort(num,10,2);
System.out.println("基数排序之后:"+Arrays.toString(num));
}
}
运行结果:
复杂度分析:
时间复杂度:O(N*k)
空间复杂度:O(N+k)
稳定性:稳定
排序算法九:桶排序
基本思想:按找最大值和最小值确定桶的数量,然后根据当前数组的值与最小值的插值来确定这个数应该放入哪个桶,等数组中的所有数全部入桶之后,再对每个桶内进行排序,排序算法自己定,然后按照桶的序号以及排好序后的顺序依次出桶,最终达到排好序的效果。
代码实现:
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
public class Main {
public static void bucketSort(int[]num,int size,int max,int min){
ArrayList<ArrayList<Integer>>list=new ArrayList<>((max-min)/size+1);
for(int i=0;i<(max-min)/size+1;++i){
list.add(new ArrayList<>());
}
for(int i=0;i<size;++i){
list.get((num[i]-min)/size).add(num[i]);
}
int k=0;
for(int i=0;i<(max-min)/size+1;++i){
Collections.sort(list.get(i));
for(int x:list.get(i)){
num[k++]=x;
}
}
}
public static void main(String[] args) {
int[]num=new int[]{1,90,8,7,10,6,5,40,3,2};
System.out.println("基数排序之前:"+ Arrays.toString(num));
bucketSort(num,10,90,1);
System.out.println("基数排序之后:"+Arrays.toString(num));
}
}
运行结果:
复杂度分析:
时间复杂度:当桶的个数特别多,也就是区间分的越细,就越接近O(N)
空间复杂度:O(N)
稳定性:稳定
以上就是九大排序算法,还有补充,或者其他想法可以评论区留言,喜欢的话可以点赞关注一波欧。