排序

1 篇文章 0 订阅
1 篇文章 0 订阅

快排

快排基础是在一个序列中选一个基准数x,把小于x的数放左边,其余放右边。然后分别对左右两边序列做该操作,直到序列是有序的(序列只有一个数时肯定有序)。

void quick_sort(int l,int r)
{
    if (l >= r) return;
    int i=l,j=r, key = a[l];
    while (i < j)
    {
        while (i < j && a[j]>=key) j--;
        a[i] = a[j];
        while (i < j && a[i]<=key) i++;
        a[j] = a[i];        
    }
    a[i] = key;// 关键在于key的最后位置
    quick_sort(l,i-1);
    quick_sort(i+1,r);
}

而非递归快排就是模拟栈的过程

void w_qsort(int l, int r) {
    stack<int> s;
    s.push(l);
    s.push(r);
    while(!s.empty()) {
        int L,R,i,j,key;
        j = R = s.top();
        s.pop();
        i = L = s.top();
        s.pop();
        if (L >= R) continue;
        key = a[L];
        while (i < j) {
            while (i<j && a[j] >= key) j--;
            a[i] = a[j];
            while (i<j && a[i] <= key) i++;
            a[j] = a[i];
        }
        a[i] = key;
        s.push(L);
        s.push(i-1);
        s.push(i+1);
        s.push(R);
    }
}

快排优化待续吧

归并排序

归并排序基础是把一个序列划分为有序的子序列,然后把相邻的子序列不断合并为新的有序序列。

void merge_sort(int left,int right)
{

    if (left>=right) return;
    int mid = (left+right)>>1;
    merge_sort(left,mid);//mid,和mid-1的区别
    merge_sort(mid+1,right);
    int i=left,j=mid+1,k=left;
    while (i<=mid || j<=right)//两个list并到一起i<=mid 对左边的list|| j<=right对右边的list
    {
        if (i<=mid)//对左边的list
        {
            if (j<=right)//对右边的list
            {
                if (a[i]<a[j])//把小的数放到前面存到tmp里
                    tmp[k++]=a[i++];
                else tmp[k++]=a[j++];
            }
            else tmp[k++] = a[i++];//j指针已指到right,,,只需把i到mid之间的数放到tmp里
        }
        else tmp[k++] = a[j++];//i指针已经知道left,,只需把j到right的数放到tmp里
    }
    for (k=left; k<=right; k++)//把tmp赋回a
        a[k]=tmp[k];
}

非递归归并排序是自底向上合并,省去分裂过程

// merge_sort(): 非递归实现-自底向上
// 将原数组划分为left[min...max] 和 right[min...max]两部分
//这里r-l为数组长,所以l=0,r=n
void wmerge_sort(int *a, int *b, int l, int r) {
    int i,lmin,lmax,rmin,rmax,cnt;
    for (i = 1; i<(r-l); i*=2) {            // i为步长,1,2,4,8……
        for (lmin = l; lmin <(r-l-i); lmin = rmax) {
            rmin = lmax = lmin + i;         //注意rmin,lmax边界
            rmax = min(rmin + i, (r-l));    //由于lmin<(r-l-i), lmax不可能越界,但要注意rmax
            cnt = 0;
            while (lmin < lmax && rmin < rmax)
                b[cnt++] = a[lmin] > a[rmin] ? a[rmin++] : a[lmin++];   //这里和递归写法有些区别
                                                                        //当左区间有部分[k..lmax)不大于右区间时,这时lmin==lmax,rmin<rmax,
                                                                        //因为此时[k+i..rmax)是最大有序的,没必要动
            while (lmin < lmax)                                         //而当左区间有部分[k..lmax)不小于右区间时,此时lmin<lmax,rmin==rmax
                a[--rmin] = a[--lmax];                                  //直接把左区间的[k..lmax)放到右区间最后
            while (cnt > 0) a[--rmin] = b[--cnt];                       //最后把cnt放到[lmin,rmax)的前cnt个即可
        }
    }
}

堆排序

设定,对一个序列a[],对于第i个数有:2*i+1为左儿子,2*i+2为右儿子。这样就可以构建一个二叉树并且是一个满二叉树。对于大顶堆,每个节点的值都不小于左右儿子的值,基于此可构建一个大顶堆。首先从非叶子节点开始构建堆,之后交换堆顶堆尾,对除堆尾外的n-1个元素再次调整堆直到堆只剩下1元素,出来结果就是升序。小顶堆则相反

void adjust_heap(int *a, int k, int n) {
    int tmp = a[k];
    for (int i=((k<<1)+1); i<n; i=(i<<1)+1) {
        if (i+1 < n && a[i+1] > a[i]) i++;  //节点的值都不小于左右儿子的值
        if (a[i] > tmp) {
            a[k] = a[i];
            k = i;
        }
        else break;
    }
    a[k] = tmp;
}

void head_sort(int *a, int n) {
    for (int i=((n>>1)-1); i>=0; i--)
        adjust_heap(a, i, n);
    for (int i=(n-1); i>0; i--) {
        int tmp = a[0];
        a[0] = a[i];
        a[i] = tmp;
        adjust_heap(a, 0, i);
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值