十大排序算法Java实现及其Leetcode算法题

十大排序算法Java实现及其Leetcode算法题

不稳定: 选择,快排,堆排
稳定: 插排,冒泡, 归并

选择排序

选择排序从数组中选择最小的元素,将它与第一个元素交换位置,再从数组剩下的元素中选择出最小的元素,将它与数组的第二个元素交换位置,不断进行这样的操作,直到将整个数组排序。

选择排序需要 N^2 / 2次比较 以及 N次交换,它的运行时间和输入无关,即使是排好序的数组也需要这么多的比较和交换操作。

public static void selectSort(int[] arr) {
        if (arr == null || arr.length < 2) return ;
        for (int i = 0; i < arr.length - 1; i++) {
            int minIndex = i;
            for (int j = i + 1; j < arr.length; j++) {
                if (arr[j] < arr[minIndex]) {
                    minIndex = j;
                }
            }
            swap(arr, i, minIndex);
        }
    }
    public static void swap(int[] arr, int i, int j) {
       int temp = arr[i];
       arr[i] = arr[j];
       arr[j] = temp;
    }

冒泡排序

从左到右不断交换相邻逆序的元素,在议论循环之后,可以将未排序的最大元素上浮到最右侧,在一轮循环中,那么说明数组已经是有序的,此时可以直接退出。

public static void bubbleSort(int[] arr) {
       if (arr == null || arr.length < 2) return;
       boolean isSorted = false;
       for (int i = arr.length - 1; i > 0 && !isSorted; i--) {
           isSorted = true;
           for (int j = 0; j < i ; j++) {
               if (arr[j] > arr[j + 1]) {
                   isSorted = false;
                   swap(arr, j , j + 1);
               }
           }
       }
    }

    public static void swap(int[] arr, int i, int j) {
        int temp = arr[i];
        arr[i] = arr[j];
        arr[j] = temp;
    }

插入排序

每次都将当前元素插入到左侧已经排好序的数组中(在左侧排好序的数组中寻找一个合适的位置插入),使得插入之后左侧的数组依然有序。

插入排序的时间复杂度取决于数组的数组的初始顺序,如果数组已经部分有序,那么逆序比较少,需要的交换次数也比较少,时间复杂度也比较低

  • 平均的插入排序需要进行 N^2 / 4 比较以及 N^2 / 4次交换
  • 最坏的时间复杂度需要 N^2 / 2 比较以及 N^2 / 2次交换 即数组为完全逆序的情况下
  • 最好的时间复杂度需要 N - 1 比较以及 0 次交换 即数组完全有序

public static void insertSort(int[] arr) {
        if (arr == null || arr.length < 2) return;
        for (int i = 1; i < arr.length; i++) {
            for (int j = i - 1; j >= 0; j--) {
                if (arr[j] > arr[j + 1]) {
                    swap(arr, j, j + 1);
                }
            }
        }
    }
    
    public static void swap(int[] arr, int i, int j) {
        arr[i] = arr[i] ^ arr[j];
        arr[j] = arr[i] ^ arr[j];
        arr[i] = arr[i] ^ arr[j];
    }

Leetcode 147. 对链表进行插入排序

147. 对链表进行插入排序

public ListNode insertionSortList(ListNode head) {
        if (head == null || head.next == null)return head;
        ListNode dummyHead = new ListNode(-1);
        dummyHead.next = head;
        ListNode insert = dummyHead;
        ListNode cur = head;
        while (cur != null && cur.next != null) {
            if (cur.val < cur.next.val) { //cur.next < cur 退出  1 2  4  5 (cur)  3 (cur.next) 产生逆序
                cur = cur.next;
                continue;
            }
            insert = dummyHead;
            while (insert.next.val < cur.next.val) { //在排好序的insert 到 cur之间寻找合适的插入位置 ,插入到insert之后。cur.next是待插入的节点。
                insert = insert.next; //退出循环时 insert.next > cur.next 2.next = 4 > 5.next = 3 
            }
            ListNode temp  = cur.next;
            cur.next = temp.next;
            temp.next = insert.next;
            insert.next = temp;
        }
        return dummyHead.next;
    }

希尔排序

java实现希尔排序(思路与实现)

