数据结构与算法 | 青训营笔记

86 阅读2分钟

1. 经典排序算法

1.1 插入排序

从头到尾遍历数组,当前元素应该插入到小于等于它的最右下标之后。实际使用相邻元素交换的方法

public void insertSort(int[] nums){
    for(int i=1;i<n;i++){
        for(int j=i;j>0;j--){
            if(nums[j]<nums[j-1]){
                swap(nums,j,j-1);
            }
        }
    }
}
public void swap(int[] nums,int i,int j){
    int temp = nums[i];
    nums[i] = nums[j];
    nums[j] = temp;
}

时间复杂度

最好平均最坏
O(n)O(n^2)O(n^2)

1.2 快速排序

分治思想,不断分割序列直到整体有序

  • 选定一个pivot
  • 遍历数组,分成比pivot小和比pivot大的左右序列
  • 递归,分别继续对左右序列进行类似处理

时间复杂度

最好平均最坏
O(n*logn)O(n*logn)O(n^2)

1.3 堆排序

利用堆的性质进行排序 每次将大顶堆的堆顶元素交换到末尾,再调整堆结构 时间复杂度

最好平均最坏
O(n*logn)O(n*logn)O(n*logn)

1.4 综合考虑

  • 在短序列或元素有序情况下,插入排序性能最好
  • 大部分情况下,快速排序有较好的综合性能
  • 在任何情况下,堆排序表现较稳定

2. 从零设计qdqsort

结合三种排序算法的优点

  • 对于短序列,使用插入排序
  • 其他情况,使用快速排序保证整体性能
  • 快速排序表现不佳时,使用堆排序保证稳定的时间复杂度O(n*logn)

Q:

  1. 短序列具体长度?

    12~32,具体依据不同语言和场景

  2. 如何得知快速排序性能不佳?

    当pivot离数组两段很接近(距离小于length/8),认为其表现不佳 当表现不佳的情况次数达到一定数值,切换为堆排序

如何设计高性能的排序算法

根据不同情况选择不同策略,取长补短