算法導論2:幾個習題 2016.1.2

1、在歸併排序中對小數組採用插入排序(放在上一篇裏了);算法

2、冒泡排序編程

   冒泡排序效率幾乎是全部排序裏最低的,但卻很流行,就是由於它的編程複雜度也是最低的。大多數時候,效率還不及插入排序,其實冒泡排序、插入排序、選擇排序基本上效果是差很少的(這個效果不是功能。。功能上講確定差很少啊都是排序),只是過程略有區別。既然寫到這裏,就本身總結一下三者吧。數組

  1.插入排序——摸撲克牌的過程函數

        假定前一個是有序的,把第二個插進它應當在的位置,那麼前兩個就是有序的了,把第三個插進它應當在的位置,那麼前三個就是有序的了……直到前n個有序。這與打撲克摸牌的時候咱們作的事差很少。優化

        時間主要耗費在插入和挪動上了。複雜度n^2。spa

  2.冒泡排序——高矮個自行排隊code

        首先對最後一我的說:「若是你前面的人比你高,你就和他換一下。」(如今倒數第二我的就是後兩我的裏最矮的了)orm

        而後對倒數第二我的說:「若是你前面的人比你高,你就和他換一下。」(如今倒數第三我的就是後三我的裏最矮的了)blog

       而後對倒數第三我的說一樣的話……一輪下來,第一我的就是最矮的那個(其實和選擇排序有點像,不過選擇的方式不太同樣,並且排的過程當中就有讓隊列趨向有序的傾向)排序

       對後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;
}

 

3、霍納規則的正確性
     這是一個求多項式函數的值的方法,看完代碼簡直跪了,居然如此簡潔的完成了這個功能!

    霍納規則是採用最少的乘法運算策略,求多項式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("\n");
    while (1) {
        scanf("%lf",&x);
        printf("A(%.2lf)=%.2lf\n",x,horner(a,n,x));
    }
    return 0;
}


4、逆序對問題

  先是逆序對的定義一個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("\n%d",k);
    return 0;
}
相關文章
相關標籤/搜索