算法导论第六章6.5有限队列中的6.5-9课后练习

由题目提示知,需要用到归并排序,又要用到最小堆,那么我想到用含有最小堆排序的归并排序对k个有序数组进行合并因为链表可以看成特殊的动态数组,那么我把链表替换成数组求解。先把k个数组放入到一个新数组A中,那么一共就有k=n/a个数组(a为k个元素数组中所含最多元素的数量)

#include <iostream>
using namespace std;
const length=100;
int LEFT(int i);
int RIGHT(int i);
void MIN_HEAPIFY(int A[],int i);
void BUILD_MIN_HEAP(int A[],int p,int q);
int*  HEAPSORT(int A[],int B[],int p,int q,int r);
void MERGE(int A[],int p,int q,int r);
void MERGE_SORT(int A[],int p,int r,int k);
int heap_size=length,a=4;
void main()
{
    int B[8][4]={{8,16,19},{1,9},{2,10,17,20},{3,11},{4,12},{5,13},{6,14,18},{7,15}};//这是k=8个数组在一个2维数组中
    int A[length]={0};
    for(int i=0,h=0;i<8;i++)//将k=8个数组合并到一个新数组中。
    {
        for (int j=0;j<4;j++,h++)
        {
            if(B[i][j]!=0) A[h]=B[i][j];
        }
    }//这个双重循环含k*a=n个元素 运行时间为O(n)
    MERGE_SORT(A,0,length-1,a);//然后将新数组每a=4个有序数进行归并,注意a值的选择 2<=a<=√总元素n (注释1)
    cout<<"排序后:"<<endl;
    for (  i=0;i<length;i++)
    {
         if(A[i]>0)
         cout<<A[i]<<" ";
    }
    cout<<endl;  
}
int LEFT(int i)
{
    return 2*i+1;
}
int RIGHT(int i)
{
    return 2*i+2;
}
void MIN_HEAPIFY(int A[],int i)
{
    int largest=0;
    int L=LEFT(i);
    int R=RIGHT(i);
    if (L<heap_size&&A[L]<A[i])
    {
        largest=L;
    }
    else largest=i;
    if (R<heap_size&&A[R]<A[largest])
    {
        largest=R;
    }
    if (largest!=i)
    {
        swap(A[i],A[largest]);
        MIN_HEAPIFY(A,largest);
    }
}
void BUILD_MIN_HEAP(int A[],int p,int q)
{
    heap_size=q;
    for (int i=q/2;i>=p;i--)
    {
        MIN_HEAPIFY(A,i);
    }
}
int* HEAPSORT(int A[],int B[],int p,int q,int r)
{
    for (int i=p,j=0;i<=q,j<r;i++,j++)
    {
        B[j]=A[i];
    }
    BUILD_MIN_HEAP(B,0,r);
    for ( i=r-1;i>=1;i--)
    {
        swap(B[0],B[i]);
        heap_size--;
        MIN_HEAPIFY(B,0);
    }
    return B;
}
void MERGE(int A[],int p,int q,int r)
{
    int n1=q-p+1,n2=r-q,i,j,flag=-1;
    int *L=new int[n1];
    int *R=new int[n2];
    L=HEAPSORT(A,L,p,q,n1);//归并时,用最小堆排序 
    R=HEAPSORT(A,R,q+1,r,n2);
    i=0;j=0;
    L[n1]=flag;
    R[n2]=flag;
    for (int k=p;k<=r;k++)
    {
        if (L[i]==flag)
        {
            A[k]=R[j];
            j++;
        }
        else if (R[j]==flag)
        {
            A[k]=L[i];
            i++;
        }
        else if (L[i]>=R[j])
        {
            A[k]=L[i];
            i++;
        }
        else 
        {
            A[k]=R[j];
            j++;
        }
    }
}
void MERGE_SORT(int A[],int p,int r,int k)
{
    int q=(r+p)/k;
    if((q-p+1)<k)    
    {             
       return;
    } 
    else
    {
        MERGE_SORT(A,p,q,k); 
        MERGE_SORT(A,q+1,r,k);
        MERGE(A,p,q,r);
    }
}

注释1:详情见这个是带有插入排序的归并算法(此链接里面的k元素长度值相当于这里的a元素长度值)也就是每个有序数组(共k个)含有有效元素的长度不能大于总元素的开方,这是能够正确进行归并排序的先决条件。这个归并排序,运行时间为O(nlgn),没有到达O(nlgk),实在想不出如何缩短运行时间的方法了。


 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
算法导论第16章16.2-5题目描述: 证明:在所有的用于求解单源最短路径问题的算法,Bellman-Ford算法是唯一一个能够处理权值可以是负数的图的算法。 证明如下: 首先,给定一个图G和一个源节点s,我们假设该图G存在至少一条从源节点s到另一个节点v的路径,使得该路径上至少有一条边的权值为负数。我们的任务是要找到一条从源节点s到节点v的最短路径。 考虑Bellman-Ford算法的实现过程。该算法通过迭代更新每个节点的松弛值来找到最短路径。在算法的每一次迭代,我们对所有的边进行一次松弛操作。如果图存在一条从源节点s到节点v的最短路径,那么这条路径上的所有边都会被松弛,且最终计算出的节点v的最短路径长度将会是这条最短路径的长度。 现在我们考虑一种情况:假设在算法的第k次迭代,我们已经找到了从源节点s到节点v的长度为k的最短路径。此时考虑该最短路径的最后一条边(u,v),且该边的权值为负数。由于在Bellman-Ford算法,我们是对所有边进行松弛操作的,因此在第k+1次迭代,我们一定会通过这条边(u,v)来进行松弛操作。此时,由于(u,v)的权值为负数,因此算法将会通过这条边来缩短v的距离值,使得v的距离值变成小于k的某个值。这就意味着我们找到了一条从源节点s到v的更短的路径,与假设矛盾。 因此,我们得出结论:在所有的用于求解单源最短路径问题的算法,Bellman-Ford算法是唯一一个能够处理权值可以是负数的图的算法。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值