由题目提示知,需要用到归并排序,又要用到最小堆,那么我想到用含有最小堆排序的归并排序对k个有序数组进行合并因为链表可以看成特殊的动态数组,那么我把链表替换成数组求解。先把k个数组放入到一个新数组A中,那么一共就有k=n/a个数组(a为k个元素数组中所含最多元素的数量)
- <span style="font-size:18px;">#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 <strong><em><u>(注释1)</u></em></strong>
- 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),实在想不出如何缩短运行时间的方法了。