题目
编写一个算法,将m(m≥2)个有序(从小到大)顺序表合并成个有序顺序表, 假设所有顺序表存储在一个m行maxSie (maxSize 足够大)列的二维数组lists[m][maxSize]中,要求把1~m-1行所在的顺序表合并在0行所在的顺序表中,各表的长度存储在数组lens[m]中,合并过程中不另设新的顺序表存储空间。
分析
可以将m各顺序表的合并先处理为两个顺序表的合并,参考:将两个有序(非递减有序)顺序表合并成为一个顺序表,合并后的结果放到A[]中不另设新的顺序表存储空间,将lists中的1~m-1行上的顺序表逐个合并到第0行上的顺序表中,返回-1表示合并失败,返回最终表的长度表示成功。
代码
核心代码:
/* 合并A表和B表到A表中 */
int comb(int A[],int &na,int B[],int nb) { // 合并后na发生变化,因此使用引用型
if(na+nb>maxSize) { // 假设maxSize是已经定义好的常量
return -1;
}
int i=na,j=nb;
while(j>0) {
if(i==0||A[i-1]<B[j-1]) {
A[j+i-1]=B[j-1];// 说明B[j-1]是第i+j大的元素
j--;
} else {
A[j+i-1]=A[i-1];// 说明A[i-1]是第i+j大的元素
i--;
}
}
na=na+nb;
return na;
}
/* 合并m各顺序表 */
/* lists[][maxSize]指的是m各顺序表,每一行是一个顺序表;lens[]表示每一个顺序表的长度;m指的是lens数组的长度 */
int combM(int lists[][maxSize],int lens[],int m){
int flag;// 标记是否合并成功
for(int i=1;i<m;i++){
flag=comb(lists[0],lens[0],lists[i],lens[i]);// lens[i]表示第i行表的长度
if(flag==-1){// 发现合并失败跳出循环
break;
}
}
return flag;
}
完整代码:
#include<stdio.h>
#define maxSize 30
/* 打印数组 */
void print(int nums[],int n) {
printf("\n");
for(int i=0; i<n; i++) {
printf("%d\t",nums[i]);
}
printf("\n");
}
/* 合并A表和B表到A表中 */
int comb(int A[],int &na,int B[],int nb) { // 合并后na发生变化,因此使用引用型
if(na+nb>maxSize) { // 假设maxSize是已经定义好的常量
return -1;
}
int i=na,j=nb;
while(j>0) {
if(i==0||A[i-1]<B[j-1]) {
A[j+i-1]=B[j-1];// 说明B[j-1]是第i+j大的元素
j--;
} else {
A[j+i-1]=A[i-1];// 说明A[i-1]是第i+j大的元素
i--;
}
}
na=na+nb;
return na;
}
/* 合并m各顺序表 */
/* lists[][maxSize]指的是m各顺序表,每一行是一个顺序表;lens[]表示每一个顺序表的长度;m指的是lens数组的长度 */
int combM(int lists[][maxSize],int lens[],int m){
int flag;// 标记是否合并成功
for(int i=1;i<m;i++){
flag=comb(lists[0],lens[0],lists[i],lens[i]);// lens[i]表示第i行表的长度
if(flag==-1){// 发现合并失败跳出循环
break;
}
}
return flag;
}
int main() {
int lists[][maxSize]={{1,2,3,4,5,6},{7,8,9},{10,12,15,16},{19},{20,21}};
int lens[]={6,3,4,1,2};
int m=5;
combM(lists,lens,m);
print(lists[0],lens[0]);
return 0;
}
运行结果: