C++基础算法之排序

一、排序

1.快速排序

基本思想

分治

基本思路

  1. 确定分界点(任意一个数都可以);
  2. 调整数字位置使得x左边的值均小于等于x,右边的值均大于等于x;
  3. 递归处理左右两个子序列。

源代码

#include <iostream>
using namespace std;
void quickSort(int q[], int l, int r)
{
    if(l >= r) return;//数组长度为1则直接返回

    int x = q[(l+r) >> 1];//取数组q的中间值
    int i = l - 1, j = r + 1;
    //定义两个指针,i指向数列q的最左边,j指向数列q的最右边
    while(i < j)//i与j相遇或者互相穿过时结束
    {
        do i ++; while(q[i] < x);//保证x左边的数都是小于x的
        do j --; while(q[j] > x);//保证x右边的数都是大于x的
        if(i < j)//此时i可能大于等于j
        swap(q[i], q[j]);//交换i指向的数字与j指向的数字的位置
    }

    quickSort(q, l, j);//递归处理左边的数组,注意边界值
    quickSort(q, j + 1, r);//递归处理右边的数组,注意边界值
}

注意事项

1.第一次调用quickSort时,q为待排序数组,l为0,r为数组最后一个元素的下标。
2.第7行这么做的原因是第11行和第12行会先做一次i++和j--,抵消掉这一次移动。
3.第34行和第35行的递归使用一定要格外注意边界值!
4.第7行为数组q中间的元素的值。

2.归并排序

基本思想

分治

基本思路

  1. 确定分界点,一定是中间下标mid;
  2. 递归排序左右两个数组;
  3. 归并——合二为一。

源代码

#include <iostream>
using namespace std;
void mergeSort(int q[], int l ,int r)
{
    if(l >= r) return;//数组长度为1则直接返回

    int mid = l + r >> 1;//取中间值下标
    int tmp[N] = 0;//tmp为辅助数组,存储最终答案,N根据题目而定

    mergeSort(q, l, mid);//归并
    mergeSort(q, mid+1, r);//归并

    int k = 0, i = l, j = mid + 1;
    //k指向数组tmp,i指向左边数组第一个元素,j指向右边数组第一个元素
    while(i <= mid && j <= r)//遍历数组,i,j其中一个到达最后一个元素时停止
    {
        if(q[i] <= q[j]) tmp[k++] = q[i++];//将较小者依次放入k
        else tmp[k++] = q[j++];
    }
    //一个数组遍历完后,另一个数组剩下的元素直接接到后面
    while(i <= mid) tmp[k++] = q[i++];
    while(j <= r) tmp[k++] = q[j++];

    for(i = l, j = 0; i <= r; i++, j++)//把答案复制给数组q
    q[i] = tmp[j];
}
注意事项
1.第一次调用mergeSort时,q为待排序数组,l为0,r为数组最后一个元素的下标。
2.第13行注意k,i,j的初始值,第15行注意判定条件。
3.第10行和第11行一定要格外注意边界值!
4.第7行为数组中间的下标值。

3.快速选择

基本思想

在快速排序的算法上稍作修改

基本思路

  1. 同快速排序;
  2. 递归时只递归答案可能位于的子区间.

源代码

#include <iostream>
using namespace std;
//输入一串数字,求第k小的数
const int N = 1e5 + 10;
int q[N];

int quickSelect(int l, int r, int q[],int k)//直接返回答案
{
    if(l>=r) return q[l];
    int x = q[(l + r) >> 1];
    int i = l-1, j = r+1;
    while(i<j)
    {
        do i++; while(q[i] < x);
        do j--; while(q[j] > x);
        if(i<j)
        swap(q[i], q[j]);
    }
    
    if(j - l + 1 >= k) return quickSelect(l, j, q, k);//递归左区间
    else return quickSelect(j+1, r, q, k-(j-l+1));//递归右区间
}

int main(void)
{
    int n,k;
    scanf("%d%d",&n,&k);
    for(int i = 0;i < n; i++) scanf("%d", &q[i]);
    cout << quickSelect(0,n-1,q,k);//直接打印答案
    return 0;
}

注意事项

1.第20行为判断左区间长度是否大于等于k,如果成立,则答案就在左区间。
2.第21行要注意递归右区间时k值的变化。

仅供参考学习。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值