java常见排序算法实现

本文以列举java中比较常见的几种排序:冒泡排序、快速排序、插入排序、希尔排序、选择排序、归并排序以及基数排序。

冒泡排序


/**
 * @author fandongfeng
 * @created 2020/1/9 17:08
 * @description 冒泡排序
 *  两两比较,大的右移,比出最大的,然后重新开始比
 */
public class BubbleSort {

    public static void main(String[] args) {
        int[] arr = new int[] {5,7,2,9,4,1,0,5,7};
        bubbleSort(arr);
        System.out.println(Arrays.toString(arr));
    }

    public static void bubbleSort(int[] arr) {
        //控制共比较多少轮
        for (int i = 0; i < arr.length -1; i++) {
            for (int j = 0; j < arr.length-1-i; j++) {
                if(arr[j]>arr[j+1]){
                    int temp = arr[j];
                    arr[j] = arr[j+1];
                    arr[j+1] = temp;
                }
            }
        }
    }

}

快速排序

/**
 * @author fandongfeng
 * @created 2020/1/9 17:08
 * @description 快速排序
 *  开始位置,结束位置,以第一个数作为标准,比标准大的放到左边,比标准大的放到右边,然后递归标准数位置左右两边的数组就OK了
 */
public class QuickSort {

    public static void main(String[] args) {
        int[] arr = new int[] {3,4,6,7,4,1,2,9,0,5,7};
        quickSort(arr, 0, arr.length - 1);
        System.out.println(Arrays.toString(arr));
    }

    public static void quickSort(int[] arr, int start, int end) {
        if(start < end) {
            //把第0个做为标准
            int stard = arr[start];
            //记录需要排序的下标
            int low = start;
            int high = end;
            //循环找比标准数大的数
            while(low<high) {
                //右边比标准大
                while(low<high && stard <= arr[high]){
                    high--;
                }
                //使用右边数字替换左边数字
                arr[low]=arr[high];
                //如果左边数字比标准数字小
                while(low<high && arr[low]<=stard){
                    low++;
                }
                arr[high] = arr[low];
            }
            //把标准数赋给低所在的位置的元素
            arr[low] = stard;
            //处理所有的比标准数小的数字
            quickSort(arr, start, low-1);
            //处理所有的比标准数大的数字
            quickSort(arr, low+1, end);
        }
    }


}

插入排序


/**
 * @author fandongfeng
 * @created 2020/1/9 20:11
 * @description 插入排序
 *  默认该位置左边都是排好序的,所以只要和左边比较
 *  如果小于左边,则此值赋给临时变量,左边值赋给当前(左边位置+1),继续向左与临时变量比较,小于继续赋值给该位置+1处,
 *  不满足则将临时变量赋给不满足位置+1处
 */
public class InsertSort {

    public static void main(String[] args) {
        int[] arr = new int[] {3,4,6,7,4,1,2,9,0,5,7};
        insertSort(arr);
        System.out.println(Arrays.toString(arr));
    }

    private static void insertSort(int[] arr) {
        //遍历所有数字
        for (int i = 1; i < arr.length; i++) {
            //如果当前数字比前一个小
            if(arr[i] < arr[i-1]){
                int temp = arr[i];
                //遍历当前数字前面的所有数字
                int j;
                for (j = i-1; j >=0 && temp < arr[j]; j--) {
                    //把前一个数字赋给后一个数字
                    arr[j+1] = arr[j];
                }
                //把临时变量赋给不满足条件的后一个元素
                arr[j+1] = temp;
            }
        }
    }
}

希尔排序

/**
 * @author fandongfeng
 * @created 2020/1/9 20:41
 * @description 希尔排序
 * 长度/2  相隔相同步长的元素进行插入排序 长度/2/2 依次进行
 * 优点,将比较小的元素快速排到前面
 */
public class ShellSort {

    public static void main(String[] args) {
        int[] arr = new int[] {3,4,6,7,4,1,2,9,0,5,7};
        shellSort(arr);
        System.out.println(Arrays.toString(arr));
    }

    private static void shellSort(int[] arr) {
        //遍历所有步长
        for (int d = arr.length/2; d > 0; d/=2) {
            //遍历所有元素
            for (int i = d; i < arr.length; i++) {
                //遍历本组中所有元素
                for (int j = i-d; j >= 0; j-=d) {
                    //如果当前元素大于加上步长后的那个元素
                    if(arr[j] > arr[j+d]){
                        int temp = arr[j];
                        arr[j] = arr[j+d];
                        arr[j+d] = temp;
                    }
                }
            }
        }
    }
}

选择排序

/**
 * @author fandongfeng
 * @created 2020/1/13 15:21
 * @description 选择排序
 *  遍历找出最小元素放在第一位,遍历找第二个...
 */
public class SelectSort {

    public static void main(String[] args) {
        int[] arr = new int[] {3,4,6,7,4,1,2,9,0,5,7};
        selectSort(arr);
        System.out.println(Arrays.toString(arr));
    }

