Java 排序算法

本文介绍了冒泡排序、选择排序、插入排序、希尔排序、快速排序、合并排序、基数排序以及堆积树排序的基本原理、实现代码和适用场景。这些排序算法在IT技术中常用于数据排列和优化性能。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

冒泡排序法

        原理是从第一个元素开始,比较相邻元素的大小,若大小顺序有误,则对调后再进行下一个元素的比较。

       1. n个元素的冒泡排序必须执行n-1次扫描。

        2.适用于数量小或者有部分数据已经过排序的情况。

/**
 * 冒牌排序,改进版
 */
public class Sentry{
    int[] data = new int[]{4,6,2,7,8,9};
    //打印输出数据
    public void showData(){
        int i;
        for (i = 0; i < data.length ; i++) {
            System.out.print(data[i] + " ");
        }
        System.out.print("\n");
    }

    //排序后并且打印输出
    public void bubble(){
        int i, j, tmp, flag;
        for (i = data.length-1;  i>= 0 ; i--) { //扫描次数
            flag = 0;
            for (j = 0; j < i; j++) { //比较、交换次数
                
                //比较相邻两个元素,进行交换操作
                if (data[j+1] > data[j]){
                    tmp = data[j];
                    data[j] = data[j+1];
                    data[j + 1] = tmp;
                    flag++; //如果执行过交换,则flag不为0
                }
            }
            //执行过一次扫描就判断是否执行过交换操作。如果没有交换过数据
            //则表示此时数组已经完成-排序,因此可以指甲跳出循环
            if (flag == 0){
                break;
            }

            System.out.print("第"+(data.length - i)+"次排序:");
            for (j = 0; j < data.length; j++) {
                System.out.print(data[j]+" ");
            }
            System.out.print("\n");
        }
        System.out.print("排序后的数据:");
        showData();
    }
}

选择排序法

        属于枚举法的应用,就是反复从未排序过的数列中取出最大或最小的元素,加入到另一个数列中,最后的结果即位已排序的数列。

        1.适用于数量小或者有部分数据已经过排序的情况。

package sort;

/**
 * 选择排序法
 */
public class Selection {
    int[] data = new int[]{9,7,5,3,4,6};
    //打印输出数据
    public void showData(){
        int i;
        for (i = 0; i < data.length ; i++) {
            System.out.print(data[i] + " ");
        }
        System.out.print("\n");
    }

    //具体排序算法
    public void select(){
        int j, k, smallest, temp, index;

        for (int i = 0; i < data.length -1; i++) { //扫描次数为数列长度-1次
            smallest = data[i];
            index = i;
            for (j = i+1;  j < data.length; j++) { //由i+1 比较起,比较次数为:数列长度 - (i+1) 次
                if (smallest > data[j]) { //比较第i个和第j个元素
                    smallest = data[j];
                    index = j;
                }
            }
            temp = data[index];
            data[index] = data[i];
            data[i] = temp;
            System.out.print("第"+(i+1)+"次排序的结果:");
            for (k = 0;  k< data.length; k++) {
                System.out.print(data[k]+ " "); //打印最后排序结果
            }
            System.out.print("\n");
        }
        System.out.print("\n");
    }
}

插入排序法

将数组中的元素逐一与排序好的数据进行比较,先将前两个元素排好,再将第三个元素插入适当的位置,接着是第四个,重复此步骤。

1.由于插入排序法会造成数据大量搬迁,因此建议在链表上使用。

package sort;

/**
 * 插入排序
 */
public class Insertion {
    int[] data = new int[]{8,4,6,7,3,5};
    int size = data.length;

    public void showData(){
        for (int i = 0; i < size; i++) {
            System.out.print(data[i] + " ");
        }
        System.out.print("\n");
    }

