Java代码-八种数组排序方法

一.冒泡排序

1.1概述

对于一组,多次将数组中的数两两比较,较大或者较小的数向后排(经过一轮比较后,最大/最小的数就会到结尾),循环直至有序排列。

1.2代码实现

import java.lang.reflect.Array;
import java.util.Arrays;
import java.util.Scanner;

public class maopao {
    public static void main(String[] args) {
        System.out.println("请输入需要排序的数字,数字之间用空格或者回车隔开,输入完数字后输入任意非数字结束输入");
        Scanner scanner = new Scanner(System.in); //复习scanner
        Double[] input1= new Double[10]; //复习数组的定义 声明 创建
        int count=0;
        while (scanner.hasNextDouble()){    //复习scanner.xxx 不用if用while
            input1[count] = scanner.nextDouble();
            count++;
        }
        scanner.close();
        Double[] input2 = new Double[count];
        for (int i = 0; i < count; i++) {  //去掉冗余
            input2[i]=input1[i];
        }
        Double[] output = new Double[count];
        output=mp(input2);
        System.out.println("排序后的数组为:"+Arrays.toString(output));
    }

    private static Double[] mp(Double[] a) {
        double temp;
        // 降序排列
        for (int i = 0; i < a.length-1; i++) {   //n个数分n-1大轮
            for (int j = 0; j < a.length-1-i; j++) {  //每小轮有n-1-i次排序,每排一大轮每小轮少比较一次(每大轮出一个最值)
                if(a[j]<a[j+1]){
                    temp=a[j+1];
                    a[j+1]=a[j];
                    a[j]=temp;
                }
            }
        }
        return a;
    }
}

二.选择排序

2.1概述

从第一个数开始,依次和后面的数进行比较,小/大的数往前放(经过一轮最小/大数出现在最前面),之后从第二个数开始上述比较方式,循环至排序结束。

2.2代码实现

import java.util.Arrays;
import java.util.Scanner;

public class xuanze {
    public static void main(String[] args) {
        System.out.println("输入需要排序的数组");
        Double[] input1 = new Double[100000000];
        int count = 0;
        Scanner scanner = new Scanner(System.in);
        while (scanner.hasNextDouble()){
            input1[count] = scanner.nextDouble();
            count++;
        }
        Double[] input2 = new Double[count];
        for (int i = 0; i < count; i++) {
            input2[i]=input1[i];
        }
        //System.out.println(Arrays.toString(input2));
        Double[] output = new  Double[count];
        //output=xz(input2);
        output=xz1(input2);
        System.out.println("排序后的数是:"+Arrays.toString(output));
    }

    private static Double[] xz(Double[] a) {
        double temp;
        for (int i = 0; i < a.length-1; i++) {
            for (int j = i; j < a.length-1; j++) {
                if(a[j]>a[j+1]){
                    temp=a[j];
                    a[j]=a[j+1];
                    a[j+1]=temp;
                }
            }
        }
        return a;
    }

    private static Double[] xz1(Double[] a) {
        double temp;
        for (int i = 0; i < a.length-1; i++) {
            for (int j = i+1; j < a.length; j++) {
                if(a[j]<a[i]){
                    temp=a[j];
                    a[j]=a[i];
                    a[i]=temp;
                }
            }
        }
        return a;
    }
}

方法xz和方法xz1是两种不同写法。第一中方法是大轮内小轮比较,第二种方法是两两比较。

三.直接插入排序

3.1概述

将数组中第一个数看成一个数组,插入原数组第二个数,使得这两个数形成有序数组,再在这个有序数组插入原数组的第三个数,使得这三个数形成有序数组,以此类推,直到将原数组排序。

3.2代码实现

import java.util.Arrays;
import java.util.Scanner;

public class charu {
    public static void main(String[] args) {
        System.out.println("输入需要排序的数组");
        Double[] input1 = new Double[10000000];
        int count = 0;
        Scanner scanner = new Scanner(System.in);
        while (scanner.hasNextDouble()){
            input1[count]=scanner.nextDouble();
            count++;
        }
        scanner.close();
        Double[] input2 = new Double[count];
        for (int i = 0; i < count; i++) {
            input2[i] = input1[i];
        }
        Double[] output = new Double[count];
        output = cr(input2);
        //output=cr1(input2);
        //output=cr2(input2);
        System.out.println("排序后的数组是:"+ Arrays.toString(output));
    }

