• 算法导论2:几个习题 2016.1.2


    一、在归并排序中对小数组采用插入排序(放在上一篇里了);

    二、冒泡排序

       冒泡排序效率几乎是所有排序里最低的,但却很流行,就是因为它的编程复杂度也是最低的。大多数时候,效率还不及插入排序,其实冒泡排序、插入排序、选择排序基本上效果是差不多的(这个效果不是功能。。功能上讲肯定差不多啊都是排序),只是过程略有区别。既然写到这里,就自己总结一下三者吧。

      1.插入排序——摸扑克牌的过程

            假定前一个是有序的,把第二个插进它应当在的位置,那么前两个就是有序的了,把第三个插进它应当在的位置,那么前三个就是有序的了……直到前n个有序。这与打扑克摸牌的时候我们做的事差不多。

            时间主要耗费在插入和挪动上了。复杂度n^2。

      2.冒泡排序——高矮个自行排队

            首先对最后一个人说:“如果你前面的人比你高,你就和他换一下。”(现在倒数第二个人就是后两个人里最矮的了)

            然后对倒数第二个人说:“如果你前面的人比你高,你就和他换一下。”(现在倒数第三个人就是后三个人里最矮的了)

           然后对倒数第三个人说同样的话……一轮下来,第一个人就是最矮的那个(其实和选择排序有点像,不过选择的方式不太一样,而且排的过程中就有让队列趋向有序的倾向)

           对后n-1个人执行同样的过程……直到对最后2个人执行同样的过程。

           时间主要耗费在交换上。复杂度n^2。

      3.选择排序——老师给排队

           首先,老师从所有人里选一个最矮的,跟第一个人交换位置。然后从后n-1个人里选一个最矮的,跟第二个人交换位置……直到从后一个人里选一个最矮的,放在最后。

           时间主要耗费在选择最值上了。复杂度n^2。(后面会有一个堆排序,就是优化了选择过程,从而实现了nlgn的复杂度)

      可以看出,这三种都是正确的排序算法。下面是冒泡排序的代码:

    #include<stdio.h>
    
    void bubblesort(int *a,int l,int r)
    {
        int i,j;
        for (i=l+1;i<=r;i++) {
            for (j=r;j>=i;j--) {
                if (a[j]<a[j-1]) {
                    int temp=a[j];
                    a[j]=a[j-1];
                    a[j-1]=temp;
                }
            }
        }
    }
    
    int main()
    {
        int n;
        scanf("%d",&n);
        int a[11]={};
        int i;
        for (i=1;i<=n;i++) {
            scanf("%d",&a[i]); 
        }
        bubblesort(a,1,n);
        for (i=1;i<=n;i++) {
            printf("%d |",a[i]);
        }
        return 0;
    }

    三、霍纳规则的正确性
         这是一个求多项式函数的值的方法,看完代码简直跪了,竟然如此简洁的完成了这个功能!

        霍纳规则是采用最少的乘法运算策略,求多项式A(x) = anxn+ an-1xn-1+...+ a1x + a0在x0处的值,该规则是A(x0)=(...((anx0+ an-1)x0+...+ a1)x0+ a0)

        下面是实现的代码:

    #include<stdio.h>
    
    double horner(double *a,int n,double x)
    {
        double y=0;
        int i;
        for (i=n;i>=0;i--) {
            y=a[i]+x*y;
        }
        return y;
    }
    
    int main()
    {
        int n;
        int i;
        double x;
        scanf("%d",&n);
        double a[11]={};
        for (i=0;i<=n;i++) {
            scanf("%lf",&a[i]);
        }
        printf("A(x)=");
        printf("%.2lf",a[0]);
        for (i=1;i<=n;i++) {
            printf("+%.2lfx^%d",a[i],i);
        }
        printf("
    ");
        while (1) {
            scanf("%lf",&x);
            printf("A(%.2lf)=%.2lf
    ",x,horner(a,n,x));
        }
        return 0;
    }


    四、逆序对问题

      先是逆序对的定义一个n个互异元素的数组a,求满足i<j时a[i]>a[j]条件的数对个数。

      输入:n(元素个数),a数组  输出:逆序对个数

       很容易想到就是逐个比较的n^2的算法,但是算法导论上引导出了nlgn的算法。(修改归并排序)

        首先,如果一个数组的已经知道了,前半部分内部的逆序对的个数k1,后半部分的逆序对的个数k2,并且两部分都已经由小到大排好序了。那么在merge的过程中就可以顺便把两部分之间的逆序对个数k求出来(因为前半部分比后半部分大的数一定是个逆序对)。那么总的逆序对的个数就是k1+k2+k。

        那么,怎么求出前半部分逆序对的个数呢?同样的方法,求出前半部分,后半部分,两部分之间。return和。所以就是一个递归的问题,只需要修改一下归并排序即可。

    下面是代码:

    #include<stdio.h>
    
    int mergenixu(int *a,int *b,int l,int mid,int r)
    {
        int k=0;
        int i=l,j=mid+1;
        int cou=l;
        while (i<=mid && j<=r) {
            if (a[i]<=a[j]) {
                b[cou]=a[i];
                i++;
                cou++;
            }
            else {
                b[cou]=a[j];
                k+=mid-i+1;
                j++;
                cou++;
            }
        }
        while (i<=mid) {
            b[cou]=a[i];
            i++;
            cou++;
        }
        while (j<=r) {
            b[cou]=a[j];
            j++;
            cou++;
        }
        for (i=l;i<=r;i++) {
            a[i]=b[i];
        }
        return k;
    }
    
    int mergesortnixu(int *a,int *b,int l,int r)
    {
        if (r-l<1) return 0;
        int mid=(l+r)/2;
        int k1=mergesortnixu(a,b,l,mid);
        int k2=mergesortnixu(a,b,mid+1,r);
        int k=mergenixu(a,b,l,mid,r);
        return (k1+k2+k);
    }
    
    int main()
    {
        int n;
        int a[11]={},b[11]={};
        scanf("%d",&n);
        int i;
        for (i=1;i<=n;i++) {
            scanf("%d",&a[i]);
        }
        int k=mergesortnixu(a,b,1,n);
        for (i=1;i<=n;i++) {
            printf("%d |",a[i]);
        }
        printf("
    %d",k);
        return 0;
    }
  • 相关阅读:
    HDU-5514 Frogs 容斥
    2019ICPC EC-FINAL H-King 随机
    2019ICPC EC-FINAL E-Flow 贪心
    洛谷P4200 千山鸟飞绝 Splay
    CodeForces 1249F Maximum Weight Subset 树形dp
    HDU-5534 Partial Tree 完全背包优化
    【数论】Lucas定理
    [APIO2009]抢掠计划 解题报告
    tarjan(缩点)
    树状数组总结
  • 原文地址:https://www.cnblogs.com/itlqs/p/5095009.html
Copyright © 2020-2023  润新知