【排序算法】希尔排序原理及Java实现
希尔排序的基本思想是:将数组列在一个表中并对列分别进行插入排序,重复组合格过程,不过每次用更少的列,最后整个表就只有一列,将数组转换至表是为了更好的理解这个算法,算法本事还是使用数组进行排序的。

 public static void shellSort(int[] nums) {
        if (nums == null || nums.length < 2) return;
        int len = nums.length;
        int gap = len / 2;
        while (gap > 0) {
            for (int i = gap; i < len; i+= gap) {
                if (nums[i] < nums[i - gap]) { //在每个gap上进行插入排序。
                    int temp = nums[i];
                    int j = i - gap;
                    while (j >= 0 && nums[j] > temp) {
                        nums[j + gap] = nums[j];
                        j = j - gap;
                    }
                    nums[j + gap] = temp;
                }
            }
            gap /= 2;
        }
    }

归并排序

归并排序的思想就是将数组分为两部分,分别对左部分和右部分进行排序,然后归并起来。

public static void mergeSort(int[] arr) {
        if (arr == null || arr.length < 2)return;
        mergeSort(arr, 0 , arr.length - 1);
    }
    
    
    private static void mergeSort(int[] arr, int left, int right) {
        if (left == right)return;
        int mid = left + (right - left) / 2;
        mergeSort(arr,left, mid);
        mergeSort(arr,mid + 1, right);
        merge(arr, left, mid ,right);
    }
    
    private static  void merge(int[] arr, int left, int mid, int right) {
        int[] help = new int[right - left + 1];
        int index = 0;
        int p1 = left;
        int p2 = mid + 1;
        while (p1 <= mid && p2 <= right) {
            help[index++] = arr[p1] < arr[p2] ? arr[p1++] : arr[p2++];
        }
        while (p1 <= mid) {
            help[index++] = arr[p1++];
        }
        while (p2 <= right) {
            help[index++] = arr[p2++];
        }
        for (int i = 0; i < help.length; i++) {
            arr[left + i] = help[i];
        }
    }

Leetcode 88. 合并两个有序数组

88. 合并两个有序数组

public void merge(int[] nums1, int m, int[] nums2, int n) {
        int[] nums3 = new int[nums1.length];
        int p1 = 0;
        int p2 = 0;
        int index = 0;
        while (p1 < m && p2 < n) {
            nums3[index++] = nums1[p1] < nums2[p2] ? nums1[p1++] : nums2[p2++];
        }
        while (p1 < m) {
            nums3[index++] = nums1[p1++];
        }
        while (p2 < n) {
            nums3[index++] = nums2[p2++];
        }
        for (int i = 0; i < nums1.length; i++) {
            nums1[i] = nums3[i];
        }
    }

从后往前遍历,省去nums3的空间

  • 因为nums1的空间都集中在后面,所以从后向前处理排序的数据会更好,节省空间,一边遍历一边将值填充进去
  • 设置指针p1 和p2分别指向nums1和nums2的有数字的尾部,从尾部值开始比较遍历,同时设置指针p3执行nums1的末尾,每次遍历比较值的大小之后,在进行填充
  • 当len1 < 0是遍历结束,此时nums2中还有数据没有拷贝完全,将其直接拷贝到nums1的nums1的前面,最后得到结果数组
public void merge(int[] nums1, int m, int[] nums2, int n) {
        int p1 = m - 1;
        int p2 = n - 1;
        int index = nums1.length - 1;
        while (p1 >= 0 && p2 >= 0) {
            nums1[index--] = nums1[p1] > nums2[p2] ? nums1[p1--] : nums2[p2--];
        }
        while (p2 >= 0) {
            nums1[index--] = nums2[p2--];
        }
    }

Leetcode 21. 合并两个有序链表

21. 合并两个有序链表

递归

public ListNode mergeTwoLists(ListNode l1, ListNode l2) {
        if (l1 == null)return l2;
        if (l2 == null)return l1;
        if (l1.val < l2.val) {
            l1.next =  mergeTwoLists(l1.next, l2);
            return l1;
        }else {
            l2.next = mergeTwoLists(l1, l2.next);
            return l2;
        }
    }

迭代

 public ListNode mergeTwoLists(ListNode l1, ListNode l2) {
        ListNode dummyHead = new ListNode(-1);
        ListNode cur = dummyHead;
        while (l1 != null && l2!= null) {
            if (l1.val < l2.val) {
                cur.next = l1;
                l1 = l1.next;
            }else {
                cur.next = l2;
                l2 = l2.next;
            }
            cur = cur.next;
        } 
        if (l1 != null)cur.next = l1;
        else cur.next = l2;
        return dummyHead.next;
    }

Leetcode 23. 合并K个排序链表

21. 合并K个排序链表

