Java排序算法

一、八大基本排序

1、快速排序

    public int partion(int[] nums, int left, int right){

        // pos充当哨兵,取最左边的
        int pos = nums[left];
        while(left<right){
            // 保证右边的值都是大于等于哨兵的
            while(left<right&&nums[right]>=pos){
                right--;
            }
            
            // 交换
            if(left<right){
                nums[left] = nums[right];
            }

            // 保证左边的都是小于等于哨兵的
            while(left<right&&nums[left]<pos){
                left++;
            }

            // 交换
            if(left<right){
                nums[right]=nums[left];
            }
           
        }
         nums[left]=pos;
         return left;   
    }

    public void QuickSort(int[] nums, int left, int right){
        if(left<right){
            int mid = partion(nums, left, right);
            QuickSort(nums,left, mid-1);
            QuickSort(nums,mid+1,right);
        }
    }

    public int[] sortArray(int[] nums) {
            QuickSort(nums, 0, nums.length-1);
            return nums;

    }

二、数组排序

1、对int数组排序

(1)正常排序

默认范围为(0,a.length-1)

public static void sort(int[] a) {
        DualPivotQuicksort.sort(a, 0, a.length - 1, null, 0, 0);
    }

示例:

int[] a = {1,5,4,3,2};
Arrays.sort(a);
// a ===> 1,2,3,4,5

(2)对一定范围内的int数组排序

自定义范围为(fromIndex, toIndex - 1)

    public static void sort(int[] a, int fromIndex, int toIndex) {
        rangeCheck(a.length, fromIndex, toIndex);
        DualPivotQuicksort.sort(a, fromIndex, toIndex - 1, null, 0, 0);
    }

示例:

int[] a = {1,5,4,3,2};
Arrays.sort(a,2,5);  // 排序索引为2~4的元素
// a ===> 1,5,2,3,4

(3)自定义排序规则

函数式接口的定义:只有一个抽象方法的接口,可以用lambda表达式简化代码。而Comparator就是一个函数式接口,所以我们可以使用lambda表达式去写。
但是千万千万要注意:这种方法是不可以对基本数据类型进行排序的,因为这里的类型是T泛型,所以它针对的是对象类型,只有将int数组转成Integer数组,才可以继续使用

    public static <T> void sort(T[] a, Comparator<? super T> c) {
        if (c == null) {
            sort(a);
        } else {
            if (LegacyMergeSort.userRequested)
                legacyMergeSort(a, c);
            else
                TimSort.sort(a, 0, a.length, c, null, 0, 0);
        }
    }

