循环链表的实现

循环链表简介

简单来说,单链表像一个小巷,无论怎么样最终都能从一端走到另一端,循环链表则像一个有传送门的小巷,因为循环链表当你以为你走到结尾的时候,其实你又回到了开头。循环链表和非循环链表其实创建的过程以及思路几乎完全一样,唯一不同的是,非循环链表的尾结点指向空(NULL),而循环链表的尾指针指向的是链表的开头。通过将单链表的尾结点指向头结点的链表称之为循环单链表(Circular linkedlist)。
在这里插入图片描述
如上图所示,循环链表将单链表中终端结点的指针端由空指针改为指向头结点,就使整个单链表形成一个环。循环链表与单链表的主要差异在于循环的判断上,原来是判断p->next是否为空,现在则是p->next不等于头结点,则循环未结束。

循环链表的实现

1、创建链表

如同单链表的创建,我们需要先创建一个头结点并且给其开辟内存空间,但与单链表不同的是,我们需要在开辟内存空间成功之后将头结点的next指向head自身。当需要进行插入时,我们首先创建一个新的节点,将原有链表尾结点的next指针修改指向到新的结点,新结点的next指针再重新指向头部结点,然后逐步进行这样的插入操作,最终完成整个单项循环链表的创建。代码示例如下:

int insert_list(list *head){  
    int data;   //插入的数据类型  
    printf("请输入要插入的元素:");  
    scanf("%d",&data);  
    list *node=initlist();  
    node->data=data; //初始化一个新的结点,准备进行链接  
    if(head!=NULL){  
        list *p=head;  
        //找到最后一个数据  
        while(p->next!=head){  
            p=p->next;  
        }  
        p->next=node;  
        node->next=head;  
        return 1;  
    }else{  
        printf("头结点已无元素\n");  
        return 0;  
    }  
}  

2、删除操作

如图2所示,循环单链表的删除操作可以参考单链表的删除操作,其都是找到需要删除的结点,将其前一个结点的next指针直接指向删除结点的下一个结点即可,但需要注意的是尾节点和头结点的特判,尤其是尾结点,因为删除尾节点后,尾节点前一个结点就成了新的尾节点,这个新的尾节点需要指向的是头结点而不是空,其重点可以记录为当前的前一节点.next=自身结点.next这样的操作可以省去头尾结点的特判。
在这里插入图片描述
示例代码:

int delete_list(list *head) {  
    if(head == NULL) {  
        printf("链表为空!\n");  
        return 0;  
    }  
    list *temp = head;            
    list *ptr = head->next;  
    int del;  
    printf("请输入你要删除的元素:");  
    scanf("%d",&del);  
    while(ptr != head) {  
        if(ptr->data == del) {  
            if(ptr->next == head) {   
                temp->next = head;  
                free(ptr);  
                return 1;  
            }  
            temp->next = ptr->next;//核心删除操作代码  
            free(ptr);  
            //printf("元素删除成功!\n");  
            return 1;  
        }  
        temp = temp->next;  
        ptr = ptr->next;  
    }  
    printf("没有找到要删除的元素\n");  
    return 0;  
}  

循环链表删除功能的实现:

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include<stdlib.h>
#define ERROR 0
#define OK 1
typedef int EleType;
typedef struct CLinkNode
{
	EleType data;
	struct CLinkNode *next;
}CLinkNode,*CLinkList;
 
/*
初始化循环链表
*/
int InitCLinkList(CLinkList *list)
{
	if (list == NULL)
	{
		return ERROR;
	}
 
	int data = 0;
	CLinkNode* target = NULL;
	CLinkNode* head_node = NULL;
	printf("输入结点数据中...\n");
	while (1)
	{
		scanf("%d", &data);
		if (data == 0)
		{
			//退出循环标志,用户输入0 表示结束输入数据
			break;
		}

		if (*list == NULL)
		{
			CLinkNode* head= (CLinkNode*)malloc(sizeof(CLinkNode));
			//分配结点空间失败
			if (head == NULL)
			{
				exit(0);
			}
 
			*list = head;//链表指向头结点
 
			CLinkNode* node = (CLinkNode*)malloc(sizeof(CLinkNode));
			if (node == NULL)
			{
				exit(0);
			}
			node->data = data;
			node->next = head;
			head->next = node;
		}
		else
		{
			for (target = (*list)->next; target->next != *list; target = target->next);
			head_node = target->next;
 
			CLinkNode* node = (CLinkNode*)malloc(sizeof(CLinkNode));
			if (node == NULL)
			{
				exit(0);
			}
			node->data = data;
			node->next = head_node;
 
			target->next = node;//将新结点插入尾部
		}
 
	}
	return OK;
}
/*
往链表指定位置插入数据
list 循环链表
loc 第loc位置插入元素,loc 从1 开始计数
data 插入元素的数据域
*/
int InsertCLinkNode(CLinkList list,int loc, EleType data)
{
	if (list == NULL || loc < 1)
		return ERROR;
	/*
	循环目的:找到第loc-1位置结点
	*/
	int i = 1;
	CLinkNode* node = list;//刚开始node指向头结点
	while (node->next!=list && i < loc)
	{
		node = node->next;
		i++;
	}
	if (i == loc)
	{
		CLinkNode* new_node = (CLinkNode*)malloc(sizeof(CLinkNode));
		if (new_node == NULL)
		{
			exit(0);
		}
		new_node->data = data;
		new_node->next = node->next;//新结点指针域 指向前驱结点的后继结点
		node->next = new_node;//将新结点加入链表
	}
	else
	{
		return	ERROR;
	}
 
	return OK;
}
/*
删除指定结点,通过指针返回删除结点的数据,并保存至data
*/
int DelCLinkNode(CLinkList list,int loc, EleType* data)
{
	if (list == NULL || loc < 1)
		return ERROR;
	/*
	循环目的:找到第loc-1位置结点
	*/
	int i = 1;// 按人类的读法 i表示第i个位置 和 loc 表达意思一致
	CLinkNode* node = list;//刚开始node指向头结点
	while (node->next != list && i < loc)
	{
		node = node->next;
		i++;
	}
	//循环结束 node 指向 loc-1 位置 且 node 不能为尾结点,为什么不能为尾结点?因为不能删除 位置上没有元素的结点!
	if (i == loc && node->next != list)
	{
        // 请在下面的Begin-End之间补充代码,完成对结点的删除。
        /********** Begin *********/
        CLinkNode* del_node = node->next; //第loc位置的结点
        *data = del_node->data; //返回删除结点的数据域
        node->next = del_node->next; //删除结点的前驱结点指向删除节点的后继结点
        free(del_node);
        /********** End **********/
 
	}
	return OK;
}
/*
展示循环链表元素
*/
int ShowCLinkList(CLinkList list)
{
	if (list == NULL)
	{
		return ERROR;
	}
	CLinkNode* target = NULL;
	
	for (target = list->next; target != list; target = target->next)
		printf("%d \t",target->data);
	printf("\n");
	return OK;
}
int main(int argc, char *argv[])
{
	int flag = 0;
	CLinkList list = NULL;
	list = NULL;
	InitCLinkList(&list);
	printf("--------循环链表初始元素------\n");
	ShowCLinkList(list); 
	int loc = 2;
	int data = 0;
	DelCLinkNode(list, loc, &data);
	printf("--------删除第二个结点后------\n");
	ShowCLinkList(list); 
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

STRUGGLE_xlf

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

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

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

打赏作者

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

抵扣说明:

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

余额充值