单向循环链表的实现

有了单向链表的实现,但是单向链表的遍历需要从头节点开始,直到尾节点结束,这就会有许多限制,比方说在不知道头节点的情况下,就无法通过单向链表来遍历,这时候就需要单向循环链表。单向循环链表可以从任意节点位置开始,一直循环遍历到该节点本身结束,只需要知道任意一个节点。
而且单向链表在进行尾插法的时候,需要特殊处理,因为尾节点没有下一个节点,而单向循环链表中,尾节点的下一个节点就是头节点,操作上更加统一和简便。

1.先将数据域定义出来

typedef int Elenment;

然后定义单向循环链表的节点结构

typedef struct loopNode{
	Elenment val;			//val 指这个节点所包含的数据
	struct loopNode *next;	//next指这个节点指向下一个节点的指针
} LoopNode;

有了节点结构,还需要定义他的头结构

typedef struct{
	LoopNode header;	//header表示LoopNode类型的成员变量
	LoopNode *rear;		//*rear是指向LoopNode类型的尾指针
	int num;
}LinkLoopList;

现在头节点和节点结构定义完了,就可以定义接口

2.静态初始化接口

void initLinkLoopList(LinkLoopList *link_loop){
	link_loop->num = 0;		//将链表的元素数量初始化为0,当前链表尾空
	link_loop->rear = &link_loop->header;	//将链表的尾指针指向链表的头节点
	link_loop->header.next = &link_loop->header;	//将头节点的next指向指针自身,形成一个闭环,形成一个循环链表的初始化状态,是循环链表的基本特征
}

3.然后就可以开始进行插入操作
3.1头插法
传入链表的指针,和待插入的数据

int insertLinkLoopHeader(LinkLoopList *link_loop, Element value){
	//1.先有新节点
	LoopNode *node = malloc(sizeof(LoopNode));	//申请一片空间,用作待插入节点的空间
	if(node ==NULL){	//申请失败
		return -1;
	}
	//2.处理关系,先处理新的关系,再处理老的关系
	node->val = value;	//将待插入的值赋值给这个节点的val成员
	node->next = link_loop->header.next;	//这个节点指向下一个节点的指针指向头节点的下一个节点
	link_loop->header.next = node;	//头节点指向下一个节点的指针指向新节点
	//头->B->C  插入A   ==> 头  A->B->C   ==>   头->A->B->C  
	//3.判断尾指针是否需要初始化
	if(link_loop->rear == &link_loop->header){	//判断尾指针是否指向链表的头节点,如果是,则说明链表之前可能为空或只有一个节点,此时要更新尾指针
		link_loop->rear = node;		//尾指针要指向最后一个节点
	}
	++link_loop->num;	//插入成功后,更新节点的数量
	return 0;
}

3.2尾插法
传入链表的指针,和待插入的数据

int insertLinkLoopRear(LinkLoopList *link_loop, Element value){
	//1.先有新节点
	LoopNode *node = malloc(sizeof(LoopNode));	//申请一片空间,用作待插入节点的空间
    if (node == NULL) {	//申请失败
        return -1;
    }
	//2.处理关系,先处理新关系,再处理老关系
	node->val = value;	//将待插入的值赋值给这个节点的val成员
	//将新节点的next指针指向link_loop->rear->next,也就是头节点,以完成循环
	node->next = link_loop->rear->next;		//让新节点的next指针指向当前链表尾部节点的下一个节点
	link_loop->rear->next = node;	//将当前链表尾部节点的next指针指向新节点,完成新节点与链表的链接,完成循环
	// 3. rear指针的更新
	if(link_loop->rear == &link_loop->header){	//如果链表里没有元素
		link_loop->rear == node;	//将链表的尾指针指向新节点
		link_loop->header.next = node;	//将链表的头节点的next指向新节点
	}else{
		link_loop->rear = node;	//如果链表里有元素,直接更新尾指针,头节点的next节点与尾插法关系不大
	}
	++link_loop->num;	//插入完成,更新链表节点数量
	return 0;
}

将数据都插入好后,封装一个用来显示的函数
通过引入一个辅助指针,来进行遍历循环链表

void showLinkLoopList(const LinkLoopList *link_loop){
	LoopNode *node = link_loop->header.next;	//引入辅助指针指向头节点的下一个节点,是第一个有效节点
	while(node != &link_loop->header){	//由于是循环链表,最后一个节点的下一个节点就是头节点,所以条件只要不等于头节点就不会重复
		printf("\t%d",node->val);	//输出当前所在的节点
		node = node->next;	//依次往后遍历循环
	}
	printf("\n");
}

最后要删除这片空间
同样也是引用辅助指针,和一个临时指针,防止释放后找不到下一个节点的内容导致释放失败

void releaseLoopList(LinkLoopList *link_loop){
	LoopNode *node = link_loop->header.next;	//指向头节点的下一个节点,也是第一个有效节点
	while(node != &link_loop->header){	由于是循环链表,最后一个节点的下一个节点就是头节点,所以条件只要不等于头节点就不会重复
		LoopNode *tmp = node;	//辅助指针指向待删除的空间
		node = node->next;	//继续向下遍历,这样就不会找不到下面的空间
		free(tmp);	//释放掉临时指针指向的待删除空间
		--link_loop->num;	//释放掉一个,个数减1
	}
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值