    private static void selectSort(int[] arr) {
        //遍历
        for (int i = 0; i < arr.length; i++) {
            int minIndex = i;
            //
            for (int j = i+1; j < arr.length; j++) {
                if(arr[minIndex] > arr[j]) {
                    //记录最小坐标
                    minIndex = j;
                }
            }
            //不相等则交换
            if(i != minIndex) {
                int temp = arr[i];
                arr[i] = arr[minIndex];
                arr[minIndex] = temp;
            }
        }
    }
}

归并排序

/**
 * @author fandongfeng
 * @created 2020/1/13 15:43
 * @description 归并排序
 *  先拆分成两个有序数组
 *  然后两个数组合并
 */
public class MergeSort {
    
    public static void main(String[] args) {
        int[] arr = new int[] {1,3,5,2,4,6,8,10};
        mergeSort(arr,0,arr.length - 1);
        System.out.println(Arrays.toString(arr));
    }

    /**
     * 将一个数组分成两个有序数组
     *   左右两边各递归出来两个有序数组,在进行合并
     */
    public static void mergeSort(int[] arr, int low, int high) {
        int middle = (low + high)/2;
        if(low < high) {
            //处理左边
            mergeSort(arr, low, middle);
            //处理右边
            mergeSort(arr, middle+1, high);
            //归并
            merge(arr, low, middle, high);
        }
    }


    public static void merge(int[] arr, int low, int middle, int high) {

        /**
         * ----------arr = [1, 3, 5, 2, 4, 6, 8, 10], low = 0, middle = 0, high = 1
         * ----------arr = [1, 3, 5, 2, 4, 6, 8, 10], low = 2, middle = 2, high = 3
         * ----------arr = [1, 3, 2, 5, 4, 6, 8, 10], low = 0, middle = 1, high = 3
         * ----------arr = [1, 2, 3, 5, 4, 6, 8, 10], low = 4, middle = 4, high = 5
         * ----------arr = [1, 2, 3, 5, 4, 6, 8, 10], low = 6, middle = 6, high = 7
         * ----------arr = [1, 2, 3, 5, 4, 6, 8, 10], low = 4, middle = 5, high = 7
         * ----------arr = [1, 2, 3, 5, 4, 6, 8, 10], low = 0, middle = 3, high = 7
         *
         * [1, 2, 3, 4, 5, 6, 8, 10]
         */
        System.out.println("----------arr = "+ Arrays.toString(arr)+", low = " + low + ", middle = " + middle + ", high = " + high);
        //用于存储归并后的临时数组
        int[] temp = new int[high-low+1];
        //记录第一个数组中需要遍历的下标
        int i = low;
        //记录第二个数组中需要遍历的下标
        int j = middle + 1;
        //用于记录在临时数组中存放的下标
        int index = 0;
        //遍历两个数组,取出小的数字,放入临时数组中
        while (i<=middle && j<=high) {
            if(arr[i] <= arr[j]) {
                temp[index] = arr[i];
                i++;
            }else {
                temp[index] = arr[j];
                j++;
            }
            index ++;
        }
        //处理多余的数据
        while (j <= high) {
            temp[index] = arr[j];
            j++;
            index++;
        }
        while (i <= middle) {
            temp[index] = arr[i];
            i++;
            index++;
        }
        //把临时数组数据重新存入原数组
        for (int k = 0; k < temp.length; k++) {
            arr[k+low] = temp[k];
        }
    }

}

基数排序

/**
 * @author fandongfeng
 * @created 2020/1/13 18:57
 * @description 基数排序
 */
public class RadixSort {

    public static void main(String[] args) {
        int[] arr = new int[]{23,6,189,45,9,287,56,1,798,34,65,652,5};
        radixSort(arr);
        System.out.println(Arrays.toString(arr));
    }

    /**
     *  假设有0,1,2,3,4,5,6,7,8,9 十个桶,
     *  获得最大数字位数轮询
     *      按个位数字依次放入对应桶中,然后从0到9,先进先出取出所有数字
     *      按十位数字依次放入对应桶中,然后从0到9,先进先出取出所有数字
     *      ...
     * @param arr
     */
    private static void radixSort(int[] arr) {
        //存取数组最大数
        int max = Integer.MIN_VALUE;
        for (int i = 0; i < arr.length; i++) {
            if(arr[i] > max) {
                max = arr[i];
            }
        }
        //最大数字位数
        int maxLength = (max+"").length();
        //存储临时的数据数组
        int[][] temp = new int[10][arr.length];
        //用于记录temp中同一列存放数字个数
        int[] count = new int[10];
        //根据最大长度数决定比较次数
        for (int i=0, n=1; i < maxLength; i++,n*=10) {
            //把每一个数字分别计算余数
            for (int j = 0; j < arr.length; j++) {
                //余数
                int ys = arr[j] / n % 10;
                //存到相应的数组中
                temp[ys][count[ys]] = arr[j];
                //记录数量
                count[ys]++;
            }
            //记录取的元素需要放的位置
            int index = 0;
            //把数字取出来
            for (int k = 0; k < count.length; k++) {
                if(count[k] != 0) {
                    //循环取出元素
                    for (int l = 0; l < count[k]; l++) {
                        arr[index] = temp[k][l];
                        index++;
                    }
                    //把数量置为0
                    count[k] = 0;
                }
            }
        }
    }
}