    //具体排序算法
    public void insert(){
        int i; //i为扫描次数
        int j; //用j来定位比较的元素
        int tmp ; // tmp用来暂存数据
        for (i = 1;  i< size ; i++) {
            tmp = data[i];
            j = i - 1;
             while (j >= 0 && tmp < data[j]){ // 如果第二个元素小于第一个元素
                 data[j + 1] = data[j]; //  就把所有元素往后推一个位置
                 j--;
             }
             data[j+1] = tmp;
             System.out.print("第"+i+"次扫描:");
             showData();
        }
    }
}

希尔排序法

排序原则是将数据区分成特定间隔的几个小区块,以插入排序法排完区块内的数据后在渐渐减少间隔的距离。可以减少插入排序法中的数据搬迁次数,以加速排序速度。

1.适用于大部分数据都已经排序第情况。

package sort;

/**
 * 希尔排序法
 */
public class Shell {

    int[] data = new int[]{63,92,27,36,45,71,58,7,109};

    public void showData(){
        for (int i = 0; i < data.length; i++) {
            System.out.print(data[i] + " ");
        }
        System.out.print("\n");
    }

    public void shell(){
        int i; //i为扫描次数
        int j; //以j来定位比较的元素
        int k = 1; //k打印计算
        int tmp; //tmp用来暂存数据
        int jmp; //设置间距位移量
        jmp = data.length / 2;
        while (jmp != 0){
            for (i = jmp; i < data.length; i++) {
                tmp = data[i];
                j = i - jmp;
                while (j >= 0 && tmp < data[j]){ //插入排序法
                    data[j + jmp] = data[j];
                    j = j - jmp;
                }
                data[jmp + j] = tmp;
            }
            System.out.print("第"+(k++)+"次排序:");
            showData();
            jmp = jmp / 2;
        }
    }
}

快速排序法

会先在数据中找到一个虚拟的中间值,并按此中间值将所有打算排序的数据分为两部分,小于中间值放于左边,大于中间值放于右边,再以同样的方法分别处理左、右两边的数据,直到排序完为止。

package sort;

import java.util.Random;

/**
 * 快速排序法
 */
public class Quick {

    int process = 0;
    public int[] data = new int[13];

    //随机生成数据
    public void inputarr(){
        Random random = new Random();
        for (int i = 0; i < data.length; i++) {
            data[i] = (Math.abs(random.nextInt(99)))+1;
        }
    }

    public void showData(){
        for (int i = 0; i < data.length; i++) {
            System.out.print(data[i] + " ");
        }
        System.out.print("\n");
    }

    // 具体算法
    public void quick(int[] d, int s,int lf, int rg){
        int i,j,tmp;
        int lf_idx;
        int rg_idx;
        int t;
        //第一个键值为data[lf]
        if (lf < rg){
            lf_idx = lf + 1;
            rg_idx = rg;

            //排序
            while (true){
                System.out.print("处理过程:"+(process ++));

                for (t = 0;  t < s ; t++) {
                    System.out.print("["+d[t]+"] ");
                }
                System.out.print("\n");

                for (i = lf+1;  i <= rg ; i++) { //从左到右找出一个键值大于data[lf]者
                    if (d[i] >= d[lf]){
                        lf_idx = i;
                        break;
                    }
                    lf_idx++;
                }

                for (j = rg; j >= lf+1 ; j--) { //从右到左找出一个键值小于data[lf]者
                    if (d[j] <= d[lf]){
                        rg_idx = j;
                        break;
                    }
                    rg_idx--;
                }

                if (lf_idx < rg_idx){  //若 lf_idx 小于 rg_idx
                    tmp = d[lf_idx];
                    d[lf_idx] = d[rg_idx]; //则将d[lf_idx] 和 d[rg_idx] 互换
                    d[rg_idx] = tmp;
                }else {
                    break;   //否则跳出排序过程
                }
            }

            if (lf_idx >= rg_idx){   //若lf_idx大于等于 rg_idx, 
                tmp = d[lf];
                d[lf] = d[rg_idx];   //将的d[lf] 和d[rg_idx]互换
                d[rg_idx] = tmp;
                //以rg_idx为基准点分成左右两半
                quick(d, data.length, lf, rg_idx - 1); //以递归方式分别为左右两部分进行排序
                quick(d, data.length, rg_idx + 1, rg); //直至完成排序
            }
        }
    }
}

