八大排序算法

排序算法

注:本文章是看韩顺平老师将的数据结构java,以及在网上查找的其他文章,以及我的理解总结的;有说的不明白的地方,可以在评论区告诉我,我会更新和修改。

排序算法的分类

冒泡排序

基本介绍

思路

代码实现

public class BubblingSort {
    public static void main(String[] args) {
        //定义一个数组
        int[] Arr = {-1,-9,6,58,99,55};
        int temp;
        //冒泡排序
        for(int i=0;i<Arr.length-1;i++) {
            
​
            for(int j = 0;j<Arr.length-i-1;j++) {
                if(Arr[j]>Arr[j+1]) {
                    temp = Arr[j];
                    Arr[j] = Arr[j+1];
                    Arr[j+1] = temp;
                }
                
            }
            System.out.printf("第%d次后",i);
            System.out.println(Arrays.toString(Arr));
        }
    }
​
}

代码优化

public class BubblingSort {
    public static void main(String[] args) {
        
​
        //测试一手,输入800000个数据
        int[] Arr = new int[80000];
        for(int i=0;i<80000;i++) {
            Arr[i] = (int)(Math.random()*80000);
        }
        //定义时间变量
        Date date1 = new Date();
        SimpleDateFormat s1 = new SimpleDateFormat("yyy-MM-dd HH:mm:ss");
        String Date_1= s1.format(date1);
        System.out.println("排序前的时间:"+Date_1);
        BubblingS(Arr);
        Date date2 = new Date();
        
        String Date_2= s1.format(date2);
        System.out.println("排序后的时间:"+Date_2);
    
    }
    //封装成方法
​
public static void BubblingS(int[] Arr) {
    int temp;
    //冒泡排序
    boolean loop = false;//定义监管loop,如果在一次排序中如果不交换,则表示数组排序已经完成,便可退出
    for(int i=0;i<Arr.length-1;i++) {
        
​
        for(int j = 0;j<Arr.length-i-1;j++) {
            if(Arr[j]>Arr[j+1]) {
                loop = true;
                temp = Arr[j];
                Arr[j] = Arr[j+1];
                Arr[j+1] = temp;
            }
            
        }
        if(!loop) {//在一次排序中,一次也没交换
            break;
            
        }else {
            loop=false;//如果交换了,重新把loop改为false;
        }
        //System.out.printf("第%d次后",i);
        //System.out.println(Arrays.toString(Arr));
    }
​
}
                
​
}

测试80000个数据排序时间

选择排序

基本介绍

给出一个数组Arr,首先从【0——n-1】中找出一个最小值,并与第一个数(Arr[0])交换 ,然后再从【1——n-1】中找出一个最小值,并与第二个数(Arr[1])交换…………,依次进行,直至最后,但最后一个不用找 换,所以值循环n-1次

思路

代码实现

//包装成方法
    public static void ChoiceS_(int[] Arr) {
        for (int j = 0; j < Arr.length - 1; j++) {
            int mintemp = Arr[j];
            int index = j;
            for (int i = j; i < Arr.length; i++) {
                if (Arr[i] < mintemp) {
                    mintemp = Arr[i];
                    index = i;
                }


        }
        Arr[index] = Arr[j];
        Arr[j] = mintemp;
​
        //System.out.println("第" + (j + 1) + "次排序" + Arrays.toString(Arr));
    }
}

测试80000个数据的时间

比冒泡吊多了

插入排序

基本介绍

把数组Arr看成一个顺序序列,一个乱序序列,顺序序列一开始就一个为数组开头,乱序是剩下的。每次插入,取乱序序列第一个值,按照顺序查入顺序数列(后移吊)

思路

代码实现

//包装成方法
    public static void ChoiceS_(int[] Arr) {
        for (int j = 0; j < Arr.length - 1; j++) {
            int mintemp = Arr[j];
            int index = j;
            for (int i = j; i < Arr.length; i++) {
                if (Arr[i] < mintemp) {
                    mintemp = Arr[i];
                    index = i;
                }


        }
        Arr[index] = Arr[j];
        Arr[j] = mintemp;
​
        //System.out.println("第" + (j + 1) + "次排序" + Arrays.toString(Arr));
    }
}

测试80000个数据

希尔排序

基本介绍

把一个数组根据下标分为int gap =(length/2)组,分别对每组进行排序,排序完在接着分为gap/2组,在分别对每组进行排序,…………直到gap等于1,排序结束。

