循环单链表

循环链表:和单链表相比,尾结点的next域不在指向NULL,而是指向头结点

循环链表的结构体声明和单链表一样:

//循环链表结构体设计
typedef int ELEMTYPE;
typedef struct Clist
{
	ELEMTYPE data; //数据域   存放数据
	struct Clist* next;//指针域   存放下一个节点的地址(尾结点的next保存头结点的地址)
}Clist, * PClist;

同样实现链表的相应功能:

函数声明

//循环链表拥有的 可执行函数声明:

//初始化
void InitClist(struct Clist* plist);

//头插
bool Insert_head(PClist plist, ELEMTYPE val);

//尾插
bool Insert_tail(PClist plist, ELEMTYPE val);

//按位置插
bool Insert_pos(PClist plist, int pos, ELEMTYPE val);

//头删
bool Del_head(PClist plist);

//尾删
bool Del_tail(PClist plist);

//按位置删
bool Del_pos(PClist plist, int pos);

//按值删除
bool Del_val(PClist plist, ELEMTYPE val);

//查找(如果查找到,需要返回找到的这个节点的地址)
struct Clist* Search(struct Clist* plist, ELEMTYPE val);

//判空
bool IsEmpty(PClist plist);
//判满(循环链表不需要这个操作)

//获取长度
int Get_length(PClist plist);

//清空
void Clear(PClist plist);

//销毁1
void Destroy1(PClist plist);

//销毁2
void Destroy2(PClist plist);

//打印
void Show(struct Clist* plist);

1.初始化:(数据域不做处理,next域为头结点自身的地址)

//初始化
void InitClist(struct Clist* plist)
{
	assert(plist != NULL);
	if (plist == NULL)
	{
		return;
	}
	//plist->data; // 数据域不处理
	plist->next = plist;
}

2.头插:

bool Insert_head(PClist plist, ELEMTYPE val)
{
	//assert断言
	assert(plist != NULL);
	if (plist == NULL)
	{
		return false;
	}
	//购买新的节点
	PClist list = (PClist)malloc(sizeof(Clist) * 1);
	assert(list != NULL);
	list->data = val;
	//找到合适的位置插入,这里是头插
	list->next = plist->next;
	plist->next = list;
	return true;
}

3.尾插:

bool Insert_tail(PClist plist, ELEMTYPE val)
{
	assert(plist != NULL);
	if(plist==NULL)
	{
		return false;
	}
	//建立一个指针p,指向最后一个节点
	PClist p = plist;
	for (p; p->next != plist; p = p->next);
	//购买新节点
	PClist list = (PClist)malloc(sizeof(Clist) * 1);
	assert(list != NULL);
	list->data = val;
	//此时 for循环执行结束   p指向尾结点
	//在最后一个节点插入
	list->next = p->next;
	p->next = list;

	return true;
}

4.按位置插

bool Insert_pos(PClist plist, int pos, ELEMTYPE val)
{
	assert(plist != NULL);
	assert(pos >= 0 && pos <= Get_length(plist));
	
	//购买新节点
	PClist list = (PClist)malloc(sizeof(Clist) * 1);
	assert(list != NULL);
	list->data = val;
	//建立一个指针通过for循环指向要插入的位置,第0个位置相当于头插
	PClist p=plist;
	for (int i = 0; i < pos; ++i)
	{
		p = p->next;
	}
	//插入
	list->next = p->next;
	p->next = list;

	return true;
}

5.头删

bool Del_head(PClist plist)
{
	assert(plist != NULL);
//删除得判断是否为空
	if (IsEmpty(plist))//不空  则至少存在一个有效值
	{
		return false;
	}

	//1.指针p指向待删除节点
	struct Clist* p = plist->next;

	//2.指针q指向待删除节点的前一个节点
	//q 就是 头结点  这里就不再额外处理

	//3.跨越指向
	plist->next = p->next;
	free(p);

	return true;
}

6.尾删

