给定两个单链表 L1=a1→a2→⋯→an−1→an 和 L2=b1→b2→⋯→bm−1→bm。如果 n≥2m,你的任务是将比较短的那个链表逆序,然后将之并入比较长的那个链表,得到一个形如 a1→a2→bm→a3→a4→bm−1⋯ 的结果。例如给定两个链表分别为 6→7 和 1→2→3→4→5,你应该输出 1→2→7→3→4→6→5。
输入格式:
输入首先在第一行中给出两个链表 L1 和 L2 的头结点的地址,以及正整数
N (≤105),即给定的结点总数。一个结点的地址是一个 5 位数的非负整数,空地址 NULL 用 -1
表示。
随后 N 行,每行按以下格式给出一个结点的信息:
Address Data Next
其中 Address
是结点的地址,Data
是不超过 105 的正整数,Next
是下一个结点的地址。题目保证没有空链表,并且较长的链表至少是较短链表的两倍长。
输出格式:
按顺序输出结果链表,每个结点占一行,格式与输入相同。
输入样例:
00100 01000 7
02233 2 34891
00100 6 00001
34891 3 10086
01000 1 02233
00033 5 -1
10086 4 00033
00001 7 -1
输出样例:
01000 1 02233
02233 2 00001
00001 7 34891
34891 3 10086
10086 4 00100
00100 6 00033
00033 5 -1
解题思路:
唉……翻了好多次车,全都在merge函数里。现在回过头看翻车的原因也不复杂,两个链表有一个走完了之后及时结束合并就可以了。还好其他部分比较顺利,总算是完成了。
#include <stdio.h>
#include <stdlib.h>
#define MAXN 100000
typedef struct node *PtrN;
struct node {
int address, data, link;
PtrN next;
};
typedef PtrN List;
typedef enum { false, true } bool;
int GetLength(List l) {
int cnt;
for ( cnt=0; l; ++cnt, l=l->next);
return cnt;
}
List Reverse(List l) {
if ( !l || !l->next ) return l;
PtrN p1, p2, p3;
p1 = l; p2 = l->next; p3 = p2->next;
p1->next = NULL;
p1->link = -1;
while ( p3 ) {
p2->next = p1;
p2->link = p1->address;
p1 = p2; p2 = p3; p3 = p3->next;
}
p2->next = p1;
p2->link = p1->address;
l = p1 = NULL; /* 内存清零 */
return p2;
}
/* 在p的后面插入node */
bool AfterInsert(PtrN p, PtrN node) {
if ( p && node ) {
node->next = p->next;
node->link = p->link;
p->next = node;
p->link = node->address;
return true;
} else {
return false;
}
}
/* 合并链表,b是短的那个 */
void Merge(List a, List b) {
PtrN pa1, pa2, pb1, pb2;
pa1 = pa2 = a; pb2 = b;
while ( pa2 && pa2->next ) {
pa1 = pa2->next;
pa2 = pa1->next;
pb1 = pb2;
pb2 = pb2->next;
if ( !AfterInsert(pa1, pb1) || !pb2 )
break;
}
}
List BuildList(int head, int temp[][MAXN]) {
if ( head == -1 ) return NULL;
List l, p, tmp;
l = (List)malloc(sizeof(struct node));
l->address = head;
l->data = temp[0][head];
l->link = temp[1][head];
p = l;
while ( p->link != -1 ) {
tmp = (List)malloc(sizeof(struct node));
tmp->address = p->link;
tmp->data = temp[0][tmp->address];
tmp->link = temp[1][tmp->address];
p->next = tmp;
p = p->next;
}
p->next = NULL;
return l;
}
void PrintList(List l) {
if ( !l ) return;
while ( l->next ) {
printf("%05d %d %05d\n", l->address, l->data, l->link);
l = l->next;
}
printf("%05d %d -1\n", l->address, l->data);
}
int main(int argc, const char *argv[]) {
int N, h1, h2, addr, data, link, length1, length2;
int temp[2][MAXN];
if ( scanf("%d %d %d", &h1, &h2, &N)==EOF ) printf("error\n");
while ( N-- ) {
if ( scanf("%d %d %d", &addr, &data, &link)==EOF ) printf("error\n");
temp[0][addr] = data;
temp[1][addr] = link;
}
List l1 = BuildList(h1, temp);
List l2 = BuildList(h2, temp);
length1 = GetLength(l1);
length2 = GetLength(l2);
if ( length1 >= length2 * 2 ) {
l2 = Reverse(l2);
Merge(l1, l2);
PrintList(l1);
} else if ( length1 * 2 <= length2 ) {
l1 = Reverse(l1);
Merge(l2, l1);
PrintList(l2);
}
return EXIT_SUCCESS;
}