排序(上)

排序(上)

都以从小到大为例

1.冒泡排序:

顾名思义每次比较两个小的那个冒上来,大的那个沉下去。

for(i=0;i<n-1;i++)
{
    for(j=0;j<n-1-i;j++)
    {
        if(a[j]>a[j+1]
        {
            t=a[j];
            a[j]=a[j+1];
            a[j+1]=t;
        }
    }
}

2.插入排序:

先取出未排序序列中的第一个元素,依次与已排序序列中元素比较并右移,直到放进合适的位置。

for(i=0;i<n;i++)
{
    t=a[i];
    for(j=n-1;j>=0&&a[j-1]>t;j--)
    {
        a[j]=a[j-1];
    }
    a[j]=t;
}

3.希尔排序:

这种方法实质上是一种分组插入方法。先取一个小于n的m1作为第一个增量,把数组m1个组。所有距离为m1的倍数的记录放在同一个组中。先在各组内进行直接插入排序;然后,取第二个增量m2<m1重复上述的分组和排序,直至所取的增量m=1(m<m-1<…<m2<m1),即所有记录放在同一组中进行直接插入排序为止 。

for(m=n/2;n>0;m/=2)
{
    for(i=0;i<m;i++)
    {
        for(j=i+m;j<n;j+=m)
        {
            if(a[j]<a[j-m]
            {
                int t=a[j];
                int k=j-m;
                while(k>0&&a[k]>t)
                {
                    a[k+m]=a[k];
                    k-=m;
                }
                a[k+m]=t;
            }
        }
    }
}

4.堆排序:

利用最大堆(或者最小堆)输出堆顶元素,即最大值(或最小值),将剩余元素重新生成最大堆(或者最小堆),继续输出堆顶元素,重复此过程,直到全部元素都已输出,得到的输出元素序列即为有序序列。

//a[]看成一颗完全二叉树
//root当前的父节点位置
//size总节点树
void heapsort(int a[],int root,int size)
{
    if(root<size)//左子树和右字数的位置
    {
        int l=2*root+1;
        int r=2*root+2;
        int max=root;//把当前父节点位置看成是最大的
        if(l<size) //如果比当前根元素要大,记录它的位置
        {
            if(a[max]<a[l])
                max=l;
        }
        if(r<size) //如果比当前根元素要大,记录它的位置
        {
            if(a[max]<a[r])
                max=r;
        }
        if(max!=root)//如果最大的不是根元素位置,那么就交换
        {
            int t=a[max];
            a[max]=a[root];
            a[root]=t;
            heapsort(a[],max,size);//继续比较,直到完成一次建堆
        }
    }
}

 5.归并排序:

采用的叫分治的思想,将数组划分为两个子数组,然后递归将每个子数组再进行划分,直到数组中只剩一下一个元素,然后开始排序合并,直到将所有的子数组合并完成,整个数据就是有序的啦。时间复杂度:NlogN。

思路:先将无序序列利用二分法划分为两个子序列,直至每个子序列只有一个元素,一个元素序列必然有序,然后再对有序子序列两两进行合并排序。合并方法是循环的将两个有序子序列当前的首元素进行比较,较小的元素取出,放入合并序列的左边空置位,直至其中一个子序列的最后一个元素放入合并序列中。最后将另一个子序列的剩余元素按顺序逐个放入合并序列尾部。

long long int c[10000],a[10000];
void  paixu(long long int a[100000],long long int l,long long int mid,long long int r)
{
    long long int i=l,j=mid+1,k=0;
    while(i<=mid&&j<=r)
    {
        if(a[i]<=a[j])
            c[k++]=a[i++];
        else
        {
            c[k++]=a[j++];
        }

    }
    while(i<=mid)
        c[k++]=a[i++];
    while(j<=r)
        c[k++]=a[j++];
    for(i=l;i<=r;i++)
    {
        a[i]=c[i-l];
    }
}
void merge(long long int a[100000],long long int l,long long int r)
{
    long long int mid;
    if(l==r)
        return;

        mid=(l+r)/2;
        merge(a,l,mid);
        merge(a,mid+1,r);
        paixu(a,l,mid,r);
}

4.例题:

求逆序数。

样例

样例输入 Copy

2
2
1 1
3
1 3 2

样例输出 Copy

0
1	

在归并的基础上加上sum即可

代码:

#include<stdio.h>
long long int sum=0;
long long int c[10000],a[10000];
void  paixu(long long int a[],long long int l,long long int mid,long long int r)
{
    int i=l,j=mid+1,k=l;
    while(i<=mid&&j<=r)
    {
        if(a[i]<=a[j])
         c[k++]=a[i++];
        else
        {
            c[k++]=a[j++];
            sum+=mid-i+1;
        }
    }
    while(i<=mid)
        c[k++]=a[i++];
    while(j<=r)
        c[k++]=a[j++];
    for(i=l;i<=r;i++)
    {
        a[i]=c[i];
    }
}
void merge(long long int a[],long long int l,long long int r)
{
    long long int mid;
    if(l<r)
     {
        mid=(l+r)/2;
        merge(a,l,mid);
        merge(a,mid+1,r);
        paixu(a,l,mid,r);
     }

}
int main()
{
    long long int n,i,t;
    scanf("%lld",&t);
    while(t--)
    {
        sum=0;
        scanf("%lld",&n);
        for(i=0;i<n;i++)
    {
        scanf("%lld",&a[i]);
    }
    merge(a,0,n-1);
    printf("%lld\n",sum);
    }
    return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值