    private static Double[] cr(Double[] a) {
        double temp = 0;
        for (int i = 0; i < a.length-1; i++) { // i定义大轮数
            for (int j = i+1; j >0 ; j--) { // j负责插入数的比较
                if (a[j]<a[j-1]){
                    temp = a[j];
                    a[j]=a[j-1];
                    a[j-1] = temp;
                }
            }
        }
        return a;
    }
    private static Double[] cr1(Double[] a) {
        for (int i = 1; i < a.length; i++) {
            int j = i;
            while (j>0&&a[j]<a[j-1]){  //j>0在前
                Double temp = a[j];
                a[j] = a[j-1];
                a[j-1]=temp;
                j--;
            }
        }
        return a;
    }
    private static Double[] cr2(Double[] a) {
        for (int i=1;i<a.length;i++){
            for (int j = i; j >0 ; j--) {
                if (a[j]<a[j-1]){
                    double temp = a[j];
                    a[j] = a[j-1];
                    a[j-1] = temp;
                }
            }
        }
        return a;
    }

}

四.希尔排序

4.1概述

希尔排序又称缩小增量排序,基本思想是将原数组按增量ht分组,每个子文件安插入法排序。同样,下一个增量ht/2将文件再分为子文件,再按插入法排序。直到ht=1排好序。该方法的关键是是选择合适的增量。

4.2代码实现

import java.util.Arrays;
import java.util.Scanner;

public class xier {
    public static void main(String[] args) {
        System.out.println("输入需要排序的数组");
        Double[] input1 = new Double[10000000];
        int count = 0;
        Scanner scanner = new Scanner(System.in);
        while (scanner.hasNextDouble()){
            input1[count]=scanner.nextDouble();
            count++;
        }
        scanner.close();
        Double[] input2 = new Double[count];
        for (int i = 0; i < count; i++) {
            input2[i] = input1[i];
        }
        Double[] output = new Double[count];
        //output = cr(input2);
        output=xe(input2);
        System.out.println("排序后的数组为:"+ Arrays.toString(output));
    }
    private static Double[] xe(Double[] a) {
//        //克努特序列
//        int jiange = 1;
//        while (jiange<a.length/3){
//            jiange=3*jiange+1;
//        }
//        for (int h = jiange; h <0; h=(h-1)/3) 
//            {...... ......}}
        for (int h = a.length; h > 0; h=h/2) {  //循环h
            for (int i = h; i <a.length ; i++) { // 大轮循环 轮数:从第h+1个个数开始到最后一个数
                for (int j = i; j-h >-1 ; j=j-h) { //小轮循环 后面的数与前面的数比较(前后差h)
                    //j-h大于-1保证索引大于等于0  j=j-h 前后两个数索引位置
                    if (a[j]<a[j-h]){
                        Double t = a[j];
                        a[j] = a[j-h];
                        a[j-h] = t;
                    }
                }
            }
        }
        return a;
    }
}

五.快速排序

5.1概述

从数组中取一个数,作为基准数,将比这个数大或者等于的数放到右边,小于的放到左边。(降序),再对左右区间重复上述方法,直到每个区间只有一个数。

5.2代码实现

import java.util.Arrays;
import java.util.Scanner;

public class kuaisu {
    public static void main(String[] args) {
        System.out.println("输入需要排序的数组");
        Double[] input1 = new Double[10000000];
        int count = 0;
        Scanner scanner = new Scanner(System.in);
        while (scanner.hasNextDouble()){
            input1[count]=scanner.nextDouble();
            count++;
        }
        scanner.close();
        Double[] input2 = new Double[count];
        for (int i = 0; i < count; i++) {
            input2[i] = input1[i];
        }
        //Double[] output = new Double[count];
        //output = cr(input2);
        ks(input2,0,input2.length-1);
        System.out.println("排序后的数组为:"+ Arrays.toString(input2));
    }