既然是FIFO的排序,则可以用队列代替

/**
 * @author fandongfeng
 * @created 2020/1/13 18:57
 * @description 基数排序 - 基于队列(FIFO)实现
 */
public class RadixQueueSort {

    public static void main(String[] args) {
        int[] arr = new int[]{23,6,189,45,9,287,56,1,798,34,65,652,5};
        radixSort(arr);
        System.out.println(Arrays.toString(arr));
    }

    /**
     *  假设有0,1,2,3,4,5,6,7,8,9 十个桶,
     *  获得最大数字位数轮询
     *      按个位数字依次放入对应桶中,然后从0到9,先进先出取出所有数字
     *      按十位数字依次放入对应桶中,然后从0到9,先进先出取出所有数字
     *      ...
     * @param arr
     */
    private static void radixSort(int[] arr) {
        //存取数组最大数
        int max = Integer.MIN_VALUE;
        for (int i = 0; i < arr.length; i++) {
            if(arr[i] > max) {
                max = arr[i];
            }
        }
        //最大数字位数
        int maxLength = (max+"").length();
        //存储临时的数据队列
        Queue[] temp = new LinkedBlockingQueue[10];
        //初始化,防止NPE报错
        for (int i = 0; i < temp.length; i++) {
            temp[i] = new LinkedBlockingQueue();
        }
        //根据最大长度数决定比较次数
        for (int i=0, n=1; i < maxLength; i++,n*=10) {
            //把每一个数字分别计算余数
            for (int j = 0; j < arr.length; j++) {
                //余数
                int ys = arr[j] / n % 10;
                //存到指定队列
                temp[ys].add(arr[j]);
            }
            //记录取的元素需要放的位置
            int index = 0;
            //把数字取出来
            for (int k = 0; k < temp.length; k++) {
                if(!temp[k].isEmpty()) {
                    //循环取出元素
                    while (!temp[k].isEmpty()) {
                        arr[index] = Integer.valueOf(temp[k].poll()+"");
                        index++;
                    }
                }
            }
        }
    }
}

堆排序

/**
 * @author fandongfeng
 * @created 2020/1/14 17:58
 * @description 堆排序
 * 堆排序:
 *  堆排序(Heapsort)是指利用堆这种数据结构所设计的一种排序算法。
 *  堆积是一个近似完全二叉树的结构,并同时满足堆积的性质:
 *      即子结点的键值或索引总是小于(或者大于)它的父节点
 *
 *  堆排序的基本思想是:将待排序序列构造成一个大顶堆,
 *  此时,整个序列的最大值就是堆顶的根节点。将其与末尾元素进行交换,此时末尾就为最大值。
 *  然后将剩余n-1个元素重新构造成一个堆,这样会得到n个元素的次小值。
 *  如此反复执行,便能得到一个有序序列了
 *  一般升序采用大顶堆,降序采用小顶堆
 */
public class HeapSort {

    public static void main(String[] args) {
        int[] arr = new int[] {9,6,8,7,0,1,10,4,2};
        heapSort(arr);
        System.out.println(Arrays.toString(arr));

    }

    private static void heapSort(int[] arr) {
        //最后一个非叶子节点
        int start = arr.length/2 -1;
        //调整成大顶堆
        for (int i = start; i >= 0; i--) {
            maxHeap(arr, arr.length, i);
        }
        //先把数组的第0个和堆中最后一个交换位置,  在把前面的处理为大顶堆
        for (int i= arr.length -1; i>0; i--) {
            int temp = arr[0];
            arr[0] = arr[i];
            arr[i] = temp;
            maxHeap(arr, i, 0);
        }
    }

    /**
     * 数组转成大顶堆
     */
    private static void maxHeap(int[] arr, int size, int index) {
        //左子节点
        int leftNode = 2*index + 1;
        //右子节点
        int rightNode = 2*index + 2;
        int max = index;
        //和两个子节点分别对比,找出最大的节点
        if(leftNode < size && arr[leftNode] > arr[max]) {
            max = leftNode;
        }
        if(rightNode < size && arr[rightNode] > arr[max]) {
            max = rightNode;
        }
        //交换位置
        if(max != index) {
            int temp = arr[index];
            arr[index] = arr[max];
            arr[max] = temp;
            //交换之后,可能会破坏之前排好的序
            maxHeap(arr, size, max);
        }

    }

}
image.png
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,293评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,604评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,958评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,729评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,719评论 5 366
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,630评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,000评论 3 397
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,665评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,909评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,646评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,726评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,400评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,986评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,959评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,197评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,996评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,481评论 2 342

推荐阅读更多精彩内容