本文主要是关于如何实现两个单向链表的合并的,即使图1中的链表rb接在链表ra之后。
实现的代码见函数ListCombine(SLNode *head1,SLNode *head2)的代码块,主要的步骤是:
(1)对链表ra进行遍历,当遍历至尾结点(p->next==NULL)时,跳出while()循环;
(2)使链表ra的尾结点指向链表rb的首元结点;
(3)释放rb的头结点所对应的内存空间。
简短地阐释一下“头指针”“头结点”“首元结点”三个概念的区别:
头指针是指向链表中第一个结点(或为头结点、或为首元结点)的指针。
头结点是在链表的首元结点之前附设的一个结点;数据域内只放空表标志和表长等信息,它不计入表长度。
首元结点是指链表中存储线性表第一个数据元素a0的结点。
其中头指针只是指针,它指向头结点或首元结点所对应的地址,在程序中,并没有给它分配固定的内存;而头结点和首元结点却对应着固定的内存。头结点和首元结点的区别在于数据域中是否存放了数据元素,头结点中的数据域为空,或存放表长信息,引入它是为了方便链表的插入和删除操作;而首元结点的数据域中会存储第一个数据元素的值。
三者的关系见图2:
程序代码如下,其中ListCombine()函数主要是实现两个链表的合并:
#include <iostream>
using namespace std;
typedef struct SNode
{
int data;
SNode *next;
}SLNode;
int main()
{
void ListInitiate(SLNode **head);
void ListCreate(SLNode *head,int m,int n);
void ListCombine(SLNode *head1,SLNode *head2);
void ListPrint(SLNode *head);
SLNode *head1,*head2;
ListInitiate(&head1);
ListInitiate(&head2);
ListCreate(head1,5,15);
ListCreate(head2,20,25);
ListCombine(head1,head2);
ListPrint(head1);
return 0;
}
/*初始化链表*/
void ListInitiate(SLNode **head)
{
*head=new SLNode;
(*head)->next=NULL;
}
/*为链表新增结点,并为结点的数字域赋值*/
void ListCreate(SLNode *head,int m,int n)
{
SLNode *p,*q;
p=head;
for(int i=m;i<=n;i++)
{
q=new SLNode;
q->data=i;
q->next=p->next;
p->next=q;
p=q; //必须要有这句话,不然p会原地不动;若无此句,head指针实际是指向最后一个数据元素所在的结点
}
}
/*将以*head2为头指针的链表2合并在以*head1为头指针的链表1之后*/
void ListCombine(SLNode *head1,SLNode *head2)
{
SLNode *p1,*p2;
p1=head1;
p2=head2;
while(p1->next!=NULL)
p1=p1->next;
p1->next=p2->next; /*丢掉链表2的头指针,并使链表1的尾结点指向链表2的首元结点*/
delete p2; /*释放链表2的头指针所指的头结点所对应的空间*/
}
/*打印链表中的元素*/
void ListPrint(SLNode *head)
{
SLNode *p;
p=head;
while(p->next!=NULL){
p=p->next;
cout<<p->data<<' ';
}
cout<<endl;
}