【排序算法总结】面试常见几种排序算法的C++实现

目录

  • 时空复杂度及稳定性对比
  • 快速排序
  • 归并排序
  • 堆排序

时空复杂度及稳定性对比

【排序算法总结】面试常见几种排序算法的C++实现_第1张图片

快速排序

思路:对于每一次递归,找到哨兵项,将小于该项的放在左边,大于该项的放在右边,详见注释。

void quicksort(vector<int> &nums, int left, int right){
	//基线条件
    if (nums.size()==0)
        return;
    if(left>=right)
        return;
    //随机找到哨兵项,避免每次取头部造成算法退化
    srand((unsigned)time(NULL));
    int base = (rand() % (right-left+1))+left;
    swap(nums[base], nums[left]);
	//进行partition
    base = nums[left];
    int i = left;
    int j = right;
    while (i < j){
        while(i<j && nums[j]>=base)
            j--;
        swap(nums[j], nums[i]);
        while (i<j && nums[i]<=base)
            i++;
        swap(nums[j], nums[i]);
    }
	//递归左右两部分
    quicksort(nums, left, i-1);
    quicksort(nums, i+1, right);
}

归并排序

思路:merge函数每次将left到mid的有序部分和mid到right的有序部分合并,mergesort每次调用merge,详见注释。
注意该排序可以用于求解逆序对问题

//用于合并两个有序部分
void merge(vector<int> &nums, int left, int mid, int right){
    vector<int> help;//利用一个额外空间help暂存
    int i = left;
    int j = mid+1;
    //每次将两者中较小值存入help数组,直到其中一个为空
    while (i <= mid && j <= right){
        if(nums[i] <= nums[j])
            help.push_back(nums[i++]);
        else
            help.push_back(nums[j++]);
    }
    //将另外一个的全部元素加到help后
    while (i <= mid){
        help.push_back(nums[i++]);
    }
    while (j <= right){
        help.push_back(nums[j++]);
    }
    //再将help拷贝回原数组
    int index = 0;
    for (i = left; i <= right; ++i) {
        nums[i] = help[index++];
    }
}
//利用merge排序
void mergesort(vector<int> &nums, int left, int right){
    if(left < right){//基线条件
        int mid = (left + right)/2;
        //递归排序好左右部分
        mergesort(nums, left, mid);
        mergesort(nums, mid+1, right);
        //合并
        merge(nums, left, mid, right);
    }
}

堆排序

思路:利用堆的性质,这里使用大根堆,并用数组模拟堆结构,详见注释。
注意该结构和快排的partition过程还可以用来解决TopK问题

//构建大根堆,一直和父节点交换,直到父节点大于新增节点或到达堆顶
void heapInsert(vector<int> &nums, int add){
    while (nums[add] > nums[(add-1)/2]){
        swap(nums[add], nums[(add-1)/2]);
        add = (add-1)/2;
    }
}
//调整堆,将一个小数从堆顶沉到其该处于的位置,注意除堆顶外其他部分需为堆结构
void heapify(vector<int> &nums, int add, int heapsize){
    int left = add*2 + 1;
    while (left < heapsize){
        int largest;
        if(left + 1 < heapsize && nums[left+1]>nums[left])
            largest = left+1;
        else
            largest = left;
        if(nums[largest] > nums[add])
            swap(nums[add], nums[largest]);
        else
            break;
        add = largest;
        left = add*2 + 1;
    }
}

//排序
void heapsort(vector<int> &nums){
    int heapsize = nums.size()-1;
    //构建大根堆
    for (int i = 0; i < nums.size(); ++i) {
        heapInsert(nums, i);
    }
    //每次把堆顶移到数组最后,再将堆的大小减一,做一次堆调整
    //重复这个过程直到堆的大小为1
    for (int j = 0; j < nums.size(); ++j) {
        swap(nums[0],nums[heapsize]);
        heapify(nums, 0, heapsize-1);
        heapsize--;
    }
}

你可能感兴趣的:(面试)