bool Del_tail(PClist plist)
{
	assert(plist != NULL);
	if (IsEmpty(plist))//不空  则至少存在一个有效值
	{
		return false;
	}
	//1.指针p指向待删除节点(尾删的话,这里指向尾结点)
	PClist p = plist;
	for (p; p->next != plist; p = p->next);
	//此时 for指向结束  代表着p指向尾结点

	//2.指针q指向倒数第二个节点
	PClist q = plist;
	for (q; q->next != p; q = q->next);
	//此时 for指向结束  代表着q指向p的上一个节点

	q->next = p->next;
	free(p);
	return true;
}

7.按位置删

bool Del_pos(PClist plist, int pos)
{
	assert(plist != NULL);
	assert(pos >= 0 && pos <= Get_length(plist));

	if (IsEmpty(plist))
	{
		return false;
	}
	//1.指针p指向待删除节点
	PClist p = plist;
	for (int i = 0; i <= pos; ++i)
	{
		p = p->next;
	}
	//2.指针q指向待删除节点的上一个节点
	PClist q = plist;
	for (q; q->next != p; q = q->next);
	//删除
	q->next = p->next;
	free(p);
	return true;
}

8.按值删

bool Del_val(PClist plist, ELEMTYPE val)
{
	assert(plist != NULL);
	struct Clist* p = Search(plist, val);//p指向要删除的节点
	if (p == NULL)
	{
		return false;
	}

	struct Clist* q = plist;//q指向上一个节点
	for (q; q->next != p; q = q->next);

	q->next = p->next;
	free(p);
	return true;
}

9.查找

//查找(如果查找到,需要返回找到的这个节点的地址)
struct Clist* Search(struct Clist* plist, ELEMTYPE val)
{
	assert(plist != NULL);
	PClist p = plist->next;
	for (p; p != plist; p = p->next)
	{
		if (p->data == val)
		{
			return p;
		}
	}
	return NULL;
}

10.判空,获取长度

//判空
bool IsEmpty(PClist plist)
{
	assert(plist != NULL);
	return plist->next==plist;
}
//判满(循环链表不需要这个操作)

//获取长度
/*指针p从头结点的下一个节点开始向后跑,如果p再次遇到了头结点,
证明p走了一圈回来了,这是有效节点肯定已经遍历结束*/
int Get_length(PClist plist)
{
	int cout=0;
	for (PClist p = plist->next; p != plist; p = p->next)
	{
		cout++;
	}
	return cout;
}

11.清空,销毁(两种方法),打印

//清空
void Clear(PClist plist)
{
	//assert
	Destroy1(plist);
}

//销毁1
void Destroy1(PClist plist)
{
	assert(plist != NULL);
	while (plist->next != plist)
	{
		struct Clist* p = plist->next;
		plist->next = p->next;
		free(p);
	}

	plist->next = plist;
}

//销毁2
void Destroy2(PClist plist)
{
	//assert
	struct Clist* p = plist->next;
	struct Clist* q = NULL;

	plist->next = plist;

	while (p != plist)
	{
		q = p->next;
		free(p);
		p = q;
	}
}

//打印
void Show(struct Clist* plist)
{
	for (PClist p = plist->next; p != plist; p = p->next)
	{
		printf("%d ", p->data);
	}
	printf("\n");
}

看一下测试结果:

主函数:

int main()
{
	struct Clist head;
	InitClist(&head);

	for (int i = 0; i < 20; i++)
	{
		Insert_pos(&head, i, i + 1);
	}//1到20按位置插给链表赋值
	Show(&head);//打印

	Insert_head(&head, 100);//头插100
	Insert_tail(&head, 200);//尾插200
	Show(&head);//打印
	printf("length = %d\n", Get_length(&head));//打印长度

	Del_head(&head);//头删
	Del_tail(&head);//尾删
	Show(&head);//打印

	Del_pos(&head, 4);//将第四个位置删除
	Del_val(&head, 14);//将值为14的结点删除
	Show(&head);

	printf("length = %d\n", Get_length(&head));//打印长度

	//Destroy(&head);
	Destroy2(&head);//销毁
	//printf("%d\n", sizeof(struct Node));

	return 0;
}

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值