    private static void ks(Double[] a,int start,int end) {
        //快速排序法需要利用前后数的位置,默认起始位置为0和length-1
        if (start<end){
            int index = getIndex(a,start,end);
            //找到选取数对应的位置后 分前后两组递归
            ks(a,start,index-1); //前组0到索引处-1
            ks(a,index+1,end);//后组索引处+1至最后
        }
    }
    private static int getIndex(Double[] a,int start,int end) {
        int i = start;//定义前半部分指向 起始是0 从前向后
        int j = end;//定义后半部分指向 起始在最后 从后向前
        double x = a[i];//选取的数 可任意选取 此处a[0]
        while (i < j) {  //前半指向和后半指向不一样
            while (i < j && a[j] >= x) { //从后向前找比选取数小的数
                j--;//j一直减,直到找到为止,此时j位置上就是比选取数小的数
            }
            if (i < j) { //还未找到选取数对应的索引
                a[i] = a[j]; //交换数
                i++; //下次从前向后找起始,新数下标
            }
            while (i < j && a[i] <= x) { //向前向后找比比新数大的数
                i++; //i一直加,直到找到为止,此时j位置上就是比选取数大的数
            }
            if (i < j) {
                a[j] = a[i]; //交换
                j--; //下次从后向前找起始,新数下标
            }
        }
        a[i]=x; //完成一次排序
        return i;
        //快速排序法 选取一个数经过左小又大的方式(升序)分左右两组,并确定其在数组中的位置;
        //再将左右两组分别重复上述方法(递归)再确定两个选取数的位置;
        //再次选取、分组、选取、分组......最终确定每个数的位置,完成排序;
        //所以ks方法中,有寻找索引和左右分组(前组从前向后,后组从后向前)
        //在寻找索引的时候,除了有选取的数,还需要两个数,一个从前向后找位置(前索引),一个从后向前找位置(后索引)
        //在两个数不等的时候,先从后找数,直到找到小数后索引一直减,找到后将该数移动到选取数的位置
        //再从前找,直到找到大数前索引一直加,找到后将该数移动到后索引的位置
        //重复上述,直到前后两索引数相同,定位选取数位置,此时前索引=后索引=选取数的索引
    }
}

六.归并排序

6.1概述

假设初始序列有N个数,可以看成是N个有序的子序列,每个子序列长度是1,然后两两归并,得到N/2个长度为2或1的有序子序列,然后两两归并,如此重复直到排序完成。

6.2代码实现

import java.util.Arrays;
import java.util.Scanner;

public class guibing {
    public static void main(String[] args) {

        System.out.println("输入需要排序的数组");
        Double[] input1 = new Double[10000000];
        int count = 0;
        Scanner scanner = new Scanner(System.in);
        while (scanner.hasNextDouble()){
            input1[count]=scanner.nextDouble();
            count++;
        }
        //scanner.close();
        Double[] input2 = new Double[count];
        for (int i = 0; i < count; i++) {
            input2[i] = input1[i];
        }
        cf(input2,0,input2.length-1);
        System.out.println("排序后的数组为:"+ Arrays.toString(input2));
    }


    private static void cf(Double[] a, int start,int end) {
        //先拆分后合并,拆分需要计算从哪分开,需要计算分开位置,所以需要起始和结束位置(start、end)
        //计算中间索引
        int centerIndex = (start+end)/2;
        //开始拆分,分为两组
        if (start<end){
            cf(a,start,centerIndex); //前半组,起始到分界
            cf(a,centerIndex+1,end);// 后半组,分界+1到最后
            //gb(a,start,centerIndex,end);
        }
        gb(a,start,centerIndex,end); //合并并排序
        //合并需要知道从哪合并,所以有centerIndex
        //排序需要有两个‘移动索引’来比较两个位置的数的大小,所以有start和end
    }


    private static void gb(Double[] a,int start,int center,int end) {
        Double[] temp = new Double[end-start+1];//定义一个数组存放比较后的数据(临时索引)

        int i =start; //定义左边(前组)的起始索引
        int j =center+1;//定义后边(后足)的起始索引
        int index = 0;//临时数组的索引 临时索引
        while (i<=center&&j<=end){ //当两个移动索引都在范围内时
            if (a[i]<=a[j]){ //比较两个位置的数
                temp[index]=a[i]; //提出较小数
                i++; //移动索引移动------------------------(1)
            }else { //同理
                temp[index]=a[j];
                j++;//-----------------------------------(2)
            }
            index++;
        }
        //处理剩余元素
        while (i<=center){ //左边元素剩余(i仍然小于等于center) i在(1)处已经移动
            temp[index]=a[i]; //赋值
            i++; //移动索引移动
            index++;  //临时索引移动
        }
        while (j<=end){
            temp[index]=a[j];
            j++;
            index++;
        }
        for (int k = 0; k < temp.length; k++) { //数组转移
            a[k+start]=temp[k]; // 注意加start
        }
    }
}
//归并排序就是先拆后合
//先拆:找分界点拆 分界点需要有起始和结束位置计算 并且需要一直拆所以递归
//合并:前后小组索引移动比较数的大小 将第i个小数/大数存放在临时数组的第i个数上的位置
//最后 处理剩余

七.基数排序

7.1概述

基数排序法基于对不同位的分组(从个位开始)进行排序。

7.2代码实现


import java.util.Arrays;
import java.util.Scanner;

import static sun.management.MemoryUsageCompositeData.getMax;

