线性表之链表基本操作的实现2
这里,我们来实现循环链表的基本操作,我们采用单链表转换为循环链表:
1.将单链表转换为循环链表
ChangeLinkListToCkList(LinkList head) //这里只需要将最后的尾指针指向头结点
{
LinkList p,p2=head,p1=head;
while(p2){ //最后这个p就是链表指向尾结点的指针
p=p2;
p2=p2->next;
}
while(p!=head) //最后这个head就是指向倒数第二个尾结点的指针
{
head=head->next;
}
head->next=p1; //将尾结点指向头结点
}
2.向循环链表添加数据
void AddElemIntoCKList(LinkList head,int index,User user)
{
LinkList p=(LinkList)malloc(sizeof(LNode));
p->user=user;
int i=0;
for(;i<index-1;i++) //这里返回的是目标位置的前一个结点
{
head=head->next;
}
p->next=head->next; //将目标结点指向当前目标位置上的结点
head->next=p; //将目标位置的前一个结点指向目标结点,至此目标结点完成插入操作
}
3.删除循环链表的某个位置的结点
void DeletElemFromCKList(LinkList head,int index)
{
int i=0;
for(;i<index-1;i++) //这里返回的是目标位置的前一个结点
{
head=head->next;
}
LinkList p=head->next;
head->next=head->next->next;
free(p);
}
4.将两个循环链表合并成一个循环链表
void ContactCKList(LinkList tails_0,LinkList tails_1) //这里的tails_0和tails_1分别为两个链表的尾指针
{
LinkList p=tails_1->next->next; //1.找到第二个循环链表的首元结点
tails_1->next=tails_0->next; //2.第二个链表的尾结点指向第一个链表的头结点
tails_0->next=p; //3.第一个链表的尾结点指向第二个链表的首元结点
}
难点:将两个循环链表合并为一个循环链表
初始状态:
第一步:
第二步:
第三步:
然后美化一下:
至此,两个循环链表合并为一个循环链表就完成了。
最后,附上完整源码一份:
#include<bits/stdc++.h>
using namespace std;
typedef struct
{
char username[20];
int id;
}User;
typedef struct LNode
{
User user;
struct LNode *next;
}LNode,*LinkList;
//创建单链表
LinkList CreateLinkList(LinkList L)
{
L=(LinkList)malloc(sizeof(LNode));
L->next=NULL;
return L;
}
//后插法插入5个数据
void InsertElem_Back(LinkList head)
{
int i=0;
LinkList r=head; //每次加入数据后,r都会指向尾节点
for(;i<5;i++)
{
User user;
user.id=i;
strcpy(user.username,"gjw");
LinkList p=(LinkList)malloc(sizeof(LNode));
p->user=user;
p->next=NULL;
r->next=p;
r=p;
}
}
//测试输出链表
void TestList(LinkList head)
{
while(head->next)
{
User user=head->next->user;
cout<<user.username<<endl;
head=head->next;
}
}
//将单链表转化为循环链表
ChangeLinkListToCkList(LinkList head) //这里只需要将最后的尾指针指向头结点
{
LinkList p,p2=head,p1=head;
while(p2){ //最后这个p就是链表指向尾结点的指针
p=p2;
p2=p2->next;
}
while(p!=head) //最后这个head就是指向倒数第二个尾结点的指针
{
head=head->next;
}
head->next=p1;
}
//测试循环链表
void TestCKList(LinkList head) //这里注意,头结点是没有数据的,所以会输出它的地址值
{
int num=0;
while(head&&num<10)
{
head=head->next;
num++;
cout<<head->user.username<<endl;
}
}
//循环链表添加数据
void AddElemIntoCKList(LinkList head,int index,User user)
{
LinkList p=(LinkList)malloc(sizeof(LNode));
p->user=user;
int i=0;
for(;i<index-1;i++) //这里返回的是目标位置的前一个结点
{
head=head->next;
}
p->next=head->next; //将目标结点指向当前目标位置上的结点
head->next=p; //将目标位置的前一个结点指向目标结点,至此目标结点完成插入操作
}
//删除第i个位置的结点
void DeletElemFromCKList(LinkList head,int index)
{
int i=0;
for(;i<index-1;i++) //这里返回的是目标位置的前一个结点
{
head=head->next;
}
LinkList p=head->next;
head->next=head->next->next;
free(p);
}
//获取链表的尾指针
LinkList GetTails(LinkList head,int i)
{
LinkList p;
int index=0;
while(head && index<i)
{
p=head==0?p:head;
head=head->next;
index++;
}
return p;
}
//合并两个循环链表成一个循环链表
void ContactCKList(LinkList tails_0,LinkList tails_1)
{
LinkList p=tails_1->next->next; //找到第二个循环链表的首元结点
tails_1->next=tails_0->next; //第二个链表的尾结点指向第一个链表的头结点
tails_0->next=p; //第一个链表的尾结点指向第二个链表的首元结点
}
int main()
{
LinkList L;
User user;
//创建单链表
LinkList head=CreateLinkList(L);
//采用后插法插入一段数据
InsertElem_Back(head);
//测试输出链表
//TestList(head);
//将单链表改为循环链表
ChangeLinkListToCkList(head);
//测试循环链表
//TestCKList(head);
//循环链表添加数据到第i个位置
//int i=3;
//user.id=0;
//strcpy(user.username,"px");
//AddElemIntoCKList(head,i,user);
//删除第i个位置的结点
//DeletElemFromCKList(head,i);
//将两个循环链表合并为一个循环链表
LinkList head1=CreateLinkList(L); //创建一个新的单链表
InsertElem_Back(head1); //向链表中添加5个数据
ChangeLinkListToCkList(head1); //将该链表转化为循环链表
LinkList tails_0=GetTails(head,5); //获取第一个链表的尾指针
LinkList tails_1=GetTails(head1,5); //获取第二个链表的尾指针
ContactCKList(tails_0,tails_1); //合并两个循环链表为一个循环链表
return 0;
}