七种常见排序方式实现及总结

七种排序方式分为:

1.直接插入排序; 2.冒泡排序; 3.简单选择排序; 4.希尔排序;

5.快速排序; 6.堆排序; 7.归并排序;

各种排序算法的性质:

算法种类 最好情况 平均情况 最坏情况 空间复杂度 稳定性
直接插入排序 O ( n ) O ( n 2 ) O ( n 2 ) O ( 1 ) 稳定
冒泡排序 O ( n ) O ( n 2 ) O ( n 2 ) O ( 1 ) 稳定
简单选择排序 O ( n 2 ) O ( n 2 ) O ( n 2 ) O ( 1 ) 不稳定
希尔排序 O ( 1 ) 不稳定
快速排序 O ( n l o g 2 n ) O ( n l o g 2 n ) O ( n 2 ) O ( l o g 2 n ) 不稳定
堆排序 O ( n l o g 2 n ) O ( n l o g 2 n ) O ( n l o g 2 n ) O ( 1 ) 不稳定
归并排序 O ( n l o g 2 n ) O ( n l o g 2 n ) O ( n l o g 2 n ) O ( n ) 稳定

一、直接插入排序:

基本思想:每一次将一个待排序的记录,按关键字大小插入到已经排好序的子序列中的合适位置上,直到全部记录插入完成。

代码实现

public class Insert {
    public static void main(String[] args) {
        Num num=new Num();
        int []sum=num.number();
        System.out.print("排序前:");
        num.print(sum);
        System.out.println();
        sort(sum);
        System.out.print("排序后:");
       num.print(sum);
    }
    public static void sort(int [] sum){
        int temp=0;
        for (int i = 1; i < sum.length; i++) {
            for (int j = i; j > 0; j--) {
                if (sum[j] < sum[j - 1]) {//直接插入--->升序
//              if(sum[j]>sum[j-1]){//直接插入--->降序
                    temp = sum[j - 1];//较大值赋给temp
                    sum[j - 1] = sum[j];
                    sum[j] = temp;
                }
            }
            System.out.print("第"+i+"次排序后的结果:");
            for(int t:sum){//循环遍历出每一次排序过程
                System.out.print(t+" ");
            }
            System.out.println("");
        }
    }
}

运行结果
排序前:
59 22 5 72 6 90 34 83 18 8
第1次排序后的结果:22 59 5 72 6 90 34 83 18 8
第2次排序后的结果:5 22 59 72 6 90 34 83 18 8
第3次排序后的结果:5 22 59 72 6 90 34 83 18 8
第4次排序后的结果:5 6 22 59 72 90 34 83 18 8
第5次排序后的结果:5 6 22 59 72 90 34 83 18 8
第6次排序后的结果:5 6 22 34 59 72 90 83 18 8
第7次排序后的结果:5 6 22 34 59 72 83 90 18 8
第8次排序后的结果:5 6 18 22 34 59 72 83 90 8
第9次排序后的结果:5 6 8 18 22 34 59 72 83 90
排序后:
5 6 8 18 22 34 59 72 83 90

二、冒泡排序:

基本思想:从前往后(或从后往前)两两比较相邻元素的值,较大值位置进行交换,序列比较完,称为一次冒泡,结果将最大的元素交换到序列的末位(或首位)。下一次冒泡时,第一次冒泡确定的最大元素不再参与比较,序列减少一个元素,每次冒泡的结果确认的最大元素放在序列的末位。

代码实现

public class Bubble {
    public static void main(String[] args) {
        Num num=new Num();
        int []sum=num.number();
        System.out.print("排序前:");
        num.print(sum);
        System.out.println();
        sort(sum);
        System.out.print("排序后:");
       num.print(sum);
    }
        public static void sort(int []sum){
        int temp = 0;
        for (int i = 0; i < sum.length - 1; i++) {
            for (int j = 0; j < sum.length - 1; j++) {
                 if(sum[j]>sum[j+1]){// 冒泡排序--->升序
//              if (sum[j] < sum[j + 1]) {//冒泡排序--->降序
                 temp=sum[j+1];//将较小值赋给temp;
                 sum[j+1]=sum[j];//位置交换
                 sum[j]=temp;
                 }
            }
//           for (int j= sum.length-1; j>0; j--) {//冒泡排序--->降序
//           if(sum[j]>sum[j-1]){
//           temp=sum[j-1];//较小值赋给temp
//           sum[j-1]=sum[j];
//           sum[j]=temp;
//           }              
//           }
            System.out.print("第" + (i + 1) + "次排序后的结果:");
            for (int t : sum) {
                System.out.print(t + " ");
            }
            System.out.println();
        }
    }
}