图解思路

代码实现

第一中是交换法实现,就是每两个数进行比较,如果条件符合就交换。这种方法速度慢。

第二钟是移动法,类似于插入排序,速度块,比较吊。

package com.hanfei.sort;
​
import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Date;
​
public class ShellSort_1 {
​
    public static void main(String[] args) {
        // TODO Auto-generated method stub
        // 创建测试数组
        // 测试一手,输入800000个数据
        int[] Arr = new int[8000000];
        for (int i = 0; i < 8000000; i++) {
            Arr[i] = (int) (Math.random() * 800000);
        }
        // 定义时间变量
        Date date1 = new Date();
        SimpleDateFormat s1 = new SimpleDateFormat("yyy-MM-dd HH:mm:ss");
        String Date_1 = s1.format(date1);
        System.out.println("排序前的时间:" + Date_1);
        ShellS_2(Arr);
        Date date2 = new Date();
    
        String Date_2 = s1.format(date2);
        System.out.println("排序后的时间:" + Date_2);
    
    }
    
    // 交换法的希尔排序
    public static void ShellS(int[] Arr) {
        // 定义辅助变量
        int temp = 0;
        int count = 0;
        for (int gap = Arr.length / 2; gap > 0; gap /= 2) {
    
            for (int i = gap; i < Arr.length; i++) {
    
                for (int j = i - gap; j >= 0; j -= gap) {
                    if (Arr[j] > Arr[j + gap]) {
                        temp = Arr[j + gap];
                        Arr[j + gap] = Arr[j];
                        Arr[j] = temp;
                    }
                }
            }
            count++;
            System.out.println("第" + count + "次" + Arrays.toString(Arr));
        }
    
    }
    // 移位法的查入排序
    
    public static void ShellS_2(int[] Arr) {
        int count = 0;
    
        for (int gap = Arr.length / 2; gap > 0; gap /= 2) {
    
            for (int i = gap; i < Arr.length; i++) {
                int temp = Arr[i];
                int index = i - gap;
                if (Arr[i] < Arr[index]) {
                    while (index >= 0 && temp < Arr[index]) {
                        Arr[index + gap] = Arr[index];
                        index -= gap;
                    }
                    Arr[index + gap] = temp;
                }
            }
            count++;
            //System.out.println("第" + count + "次" + Arrays.toString(Arr));
        }
    }
​
}
​
​

移动法比较800000个数据,仅仅只需两秒。80000只需不到一秒

快速排序

基本介绍

以数组{6,3,7,1,9,4,8,5,2,10}为例。 1.为了便于理解,就以6作为节点,开始排序时low等于6,high等于10 在这里插入图片描述 2.从由右往左找比节点6小的数就是2,从左往右找比节点6大的数就是7,把这两个数交换(这样查找的目的是为了将大的数放后面,较小的数放前面) 在这里插入图片描述 交换后: 在这里插入图片描述 3.交换后,high接着往左找比节点6小的数,同时low接着往右找比6大的数,分别是5和9,交换low和high 在这里插入图片描述 交换后: 在这里插入图片描述 4.接着相同操作,high往左找到比6小的数4,low往右找大于节点6的数时,low与high相遇,那么本轮查找就结束。接着节点6与low和high的相遇点4交换。这样比6小的数都在其前面,比6da的数都在其后面。 在这里插入图片描述 交换后: 在这里插入图片描述 5.一轮操作结束后,原数组被节点6“一分为二”,分别是比6都小的4,3,2,1,5和比6都大的8,9,7,10两个数组。接着就将这两个数组重复上面的操作,操作完成后理论上是数组被“一分为四”,四个数组再进行上面的操作如此循环

注意:上面讲的是以左端(6)为中轴,我写的代码是以右端(10)为中轴写的;

代码实现

package com.hanfei.sort;
​
import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Date;
​
public class ShellSort_1 {
​
    public static void main(String[] args) {
        // TODO Auto-generated method stub
        // 创建测试数组
        // 测试一手,输入800000个数据
        int[] Arr = new int[8000000];
        for (int i = 0; i < 8000000; i++) {
            Arr[i] = (int) (Math.random() * 800000);
        }
        // 定义时间变量
        Date date1 = new Date();
        SimpleDateFormat s1 = new SimpleDateFormat("yyy-MM-dd HH:mm:ss");
        String Date_1 = s1.format(date1);
        System.out.println("排序前的时间:" + Date_1);
        ShellS_2(Arr);
        Date date2 = new Date();
    
        String Date_2 = s1.format(date2);
        System.out.println("排序后的时间:" + Date_2);
    
    }
    