合并排序法

针对已经排序好的两个或者两个以上的数列(或数据文件),通过合并方式将其组成一个大的且已排好序的数列(或数据文件)。

基数排序法

此方法按比较的方向分为最高位优先(MSD)和最低位优先(LSD)两种方式。MSD是从最左边的位数开始比较,LSD是从最右边的位数开始比较。

5995734601681712593724588133

把每个整数按个位数相同放到同一个列表下

个位数0123456789
数据6017137213334

95

45

7

88

168

59

259

合并后

6017137213334954571688859259

然后是十位数,再到百位是或千位数,以此类推最后完成合并。

7343545608895133168171259372
package sort;

import java.util.Random;

/**
 * 基数排序法
 */
public class Radix {
    int size = 12;
    int[] data = new int[12];
    //随机生成数据
    public void inputarr(){
        Random random = new Random();
        for (int i = 0; i < data.length; i++) {
            data[i] = (Math.abs(random.nextInt(999)))+1;
        }
    }

    public void showData(){
        for (int i = 0; i < data.length; i++) {
            System.out.print(data[i] + " ");
        }
        System.out.print("\n");
    }

    public void radix(){
        int i,j,k,n,m;
        for (n = 1;  n<= 100 ; n=n*10) { //n为基数,从个位数开始排序
            //设置暂存数组,【0-9位数】【数据个数】
            int[][] tmp = new int[10][data.length];
            for (i = 0;  i<data.length ; i++) {
                m = (data[i] /n )%10; //m为n位数的值,如36取十位数(36 / 10)%10 = 3
                tmp[m][i] = data[i];
            }
            k = 0;
            for (i = 0;  i<10 ; i++) {
                for (j = 0;  j< data.length ; j++) {
                    if (tmp[i][j] != 0){
                        data[k] = tmp[i][j];
                        k++;
                    }
                }
            }
            System.out.print("经过"+n+"位数排序后:");
            showData();
        }
    }
}

堆积树排序法

堆积数排序法是选择排序法的改进版,减少选择排序法中的比较次数,进而减少排序时间。用到二叉树的技巧,利用堆积树来排序。分为最大堆积数和最小堆积数两种。

最大堆积数:

1.一棵完整的二叉树

2.所有节点的值都大于或等于它左、右子节点的值。

3.树根是堆积数最大的。

最小堆积数:

1,一颗完全的二叉树。

2.所有节点的值都小于或等于它左、右子节点的值。

3.树根是堆积数最小的。

package sort;

/**
 * 堆积数排序法
 */
public class Three {




    public void showData(int[] data){
        for (int i = 0; i < data.length; i++) {
            System.out.print(data[i] + " ");
        }
        System.out.print("\n");
    }

    public void heap(int[] data, int size){
        int i, j, tmp;
        for (i = (size / 2);  i>0 ; i--) { //建立堆积数节点
            ad_heap(data, i, size - 1);
        }
        System.out.print("堆积内容:");
        for (i = 1;  i<size ; i++) { //原始堆积树内容
            System.out.print("["+data[i]+"] ");
        }
        System.out.print("\n");
        for (i = size - 2; i > 0 ; i--) { //堆积排序
            tmp = data[i + 1]; //头尾节点交换
            data[i + 1] = data[1];
            data[1] = tmp;
            ad_heap(data,1, i); //处理剩余节点
            System.out.print("处理过程:");
            for (j = 1;  j<size ; j++) {
                System.out.print("["+data[j]+"] ");
            }
        }
    }

    public void ad_heap(int[] data, int i, int size){
        int  j, tmp, post;
        j = 2* i;
        tmp = data[i];
        post = 0;
        while (j <= size && post==0){
            if (j < size){
                if (data[j] < data[j+1]){
                    j++;
                }
            }
            if (tmp >= data[j]){
                post = 1;
            }else {
                data[j /2] = data[j];
                j = 2 * j;
            }
        }
        data[j / 2] = tmp;
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值