直接对链表数组进行分治算法,然后在进行双链表的归并

 public ListNode mergeKLists(ListNode[] lists) {
        if (lists == null || lists.length == 0)return null;
        return mergeKLists( lists, 0 , lists.length - 1);
    }

    private ListNode mergeKLists(ListNode[] lists, int left ,int right) {
        if (left == right) return lists[left];
        int mid = left + (right - left) / 2;
        ListNode l1 =  mergeKLists(lists, left , mid);
        ListNode l2 = mergeKLists(lists, mid + 1, right);
        return mergeTwoLists(l1, l2);
    }

    private ListNode mergeTwoLists(ListNode l1, ListNode l2) {
        if (l1 == null) return l2;
        if (l2 == null) return l1;
        if (l1.val < l2.val) {
            l1.next = mergeTwoLists(l1.next, l2);
            return l1;
        }else {
            l2.next = mergeTwoLists(l1, l2.next);
            return l2;
        }
    }

Leetcode 148. 排序链表

148. 排序链表

对单链表进行归并

public ListNode sortList(ListNode head) {
        return head == null ? head : mergeSort(head);
    }

    private ListNode mergeSort(ListNode head) {
        if (head == null)return null;
        if (head.next == null)return head;
        ListNode midPre = getMidPre(head);
        ListNode mid = midPre.next;
        midPre.next = null;
        ListNode left = mergeSort(head);
        ListNode right = mergeSort(mid);
        return mergeTwoSortedList(left, right);
    }

    private ListNode mergeTwoSortedList(ListNode left, ListNode right) {
        if (left == null)return right;
        if (right == null) return left;
        if (left.val < right.val) {
            left.next = mergeTwoSortedList(left.next, right);
            return left;
        }else {
            right.next = mergeTwoSortedList(left, right.next);
            return right;
        }
    }


    private ListNode getMidPre(ListNode head) {
        ListNode fast = head.next;
        ListNode slow = head;
        ListNode pre = slow;
        while (fast != null && fast.next != null) {
            pre = slow;
            slow = slow.next; 
            fast = fast.next.next;
        }
        return pre;
    }

快速排序

  • 归并排序将数组分为两个子数组分别进行排序,并将有序的子数组归并得到整个数组排序
  • 快速排序用过一个切分元素将数组划分为两个部分,左边的子数组小于等于切分元素,右边的数组大于等于切分元素,将这两个子数组排序也就将整个数数排序了。
    快速排序的改进:
  1. 切换到插入排序,因为快速排序在小数组也会递归调用自己,对于小数组,插入排序比快速排序的性能更好,因此,在小数组中可以切换到插入排序
  2. 三数取中:最好的情况下是每次都能取的中位数作为切分元素,->随机快排
    防止本来就是近似排好序的数组快排导致左右不平衡
  3. 三向切分,将数组切分为三个部分,分别对应小于、等于、大于。三向切分快速排序对于有大量重复元素的随机数组可以在线性时间内完成排序。

十大排序算法Java实现及其Leetcode算法题_第1张图片

    public static void quickSort(int[] arr) {
      if (arr == null || arr.length < 2)return;
      quickSort(arr, 0 , arr.length - 1);
    }

    private  static  void quickSort(int[] arr, int left, int right) {
       if (left < right) {
       //随机快排,避免由于原数据的特殊性(已排好序),将时间复杂度变为O(n^2)
           swap(arr, right, left + (int)((right - left + 1) * Math.random())); 
           int[] p = partition(arr, left, right);
           quickSort(arr, left, p[0] - 1);
           quickSort(arr, p[1] + 1, right);
       }
    }

    private static  int[] partition(int[] arr, int left, int right) {
       int less = left - 1;
       int more = right + 1;
       int value = arr[right]; //以数组的右边界值作为划分值
       int cur = left;
       while (cur < more) {
           if (arr[cur] < value) {
               swap(arr, ++less, cur++); //和小于区域的下一个位置交换
           }else if (arr[cur] > value) { 
               swap(arr, --more, cur); //和大于区域的前一个位置交换 
           }else {
               cur++;
           }
       }
       return new int[]{less + 1, more - 1}; //返回等于区域的开始位置和结束位置
    }

Leetcode 75. 颜色分类

荷兰国旗问题
75. 颜色分类

1.第一种方法就是计数排序,统计0 , 1, 2出现的次数。但是需要扫描两遍,不符合题目的要求

 public void sortColors(int[] nums) {
        int[] count = new int[3];
        for (int i = 0; i < nums.length; i++) {
            count[nums[i]]++;
        }
        int index = 0;
        for (int i = 0; i < 3; i++) {
            for (int j = 0; j < count[i]; j++) { //count[0] 0出现的次数
                nums[index++] = i;
            }
        }
    }