运行结果:
排序前:
69 23 46 85 19 38 97 45 77 84
第1次排序后的结果:23 46 69 19 38 85 45 77 84 97
第2次排序后的结果:23 46 19 38 69 45 77 84 85 97
第3次排序后的结果:23 19 38 46 45 69 77 84 85 97
第4次排序后的结果:19 23 38 45 46 69 77 84 85 97
第5次排序后的结果:19 23 38 45 46 69 77 84 85 97
第6次排序后的结果:19 23 38 45 46 69 77 84 85 97
第7次排序后的结果:19 23 38 45 46 69 77 84 85 97
第8次排序后的结果:19 23 38 45 46 69 77 84 85 97
第9次排序后的结果:19 23 38 45 46 69 77 84 85 97
排序后:
19 23 38 45 46 69 77 84 85 97

三 、简单选择排序

基本思想:将序列的最小元素找出并放在序列的最前面,在剩下的元素中找出最小元素放在第二个位置上,以此类推,最后得到序列的有序序列。

代码实现

public class Select {
    public static void main(String[] args) {
        Num num=new Num();
        int []sum=num.number();
        System.out.print("排序前:");
        num.print(sum);
        System.out.println();
        sort(sum);
        System.out.print("排序后:");
       num.print(sum);
    }
    public static void sort(int []sum){
    int min=0;
    for(int i=0;i<sum.length-1;i++){
        min=sum[i];//假定序列首位元素为最小值
        for(int j=i+1;j<sum.length;j++){//简单选择排序--->升序      
            if(sum[j]<min){//若序列中有元素小于最小值
                min=sum[j];//最小值更新
                sum[j]=sum[i];//交换位置
                sum[i]=min;
            }   
        }   
        System.out.print("第"+(i+1)+"次排序后结果:");
        for (int t : sum) {
            System.out.print(t + " ");
        }
        System.out.println();
    }
//  for(int i=sum.length-1;i>0;i--){//简单选择排序--->降序
//      min=sum[i];
//      for(int j=0;j<i;j++){
//          if(sum[j]<min){
//              min=sum[j];
//              sum[j]=sum[i];
//              sum[i]=min;
//          }
//      }
//  }
}
}

运行结果
排序前:
56 94 36 12 68 97 92 15 37 60
第1次排序后结果:12 94 56 36 68 97 92 15 37 60
第2次排序后结果:12 15 94 56 68 97 92 36 37 60
第3次排序后结果:12 15 36 94 68 97 92 56 37 60
第4次排序后结果:12 15 36 37 94 97 92 68 56 60
第5次排序后结果:12 15 36 37 56 97 94 92 68 60
第6次排序后结果:12 15 36 37 56 60 97 94 92 68
第7次排序后结果:12 15 36 37 56 60 68 97 94 92
第8次排序后结果:12 15 36 37 56 60 68 92 97 94
第9次排序后结果:12 15 36 37 56 60 68 92 94 97
排序后:
12 15 36 37 56 60 68 92 94 97

四、希尔排序

基本思想:首先取一个小于序列长度的增量grap,将序列元素分为grap个组,距离为grap倍数的元素放在同一个组,在各组中进行直接插入排序,然后再取第二个增量,以此类推,直到增量为1,所有元素都放入一个组内。此时,序列已经基本有序,最后一次进行直接插入排序,得到最终结果。

public class Shell {
    public static void main(String[] args) {
        Num num=new Num();
        int []sum=num.number();
        System.out.print("排序前:");
        num.print(sum);
        System.out.println();
        sort(sum);
        System.out.print("排序后:");
       num.print(sum);
    }
        public static void sort(int []sum){
        int grap=sum.length/2;
        while(grap>=1){// 把等距的元素放入一个组
            for(int i=grap;i<sum.length;i++){
                int j=0;
                int temp=sum[i];
                for(j=i-grap;j>=0&&temp<sum[j];j=j-grap){//将等距元素进行排序
                    sum[j+grap]=sum[j];
                }
                sum[j+grap]=temp;
            }
            System.out.print("增量"+grap+":");
            for(int k:sum){
                System.out.print(k+" ");
            }
            System.out.println("");
            grap=grap/2;        
        }
    }
}

运行结果
排序前:
24 77 16 63 40 11 36 3 64 43
增量5:11 36 3 63 40 24 77 16 64 43
增量2:3 16 11 24 40 36 64 43 77 63
增量1:3 11 16 24 36 40 43 63 64 77
排序后:
3 11 16 24 36 40 43 63 64 77

五、快速排序

基本思想:快速排序是在冒泡排序的基础上改进而来,基于分治的思想。先在序列中任取某个元素为基准,将序列分为两个子序列,基准左边的子序列元素都小于基准元素的值,基准右边的子序列元素都大于基准元素的值,而基准最后放在其最终位置上。

public class Quick {
    public static void main(String[] args) {
        Num num=new Num();
        int []sum=num.number();
        System.out.print("排序前:");
        num.print(sum);
        System.out.println("");
        quick(sum,0,sum.length-1);
        System.out.print("排序后:");
        num.print(sum);
    }
    public static void quick(int[] list, int left, int right) {
        if (left < right) {// 左下标小于右下标
            int base = sort(list, left, right);// 数组分割
            quick(list, left, base - 1);// 对基准左侧数值进行递归分割
            quick(list, base + 1, right);// 对基准右侧数值进行递归分割
        }
    }
    public static int sort(int[] list, int left, int right) {
        int base = list[left];// 以序列首位元素(left)为基准
        while (left < right) {
            // 从序列右端开始向左遍历找到小于base的数
            while (left < right && list[right] >base) {
                right--;//
            }
            list[left] = list[right];// 将比base小的元素放到序列末尾
            while (left < right && list[left] <base) { // 从序列左端开始向右遍历找到大于base的数
                left++;
            }
            list[right] = list[left];// 将比base大的元素放到序列末尾
        }
        list[left] = base; // 将base放在left位置上,此时,base左侧数值比base小,右侧数组比baseSystem.out.print("排序过程:");
        for(int m:list){
            System.out.print(m+" ");
        }
        System.out.println("");
        return left;
    }
}

运行结果
排序前:
60 91 25 48 86 17 87 47 26 36
排序过程:36 26 25 48 47 17 60 87 86 91
排序过程:17 26 25 36 47 48 60 87 86 91
排序过程:17 26 25 36 47 48 60 87 86 91
排序过程:17 25 26 36 47 48 60 87 86 91
排序过程:17 25 26 36 47 48 60 87 86 91
排序过程:17 25 26 36 47 48 60 86 87 91
排序后:
17 25 26 36 47 48 60 86 87 91

六、归并排序(二路归并排序)

基本思想:归并的含义是将两个或两个以上的有序表合并成一个新的有序表。将n个元素的序列视作n个有序表,每个字表长度为1,然后两两合并,得到长度为2(或为1)的有序表,再两两合并,如此重复直到合并为一个长度为n的有序表。

public class Merge {
    public static void main(String[] args) {
        Num num=new Num();
        int []sum=num.number();
        System.out.print("排序前:");
        num.print(sum);
        System.out.println();
        merge(sum,0,sum.length-1);
        System.out.print("\n排序后:");
        num.print(sum);
    }
    public static void merge(int[] list, int low, int high) {
        int mid = (low + high) / 2;
        if (low < high) {//递归 折半划分
            merge(list, low, mid);
            merge(list, mid + 1, high);
            sort(list, low, mid, high); 
        }
    }
    public static void sort(int[] list, int low, int mid, int high) {
        int i=low;//第一段序列下标
        int j=mid+1;//第二段序列下标
        int k=0;//临时序列下标
        int array[]=new int [high-low+1];//临时合并数组
        while(i<=mid&&j<=high){//判断第一段与第二序列取出的值谁更小
                if(list[i]<list[j]){
                    array[k++]=list[i++];
                }else{
                    array[k++]=list[j++];
                }
            }
            while(i<=mid){//将第一段序列剩余元素复制到合并序列
                array[k++]=list[i++];
            }
            while(j<=high){//将第二段序列剩余元素复制到合并序列
                array[k++]=list[j++];
            }
            for(k=0,i=low;i<=high;k++,i++){//合并复制到原始数组
                list[i]=array[k];
            }
            System.out.print("排序过程:");
            for(int m:list){
                System.out.print(m+" ");
            }
            System.out.println("");
        }
}

运行结果
排序前:
81 8 63 47 46 78 89 11 39 1
排序过程:8 81 63 47 46 78 89 11 39 1
排序过程:8 63 81 47 46 78 89 11 39 1
排序过程:8 63 81 46 47 78 89 11 39 1
排序过程:8 46 47 63 81 78 89 11 39 1
排序过程:8 46 47 63 81 78 89 11 39 1
排序过程:8 46 47 63 81 11 78 89 39 1
排序过程:8 46 47 63 81 11 78 89 1 39
排序过程:8 46 47 63 81 1 11 39 78 89
排序过程:1 8 11 39 46 47 63 78 81 89

排序后:
1 8 11 39 46 47 63 78 81 89

七、堆排序

1.基本思想:堆排序是一种树形选择排序方法。
2.特点:在排序过程中,将序表看出是一颗完全二叉树的顺序存储结构,首元素作为二叉树的根,其余元素依次递层从左到右顺序排序,利用完全二叉树中的双亲节点和孩子节点的内在关系,在初始堆选择关键字最大(或最小)的元素。
3.堆排序分为两个阶段:构建初始堆和利用堆排序。
(1).构建初始堆:根节点的关键字要大于孩子节点,若小于,则在左右孩子节点中的较大值进行交换,交换后又可能会破坏下一级堆的,因此继续初始化下一级的堆,直到节点为根的子树构成堆。
(2).利用堆排序:初始化堆之后,堆顶元素是最大值(或最小值),输出堆顶元素后,将堆底元素放入堆顶位置,然后再次初始化堆,保持堆顶元素为最大值(或最小值),输出堆顶元素,直到堆中只剩下一个元素为止。

public class Heap {
    public static void main(String[] args) {
        Num num=new Num();
        int []sum=num.number();
        System.out.print("排序前:");
        num.print(sum);
        System.out.println();
        sort(sum);
        System.out.print("排序后:");
        num.print(sum);
    }
    public static void sort(int []list){
        for(int i=list.length/2-1;i>=0;i--){//建立初始堆
            tree(list,i,list.length);
        }
        for(int i=list.length-1;i>0;i--){//进行n-1次循环
            int temp=list[i];//排好序的堆根位置元素与堆末尾元素交换位置
            list[i]=list[0];
            list[0]=temp;
            tree(list,0,i);
            System.out.print("排序过程:");
            for(int m:list){
                System.out.print(m+" ");
            }
            System.out.println("");
        }
    }
    public static  void  tree(int []list,int parent,int length){
        int temp=list[parent];// 保存父节点
        int child=parent*2+1;// 获得左孩子
        while(child<length){
            // 判断是否有右孩子结点且右孩子结点的值大于左孩子结点,取右孩子结点
            if(child+1<length&&list[child]<list[child+1]){
                child++;
            }
            // 若父结点的值大于孩子结点的值,结束
            if(list[child]<temp)break;
            list[parent]=list[child]; // 将孩子结点的值赋给父结点
            parent=child;// 取孩子结点的左孩子,向下筛选
            child=child*2+1;
        }
        list[parent]=temp;
    }
}

运行结果
排序前:
43 97 52 63 27 74 18 60 81 8
排序过程:81 63 74 60 27 52 18 8 43 97
排序过程:74 63 52 60 27 43 18 8 81 97
排序过程:63 60 52 8 27 43 18 74 81 97
排序过程:60 27 52 8 18 43 63 74 81 97
排序过程:52 27 43 8 18 60 63 74 81 97
排序过程:43 27 18 8 52 60 63 74 81 97
排序过程:27 8 18 43 52 60 63 74 81 97
排序过程:18 8 27 43 52 60 63 74 81 97
排序过程:8 18 27 43 52 60 63 74 81 97
排序后:
8 18 27 43 52 60 63 74 81 97

获取随机数

import java.util.ArrayList;
import java.util.List;
import java.util.Random;

public class Num {
    public int[] number(){
        Random ran = new Random();
        int []sum=null;
        List<Integer> list = new ArrayList<Integer>();
        while (list.size() < 10) {// 随机生成十个(1-100)不重复的数
            int num = ran.nextInt(99) + 1;
            if (!list.contains(num)) {
                list.add(num);
            }
        }
//        System.out.println("转换前:" + list);// 转换前打印
        sum = new int[list.size()];// 将集合转换成数组
//        System.out.print("转换后:");
        for (int i = 0; i < list.size(); i++) {
            sum[i] = list.get(i);
    //        System.out.print(sum[i] + " ");// 转换后打印
        }
    //    System.out.println("");
        return sum;
    }
    public void print(int []sum){
        System.out.print("\n");
        for(int i:sum){
            System.out.print(i+" ");
        }
    }
}

八、总结

稳定性:若待排序列表里有两个关键字相等的元素,使用某种排序算法排序之后,两个元素的相对位置没有发生改变,则称该种排序算法是稳定的。

1.若序表较短,则可以采用直接插入或简单选择排序。
2.当记录本身信息量交大时,用简单选择排序较好。
3.若序表较长,应采用 O ( n l o g 2 n ) 的排序方法:快速排序、堆排序或归并排序。
4.文件的初始状态已按关键字基本有序时,选择直接插入或者冒泡排序较好。

猜你喜欢

转载自blog.csdn.net/weixin_42880312/article/details/81478420