第二章 2.3 設計算法

2.3-1 使用圖2-4作爲模型,說明歸併排序在數組A=<3,41,52,26,38,57,9,49>上得操作。

{3,41}{26,52}{38,57}{9,49}
{3,26,41,52}{9,38,49,57}
{3,9,26,38,41,49,52,57}

2.3-2重寫過程MERGE,使之不使用哨兵,而是一旦數組L或R的所有元素均被複制回A就立刻停止,然後把另一個數組的剩餘部分複製回A

MERGE(A,p,q,r)
    n1=q-p+1
    n2=r-1
    '讓 L[1...n1+1]和 R[1...n2+1] 爲截取的新數組'
    for i=1 to n1
        L[i]=A[p+i-1]
    for j=1 to n2
        R[j]=A[q+j]
    '把兩個數組合併成一個數組'
    i=1
    j=1
    n=min{n1,n2}
    for k=p to n
        if L[i]<=R[j]
            A[k]=L[i]
            i++
        else 
            A[k]=R[j]
            j++

'判斷L數組是否去空,若爲空將R內容移入A'  
    if i==L.length+1
        for k to r
            A[k]=R[j]
            j++
    else if j==R.length+1
         for k to r
            A[k]=l[i]
            i++

2.3-3 用數學歸納法證明:當n剛好是2的冪時,以下遞歸式的解是T(n)=nlgn。

T(n)=(2...........................................n=22Tn/2+n........n=2k,k>1)

解:
當n=2時,T(2)=2………………………………………=2log2 2=2
當n=4時,T(4)=2*2+4=8……………………………..=4*2log2 2=8
當n=8時,T(8)=8*2+8=24……………………………=8*3log2 2=24
.
.
.
當n=2^k時,T(n)=nT(n-1)+n……………………..=nlog2 n=n*k
當n+1=2^(k+1)時,T(n+1)=(n+1)*k+(n+1)………………=(n+1)(k+1)=(n+1)log2 (n+1)
綜上所述,當n剛好是2的冪時,以下遞歸式的解是T(n)=nlgn。

2.3-4 我們可以把插入排序表示爲如下的一個遞歸過程。爲了排序A[1…n],我們遞歸地排序A[1…n-1],然後把A[n]插入已排序的數組A[1…n-1]。爲插入排序的這個遞歸版本的最壞情況運行時間寫一個遞歸式。

// test.cpp : 定義控制檯應用程序的入口點。
//

#include "stdafx.h"
#include<stdlib.h>

//將A[n]插入A[i]位置的函數
void insert(int *A,int i,int n)
{
    int tmp=A[n];
    for(int j=n;j>i;j--)
    {
        A[j]=A[j-1];
    }
    A[i]=tmp;
}

void sort(int *A,int n)
{
    if(n==0)
    {
        return;
    }
    else
    {
        //將A[n-1]排序,
        sort(A,n-1);
        //將A[n]插入A[n-1]中
        for(int i=0;i<n;i++)
        {
            if(A[i]>A[n])
            {
                //將A[n]插入A[i]位置
                insert(A,i,n);
                break;
            }
        }
    }
}

int _tmain(int argc, _TCHAR* argv[])
{
    //傳入一個數組
    int A[]={1,14,8,7,0,10};//測試數組
    int size=(sizeof(A)/sizeof(A[0]));
    sort(A,size-1);
    for(int i=0;i<size;i++)
    {
        printf("%d ",A[i]);
    }
    printf("\n");
    system("pause");
    return 0;
}

2.3-5 回顧查找問題(參見練習2.1-3),注意到,如果序列A已經排好序,就可以將該序列的中點與v進行比較。根據比較結果,原序列中有一般就可以不用再做進一步的考慮了。二分查找算法重複這個過程,每次都將序列剩餘部分的規模減半。爲二分查找寫出迭代或遞歸的僞代碼。證明:二分查找的最壞情況運行時間爲θ(lgn)

1)這裏用可運行代碼代替僞代碼

// test.cpp : 定義控制檯應用程序的入口點。
//

#include "stdafx.h"
#include<stdlib.h>

//將A[n]插入A[i]位置的函數
void insert(int *A,int i,int n)
{
    int tmp=A[n];
    for(int j=n;j>i;j--)
    {
        A[j]=A[j-1];
    }
    A[i]=tmp;
}
//折半查找
int check(int *A,int begin,int end,int tmp)
{
    if(begin==end)
    {
        if(A[begin]>tmp)
        {
            return begin;
        }
        else
        {
            return begin+1;
        }
    }
    else
    {
        if(A[(end-begin)/2]>tmp)
        {
            return check(A,begin,(end+begin)/2-1,tmp);
        }
        else if(A[(end-begin)/2]<tmp)
        {
            return check(A,((end+begin)/2)+1,end,tmp);
        }
        else
        {
            return (end+begin)/2;
        }


    }
}

void sort(int *A,int n)
{
    if(n==0)
    {
        return;
    }
    else
    {
        //將A[n-1]排序,
        sort(A,n-1);

        int i=check(A,0,n-1,A[n]);
        //將A[n]插入A[i]位置
        insert(A,i,n);
    }
}

int _tmain(int argc, _TCHAR* argv[])
{
    //傳入一個數組
    int A[]={1,14,8,7,0,10};
    int size=(sizeof(A)/sizeof(A[0]));
    sort(A,size-1);
    for(int i=0;i<size;i++)
    {
        printf("%d ",A[i]);
    }
    printf("\n");
    system("pause");
    return 0;
}

2)每次查找都要進行除以2操作,當進行log2n 故複雜度爲θ(lgn)。

2.3-6 注意到2.1節中的過程INSERTION-SORT的第5~7行的while循環採用一種線性查找來(反向)掃描已排好序的子數組A[1…j-1]。我們可以使用二分查找(參見習題2.3-5)來把插入排序的最壞情況總運行時間改進到θ(nlgn)嗎?

用上題中的check函數即可。

2.3-7 描述一個運行時間爲θ(nlgn)的算法,給定n個整數的集合S和另一個整數x,該算法能確定S中是否存在兩個其和剛好爲x的元素

描述:(隱含條件,S是有序的)
1)利用折半查找,找到i之前的元素都小於x的位置
2)設兩個指針p,q。p從零向i移動,q由i向0移動。
3)比較A[p]+A[q]是否等於x,如果等於則作爲結果輸出;如果大於x,q–;如果小於x,q++。

發佈了42 篇原創文章 · 獲贊 10 · 訪問量 3萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章