快速排序的思想,以1作为划分值,小于1的放在左边 大于1的放在右边

public void sortColors(int[] nums) {
        int value = 1;
        int less = -1;
        int more = nums.length;
        int cur = 0;
        while (cur < more) {
            if (nums[cur] < value) {
                swap(nums,++less,cur++);
            }else if (nums[cur] > value) {
                swap(nums, --more, cur);
            }else {
                cur++;
            }
        }
    }

    private void swap(int[] nums, int i , int j) {
        int temp = nums[i];
        nums[i] = nums[j];
        nums[j] = temp;
    }

堆排序

堆 完全二叉树
大根堆 在一颗完全二叉树中,任何一颗子树的最大值都是这颗子树的头部
堆中某个节点的值总是大于等于其子节点的值,并且堆是一颗完全二叉树
堆可以用数组来表示,这是因为堆是完全二叉树,而完全二叉树很容易就存储在数组中,位置k的节点的父节点的位置为k - 1 / 2,它的两个子节点的位置分别为2k和 2k + 1
2.上浮和下沉
上浮: heapInsert构建堆的过程中,当新加入的节点其幅节点要大的时候,就需要交换着两个节点,交换后还可能比它新的父节点还要大,因此需要不断的进行比较和交换操作
下沉:(heapify)当一个节点比子节点,就需要不断下沉的过程,把这种操作称为下沉,一个节点如果有两个子节点,应当与两个子节点中最大的那个节点进行交换
3。从数组顶端删除最大的元素,与数组最后一个元素进行交换,并让这个元素下沉到合适的位置。

1.构建堆
2. 交换堆顶元素与最后一个元素,并将堆的大小减1

 public static void heapSort(int[] arr) {
        if (arr == null || arr.length < 2) return;
        for (int i = 0; i < arr.length; i++) {
            heapInsert(arr, i);
        }
        int size = arr.length;
        swap(arr, 0, --size);
        while (size > 0) {
            heapify(arr, 0, size);
            swap(arr, 0, --size);
        }
    }


    public static void heapInsert(int[] arr, int index) {
        while (arr[index] > arr[(index - 1) / 2]) {
            swap(arr, index, (index - 1) / 2);
            index = (index - 1) / 2;
        }
    }

    public static void heapify(int[] arr, int index, int size) {
        int left = index * 2 + 1;
        while (left < size) {
            int right = left + 1;
            int largest = right < size && arr[right] > arr[left] ? right : left;
            largest = arr[largest] > arr[index] ? largest : index;
            if (largest == index) {
                break;
            }
            swap(arr, largest, index);
            index = largest;
            left = index * 2 + 1;
        }
    }
    public static void swap(int[] arr, int i, int j) {
        int tmp = arr[i];
        arr[i] = arr[j];
        arr[j] = tmp;
    }

Leetcode 215. 数组中的第K个最大元素

215. 数组中的第K个最大元素

  1. 按照从大到小全排序,然后取出第k个数
  2. 利用堆进行部分排序,维护一个大根堆,将数组元素全部压入堆,然后弹出k次,第k个旧市答案
  3. 选择排序,第k次选择后即可得到第k大的数
  4. 堆排序,维护一个k大小的小根堆,将数组中的每个元素与堆顶的元素进行比较,如果比堆顶的元素大,则删除堆顶的元素并添加这个元素,如果比堆顶的元素小,则什么也不做,继续下一个元素
  5. 利用快速排序中的partition的思想,从数组中随机选择一个元素x,将数组划分为前后两个部分s1 和 s2 s2中的元素大于或者等于x这时候有两种情况:
  • s1的元素小于k,则递归求解s2 中的第k - s1大的元素
  • s1的元素的个数大于或者等于k,则递归求解S1中第k大的元素

堆排序的思想

 public int findKthLargest(int[] nums, int k) {
        Queue<Integer> heap = new PriorityQueue<>();
        for (int x : nums) {
            if (heap.size() < k) {
                heap.add(x);
            }else {
                if (x > heap.peek()) {
                    heap.poll();
                    heap.offer(x);
                }
            }
        }
        return heap.peek();      
    }

桶排序