public class jishu {
    public static void main(String[] args) {
        System.out.println("输入需要排序的数组");
        Double[] input1 = new Double[10000000];
        int count = 0;
        Scanner scanner = new Scanner(System.in);
        while (scanner.hasNextDouble()){
            input1[count]=scanner.nextDouble();
            count++;
        }
        scanner.close();
        Double[] input2 = new Double[count];
        for (int i = 0; i < count; i++) {
            input2[i] = input1[i];
        }
        Double[] output = new Double[count];
        //output = cr(input2);
        output = js(input2);
        System.out.println("排序后的数组为:"+ Arrays.toString(output));
    }

    private static Double[] js(Double[] a) {
        double max = getMaxNumber(a); //得到数组中的最大值
        int len = String.valueOf(max).length(); //得到最大数一共几位,几位就大循环几次
        double[][] temp = new double[10][a.length]; //根据需要创建
        int[] c = new int[10]; //c用于计数 c[余数]=有几个某位相同的数  根据需要创建
        for (int i = 0,n=1; i < len; i++,n=n*10) {  //大循环 n为后加
            for (int j = 0; j < a.length; j++) { //将a中的每个数转移出去
                int ys = (int) ((a[j] / n) % 10); //丢失精度 该代码比较小数有问题  后加
                temp[ys][c[ys]] = a[j]; //赋值 temp[余数][该余数下有多少个数]
                c[ys]++;
            }

            //反转移数
            int index=0; //创建反转回的索引
            //for (int j = 0; j < a.length; j++) { //错误
                for (int k = 0; k < c.length; k++) { //遍历余数(0-9)
                    if (c[k]!=0){
                    for (int l = 0; l < c[k]; l++) {//遍历c
                        a[index]=temp[k][l];
                        index++;
                    }}
                    c[k]=0;
                }
            //}
            //Arrays.fill(c, 0);// 正确
        }

        return a;
    }

    private static double getMaxNumber(Double[] a) {
        double max = a[0];
        for (int i = 0; i < a.length; i++) {
            if (a[i]>max){
                max = a[i];
            }
        }
        return max;
    }
}
//基数排序法不需要两个索引去比较两个数的大小
//需要将数不断按...、十、个位分组排序

八.堆排序

8.1概述

堆排序利用堆这种数据结构进行偶爱徐,堆排序是一种选择性排序。

8.2代码实现

import java.util.Arrays;
import java.util.Scanner;

public class dui {
    public static void main(String[] args) {
        System.out.println("输入需要排序的数组");
        Double[] input1 = new Double[10000000];
        int count = 0;
        Scanner scanner = new Scanner(System.in);
        while (scanner.hasNextDouble()){
            input1[count]=scanner.nextDouble();
            count++;
        }
        scanner.close();
        Double[] input2 = new Double[count];
        for (int i = 0; i < count; i++) {
            input2[i] = input1[i];
        }
        Double[] output = new Double[count];
        //output = cr(input2);
        output=d(input2);
        System.out.println("排序后的数组为:"+ Arrays.toString(output));
    }

    private static Double[] d(Double[] a) {
        //定义开始调整的位置
        int start = (a.length-1)/2; //从一半开始调 方便遍历数组全部元素
        for (int i = start; i >=0 ; i--) {
            toMaxHeap(a,a.length,i); // 将数组变成一个大顶堆
        }
        for (int i = a.length-1; i >=0 ; i--) { //最后一个数和第一个数交换位置并再次调整大顶堆
            double t = a[0];
            a[0] = a[i];
            a[i] = t;
            toMaxHeap(a,i,0);
        }
        return a;
    }


    private static void toMaxHeap(Double[] a, int size, int index) {
        int left = index*2+1; //左节点
        int right = index*2+2;//右节点
        int maxIndex = index;
        //获取最大节点对应的索引
        if(left<size&&a[left]>a[maxIndex]){
            maxIndex=left;
        }
        if (right<size&&a[right]>a[maxIndex]){
            maxIndex=right;
        }
        //调换位置
        if (maxIndex!=index){
            double t = a[maxIndex];
            a[maxIndex] = a[index];
            a[index] = t;
            //调换之后可能会影响到下面的子数,不是大顶堆,我们还需要再次调换
            toMaxHeap(a,size,maxIndex);
        }

    }
}

九.总结归纳

时间复杂度和空间复杂度比较

排序方法时间复杂度空间复杂度稳定性
冒泡排序O(n^2) O(1)很好
选择排序O(n^2)O(1)很差
插入排序 O(n^2)O(1)很好
希尔排序介于O(n)和O(n ^ 2)之间O(1)较差
快速排序O(nlogn)O(logn)较差
并归排序O(nlogn)O(n)较好
基数排序O(n+k) O(n+k)很不好
堆排序O(nlogn)O(1)较差

其中k是最大元素的值。

更多:8 种常见排序的总结

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值