循环单链表的初始化、插入、删除、按位遍历、融合、销毁、求节点数等操作(C语言实战题代码详解)
本题以尾插法构建带头结点的循环链表,在插入、删除、按位遍历中添加了异常判断的情况,并可以实现循环操作,具体各部分代码如下:
一、循环单链表的抽象数据类型定义:
#include<stdio.h>
#include<stdlib.h>
#define OK 1
#define ERROR 0
typedef int Elemtype; //数据类型重定义
typedef int Status; //状态类型重定义
typedef struct CLNode{
Elemtype data; //链表数据域
struct CLNode *next; //链表指针域
}CLNode,*CLinklist;
Status Length_CLinklist(CLinklist *L); //函数声明
二、循环单链表初始化:
/*循环单链表初始化*/
Status Init_CLinklist(CLinklist *L)
{
*L=(CLinklist)malloc(sizeof(CLNode)); //创建头结点
if(!(*L)) return ERROR; //创建失败返回ERROR
(*L)->next=*L; //头结点指针指向本身
return OK;
}
三、循环单链表的尾插法构建:
/*循环单链表的尾插法构建,输入data,0的时候结束输入*/
void Create_CLinklist(CLinklist *L)
{
CLNode *p,*q; //定义链尾节点和新生节点
int flag=1,number; //设立旗帜,
p = *L;
while(flag)
{
scanf("%d",&number);
if( number!=0 )
{
q=(CLinklist)malloc(sizeof(CLNode)); //创建新生节点
if(!q) exit(0); //创建失败结束程序
q->data=number;
p->next=q; p=q; //这里和单链表的尾插法相同
}
else
{
p->next = *L; //尾指针指向头结点
flag=0;
}
}
}
四、循环单链表的插入:
/*循环单链表的插入,插入错误返回0,插入成功返回1*/
Status Insert_CLinklist(CLinklist *L,int i,Elemtype e)
{
int j=1;
CLNode *p,*q; //定义链尾节点和新生节点
p = *L;
if(i<1||p->next==*L||i>Length_CLinklist(L))
return ERROR; //插入位置小于1,空表或大于表长则返回0
while( p->next!=*L && j<i )
{
p=p->next;
j++;
}
q=(CLinklist)malloc(sizeof(CLNode));
q->data=e;
q->next=p->next;
p->next=q;
return OK;
}
五、循环单链表的删除:
/*循环单链表的删除,删除错误返回0,删除成功返回1,用e返回被删除的元素*/
Status Delete_CLinklist(CLinklist *L,int i,Elemtype *e)
{
int j=1;
CLNode *p,*q;
p = *L;
if(i<1||p->next==*L||i>Length_CLinklist(L))
return ERROR; //删除位置小于1,空表或大于表长则返回0
while( p->next != *L && j<i)
{
p=p->next;
j++;
}
q=p->next;
*e=q->data;
p->next=q->next;
free(q); //释放掉删除结点
return OK;
}
六、循环单链表按指定结点位置开始遍历:
/*从指定的结点遍历循环链表*/
Status Print_CLinklist(CLinklist *L,int i)
{
int j=1;
CLNode *p,*q;
p = *L;
if(i<1||p->next==*L||i>Length_CLinklist(L))
return ERROR; //遍历位置小于1,空表或大于表长则返回0
printf("\n从第%d个结点开始遍历的链表为:\n",i);
while(j<i) //找到要开始遍历的节点
{
p=p->next;
j++;
}
q=p->next; //开始遍历的节点赋给q
while(q != *L) //找到头结点,因为头结点不遍历,所以要跳过头结点
{
printf("%d ",q->data);
q=q->next;
}
q=(*L)->next; //把首节点赋给q
while(q != p->next) //以开始遍历节点为止,继续遍历
{
printf("%d ",q->data);
q=q->next;
}
return OK;
}
七、循环单链表的融合(将两个循环单链表融合成一个循环单链表):
/*循环链表的连接,将循环链表L,和循环链表L1融合为循环链表L*/
void Merge_Linklist(CLinklist *L,CLinklist *L1)
{ /*链表融合后返回的是*L,这有一个头结点*/
CLNode *p,*q;
p = (*L)->next;
if( p == *L ) return; //空表结束
q = (*L1)->next;
if( q == *L1 ) return;
while( p->next != *L ) p=p->next; //让链表一指向最后一个结点
while( q->next != *L1) q=q->next; //让链表二指向最后一个结点
p->next=(*L1)->next; //让链表一尾结点指向链表二首节点
q->next=*L; //让链表二尾结点指向链表一头结点
}
八、循环单链表求节点数(表长):
/*求循环链表表长*/
Status Length_CLinklist(CLinklist *L)
{
int i=0;
CLNode *p;
p=(*L)->next;
if( p == *L ) return ERROR; //空表返回0
while(p != *L)
{
i++;
p=p->next;
}
return i; //返回表长
}
九、循环单链表的遍历(头结点开始遍历):
/*循环单链表的遍历*/
void Display(CLinklist *L)
{
CLNode *p;
p=(*L)->next; //头结点指向第一个节点
while(p!=*L)
{
printf("%d ",p->data);
p=p->next;
}
}
十、循环链表的清除:
/*清除循环链表*/
Status Clear_CLinklist(CLinklist *L)
{
CLNode *p,*q;
p = (*L)->next;
if( p == *L ) return ERROR; //空表返回0
while( p != *L)
{
q=p->next;
free(p);
p=q;
}
p->next = *L; // 循环链空表是指向头结点
return OK;
}
十一、主函数:
int main()
{
int value,e,length,n,num;
CLinklist L,L1;
printf("\t\t........................... 0 退出 .............................\n\n");
printf("\t\t........................... 1 循环链表初始化.............................\n\n");
printf("\t\t........................... 2 循环链表的插入.............................\n\n");
printf("\t\t........................... 3 循环链表的删除.............................\n\n");
printf("\t\t........................... 4 循环链表的遍历.............................\n\n");
printf("\t\t........................... 5 循环链表的表长.............................\n\n");
printf("\t\t........................... 6 循环链表的融合.............................\n\n");
printf("\t\t........................... 7 循环链表的销毁.............................\n\n");
do
{
printf("\n\n请选择操作序号:");
scanf("%d",&num);
switch(num)
{
case 1:
value=Init_CLinklist(&L);
if(value==0)
{
printf("\n初始化失败!\n");
continue;
}
printf("请输入循环链表数据(0表示结束输入):\n");
Create_CLinklist(&L);
printf("\n初始化循环单链表元素为:\n");
Display(&L);
break;
case 2:
printf("\n请输入插入的序号:");
scanf("%d",&n);
printf("请输入要插入的值:");
scanf("%d",&num);
value=Insert_CLinklist(&L,n,num);
if(value==0)
{
printf("\nposition error!\n");
continue;
}
printf("\n插入后循环单链表元素为:\n");
Display(&L);
break;
case 3:
printf("\n请输入删除结点的序号:");
scanf("%d",&n);
value=Delete_CLinklist(&L,n,&e);
if(value==0)
{
printf("\nposition error!\n");
continue;
}
printf("被删除的元素为:%d\n",e);
printf("删除后循环单链表元素为:\n");
Display(&L);
break;
case 4:
printf("\n从第几个结点开始遍历:");
scanf("%d",&n);
value=Print_CLinklist(&L,n);
if(value == 0)
{
printf("\nposition error!\n");
continue;
}
break;
case 5:
length=Length_CLinklist(&L);
printf("\n当前循环链表表长为:%d",length);
break;
case 6:
Init_CLinklist(&L1);
printf("请输入你要融合的另一个循环链表的数据(0表示结束输入):\n");
Create_CLinklist(&L1);
Merge_Linklist(&L,&L1);
printf("\n融合后的循环链表从第几个结点开始遍历:");
scanf("%d",&num);
printf("从第%d个结点开始遍历的链表为:\n",num);
Print_CLinklist(&L,num);
break;
case 7:
Clear_CLinklist(&L);
break;
}
}while(num!=0);
return 0;
}
十二、部分运行效果截图: