美文网首页Android开发
十大经典排序算法(java实现)

十大经典排序算法(java实现)

作者: 梦星夜雨 | 来源:发表于2020-06-16 17:56 被阅读0次

    前言

    本文我们将以java代码实现十大经典排序算法,包括冒泡排序、选择排序、插入排序、希尔排序、归并排序、快速排序、堆排序、计数排序、桶排序、基数排序。

    排序算法相关的时间复杂度和空间复杂度

    1、冒泡排序(Bubble Sort)

    算法描述

    1. 比较相邻的元素。如果第一个比第二个大,就交换它们两个;
    2. 对每一对相邻元素作同样的工作,从开始第一对到结尾的最后一对,这样在最后的元素应该会是最大的数;
    3. 针对所有的元素重复以上的步骤,除了最后一个;
    4. 重复步骤1~3,直到排序完成。

    代码实现

    public void sort(int[] nums) {
            for(int i = 0;i<nums.length -1;i++){
                for (int j = 0; j < nums.length - 1-i; j++) {
                    int c;
                    if (nums[j] > nums[j + 1]) {
                        c = nums[j];
                        nums[j] = nums[j + 1];
                        nums[j + 1] = c;
                    }
                }
            }
        }
    

    这里有个问题,冒泡排序的时间复杂度最好是n,但上述代码不管如何时间复杂度都是n²,所以有了以下改进算法。

    public void bubbleSort(int arr[]) {
            boolean didSwap;
            for(int i = 0, len = arr.length; i < len - 1; i++) {
                didSwap = false;
                for(int j = 0; j < len - i - 1; j++) {
                    if(arr[j + 1] < arr[j]) {
                        int temp = arr[j];
                        arr[j]=arr[j+1];
                        arr[j+1]=temp;
                        didSwap = true;
                    }
                }
                if(didSwap == false)
                    return;
            }
        }
    

    2、选择排序(Selection Sort)

    算法描述
    选择排序一种简单直观的排序算法。首先在未排序序列中找到最小(大)元素,存放到排序序列的起始位置,然后,再从剩余未排序元素中继续寻找最小(大)元素,然后放到已排序序列的末尾。以此类推,直到所有元素均排序完毕。
    代码实现

    public int[] sort(int[] nums) {
            int len = nums.length;
            int temp;
            for(int i = 0;i<len;i++){
                for(int j =i;j<len;j++){
                    if(nums[i]>nums[j]){
                        temp = nums[i];
                        nums[i] = nums[j];
                        nums[j] = temp;
                    }
                }
            }
            return nums;
        }
    

    3、插入排序(Insertion Sort)

    算法描述

    1. 从第一个元素开始,该元素可以认为已经被排序;
    2. 取下一元素,在已经排序的元素序列中从后向前扫描;
    3. 如果该元素(已排序)大于新元素,将该元素移到下一位置;
    4. 重复步骤3,直到找到已排序的元素小于或者等于新元素的位置;
    5. 将新元素插入到该位置后;
    6. 重复步骤2~5。

    代码实现

    public void sort(int[] nums) {
            int len = nums.length;
            int preIndex,current;
            for(int i = 0;i<len;i++){
                preIndex = i - 1;
                current = nums[i];
                while(preIndex >= 0 && nums[preIndex] > current){
                    nums[preIndex + 1] = nums[preIndex];
                    preIndex--;
                }
                nums[preIndex + 1] = current;
            }
        }
    

    4、希尔排序(Shell Sort)
    算法排序
    希尔排序(Shell's Sort)是插入排序)的一种又称“缩小增量排序”,是直接插入排序算法的一种更高效的改进版本。希尔排序是非稳定排序算法。

    1. 选择一个增量序列t1,t2,…,tk,其中ti>tj,tk=1;
    2. 按增量序列个数k,对序列进行k 趟排序;
    3. 每趟排序,根据对应的增量ti,将待排序列分割成若干长度为m 的子序列,分别对各子表进行直接插入排序。仅增量因子为1 时,整个序列作为一个表来处理,表长度即为整个序列的长度。
      代码实现
    public void sort(int[] nums) {
            int len = nums.length;
            for (int gap = (int) Math.floor(len / 2); gap > 0; gap = (int) Math.floor(gap / 2)) {
                // 注意:这里和动图演示的不一样,动图是分组执行,实际操作是多个分组交替执行
                for (int i = gap; i < len; i++) {
                    int j = i; 
                    int current = nums[i];
                    while (j - gap >= 0 && current < nums[j - gap]) {
                        nums[j] = nums[j - gap];
                         j = j - gap;
                    }
                    nums[j] = current;
                }
            }
            
        }
    

    5、归并排序(Merge Sort)

    算法描述
    归并排序(MERGE-SORT)是建立在归并操作上的一种有效的排序算法,该算法是采用分治法(Divide and Conquer)的一个非常典型的应用。将已有序的子序列合并,得到完全有序的序列;即先使每个子序列有序,再使子序列段间有序。若将两个有序表合并成一个有序表,称为二路归并。归并排序是一种稳定的排序方法。实际上就是用的递归的思想。

    1. 把长度为n的输入序列分成两个长度为n/2的子序列;
    2. 对这两个子序列分别采用归并排序;
    3. 将两个排序好的子序列合并成一个最终的排序序列。

    代码实现

    public int[] sort(int[] nums) {
            int len = nums.length;
            if(len<2){
                return nums;
            }
            int middle = (int) Math.floor(len/2);
            int[] left = new int[middle],right = new int[len-middle];
            System.arraycopy(nums, 0, left, 0, middle);
            System.arraycopy(nums, middle, right, 0, len-middle);
            return merge(sort(left),sort(right));
        }
        
        private int[] merge(int[] left, int[] right) {
            // TODO Auto-generated method stub
              int[] result = new int[left.length+right.length];
              int i = 0, j = 0, k = 0;
                while ((left.length - j) > 0 && (right.length - k) > 0) {
                    if (left[j] <= right[k]) {
                        result[i] = left[j];
                        j++;
                    } else {
                        result[i] = right[k];
                        k++;
                    }
                    i++;
                }
                while (j < left.length){
                    System.arraycopy(left, j, result, i, left.length-j);
                    j++;
                    i++;
                }
                    
                while (k < right.length){
                    System.arraycopy(right, k, result, i, right.length-k);
                    k++;
                    i++;
                }
                return result;
        }
    

    6、快速排序(Quick Sort)

    算法描述
    快速排序(Quicksort)是对冒泡排序的一种改进。

    1. 首先选择一个分界值,通过该分界值将数组分成左右两部分。
    2. 重新对数组进行排序,比分界值小的集中到数组左边,比分界值大的位于数组右边。
    3. 然后左右两边数组再次进行快速排序。
    4. 最后重复上述步骤,实现递归。

    代码实现

    public void sort(int[] arr,int low, int high) {
            int i, j ,temp,snap;
            if(low > high){
                return;
            }
            i = low;
            j = high;
            // 基准位置
            temp = arr[low];
            while (i<j) {
                while (temp<=arr[j] && i<j) {
                    j--;
                }
                while (temp>=arr[i] && i<j) {
                    i++;
                }
                if (i<j) {
                    // 交换满足条件的 i j位置的值
                    snap = arr[i];
                    arr[i] = arr[j];
                    arr[j] = snap;
                }
            }
            // 交换基准位置的值
            arr[low] = arr[i];
            arr[i] = temp;
            
            // 递归调用, 左右
            sort(arr,low,j-1);
            sort(arr,j+1,high);
        }
    

    7、堆排序(Heap Sort)

    算法描述
    堆排序是指利用堆这种数据结构所设计的一种排序算法。堆是一个近似完全二叉树的结构,并同时满足堆积的性质:即子结点的键值或索引总是小于(或者大于)它的父节点。

    1. 将初始待排序关键字序列(R1,R2….Rn)构建成大顶堆
    2. 将堆顶元素R[1]与最后一个元素R[n]交换。
    3. 由于交换后新的堆顶R[1]可能违反堆的性质,因此需要对当前无序区(R1,R2,……Rn-1)调整为新堆,然后再次将R[1]与无序区最后一个元素交换,得到新的无序区(R1,R2….Rn-2)和新的有序区(Rn-1,Rn)。不断重复此过程直到有序区的元素个数为n-1,则整个排序过程完成。

    代码实现

    public static void sort(int[] array) {
            if (array == null || array.length <= 1) {
                return;
            }
            buildMaxHeap(array);
    
            int temp;
            for(int arg:array){
                System.out.print(arg+" ");
            }
            for (int i = array.length - 1; i >= 1; i--) {
    
                temp = array[0];
                array[0] = array[i];
                array[i] = temp;
                
                maxHeap(array, i, 0);
                System.out.println(" ");
                System.out.println("-------"+i+"-------");
                for(int arg:array){
                    System.out.print(arg+" ");
                }
            }
        }
    
        private static void buildMaxHeap(int[] array) {
            if (array == null || array.length <= 1) {
                return;
            }
    
            int half = array.length / 2;
            for (int i = half; i >= 0; i--) {
                maxHeap(array, array.length, i);
            }
        }
    
        private static void maxHeap(int[] array, int heapSize, int index) {
            int left = index * 2 + 1;
            int right = index * 2 + 2;
            int largest = index;
            if (left < heapSize && array[left] > array[index]) {
                largest = left;
            }
    
            if (right < heapSize && array[right] > array[largest]) {
                largest = right;
            }
    
            if (index != largest) {
    
                int temp;
                temp = array[index];
                array[index] = array[largest];
                array[largest] = temp;
                
                maxHeap(array, heapSize, largest);
            }
        }
    

    8、计数排序(Counting Sort)

    算法描述
    计数排序是一个非基于比较的排序算法,牺牲空间换取时间。

    1. 得到数组的最大和最小元素。
    2. 统计出每个数据为i的值出现的次数,将次数存入数组C中。
    3. 以数组C为模板重新填充目标数组。

    代码实现

    public void sort(int[] nums) {
            int min = nums[0],max = nums[0];
            for(int num: nums){
                max = Math.max(max, num);
                min = Math.min(min, num);
            }
            int[] counts = new int[max - min+1];
            for(int num: nums){
                counts[num - min]++;
            }
            int i = 0,j = 0;
            for(int count:counts){
                while (count > 0) {
                    nums[i] = j + min;
                    count --;
                    i ++;
                }
                j++;
            }
        }
    

    9、桶排序(Bucket Sort)

    算法描述
    将数组分到有限数量的桶子里。每个桶子再个别排序(有可能再使用别的排序算法)。

    1. 设置一个定量的链表当作空桶。
    2. 遍历输入数据,并且把数据一个一个放到对应的桶里去。
    3. 对每个不是空的桶进行排序。
    4. 从不是空的桶里把排好序的数据拼接起来。

    代码实现

    public void sort(int[] nums) {
            int min = nums[0],max = nums[0];
            for(int num: nums){
                max = Math.max(max, num);
                min = Math.min(min, num);
            }
            int bucketBottom = (int) Math.floor((float)min/10);
            int bucketTop = (int) Math.ceil((float)max/10);
            ArrayList<ArrayList<Integer>> bucketsList = new ArrayList<ArrayList<Integer>>();
            for(int i = 0;i<(bucketTop-bucketBottom);i++){
                bucketsList.add(new ArrayList<Integer>());
            }
            for(int num: nums){
                int index = getBucketIndex(num);
                insertBucket(bucketsList.get(index),num);
            }
            int index = 0;
            for (ArrayList<Integer> list : bucketsList) {
                for(int data: list){
                    nums[index++] = data;
                }
            }
        }
        
        // 将数据放入具体的桶内
        private void insertBucket(ArrayList<Integer> arrayList, int num) {
            boolean insertFlag = true;
            ListIterator<Integer> it = arrayList.listIterator();
            while (it.hasNext()) {
                if (num <= it.next()) {
                    it.previous(); // 把迭代器的位置偏移回上一个位置
                    it.add(num); // 把数据插入到迭代器的当前位置
                    insertFlag = false;
                    break;
                }
            }
            // 否则把数据插入到链表末端
            if (insertFlag) {
                arrayList.add(num); 
            }
        }
        // 判断放入哪个桶内的方法
        private int getBucketIndex(int data){
            return (int) Math.floor(data/10);
        }
    

    10、基数排序(Radix Sort)

    算法描述
    基数排序是按照低位先排序,然后收集;再按照高位排序,然后再收集;依次类推,直到最高位。

    1. 取得数组中的最大数,并取得位数。
    2. 使用链表对按照当前位数大小存储数据,然后重新写入数组。
    3. 根据位数的不同重复步骤2。

    代码实现

    public void sort(int[] nums) {
             int max = 0;
             int exp = 1;
             for (int num:nums){
                 max = Math.max(max,num);
             }
             while(max/Math.pow(10,exp) > 1){
                 exp++;
             }
            //存储待排元素
             ArrayList<ArrayList<Integer>> radixList = new ArrayList<ArrayList<Integer>>();
             for(int j = 0;j<10;j++){
                 ArrayList<Integer> list = new ArrayList<Integer>();
                 radixList.add(list);
             }
             
             for(int i = 0;i<=exp;i++){
                 for(int num:nums){
                     int positionValue = getPositionValue(num, i);
                     radixList.get(positionValue).add(num);
                 }
                 int index = 0;
                 for(ArrayList<Integer> list:radixList){
                     for(int value: list){
                         nums[index] = value;
                         index++;
                     }
                     list.clear();
                 }
             }
        }
        // 获取当前位数对应的值
        private int getPositionValue(int num,int exp){
            return (int) (num % Math.pow(10, exp)/Math.pow(10, exp-1));
        }
    

    源码地址

    相关文章

      网友评论

        本文标题:十大经典排序算法(java实现)

        本文链接:https://www.haomeiwen.com/subject/ajyrxktx.html