【单循环链表】

链表比较

单循环链表:和单链表相比,尾结点的next域不再保存NULL,而是保存上一个结点的地址
双向链表:和单链表相比,每个节点不仅仅只保存了一个节点的地址,还需要一个指针域保存上一个结点的地址

单循环链表存在的意义:可以从循环链表的任意一点出发,就可以遍历整个链表的所有结点,

双向链表存在的意义:每一个结点既可以找到直接后继,也可以找到直接前驱

单循环链表

增删查改等操作的思路

单循环链表代码思路大致与单链表相同,只是两种循环的停止条件变成了不等于头节点

初始化

初始化也就是没有有效结点,因此链表的头节点应该:
头节点的数据域浪费掉,不使用
头节点的next域,赋值为pclist

插入

0、安全性处理
1、购买新节点
2、找到合适的插入位置
3.插入
举例:尾插
0.安全性处理
1.购买新节点
2.找到合适的插入位置(也就是说找到在哪一个节点后面插入)
尾插,找尾结点,用指针p指向,通过判断,确实使用需要前驱的for循环,也就是说,申请一个临时指针p,执行头结点,此时,for循环,跑完,p指向尾结点。
struct CNode* p = pclist;
for (; p->next != pclist; p = p->next);)

3.插入即可

删除

举例:头删来回顾思路
0:安全性处理(确保至少存在一个有效节点)
1.找到待删除节点,用指针p指向(头删的话,待删除节点就是第一个有效节点)
2.找到待删除节点的前驱,用指针q指向,这里不用处理,因为这里pclist就可以代替q
3.跨越指向+释放

结构体设计

typedef int ELEM_TYPE;

typedef struct CNode
{
    ELEM_TYPE data;//数据域
    struct CNode* next;//指针域
}CNode, * PCNode;

//可实现的操作:
//初始化
void Init_clist(struct CNode* pclist);

//头插
bool Insert_head(PCNode pclist, ELEM_TYPE val);

//尾插
bool Insert_tail(PCNode pclist, ELEM_TYPE val);

//按位置插
bool Insert_pos(PCNode pclist, int pos, ELEM_TYPE val);

//头删
bool Del_head(PCNode pclist);

//尾删
bool Del_tail(PCNode pclist);

//按位置删
bool Del_pos(PCNode pclist, int pos);

//按值删
bool Del_val(PCNode pclist, ELEM_TYPE val);

//查找 //查找到,返回的是查找到的这个节点的地址
struct CNode* Search(PCNode pclist, ELEM_TYPE val);

//获取有效值个数
int Get_length(PCNode pclist);

//判空
bool IsEmpty(PCNode pclist);

//清空
void Clear(PCNode pclist);

//销毁1 无限头删
void Destroy1(PCNode pclist);

//销毁2 不借助头结点,有两个辅助指针
void Destroy2(PCNode pclist);

//打印
void Show(PCNode pclist);

函数实现

#include <stdio.h>
#include <assert.h>
#include <stdlib.h>
#include "clist.h"


//可实现的操作:
//初始化
void Init_clist(struct CNode* pclist)
{
	//0.安全性处理
	assert(pclist != NULL);

	//1.对pclist指向的头结点里面的成员进行赋值:
	//头结点的数据域不使用,只需要对指针域赋值即可,赋值为自身地址
	pclist->next = pclist;

}

//头插
bool Insert_head(PCNode pclist, ELEM_TYPE val) {
	assert(pclist!=NULL);
	struct CNode* pnewnode = (struct CNode*)malloc(1 * sizeof(struct CNode));
	assert(pnewnode!=NULL);
	pnewnode->data = val;
	pnewnode->next = pclist->next;
	pclist->next = pnewnode;
	return true;
}

//尾插
bool Insert_tail(PCNode pclist, ELEM_TYPE val)
{
	//0.安全性处理
	assert(pclist != NULL);

	//1.购买新节点
	struct CNode* pnewnode = (struct CNode*)malloc(1 * sizeof(struct CNode));
	assert(pnewnode != NULL);
	pnewnode->data = val;

	//2.找到合适的插入位置(也就是说找到在哪一个节点后面插入)
	//尾插,找尾结点,用指针p指向
	//通过判断,确实使用需要前驱的for循环,也就是说,申请一个临时指针p,执行头结点
	struct CNode* p = pclist;
	for (; p->next != pclist; p = p->next);
	//此时,for循环,跑完,p指向尾结点

	//3.插入即可
	pnewnode->next = p->next;
	p->next = pnewnode;

	return true;
}

