循环单向链表的相关算法

代码是初学者边学边写,一则记录成长历程,二则希望能给像我一样的初学者带来点滴帮助,如有错误欢迎指正;

C语言描述;

只带尾指针的循环单向链表算法;

何为循环单向链表看数据结构书?这里不做介绍,只给代码;

包含:创建空表,销毁,清空,插入,删除,判断是否为空表,返回表的长度,得到第i个结点的值,得到表中第一个等于e的结点的位置,合并两个链表;

/*注意点:
  1,可能改变谁是尾结点的操作,函数形参需是原变量
  2,可能改变谁是尾结点的操作,末尾勿忘更改尾指针
  3,练习题 
           * 在空表中正序插入5个结点 
           * 对上述5个结点非递增排序             */  
#include<stdio.h>
#include<stdlib.h>
typedef int ElemType;
typedef struct LNode
{
	ElemType data;
	struct LNode* next;
} LNode;
 typedef LNode* LinkList;
 //创建空表:尾指针指向头结点,头结点的指针域指向自己 
 void InitList(LinkList* L)
 {
 	*L = (LNode*)malloc(sizeof(LNode));
 	if(!*L)  exit(-1);
 	(*L)->next = *L;
 }
 bool DestroyList(LinkList* L)
 {//注意循环链表,p的开始状态要和判断状态中间隔一个结点
  //因为对于循环链表,开始p指向头结点,而循环条件是p不指向头结点 
 	LNode* q;
 	LNode* p = (*L)->next;//p指向头结点 
 	while(p!=*L)//到倒二结点 
 	{
 		q = p->next;
 		free(p);
 		p = q;
	}
	free(*L);//此处是坑!!!释放最后一个结点 
	*L = NULL;
	return true;
 }
bool ClearList(LinkList *L)
{//可能改变谁是最后一个结点的函数形参设置成LNode**L; 
	LNode* p,* q;
	p = (*L)->next->next;
	while(p!=(*L)->next)
	{
		q = p->next;
		free(p);
		p = q;
	}
	*L = p;
	p->next = p;
	return true;
}
bool EmptyList(LinkList L)
{
	return L->next==L?true:false;
}
int LengthList(LinkList L)
{
	int j = 0;
	LNode* p = L->next;
	while(p!=L)
	{
		j++;
		p = p->next;
	}
	return j;
}
bool GetElem(LinkList L,int i,ElemType* e)
{
	if(i<1||i>LengthList(L))
	{
		printf("i的值不合理\n");
		return false;
	}
	LNode* p = L->next;
	for(int j=0;j<i;j++)
	p=p->next;
	*e = p->data;
	return true;
}
int LocateElem(LinkList L,ElemType e)
{
	int j = 1;
	LNode* p = L->next->next;//p指向首元结点 
	while(p!=L->next)//p到尾结点后结束 
	{
		if(p->data==e)
		    return j;
		    j++;
		    p=p->next;
	}
	return 0;
}
//在第i个位置前插入值为e的新结点:i值可以是length+1 
bool InsertList(LinkList* L,int i,ElemType e)
{
	if(i<1||i>LengthList(*L)+1)
	return false;//i值是否合理 
	LNode* p = (*L)->next;
	for(int j=0;j<i-1;j++)
	{
		p = p->next;
	}
	LNode* New = (LNode*)malloc(sizeof(LNode));//构建新结点 
	if(!New)   return false;
	New->data = e;
	New->next = p->next;
	p->next = New;//插入结束 
	if(p==*L)//如果新结点是最后一个结点 
	*L = New;//更改尾指针 
	return true;
}
//删除链表第i个结点,被删除结点的值返回给e 
bool DeleteList(LinkList* L,int i,ElemType* e)
{
	if(i<1||i>LengthList(*L))
	return false;//i值是否合理 
	LNode* p = (*L)->next;
	for(int j=0;j<i-1;j++)
	p = p->next;
	LNode* q;
	q = p->next;//先保存被删除结点的地址留着释放 
	*e = q->data;//被删除结点的值返回给e 
	p->next = q->next;//删除结点 
	if(q==*L)//如果被删除结点是最后一个结点 
	*L = p;//改变尾指针为倒数第二个结点 
	free(q);//释放被删除的结点 
	return true;
} 
//在单向循环链表中寻找第一个与e相等的结点的位置 

void TraverseList(LinkList L)
{
	LNode* p = L->next->next;
	while(p!=L->next)
	{
		printf("%d  ",p->data);
		p = p->next;
	}
	printf("\n");
}
//合并Lb到La中:La和Lb均是只有尾指针的单向循环链表 
void MergeList(LinkList* La,LinkList Lb)
{
	(*La)->next = Lb->next->next;//La尾结点接Lb首元结点 
	free(Lb->next);//释放Lb头结点 
	Lb->next = (*La)->next;//Lb尾结点接La头结点 
	*La = Lb;//更改La的尾指针 
}
int main()
 {
   LinkList L;
   ElemType e;
   int j;
   InitList(&L); /* 初始化单循环链表L */
   EmptyList(L);
   if(!InsertList(&L,1,3)) /* 在L中依次插入3,5 */
   printf("i的值不合理\n");
   else
   printf("在第1个结点前插入3\n");
   if(!InsertList(&L,2,5))
   printf("i的值不合理\n");
   else
   printf("在第2个结点前插入5\n");
   if(!InsertList(&L,2,7))
   printf("i的值不合理\n");
   else
   printf("在第2个结点前插入7\n");
   GetElem(L,1,&e);
   printf("L中数据元素个数=%d,第1个元素的值为%d。\n",LengthList(L),e);
   printf("L中的数据元素依次为:");
   TraverseList(L);
   j = LocateElem(L,4);
   if(j)
   printf("L的第%d个元素为4。\n",j);
   else
   printf("没有与4相等的结点\n");
   j = LocateElem(L,5);
   if(j)
   printf("L的第%d个元素为5。\n",j);
   else
   printf("没有与5相等的结点\n");
   if(!DeleteList(&L,1,&e))
   printf("i的值不合理!\n");
   else
   printf("删除了第1个结点%d\n",e);
   printf("删除第1个结点后遍历链表:\n");
   TraverseList(L);
   printf("清空L:%d(1: 成功)\n",ClearList(&L));
   printf("清空L后,L是否空:%d(1:空 0:否)\n",EmptyList(L));
   printf("销毁L:%d(1: 成功)\n",DestroyList(&L));
 }




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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值