桶排序的基本思路是:

  1. 将待排序的元素划分到不同的桶,先臊面一遍序列求出最大值maxV和最小值minV,设桶的个数为k,则把区间[minV,maxV]均匀划分为k个区间,每个区间就是一个桶,。将序列中的元素分配到各自的桶。
  2. 对每个桶中的元素进行排序,可以选择任意一种排序算法
  3. 将各个同种的元素合并成一个大的有序序列。

假设数据是均匀分布的,则每个桶的元素的平均个数为n / k,假设选择用快速排序对每个桶内的元素进行排序的话,那么每次排序的时间复杂度就是O(n/k log(n /k) )总的时间复杂度 为 O(n)+O(m)O(n/klog(n/k)) = O(n+nlog(n/k)) = O(n+nlogn-nlogk 。当k接近于n的嘶吼,桶排序的时间复杂度就可以近似为O(n)的,即桶越多,时间效率就越高,而桶越多时间复杂对就越大。

Leetcode 41. 缺失的第一个正数

41. 缺失的第一个正数
题解:
桶的思想 + 抽屉原理

public int firstMissingPositive(int[] nums) {
        bucketSort(nums);
        int len = nums.length;
        for (int i = 0; i < len; i++) {
            if (nums[i] != i + 1) { //[1, - 1, 3, 4]
                return i + 1;
            }
        }
        return len + 1; //都正确则返回len + 1
    }

    private static void bucketSort(int[] nums) {
        if (nums == null || nums.length < 1)return ;
        int n = nums.length;
        for (int i = 0; i < n; i++) {
            //满足在指定的范围内,并且没有放在正确的位置上,才交换
            //3应该放在2位置上 
            while (nums[i] > 0 && nums[i] < n && nums[nums[i] - 1] != nums[i]) {
                swap(nums, i , nums[i] - 1);
            }
        }
    }

    private static void swap(int[] nums, int i, int j) {
        int temp = nums[i];
        nums[i] = nums[j];
        nums[j] = temp;
    }

Leetcode 164. 最大间距

164. 最大间距

public int maximumGap(int[] nums) {
        if (nums == null || nums.length < 2) return 0;
        int len = nums.length;
        int max = Integer.MIN_VALUE;
        int min = Integer.MAX_VALUE;
        for (int i = 0; i < nums.length; i++) { //找到数组的最大值与最小值
            max = Math.max(max, nums[i]);
            min = Math.min(min, nums[i]);
        }
        if (min == max) return 0;
        boolean[] hasNum = new boolean[len + 1]; //准备 len + 1 个桶
        int[] maxs = new int[len + 1]; //用于存放每个桶中的最大值
        int[] mins = new int[len + 1]; //用于存放每个桶中的最小值
        int bid = 0;//记录元素在桶中的位置
        for (int i = 0; i < len; i++) {
            bid = bucket(nums[i], len , min, max);
            mins[bid] = hasNum[bid] ? Math.min(mins[bid], nums[i]) : nums[i];
            maxs[bid] = hasNum[bid] ? Math.max(maxs[bid], nums[i]) : nums[i];
            hasNum[bid] = true;
        }
        //开始求最大的间隙
        int res = 0;
        int lastMax = maxs[0];
        for (int i = 1; i <= len; i++) {
            if (hasNum[i]) {
                res = Math.max(mins[i] - lastMax, res);
                lastMax = maxs[i];
            }
        }
        return res;
    }

    private static int bucket(long num, int len, int min, int max) {
        return (int)((num - min) * len / (max - min)); //元素在同种的下标
    }

计数排序

计数排序(Counting Sort)是一种O(n)的排序算法,其思路是开一个长度为 然
后开一个maxValue-minValue+1的数组,

  1. 分配。扫描一遍原始数组,以当前值- minValue 作为下标,将该下标的计数器增1。
  2. 收集。扫描一遍计数器数组,按顺序把值收集起来。

举个例子, nums=[2, 1, 3, 1, 5] , 首先扫描一遍获取最小值和最大值, 于是开一个长度为5的计数器数组 counter ,
maxValue=5 ,
minValue=1 ,

  1. 分配。统计每个元素出现的频率,得到 counter=[2, 1, 1, 0, 1] ,例如 counter[0] 值表示 0+minValue=1 出现了2次。

  2. 收集。 counter[0]=2 表示 1 出现了两次,那就向原始数组写入两个1, counter[1]=1表示2出现了1次,那就向原始数组写入一个2,依次类推,最终原始数组变为[1,1,2,3,5],排序好了。

计数排序本质上是一种特殊的桶排序,当桶的个数最大的时候,就是计数排序。

public static void bucketSort(int[] arr) {
        if (arr == null || arr.length < 2)return;;
        int max = Integer.MIN_VALUE;
        for (int i = 0; i < arr.length; i++) {
            max = Math.max(max, arr[i]);
        }
        int[] bucket = new int[max + 1];
        for (int i = 0; i < arr.length; i++) {
            bucket[arr[i]]++;
        }
        int index = 0;
        for (int j = 0; j < bucket.length; j++) {
            while (bucket[j]-- > 0) {
                arr[index++] = j;
            }
        }
    }

Leetcode 274. H指数

274. H指数


想象一个直方图,其中x表示文章数,y中表示每篇文章的引用次数。如果将这些文章按照引用次数,降序排序并在直方图上表示,那么直方图上的最大的正方形边长h,就是我们要求的h

 public int hIndex(int[] citations) {
        Arrays.sort(citations);
        reverse(citations);
        for (int i = 0; i < citations.length; i++) {
            if (i + 1 == citations[i])return i + 1;
            if (i + 1 > citations[i]) return i;
        }
        return citations.length;
    }

    private static void reverse(int[] nums) {
        int left = 0;
        int right = nums.length - 1;
        while (left < right) {
            int temp = nums[left];
            nums[left] = nums[right];
            nums[right] = temp;
            left++;
            right--;
        }
    }

思路二: 计数排序,不过排序算法换成了计数排序。有一个小技巧,因为H-Index最大不可能超过论文 综述,所以我们只需要开一个长度为 n+1 的数组,如果某篇论文的引用数超过了 n ,就将其当做 n 。

 public int hIndex(int[] citations) {
        int n = citations.length + 1;
        int[] papers = new int[n + 1];
        for (int x :citations) {
            papers[Math.min(x, n)]++; 
        }
        int sum = 0;//当前的文章数
        for (int i = n; i > 0; i--) {
            sum += papers[i];
            if (sum >= i) {
                return i;
            }
        }
        return 0;
    }

基数排序

基数排序是一种费比较的排序算法,时间复杂度是O(n),它的主要思路是

  1. 将所有待排序的整数,注意必须是肺腑整数,统一为位数相同的整数,位数较少的数前面补零,一般用10进制,也可以用16进制甚至2进制,所以前提是能够找到最大值,得到最长的位数。
  2. 从最低位开始,一次进行一次稳定的排序,这样从最低位一直到最高位排序完成之后,整个序列就成为了一个有序序列。

举个例子,有一个整数序列 0 , 123, 45, 386, 106 先面试排序的过程:
第一次排序个位:
000, 123, 045, 386, 106
第二次排序十位:
000,106,123,045,386
第三次排序百位:
000, 045, 106, 123,386 排序完成。

**为什么同一数位的排序子程序要用稳定排序?**因为稳定排序能将上一次排序的成果保留下来,例如十位数的排序过程能保留个位数的排序成果,百位数的排序过程能够保留十位数的排序成果。

public static void radixSort(int[] arr) {
        if (arr == null || arr.length < 2) return;
        int max = Integer.MIN_VALUE;
        for (int x : arr) {
            max = Math.max(x, max); //找到数组中最大的数
        }
        int maxBit = 0; //计算最大的数的位数
        while (max != 0) {
            maxBit++;
            max /= 10; 
        }
        Queue<Integer>[] queues = new LinkedList[10];
        for (int i = 0, mod = 1; i < maxBit; i++, mod *= 10) {
            for (int x : arr) {
                int index = (x / mod) % 10;
                queues[index].add(x);
            }
            int count = 0;
            for (Queue<Integer> queue: queues) {
                while (queue.size() > 0) {
                    arr[count++] = queue.poll();
                }
            }
        }
    }

小结:

排序算法的比较

快速排序是最快的通用排序算法,它的内循环的指令很少,而且它还能利用缓存,因为他总是顺序的访问数据,它的运行时间近似为~cNlogN,这里的c比其他线性对数级别的排序算法都小

使用三向切分快速排序,实际应用中可能出现的某些分布的输入能够达到线性级别,而且他排序算法仍然需要线性对数时间。

Java的排序算法的实现

十大排序算法Java实现及其Leetcode算法题_第2张图片
Java主要的排序方式为Arrays.sort(),对于原始数据类型使用三向切分的快速排序,对于引用类型使用归并排序(因为归并排序具有稳定性)

参考:
CS-NOTES

你可能感兴趣的:(数据结构与算法,算法,快速排序,java,排序算法)