//按位置插
bool Insert_pos(PCNode pclist, int pos, ELEM_TYPE val) {
	assert(pclist != NULL);
	struct CNode* pnewnode = (struct CNode*)malloc(1 * sizeof(struct CNode));
	assert(pnewnode!=NULL);
	pnewnode->data = val;
	struct CNode* p = pclist;
	for (int i = 0;i<pos;i++ ) {
		p = p->next;
	}
	pnewnode->next = p->next;
	p->next = pnewnode;
	return true;

}

//头删
bool Del_head(PCNode pclist)
{
	//0:安全性处理
	assert(pclist != NULL);
	if (IsEmpty(pclist))
	{
		return false;
	}//确保至少存在一个有效节点

	//1.找到待删除节点,用指针p指向(头删的话,待删除节点就是第一个有效节点)
	struct CNode* p = pclist->next;

	//2.找到待删除节点的前驱,用指针q指向
	//这里不用处理,因为这里pclist就可以代替q

	//3.跨越指向+释放
	pclist->next = p->next;
	free(p);

	return true;
}


//尾删
bool Del_tail(PCNode pclist) {
	assert(pclist != NULL);
	if (IsEmpty(pclist))
	{
		return false;
	}
	struct CNode* p = pclist;
	for (; p->next != pclist; p = p->next);
	struct CNode* q = pclist;
	for (; q->next != p; q = q->next);
	q->next = p->next;
	free(p);
	return true;

}

//按位置删
bool Del_pos(PCNode pclist, int pos) {
	assert(pclist != NULL);
	if (IsEmpty(pclist))
	{
		return false;
	}
	struct CNode* q = pclist;
	for (int i = 0; i < pos; i++) {
		q = q->next;
	}
	struct CNode* p = q->next;
	q->next = p->next;
	free(p);
	return true;
}

//按值删
bool Del_val(PCNode pclist, ELEM_TYPE val) {
	assert(pclist != NULL);
	struct CNode* p= Search(pclist, val);
	if (p == NULL) {
		return false;
	}
	struct CNode* q = pclist;
	for (; q->next != p; q = q->next);
	q->next = p->next;
	free(p);
	return true;

}

//查找 //查找到,返回的是查找到的这个节点的地址
struct CNode* Search(PCNode pclist, ELEM_TYPE val) {
	struct CNode* p = pclist->next;
	for (; p != pclist; p = p->next) {
		if (p->data == val) {
			return p;
		}
	}
	return NULL;

}

//获取有效值个数
int Get_length(PCNode pclist) {
	assert(pclist != NULL);
	struct CNode* p = pclist->next;
	int count = 0;
	for (; p != pclist; p = p->next) {
		count++;
	}
	return count;

}

//判空
bool IsEmpty(PCNode pclist) {

	return pclist->next== pclist;
}

//清空
void Clear(PCNode pclist) {
	Destroy1(pclist);
}

//销毁1 无限头删
void Destroy1(PCNode pclist) {
	/*while (IsEmpty(pclist)) {
		Del_head(pclist);
	}*/
	while (pclist->next != pclist) {
		struct CNode* p = pclist->next;
		pclist->next = p->next;
		free(p);
	}

}

//销毁2 不借助头结点,有两个辅助指针
void Destroy2(PCNode pclist) {
	assert(pclist != NULL);
	struct CNode* p = pclist->next;
	struct CNode* q;
	pclist->next = pclist;
	while (p != pclist) {
		q = p->next;
		free(p);
		p = q;
	}
}

//打印
void Show(PCNode pclist)
{
	//判定使用不需要前驱的for循环

	struct CNode* p = pclist->next;
	for (; p != pclist; p = p->next)
	{
		printf("%d ", p->data);
	}
	printf("\n");
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

*闲鱼

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值