    // 交换法的希尔排序
    public static void ShellS(int[] Arr) {
        // 定义辅助变量
        int temp = 0;
        int count = 0;
        for (int gap = Arr.length / 2; gap > 0; gap /= 2) {
    
            for (int i = gap; i < Arr.length; i++) {
    
                for (int j = i - gap; j >= 0; j -= gap) {
                    if (Arr[j] > Arr[j + gap]) {
                        temp = Arr[j + gap];
                        Arr[j + gap] = Arr[j];
                        Arr[j] = temp;
                    }
                }
            }
            count++;
            System.out.println("第" + count + "次" + Arrays.toString(Arr));
        }
    
    }
    // 移位法的查入排序
    
    public static void ShellS_2(int[] Arr) {
        int count = 0;
    
        for (int gap = Arr.length / 2; gap > 0; gap /= 2) {
    
            for (int i = gap; i < Arr.length; i++) {
                int temp = Arr[i];
                int index = i - gap;
                if (Arr[i] < Arr[index]) {
                    while (index >= 0 && temp < Arr[index]) {
                        Arr[index + gap] = Arr[index];
                        index -= gap;
                    }
                    Arr[index + gap] = temp;
                }
            }
            count++;
            //System.out.println("第" + count + "次" + Arrays.toString(Arr));
        }
    }
​
}

注意:当选最后一个为中轴数的时候,需要先从左边找比他大的数,因为最后左边找到的最后一个数要与中轴值交换

归并排序

基本介绍

归并排序主要思想是分而治之,先将数组逐步分开,在排序合并(很吊)

图解思路

代码实现

package com.hanfei.sort;
​
import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Date;
​
public class MergeSort {
    public static void main(String[] args) {
        int[] Arr = new int[8000000];
        int[] temp = new int[Arr.length];
        // 测试一手,输入800000个数据
        
​
        for (int i = 0; i < 8000000; i++) {
            Arr[i] = (int) (Math.random() * 800000);
        }
        // 定义时间变量
        Date date1 = new Date();
        SimpleDateFormat s1 = new SimpleDateFormat("yyy-MM-dd HH:mm:ss");
        String Date_1 = s1.format(date1);
        System.out.println("排序前的时间:" + Date_1);
        MerGe_1(Arr, 0, Arr.length-1, temp);
        Date date2 = new Date();
    
        String Date_2 = s1.format(date2);
        System.out.println("排序后的时间:" + Date_2);
    
    }
    
    // 分和和
    //left代表数组最左边下边,初始0
    //right代表数组最右边下标,初始Arr.length-1
    //Arr,排序数组
    //temp 辅助数组
    public static void MerGe_1(int[] Arr, int left, int right, int[] temp) {
    
        if (left < right) {
            int mid = (left + right) / 2;
            // 向左边分
            MerGe_1(Arr, left, mid, temp);
            // 向右分
            MerGe_1(Arr, mid + 1, right, temp);
            Merge_(Arr, left, mid, right, temp);
        }
    
    }
    
    // 写和并的过程
    public static void Merge_(int[] Arr, int left, int mid, int right, int[] temp) {
    
        int l = left;
        int r = mid + 1;
        int t = 0;// temp数组辅助变量
    
        // 比较两个有序数组按顺序存入temp中
        while (l <= mid && r <= right) {
            // 如果左测数组值比右边小就存左边的,否则存右边的
            if (Arr[l] <= Arr[r]) {
                temp[t] = Arr[l];
                t += 1;
                l += 1;
            } else {
                temp[t] = Arr[r];
                t += 1;
                r += 1;
            }
        }
        // 将剩余值存入temp
        // 先判断左边
        while (l <= mid) {
            temp[t] = Arr[l];
            t += 1;
            l += 1;
        }
        // 再判断右边
        while (r <= right) {
            temp[t] = Arr[r];
            t += 1;
            r += 1;
        }
    
        // 最后将temp数组的值赋值给Arr
        t = 0;// 将t指向第一个
        int tempLeft = left;
        while (tempLeft <= right) {
            Arr[tempLeft] = temp[t];
            tempLeft++;
            t++;
        }
    }
​
}