示例:(错误做法

int[] a = {1,5,4,3,2};
Arrays.sort(a, (o1,o2)-{   // 逆序排序
      return o2-o1;
 });  

正确做法

Integer[] a = {1,5,4,3,2};
Arrays.sort(a, (o1,o2)-{   // 逆序排序
      return o2-o1;
 });  
// a ===> 5,4,3,2,1

那么对一定范围内的数组进行自定义排序了,可以使用下面的方法
public static <T> void sort(T[] a, int fromIndex, int toIndex, Comparator<? super T> c)

2、对String数组排序

(1)按字典数大小升序

String是引用类型,所以调用下列方法,类型是Object[]

    public static void sort(Object[] a) {
        if (LegacyMergeSort.userRequested)
            legacyMergeSort(a);
        else
            ComparableTimSort.sort(a, 0, a.length, null, 0, 0);
    }

默认为按字典大小进行升序
示例:

public static void main(String[] args) {
        String[] str = {"abb","cssss","abaz","abba","1dff","5frgh"};
        Arrays.sort(str);
        for (String s : str) {
            System.out.println(s);
        }
    }

结果:
在这里插入图片描述

(2)对一定范围内的String数组排序

同int数组,只需要加上一个范围即可

    public static void sort(Object[] a, int fromIndex, int toIndex) {
        rangeCheck(a.length, fromIndex, toIndex);
        if (LegacyMergeSort.userRequested)
            legacyMergeSort(a, fromIndex, toIndex);
        else
            ComparableTimSort.sort(a, fromIndex, toIndex, null, 0, 0);
    }

示例:

    public static void main(String[] args) {
        String[] str = {"abb","cssss","abaz","abba","1dff","5frgh"};
        Arrays.sort(str,2,6);
        for (String s : str) {
            System.out.print(s+"  ");
        }
    }

结果:
在这里插入图片描述

(3)自定义排序规则

如何按照字典序大小进行降序了?

不同于int数组,两个String是不可以直接比较大小的,幸好Java给我们提供了一个方法compareTo,能够直接比较两个String的字典序大小

示例:

String s1 = "abc";
String s2 = "bab";
int cmp = s1.compareTo(s2);
System.out.println(cmp);  // -1
  • cmp == -1时,说明s1字典序小于s2的字典序
  • cmp == 0时,说明s1字典序等于s2的字典序
  • cmp == 1时,说明s1字典序大于s2的字典序

因此,我们可以使用以下lambda表达式来对String数组按照字典序大小进行降序排列!

示例:

    public static void main(String[] args) {
        String[] str = {"abb","cssss","abaz","abba","1dff","5frgh"};
        Arrays.sort(str, (o1,o2)->{
            int cmp = o2.compareTo(o1);
            return cmp;
        });
        for (String s : str) {
            System.out.print(s+"  ");
        }
    }

结果:
在这里插入图片描述

三、List排序

不同于数组是使用Arrays.sort()进行排序,List既可以使用自己自带的sort(Comparator c)方法进行排序,也可以使用工具类Collections进行排序(Collections.sort())。但是Collections.sort()本质上也是调用了List自带的sort()方法。

1、 List自带的sort(Comparator c)方法(没有无参的方法,如果想使用默认的升序,可以将null作为参数
也分了两种,一种是LinkedList,它使用的sort(Comparator c)方法是List接口里面的方法,一种是ArrayList,它重写了List接口里面的sort(Comparator c)方法。

(1) LinkedList

    @SuppressWarnings({"unchecked", "rawtypes"})
    default void sort(Comparator<? super E> c) {
        Object[] a = this.toArray();
        Arrays.sort(a, (Comparator) c);
        ListIterator<E> i = this.listIterator();
        for (Object e : a) {
            i.next();
            i.set((E) e);
        }
    }

可以看到是将List转为了数组,然后使用Arrays.sort()排序,最后再将数组又转为了List

(2)ArrayList

ArrayList重写了List接口的方法

    @Override
    @SuppressWarnings("unchecked")
    public void sort(Comparator<? super E> c) {
        final int expectedModCount = modCount;
        Arrays.sort((E[]) elementData, 0, size, c);
        if (modCount != expectedModCount) {
            throw new ConcurrentModificationException();
        }
        modCount++;
    }

2、使用工具类Collections进行排序(Collections.sort()
本质上是使用list.sort()方法

不带Comparator接口的

    @SuppressWarnings("unchecked")
    public static <T extends Comparable<? super T>> void sort(List<T> list) {
        list.sort(null);
    }

Comparator接口的

@SuppressWarnings({"unchecked", "rawtypes"})
    public static <T> void sort(List<T> list, Comparator<? super T> c) {
        list.sort(c);
    }

1、对List<Integer>进行排序

(1)正常升序排列

示例:

public static void main(String[] args) {
        List<Integer> list = new LinkedList<>();

        list.add(2);
        list.add(1);
        list.add(5);
        list.add(4);
        list.add(3);

        // Collections.sort(list);  // Collections工具类
        list.sort(null);   // List自带的sort()方法

        for (int integer : list) {   // 这里的integer本来为Integer类型,不过被强转成了int
            System.out.println(integer);
        }
}

结果:
在这里插入图片描述

(2)降序排列

需要自定义排序规则,定义Comparator接口,重写里面的compare()方法

降序排列List

示例:

    public static void main(String[] args) {
        List<Integer> list = new LinkedList<>();

        list.add(2);
        list.add(1);
        list.add(5);
        list.add(4);
        list.add(3);
        
//        Collections.sort(list, (o1, o2) -> {  // 第二种方法:使用Collections工具类
//            return o2-o1;
//        });

        list.sort((o1, o2) -> { // 第一种方法:List自带的sort()方法
            return o2-o1;
        });

        for (int integer : list) {   // 这里的integer本来为Integer类型,不过被强转成了int
            System.out.print(integer+"  ");
        }
}

结果:
在这里插入图片描述

2、对List<int[]>排序

按照数组中的第一个元素进行降序排列

    public static void main(String[] args) {
        List<int[]> list = new LinkedList<>();

        list.add(new int[]{6,2});
        list.add(new int[]{8,4});
        list.add(new int[]{5,6});

        Collections.sort(list,(o1,o2)->{
            return o2[0]-o1[0];
        });
        for (int[] ints : list) {
            for (int anInt : ints) {
                System.out.print(anInt+"  ");
            }
            System.out.println();
        }
//        int[][] arr = list.toArray(new int[list.size()][]);   // 可以将list转化为数组
    }

3、对Map排序

其实这个用处还挺多的,一般可以用来计算频率问题topK问题

示例:前 K 个高频元素

给你一个整数数组 nums 和一个整数 k ,请你返回其中出现频率前 k 高的元素。你可以按 任意顺序 返回答案。

例如:

输入: nums = [1,1,1,2,2,3], k = 2
输出: [1,2]

思路:使用Map去对频率存值,然后对Map的Value字段进行降序排列,取前k个

class Solution {
    public int[] topKFrequent(int[] nums, int k) {
        int[] result = new int[k];
        HashMap<Integer, Integer> map = new HashMap<>();
        for (int num : nums) {
           //  map.getOrDefault(num, 0),通过key(num值)去寻找Value,如果key值中没有num,则返回0,否则返回对应的Value
            map.put(num, map.getOrDefault(num, 0) + 1);  
        }

        Set<Map.Entry<Integer, Integer>> entries = map.entrySet();


        List<Map.Entry<Integer, Integer>> list = new ArrayList<>();

        for(Map.Entry<Integer, Integer> entry : entries){
            list.add(entry);
        }

        list.sort((o1, o2) -> {  // 根据Value进行降序排列
             return o2.getValue() - o1.getValue();
        });

        for(int i=0;i<k;i++){
            result[i] = list.get(i).getKey();
        }

        return result;

    }
}

除了List外,我们也可以使用优先队列(PriorityQueue)的办法,去建立一个小根堆(大根堆也可以)

PriorityQueue也可以自定义排序规则

    public PriorityQueue(Comparator<? super E> comparator) {
        this(DEFAULT_INITIAL_CAPACITY, comparator);
    }

解答如下:

class Solution {
    public int[] topKFrequent(int[] nums, int k) {
        int[] result = new int[k];
        HashMap<Integer, Integer> map = new HashMap<>();
        for (int num : nums) {
            map.put(num, map.getOrDefault(num, 0) + 1);
        }

        Set<Map.Entry<Integer, Integer>> entries = map.entrySet();

        // 根据map的value值正序排,相当于一个小顶堆
        PriorityQueue<Map.Entry<Integer, Integer>> queue = new PriorityQueue<>((o1, o2) -> o1.getValue() - o2.getValue());
        
        for (Map.Entry<Integer, Integer> entry : entries) {
            queue.offer(entry);
            if (queue.size() > k) {  // 保证最后只剩下k个频率最高的元素
                queue.poll();
            }
        }
        for (int i = k - 1; i >= 0; i--) {
            result[i] = queue.poll().getKey();
        }
        return result;
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值