1105. 链表合并(25分)

给定两个单链表 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

这个题目所述的链表是给定了地址的,不太好用链表去实现,只能用数组来模拟。

感觉我的做法有点复杂,关键是合并链表的地方,可以参考一下思路,有图。

#include<cstdio>
#include<set>
#include<map>
#include<cmath> 
#include<cstring>
#include<iostream>
#include<algorithm>
#include<iomanip>
using namespace std;

//定义双向链表节点 
struct Node{
	 int pre;
	 int num;
	 int now;	//当前节点地址 
	 int next;
};

void print(Node node);
Node nodes[100005];
Node L1,L2,preNode; 

int main(){
	int head1,head2,N;
	int tail1,tail2; 
	int length1=0,length2=0; 
	int nowAddress=0,nextAddress=0;
	cin>>head1>>head2>>N;	
	int Address,Data,Next;
	
	while(N--){
		cin>>Address>>Data>>Next;
		nodes[Address].num = Data;
		nodes[Address].next = Next;
		nodes[Address].now =  Address; 
		nodes[Next].pre = Address;
	} 
	
	//头结点的前一个为空 
	nodes[head1].pre = -1;
	L1 = nodes[head1];
	//分别从头结点遍历两个链表 计算长度 
	while(L1.next != -1){
		nextAddress = L1.next;
		L1 = nodes[nextAddress];
		length1++;
	}  
	//记录尾节点地址 
	tail1 = nextAddress;
	
	nodes[head2].pre = -1;
	L2 = nodes[head2];
	while(L2.next != -1){
		nextAddress = L2.next;
		L2 = nodes[L2.next];
		length2++;
	}  
	tail2 = nextAddress;
	

	int times = 1;
	int tempL1,tempL2;
	bool end = false;
	
	//如果B链更长,则互换,保证A链始终是最长的 
	if(length2>length1){
		swap(L1,L2); 
		swap(head1,head2); 
		swap(tail1,tail2); 
	} 
	
	L1 = nodes[head1];
	L2 = nodes[tail2];
	while(1){
		//A链表2个节点 且 B 链条还有节点  end说明没节点了 
		if(times==2 && !end){
			//1.记录当前L1的下一个节点,用作下次循环的头节点 
			tempL2 = L2.pre	;
			//2.改变L2指向 
			nodes[L2.now].next = L1.next;
			//3.改变L1指向 
			nodes[L1.now].next = L2.now;
			//判断链表是否已经结束条件 
			if(L2.pre == -1){
				end = true;
			}
			//4.L2向后移1个节点 
			L1 = nodes[L2.now];
			//5.L1向前移1个节点 
			L2 = nodes[tempL2];
			//清空次数 
			times = 0;
		}else{
			//循环结束条件 L1链表结束则结束 
			if(L1.next == -1){
				break;
			}
			L1=nodes[L1.next]; 
			//次数加一 
			times++;
		}
	}	
	//输出
	L1 = nodes[head1]; 
	while(1){
		print(L1); 
		if(L1.next == -1)
			break;
		L1 = nodes[L1.next];
	}
	return 0;
}

//打印 
void print(Node node){
	if(node.next!=-1){
		cout<<setw(5) << setfill('0') <<node.now<<" "<<node.num<<" "<<setw(5) << setfill('0') <<node.next<<endl;
	}
	else{
		cout<<setw(5) << setfill('0') <<node.now<<" "<<node.num<<" "<<node.next<<endl;
	}
}

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

风间琉璃c

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值