基数排序

基本介绍

将数组中的数,按照不同位数的大小存入对应的桶中(二维数组),先按个位-十位-……等等依次,每次存储一次后,都要按桶中的顺序在输回原数组。(说的不好!下次一定)。

图解思路

 

代码实现

package com.hanfei.sort;
​
import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Date;
​
public class RedixSort {
    public static void main(String[] args) {
        // 测试一手,输入800000个数据
        int[] Arr = new int[8000000];
        for (int i = 0; i < 8000000; i++) {
            Arr[i] = (int) (Math.random() * 800000);
        }
        // 定义时间变量
        Date date1 = new Date();
        SimpleDateFormat s1 = new SimpleDateFormat("yyy-MM-dd HH:mm:ss");
        String Date_1 = s1.format(date1);
        System.out.println("排序前的时间:" + Date_1);
        Redix_1(Arr);
        Date date2 = new Date();
​
        String Date_2 = s1.format(date2);
        System.out.println("排序后的时间:" + Date_2);
    
    }
    
    // 排序方法
    public static void Redix_1(int[] Arr) {
    
        int max = Arr[0];
        // 去数组中最大的数
        for (int i = 0; i < Arr.length; i++) {
            if (Arr[i] > max) {
                max = Arr[i];
            }
        }
        int maxlength = (max + "").length();
        // 创建二维数组,做桶元素,定义十个桶存储各个位数的数
        // 10代表0-9十个数
        // 不知道一个桶存放几个元素,所以按照最环情况处理
        int[][] bucket = new int[10][Arr.length];
    
        // 定义一维数组,当作每个桶的指针
        int[] bucketcount = new int[10];
    
        for (int r = 0, n = 1; r < maxlength; r++, n *= 10) {
    
            // 第一次存储
            // 遍历所给数组
            for (int i = 0; i < Arr.length; i++) {
                // 判断个位数是什么
                int weishuDate = Arr[i] / n % 10;
    
                bucket[weishuDate][bucketcount[weishuDate]] = Arr[i];
                // 该位置的指针自增
                bucketcount[weishuDate]++;
    
            }
            int index = 0;
            // 从桶中依次取出数据
            for (int j = 0; j < 10; j++) {
                if (bucketcount[j] != 0) {
                    for (int l = 0; l < bucketcount[j]; l++) {
                        Arr[index] = bucket[j][l];
                        index++;
                    }
    
                }
                // 靠这条语句控制数组数据
                bucketcount[j] = 0;
            }
    
        }
    }
​
}

排序算法的比较

堆排序

基本介绍

代码实现

package com.hanfei.sort;
​
import java.util.Arrays;
​
import org.omg.PortableServer.ID_ASSIGNMENT_POLICY_ID;
​
public class HeapSort {
    public static void main(String[] args) {
        int[] Arr = {20000,3,323,-2,56,-56};
        for(int i = Arr.length/2-1;i<0;i--) {
            adjustHeap(Arr, i, Arr.length);
        }
        for (int j = Arr.length-1; j > 0; j--) {
            int temp = Arr[j];
            Arr[j] = Arr[0];
            Arr[0] = temp;
            /*为什么从0开始?
                因为在第一次构建大顶堆后让堆顶元素和末尾元素进行交换
                而对于其他的非叶子结点所对应的子树都是大顶堆就无需调整,
                只需要堆顶元素(下标为0的非叶子结点)的子树调整成大顶堆
            */
            adjustHeap(Arr,0,j);
​
        }
        System.out.println(Arrays.toString(Arr));
    
    }
​
//将完全二叉树转化为大堆顶
    /**
     * 
     * @param Arr 要转化的数组
     * @param i   从哪个结点开始转化
     * @param length 转化数组的长度
     */
    public static void adjustHeap(int[] Arr,int i,int length) {
        
​
        /*
         * 取出当前叶子结点的值
         */
        int temp = Arr[i];
        for(int k = i*2+1;k<length;k = i*2+2) {
            if(k+1<length&&Arr[k]<Arr[k+1]) {//如果右结点大于左节点
                k++;//k指向右节点
            }
            if(temp<Arr[k]) {
                Arr[i] = Arr[k];
                i = k;
            }else {
                break;
            }
            
            Arr[k]=temp;
        }
    }
​
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值