面试常见排序问题


手撸快排居然失败,可怕。准备好这几种排序算法,面试不心慌。

3.1 排序

leetcode 912

3.1.0 堆排序

class Solution {
public:
    vector<int> sortArray(vector<int>& nums) {
        nums.insert(nums.begin(), 0);
        heapSort(nums, nums.size()-1);
        vector<int> res(nums.begin()+1, nums.end());
        return res;
    }
    
    void heapSort(vector<int>& a, int len) {
        buildHeap(a, len); // 初始建堆
        for (int i = len; i > 1; i--) { // n-1趟的交换和建堆过程
            swap(a[i], a[1]); // 和堆底元素交换
            adjustDown(a, 1, i - 1); // 把剩余的i-1个元素整理成堆
        }
    }
    
    void adjustDown(vector<int>& a, int k, int len) {
        a[0] = a[k]; // a[0]暂存
        for (int i = 2 * k; i <= len; i *= 2) {  // 沿key较大的子节点向下筛选
            if (i < len && a[i] < a[i+1]) {  // 小顶堆只需要需改 a[i] > a[i+1] 以及下面结束 a[0] <= a[i]即可
                i++; // 取key较大的子节点下标
            }
            if (a[0] >= a[i]) {
                break; // 筛选结束
            } else {
                a[k] = a[i]; // 将A[i]调整到双亲节点上
                k = i; // 修改k值,以便继续向下筛选
            }
        }
        a[k] = a[0]; // 将被筛选的节点的值放入最终位置
    }
    
    void buildHeap(vector<int>& a, int len) {
        for (int i = len / 2; i > 0; i--) { // 从i = n/2 到 1 反复调整堆
            adjustDown(a, i, len);
        }
    }
};

3.1.1 归并排序 √

devide & conquer的思想。 mergeSort就是devide, merge就是conquer。

func sortArray(nums []int) []int {
    mergeSort(nums, 0, len(nums)-1)
    return nums
}


func mergeSort(nums []int, p, r int) {
    if p < r {
        mid := p + (r-p)/2
        mergeSort(nums, p, mid)
        mergeSort(nums, mid+1, r)
        merge(nums, p, mid, r)
    }
}

func merge(nums []int, p, mid, r int) {
    a := make([]int, mid-p+1)
    b := make([]int, r-mid)
    copy(a, nums[p:mid+1])
    copy(b, nums[mid+1:r+1])
    i, j := 0, 0
    idx := p
    for i < len(a) && j < len(b) {
        if a[i] < b[j] {
            nums[idx] = a[i]
            i++
        }else {
            nums[idx] = b[j]
            j++
        }
        idx++
    }
    for i < len(a) {
        nums[idx] = a[i]
        i++
        idx++
    }
    for j < len(b) {
        nums[idx] = b[j]
        j++
        idx++
    }
} 

3.1.2 快速排序 √

快速排序分三个阶段
1 写出最基本的快速排序 2-3分钟 pivot = a[r];
2 使用median对快速排序的pivot进行优化 pivot = median3(); 1-2min
3 使用cutoff和insertionSort对快速排序进行优化 if (p + cutoff < r){}else{}; 2-3min

  • 快排的基本版本 5min
func sortArray(nums []int) []int {
    quickSort(&nums, 0, len(nums)-1)
    return nums
}

func quickSort(a *[]int, p, r int) {
    if p < r {
        q := partition(a, p, r)
        quickSort(a, p, q-1)
        quickSort(a, q+1, r)
    }
}

func partition(a *[]int, p, r int) int {
    pivot := (*a)[r]
    i := p-1
    for j := p; j < r; j++ {
        if (*a)[j] <= pivot {
            i++
            swap(a, i, j)
        } 
    }
    swap(a, i+1, r)
    return i+1
}

func swap(a []int, i, j int){
    a[i], a[j] = a[j], a[i]
}
  • 快排的进阶版本2.0 pivot := median3(*a, p, r) 替换 pivot := (*a)[r]
func median3(a []int, p, r int) int {
    q := p + (r-p)/2
    if a[p] > a[q] {
        swap(a, p, q)
    }
    if a[q] > a[r] {
        swap(a, q, r)
    }
    if a[p] > a[q] {
        swap(a, p, q)
    }
    swap(a, q, r)
    return a[r]
}
  • 快排的进阶版本3.0 添加cutoff 小于cutoff用插入排序
func insertionSort(a []int, p, r int){
    for i := p+1; i <= r; i++ {
        tmp := a[i]
        j := i-1
        for j >= p && tmp < (*a)[j] {
            a[j+1] = a[j]
            j--
        }
        a[j+1] = tmp
    }
}
class Solution {
    public int[] sortArray(int[] nums) {
        quickSort(nums, 0, nums.length-1);
        return nums;
    }

    private static int CUTOFF = 10;
    public static void quickSort(int[] a, int p, int r){
        if(p + CUTOFF < r){
            int q = partition(a, p, r);
            quickSort(a, p, q-1);
            quickSort(a, q+1, r);
        }else{
            insertionSort(a, p, r);
        }
    }
    public static int partition(int[] a, int p, int r){
        int pivot = median3(a, p, r);
        int i = p-1;
        for(int j = p; j < r; j++){
            if( a[j] <= pivot) { // 注意这个等于号
                i++;
                swap(a, i, j);
            }
        }
        swap(a, i+1, r);  // 因为在median中将pivot放在最后一位了  此处的swap一定要和median统一   因为是逐步改进而来的 所以pivot在median中的位置放最后
        return i+1;
    }

    public static void swap(int[] a, int p, int r){
        int tmp = a[p];
        a[p] = a[r];
        a[r] = tmp;
    }


    public static int median3(int[] a, int p, int r){
        int mid = p + (r-p)/2;
        if(a[mid] < a[p]){
            swap(a, p, mid);
        }
        if(a[r] < a[p]){
            swap(a, p, r);
        }
        if(a[r] < a[mid]){
            swap(a, mid, r);
        }
        swap(a, mid, r);
        return a[r]; 
    }

    public static void insertionSort(int[] a, int p, int r){
        for(int i = p+1; i <= r; i++){
            int tmp = a[i];
            int j = i - 1;
            while(j >= p && a[j] > tmp){
                a[j+1] = a[j];
                j--;
            }
            a[j+1] = tmp;
        }
    }
}

3.1.3 插入排序 √

将待排序序列分为已排序和未排序两个部分。初始状态,已排序序列只包含第一个元素,此后将未排序的元素逐一(key)插入到已排序元素中。

func insertionSort(nums []int) []int {
    for i := 1; i < len(nums); i++ {
        tmp := nums[i]
        j := i-1
        for j >= 0 && tmp <= nums[j] {
            nums[j+1] = nums[j]
            j--
        }
        nums[j+1] = tmp
    }
    return nums
}

3.1.4 选择排序 √

它的工作原理是每一次从待排序的数据元素中选出最小的一个元素,存放在序列的起始位置,直到全部待排序的数据元素排完。

func selectionSort(nums []int) []int {
    for i := 0; i < len(nums); i++ {
        min := i
        for j := i+1; j < len(nums); j++ {
            if nums[j] < nums[min] {
                min = j
            }
        }
        nums[i], nums[min] = nums[min], nums[i]
    }
    return nums
}
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值