文章目录
一、八大基本排序
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;
}
}