7-51 兩個有序鏈表序列的合併(20 分)
已知兩個非降序鏈表序列S1與S2,設計函數構造出S1與S2的並集新非降序鏈表S3。
輸入格式:
輸入分兩行,分別在每行給出由若干個正整數構成的非降序序列,用−1表示序列的結尾(−1不屬於這個序列)。數字用空格間隔。
輸出格式:
在一行中輸出合併後新的非降序鏈表,數字間用空格分開,結尾不能有多餘空格;若新鏈表爲空,輸出NULL
。
輸入樣例:
1 3 5 -1
2 4 6 8 10 -1
輸出樣例:
1 2 3 4 5 6 8 10
這個題看完後給人的感覺就是用鏈表硬解比較麻煩,事實上也是代碼冗長,操作複雜,但是實用性較強,可以通過所有測試點,獲得滿分,下面是c語言下的鏈表解法
#include "stdio.h"
#include<stdlib.h>
typedef struct Node
{
int data;
struct Node *next;
}Node, *linkList;
void InitList(linkList *L)
{
(*L) = (linkList)malloc(sizeof(Node));
(*L)->next = NULL;
}
void creat(linkList L)
{
Node *s, *r = L;
int num, flag = 1;
while(flag)
{
scanf("%d", &num);
if(num >= 0) //num
{
s = (linkList)malloc(sizeof(Node));
s->data = num;
r->next = s;
r = r->next;
}
else
{
flag = 0;
r->next = NULL;
}
}
}
void print(Node * L)
{
Node * t = L->next;
int firstNum = 1;
if(t == NULL) printf("NULL\n");
while(t != NULL)
{
if(firstNum)
{
printf("%d", t->data);
firstNum = 0;
}
else
printf(" %d", t->data);
t = t->next;
}
}
void sort(Node *L1, Node *L2, Node *L3)
{
Node *s1 = L1->next, *s2 = L2->next;
Node *r = L3;
while(s1 != NULL && s2 != NULL)
{
if(s1->data < s2->data)
{
r->next = s1;
r = r->next;
s1 = s1->next;
}
else
{
r->next = s2;
r = r->next;
s2 = s2->next;
}
}
if(s1 != NULL)
r->next = s1;
else
r->next = s2;
// return s3;
}
int main(int argc, char const *argv[])
{
Node *L1, *L2, *L3;
InitList(&L1);
InitList(&L2);
InitList(&L3);
creat(L1);
creat(L2);
sort(L1, L2, L3);
print(L3);
return 0;
}
這段代碼是網上摘下來的,自己之前寫過類似的,但不完全一樣
下面是測試結果
2018/3/20 12:12:42 | 答案正確 | 20 | 7-51 | C (gcc) | 481 ms |
測試點 | 結果 | 耗時 | 內存 |
---|---|---|---|
0 | 答案正確 | 1 ms | 128KB |
1 | 答案正確 | 1 ms | 132KB |
2 | 答案正確 | 2 ms | 132KB |
3 | 答案正確 | 481 ms | 38648KB |
這個題目簡單粗暴的方法就是兩個數組模擬鏈表,然後c++sort排序
#include<bits/stdc++.h>
using namespace std;
int main()//有重複元素版
{
int a[10000];
int b[10000];
int t,s,n1=0,n2=0;
scanf("%d",&t);
int i=0;
while(t!=-1)
{
a[i]=t;
i++;
n1=i;
scanf("%d",&t);
}
getchar();
scanf("%d",&s);
int j=0;
while(s!=-1)
{
b[j]=s;
j++;
n2=j;
scanf("%d",&s);
}
if(n1+n2!=0)
{
for(i=0;i<n2;i++)
{
a[n1+i]=b[i];
}
sort(a,a+n1+n2);
for(i=0;i<n1+n2;i++)
{
if(i==n1+n2-1)
{
printf("%d",a[i]);
}
else
printf("%d ",a[i]);
}
}
else
printf("NULL");
}
測試結果如下
0 | 答案正確 | 2 ms | 256KB |
1 | 答案正確 | 2 ms | 256KB |
2 | 答案正確 | 2 ms | 248KB |
3 | 段錯誤 | 6 ms | 352KB |
第四個測試點有錯,現在仍未找到問題
我找改程序測試點的時候衍生出了第二個版本,即兩鏈表和並後無重複元素的版本,雖然背離的不明確的題意但是誤打誤撞發現了一個新的c++函數unique(a,a+n1+n2)可以去除數組中的重複元素,實際上並沒有刪除,而是移動到了數組最後的位置
下面是代碼
#include<bits/stdc++.h>
//#include<ctype.h>
using namespace std;
int main()
{
int a[10000];
int b[10000];
int t,s,n1=0,n2=0;
scanf("%d",&t);
int i=0;
while(t!=-1)
{
a[i]=t;
i++;
n1=i;
scanf("%d",&t);
}
getchar();
scanf("%d",&s);
int j=0;
while(s!=-1)
{
b[j]=s;
j++;
n2=j;
scanf("%d",&s);
}
for(i=0;i<n2;i++)
{
a[n1+i]=b[i];
}
if(n1+n2!=0)
{
sort(a,a+n1+n2);//將整形數組按非遞減排序
unique(a,a+n1+n2);//除去數組中重複的元素
int N=0;//用作計數器
for(i=0;i<n1+n2;i++)
{
if(isalnum(a[i]%10+'0')&&a[i]>a[i-1])//調用isalnum()函數判斷該字符的ascii碼是不是字母或數字,整形值必須加上'0'
{
N++;
}
else
break;
}
for(i=0;i<N;i++)
{
if(i==N-1)
{
printf("%d",a[i]);//按要求輸出,結尾不帶空格
}
else
printf("%d ",a[i]);
}
}
else
printf("NULL");
}
測試的結果
0 | 答案正確 | 2 ms | 248KB |
1 | 答案錯誤 | 2 ms | 256KB |
2 | 答案正確 | 2 ms | 384KB |
3 | 段錯誤 | 6 ms | 248KB |