Bootstrap

两个有序链表序列的合并(附加代码模式)

题目描述:

将两个链表表示的递增整数序列合并为一个非递减的整数序列

本题是附加代码模式,主函数main的代码会自动附加在同学们提交的代码后面,请同学们在提交的时候注释掉自己的main函数。
main函数代码如下:

int main()
{
	int m,n;
	cin>>m>>n;
	List listA,listB;
	
	InitList(listA);//初始化单链表
	InitList(listB);
	
	for(int i=0;i<m;i++)
	{
		int v;
		cin>>v;
		AddNode(listA,v);
	}
	
	for(int i=0;i<n;i++)
	{
		int v;
		cin>>v;
		AddNode(listB,v);//在单链表尾添加节点
	}
	
	List listC=MergeList(listA,listB);//合并单链表
	
	PrintfList(listC);
	
	DestroyList(listA);
	DestroyList(listB);
	DestroyList(listC);//销毁单链表
}

1.定义链表

struct Node{
	int Date;
	struct Node* next; 
}; 
 
typedef struct Node* List;

//用头指针代表一整个链表

2.初始化单链表函数

void InitList(List &headNode)
{
	headNode=(List)malloc(sizeof(Node));
	headNode -> next = NULL;
}

注意:
1.链表初始化,动态分配内存
2.注意这里的结构体指针的引用,要把原结构体指针引用过来
这里的引用很重要,不进行引用就无法把主函数里的链表头同时初始化

3.尾插函数

void AddNode(List Lists,int date)
{
	List NewNode = (List)malloc(sizeof(Node));
	
	List p=Lists;
	
	while(p -> next!=NULL)
	{
		p = p -> next;
	}
	p -> next = NewNode; 
	NewNode -> Date = date;
	NewNode -> next = NULL;
}

注意:因为要用链表头代表一整个链表,链表头不能动,所以用一个结构体指针变量找到最后一个节点,把新结点放到最后一个节点后面,并赋值;
4.合并函数

List ListC=(List)malloc(sizeof(Node)),tail;//建立一个头指针代表新链表和尾指针 
	ListC -> next = NULL;
	tail=ListC;//尾指针一开始在头指针的位置
	
	while(ListA -> next&&ListB -> next)
	{
		int date1=ListA -> next -> Date;
		int date2=ListB -> next -> Date;
		
		if(date1<date2)
		{
			tail -> next = ListA ->next;
			ListA -> next = ListA -> next -> next;//每次从链表上摘除一个元素放到新链表上去
			tail = tail -> next;
			tail -> next = NULL;//尾指针后移
		}
		else
		{
			tail -> next = ListB ->next;
			ListB -> next = ListB -> next -> next;
			tail = tail -> next;
			tail -> next = NULL;	
		}
	}//先把其中一个处理完 
	
	
	if(ListA -> next)
	{
		tail -> next = ListA -> next;
		ListA -> next = NULL;	
	}
	
	if(ListB -> next)
	{
		tail -> next = ListB -> next;
		ListB -> next = NULL;	
	}//把没处理的部分直接接到新链表上去
		
	return ListC;//返回 ListC 而不是返回 tail 要返回头指针	

注意:在这里 ListC 是头指针代表整个新链表,tail指针是尾指针不断后移把数据放到新链表里去,最后函数返回的一定是头指针
两个链表都是有序的,先处理完一个以后,另一个链表剩下的元素直接接到新链表之后就可;
注意每次处理完之后要给尾指针赋空

5.销毁函数:

void DestroyList(List &Lists)
{
	List p1;
	while(Lists)
	{
		p1=Lists -> next;
		free(Lists);
		Lists = p1;
	}
}

注意:这里也要 引用链表 一定要加引用符号,一个头指针,一个中间指针,一个一个逐个释放空间即销毁完成;

总函数:

#include<bits/stdc++.h> 
using namespace std;

struct Node{
	int Date;
	struct Node* next; 
}; 

//用头指针代表一整个链表 

typedef struct Node* List;        

void InitList(List &headNode)
{
	headNode=(List)malloc(sizeof(Node));
	headNode -> next = NULL;
}//链表初始化,动态分配内存     //注意这里的结构体指针的引用,要把原结构体指针引用过来 

void AddNode(List Lists,int date)
{
	List NewNode = (List)malloc(sizeof(Node));
	
	List p=Lists;
	
	while(p -> next!=NULL)
	{
		p = p -> next;
	}
	p -> next = NewNode; 
	NewNode -> Date = date;
	NewNode -> next = NULL;
}//找到最后一个节点,把新结点放到最后一个节点后面,并赋值 

void PrintfList(List Lists)
{
	List p=Lists -> next;
	
	while(p!=NULL)
	{
		cout<<p->Date<<" ";
		p = p->next;
	}
}//一个一个打印所有节点 

void DestroyList(List &Lists)
{
	List p1;
	while(Lists)
	{
		p1=Lists -> next;
		free(Lists);
		Lists = p1;
	}
}

List MergeList(List ListA,List ListB)//合并 
{
	List ListC=(List)malloc(sizeof(Node)),tail;//建立一个头指针代表新链表和尾指针 
	ListC -> next = NULL;
	tail=ListC;
	
	while(ListA -> next&&ListB -> next)
	{
		int date1=ListA -> next -> Date;
		int date2=ListB -> next -> Date;
		
		if(date1<date2)
		{
			tail -> next = ListA ->next;
			ListA -> next = ListA -> next -> next;
			tail = tail -> next;
			tail -> next = NULL;
		}
		else
		{
			tail -> next = ListB ->next;
			ListB -> next = ListB -> next -> next;
			tail = tail -> next;
			tail -> next = NULL;	
		}
	}//先把其中一个处理完 
	
	
	if(ListA -> next)
	{
		tail -> next = ListA -> next;
		ListA -> next = NULL;	
	}
	
	if(ListB -> next)
	{
		tail -> next = ListB -> next;
		ListB -> next = NULL;	
	}
		
	return ListC;//返回 ListC 而不是返回 tail 要返回头指针		
}

int main()
{
	int m,n;
	cin>>m>>n;
	List listA,listB;
	
	InitList(listA);
	InitList(listB);
	
	
	for(int i=0;i<m;i++)
	{
		int v;
		cin>>v;
		AddNode(listA,v);
	}
	
	
	for(int i=0;i<n;i++)
	{
		int v;
		cin>>v;
		AddNode(listB,v);
	}
	
	List listC=MergeList(listA,listB);
	
	PrintfList(listC);
	
	DestroyList(listA);
	DestroyList(listB);
	DestroyList(listC);
}

总结:

注意引用的使用,当函数类型 为 void 的时候往函数里传链表头的时候一定要用引用;

合并的时候,当两个链表都没合并完的时候采取一个一个在原链表上取下来的策略,而当一个链表合并完的时候剩余链表一定大于新链表的所有元素,采用直接接上去的策略;

;